diff options
Diffstat (limited to 'ext/psych')
54 files changed, 3460 insertions, 1331 deletions
diff --git a/ext/psych/.gitignore b/ext/psych/.gitignore new file mode 100644 index 0000000000..92946455b0 --- /dev/null +++ b/ext/psych/.gitignore @@ -0,0 +1 @@ +/yaml-[0-9]*.*.* diff --git a/ext/psych/depend b/ext/psych/depend new file mode 100644 index 0000000000..95175841a2 --- /dev/null +++ b/ext/psych/depend @@ -0,0 +1,906 @@ +$(TARGET_SO): $(LIBYAML) + +libyaml $(LIBYAML): + cd libyaml && $(MAKE) + $(AR) $(ARFLAGS) $(LIBYAML) $(LIBYAML_OBJDIR)/*.$(OBJEXT) + $(RANLIB) $(LIBYAML) + +clean-so:: + -cd libyaml && $(MAKE) clean + +distclean-so:: + -cd libyaml && $(MAKE) distclean + -$(Q)$(RMDIRS) libyaml/* libyaml + +# AUTOGENERATED DEPENDENCIES START +psych.o: $(RUBY_EXTCONF_H) +psych.o: $(arch_hdrdir)/ruby/config.h +psych.o: $(hdrdir)/ruby.h +psych.o: $(hdrdir)/ruby/assert.h +psych.o: $(hdrdir)/ruby/backward.h +psych.o: $(hdrdir)/ruby/backward/2/assume.h +psych.o: $(hdrdir)/ruby/backward/2/attributes.h +psych.o: $(hdrdir)/ruby/backward/2/bool.h +psych.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych.o: $(hdrdir)/ruby/backward/2/limits.h +psych.o: $(hdrdir)/ruby/backward/2/long_long.h +psych.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych.o: $(hdrdir)/ruby/defines.h +psych.o: $(hdrdir)/ruby/encoding.h +psych.o: $(hdrdir)/ruby/intern.h +psych.o: $(hdrdir)/ruby/internal/abi.h +psych.o: $(hdrdir)/ruby/internal/anyargs.h +psych.o: $(hdrdir)/ruby/internal/arithmetic.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych.o: $(hdrdir)/ruby/internal/assume.h +psych.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych.o: $(hdrdir)/ruby/internal/attr/cold.h +psych.o: $(hdrdir)/ruby/internal/attr/const.h +psych.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych.o: $(hdrdir)/ruby/internal/attr/error.h +psych.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych.o: $(hdrdir)/ruby/internal/attr/format.h +psych.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych.o: $(hdrdir)/ruby/internal/attr/pure.h +psych.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych.o: $(hdrdir)/ruby/internal/attr/warning.h +psych.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych.o: $(hdrdir)/ruby/internal/cast.h +psych.o: $(hdrdir)/ruby/internal/compiler_is.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych.o: $(hdrdir)/ruby/internal/compiler_since.h +psych.o: $(hdrdir)/ruby/internal/config.h +psych.o: $(hdrdir)/ruby/internal/constant_p.h +psych.o: $(hdrdir)/ruby/internal/core.h +psych.o: $(hdrdir)/ruby/internal/core/rarray.h +psych.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych.o: $(hdrdir)/ruby/internal/core/rclass.h +psych.o: $(hdrdir)/ruby/internal/core/rdata.h +psych.o: $(hdrdir)/ruby/internal/core/rfile.h +psych.o: $(hdrdir)/ruby/internal/core/rhash.h +psych.o: $(hdrdir)/ruby/internal/core/robject.h +psych.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych.o: $(hdrdir)/ruby/internal/core/rstring.h +psych.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych.o: $(hdrdir)/ruby/internal/ctype.h +psych.o: $(hdrdir)/ruby/internal/dllexport.h +psych.o: $(hdrdir)/ruby/internal/dosish.h +psych.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych.o: $(hdrdir)/ruby/internal/encoding/re.h +psych.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych.o: $(hdrdir)/ruby/internal/encoding/string.h +psych.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych.o: $(hdrdir)/ruby/internal/error.h +psych.o: $(hdrdir)/ruby/internal/eval.h +psych.o: $(hdrdir)/ruby/internal/event.h +psych.o: $(hdrdir)/ruby/internal/fl_type.h +psych.o: $(hdrdir)/ruby/internal/gc.h +psych.o: $(hdrdir)/ruby/internal/glob.h +psych.o: $(hdrdir)/ruby/internal/globals.h +psych.o: $(hdrdir)/ruby/internal/has/attribute.h +psych.o: $(hdrdir)/ruby/internal/has/builtin.h +psych.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych.o: $(hdrdir)/ruby/internal/has/extension.h +psych.o: $(hdrdir)/ruby/internal/has/feature.h +psych.o: $(hdrdir)/ruby/internal/has/warning.h +psych.o: $(hdrdir)/ruby/internal/intern/array.h +psych.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych.o: $(hdrdir)/ruby/internal/intern/class.h +psych.o: $(hdrdir)/ruby/internal/intern/compar.h +psych.o: $(hdrdir)/ruby/internal/intern/complex.h +psych.o: $(hdrdir)/ruby/internal/intern/cont.h +psych.o: $(hdrdir)/ruby/internal/intern/dir.h +psych.o: $(hdrdir)/ruby/internal/intern/enum.h +psych.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych.o: $(hdrdir)/ruby/internal/intern/error.h +psych.o: $(hdrdir)/ruby/internal/intern/eval.h +psych.o: $(hdrdir)/ruby/internal/intern/file.h +psych.o: $(hdrdir)/ruby/internal/intern/hash.h +psych.o: $(hdrdir)/ruby/internal/intern/io.h +psych.o: $(hdrdir)/ruby/internal/intern/load.h +psych.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych.o: $(hdrdir)/ruby/internal/intern/object.h +psych.o: $(hdrdir)/ruby/internal/intern/parse.h +psych.o: $(hdrdir)/ruby/internal/intern/proc.h +psych.o: $(hdrdir)/ruby/internal/intern/process.h +psych.o: $(hdrdir)/ruby/internal/intern/random.h +psych.o: $(hdrdir)/ruby/internal/intern/range.h +psych.o: $(hdrdir)/ruby/internal/intern/rational.h +psych.o: $(hdrdir)/ruby/internal/intern/re.h +psych.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych.o: $(hdrdir)/ruby/internal/intern/select.h +psych.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych.o: $(hdrdir)/ruby/internal/intern/set.h +psych.o: $(hdrdir)/ruby/internal/intern/signal.h +psych.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych.o: $(hdrdir)/ruby/internal/intern/string.h +psych.o: $(hdrdir)/ruby/internal/intern/struct.h +psych.o: $(hdrdir)/ruby/internal/intern/thread.h +psych.o: $(hdrdir)/ruby/internal/intern/time.h +psych.o: $(hdrdir)/ruby/internal/intern/variable.h +psych.o: $(hdrdir)/ruby/internal/intern/vm.h +psych.o: $(hdrdir)/ruby/internal/interpreter.h +psych.o: $(hdrdir)/ruby/internal/iterator.h +psych.o: $(hdrdir)/ruby/internal/memory.h +psych.o: $(hdrdir)/ruby/internal/method.h +psych.o: $(hdrdir)/ruby/internal/module.h +psych.o: $(hdrdir)/ruby/internal/newobj.h +psych.o: $(hdrdir)/ruby/internal/scan_args.h +psych.o: $(hdrdir)/ruby/internal/special_consts.h +psych.o: $(hdrdir)/ruby/internal/static_assert.h +psych.o: $(hdrdir)/ruby/internal/stdalign.h +psych.o: $(hdrdir)/ruby/internal/stdbool.h +psych.o: $(hdrdir)/ruby/internal/stdckdint.h +psych.o: $(hdrdir)/ruby/internal/symbol.h +psych.o: $(hdrdir)/ruby/internal/value.h +psych.o: $(hdrdir)/ruby/internal/value_type.h +psych.o: $(hdrdir)/ruby/internal/variable.h +psych.o: $(hdrdir)/ruby/internal/warning_push.h +psych.o: $(hdrdir)/ruby/internal/xmalloc.h +psych.o: $(hdrdir)/ruby/missing.h +psych.o: $(hdrdir)/ruby/onigmo.h +psych.o: $(hdrdir)/ruby/oniguruma.h +psych.o: $(hdrdir)/ruby/ruby.h +psych.o: $(hdrdir)/ruby/st.h +psych.o: $(hdrdir)/ruby/subst.h +psych.o: psych.c +psych.o: psych.h +psych.o: psych_emitter.h +psych.o: psych_parser.h +psych.o: psych_to_ruby.h +psych.o: psych_yaml_tree.h +psych_emitter.o: $(RUBY_EXTCONF_H) +psych_emitter.o: $(arch_hdrdir)/ruby/config.h +psych_emitter.o: $(hdrdir)/ruby.h +psych_emitter.o: $(hdrdir)/ruby/assert.h +psych_emitter.o: $(hdrdir)/ruby/backward.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/assume.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/bool.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/limits.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_emitter.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_emitter.o: $(hdrdir)/ruby/defines.h +psych_emitter.o: $(hdrdir)/ruby/encoding.h +psych_emitter.o: $(hdrdir)/ruby/intern.h +psych_emitter.o: $(hdrdir)/ruby/internal/abi.h +psych_emitter.o: $(hdrdir)/ruby/internal/anyargs.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_emitter.o: $(hdrdir)/ruby/internal/assume.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/const.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/format.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_emitter.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_emitter.o: $(hdrdir)/ruby/internal/cast.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_emitter.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_emitter.o: $(hdrdir)/ruby/internal/config.h +psych_emitter.o: $(hdrdir)/ruby/internal/constant_p.h +psych_emitter.o: $(hdrdir)/ruby/internal/core.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/robject.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_emitter.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_emitter.o: $(hdrdir)/ruby/internal/ctype.h +psych_emitter.o: $(hdrdir)/ruby/internal/dllexport.h +psych_emitter.o: $(hdrdir)/ruby/internal/dosish.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_emitter.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_emitter.o: $(hdrdir)/ruby/internal/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/eval.h +psych_emitter.o: $(hdrdir)/ruby/internal/event.h +psych_emitter.o: $(hdrdir)/ruby/internal/fl_type.h +psych_emitter.o: $(hdrdir)/ruby/internal/gc.h +psych_emitter.o: $(hdrdir)/ruby/internal/glob.h +psych_emitter.o: $(hdrdir)/ruby/internal/globals.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/extension.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/feature.h +psych_emitter.o: $(hdrdir)/ruby/internal/has/warning.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/array.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/class.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/error.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/file.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/io.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/load.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/object.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/process.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/random.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/range.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/re.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/select.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/set.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/string.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/time.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_emitter.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_emitter.o: $(hdrdir)/ruby/internal/interpreter.h +psych_emitter.o: $(hdrdir)/ruby/internal/iterator.h +psych_emitter.o: $(hdrdir)/ruby/internal/memory.h +psych_emitter.o: $(hdrdir)/ruby/internal/method.h +psych_emitter.o: $(hdrdir)/ruby/internal/module.h +psych_emitter.o: $(hdrdir)/ruby/internal/newobj.h +psych_emitter.o: $(hdrdir)/ruby/internal/scan_args.h +psych_emitter.o: $(hdrdir)/ruby/internal/special_consts.h +psych_emitter.o: $(hdrdir)/ruby/internal/static_assert.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdalign.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdbool.h +psych_emitter.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_emitter.o: $(hdrdir)/ruby/internal/symbol.h +psych_emitter.o: $(hdrdir)/ruby/internal/value.h +psych_emitter.o: $(hdrdir)/ruby/internal/value_type.h +psych_emitter.o: $(hdrdir)/ruby/internal/variable.h +psych_emitter.o: $(hdrdir)/ruby/internal/warning_push.h +psych_emitter.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_emitter.o: $(hdrdir)/ruby/missing.h +psych_emitter.o: $(hdrdir)/ruby/onigmo.h +psych_emitter.o: $(hdrdir)/ruby/oniguruma.h +psych_emitter.o: $(hdrdir)/ruby/ruby.h +psych_emitter.o: $(hdrdir)/ruby/st.h +psych_emitter.o: $(hdrdir)/ruby/subst.h +psych_emitter.o: psych.h +psych_emitter.o: psych_emitter.c +psych_emitter.o: psych_emitter.h +psych_emitter.o: psych_parser.h +psych_emitter.o: psych_to_ruby.h +psych_emitter.o: psych_yaml_tree.h +psych_parser.o: $(RUBY_EXTCONF_H) +psych_parser.o: $(arch_hdrdir)/ruby/config.h +psych_parser.o: $(hdrdir)/ruby.h +psych_parser.o: $(hdrdir)/ruby/assert.h +psych_parser.o: $(hdrdir)/ruby/backward.h +psych_parser.o: $(hdrdir)/ruby/backward/2/assume.h +psych_parser.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/bool.h +psych_parser.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_parser.o: $(hdrdir)/ruby/backward/2/limits.h +psych_parser.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_parser.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_parser.o: $(hdrdir)/ruby/defines.h +psych_parser.o: $(hdrdir)/ruby/encoding.h +psych_parser.o: $(hdrdir)/ruby/intern.h +psych_parser.o: $(hdrdir)/ruby/internal/abi.h +psych_parser.o: $(hdrdir)/ruby/internal/anyargs.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_parser.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_parser.o: $(hdrdir)/ruby/internal/assume.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/const.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/error.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/format.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_parser.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_parser.o: $(hdrdir)/ruby/internal/cast.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_parser.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_parser.o: $(hdrdir)/ruby/internal/config.h +psych_parser.o: $(hdrdir)/ruby/internal/constant_p.h +psych_parser.o: $(hdrdir)/ruby/internal/core.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_parser.o: $(hdrdir)/ruby/internal/core/robject.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_parser.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_parser.o: $(hdrdir)/ruby/internal/ctype.h +psych_parser.o: $(hdrdir)/ruby/internal/dllexport.h +psych_parser.o: $(hdrdir)/ruby/internal/dosish.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_parser.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_parser.o: $(hdrdir)/ruby/internal/error.h +psych_parser.o: $(hdrdir)/ruby/internal/eval.h +psych_parser.o: $(hdrdir)/ruby/internal/event.h +psych_parser.o: $(hdrdir)/ruby/internal/fl_type.h +psych_parser.o: $(hdrdir)/ruby/internal/gc.h +psych_parser.o: $(hdrdir)/ruby/internal/glob.h +psych_parser.o: $(hdrdir)/ruby/internal/globals.h +psych_parser.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_parser.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_parser.o: $(hdrdir)/ruby/internal/has/extension.h +psych_parser.o: $(hdrdir)/ruby/internal/has/feature.h +psych_parser.o: $(hdrdir)/ruby/internal/has/warning.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/array.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/class.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/error.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/file.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/io.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/load.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/object.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/process.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/random.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/range.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/re.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/select.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/set.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/string.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/time.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_parser.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_parser.o: $(hdrdir)/ruby/internal/interpreter.h +psych_parser.o: $(hdrdir)/ruby/internal/iterator.h +psych_parser.o: $(hdrdir)/ruby/internal/memory.h +psych_parser.o: $(hdrdir)/ruby/internal/method.h +psych_parser.o: $(hdrdir)/ruby/internal/module.h +psych_parser.o: $(hdrdir)/ruby/internal/newobj.h +psych_parser.o: $(hdrdir)/ruby/internal/scan_args.h +psych_parser.o: $(hdrdir)/ruby/internal/special_consts.h +psych_parser.o: $(hdrdir)/ruby/internal/static_assert.h +psych_parser.o: $(hdrdir)/ruby/internal/stdalign.h +psych_parser.o: $(hdrdir)/ruby/internal/stdbool.h +psych_parser.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_parser.o: $(hdrdir)/ruby/internal/symbol.h +psych_parser.o: $(hdrdir)/ruby/internal/value.h +psych_parser.o: $(hdrdir)/ruby/internal/value_type.h +psych_parser.o: $(hdrdir)/ruby/internal/variable.h +psych_parser.o: $(hdrdir)/ruby/internal/warning_push.h +psych_parser.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_parser.o: $(hdrdir)/ruby/missing.h +psych_parser.o: $(hdrdir)/ruby/onigmo.h +psych_parser.o: $(hdrdir)/ruby/oniguruma.h +psych_parser.o: $(hdrdir)/ruby/ruby.h +psych_parser.o: $(hdrdir)/ruby/st.h +psych_parser.o: $(hdrdir)/ruby/subst.h +psych_parser.o: psych.h +psych_parser.o: psych_emitter.h +psych_parser.o: psych_parser.c +psych_parser.o: psych_parser.h +psych_parser.o: psych_to_ruby.h +psych_parser.o: psych_yaml_tree.h +psych_to_ruby.o: $(RUBY_EXTCONF_H) +psych_to_ruby.o: $(arch_hdrdir)/ruby/config.h +psych_to_ruby.o: $(hdrdir)/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/assert.h +psych_to_ruby.o: $(hdrdir)/ruby/backward.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/assume.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/bool.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/limits.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_to_ruby.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_to_ruby.o: $(hdrdir)/ruby/defines.h +psych_to_ruby.o: $(hdrdir)/ruby/encoding.h +psych_to_ruby.o: $(hdrdir)/ruby/intern.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/abi.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/anyargs.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/assume.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/const.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/format.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/cast.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/config.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/constant_p.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/robject.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/ctype.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/dllexport.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/dosish.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/eval.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/event.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/fl_type.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/gc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/glob.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/globals.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/extension.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/feature.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/has/warning.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/array.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/class.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/error.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/file.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/io.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/load.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/object.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/process.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/random.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/range.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/re.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/set.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/string.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/time.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/interpreter.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/iterator.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/memory.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/method.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/module.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/newobj.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/scan_args.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/special_consts.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/static_assert.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdalign.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdbool.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/symbol.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/value.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/value_type.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/variable.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/warning_push.h +psych_to_ruby.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_to_ruby.o: $(hdrdir)/ruby/missing.h +psych_to_ruby.o: $(hdrdir)/ruby/onigmo.h +psych_to_ruby.o: $(hdrdir)/ruby/oniguruma.h +psych_to_ruby.o: $(hdrdir)/ruby/ruby.h +psych_to_ruby.o: $(hdrdir)/ruby/st.h +psych_to_ruby.o: $(hdrdir)/ruby/subst.h +psych_to_ruby.o: psych.h +psych_to_ruby.o: psych_emitter.h +psych_to_ruby.o: psych_parser.h +psych_to_ruby.o: psych_to_ruby.c +psych_to_ruby.o: psych_to_ruby.h +psych_to_ruby.o: psych_yaml_tree.h +psych_yaml_tree.o: $(RUBY_EXTCONF_H) +psych_yaml_tree.o: $(arch_hdrdir)/ruby/config.h +psych_yaml_tree.o: $(hdrdir)/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/assert.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/assume.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/attributes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/bool.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/inttypes.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/limits.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/long_long.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdalign.h +psych_yaml_tree.o: $(hdrdir)/ruby/backward/2/stdarg.h +psych_yaml_tree.o: $(hdrdir)/ruby/defines.h +psych_yaml_tree.o: $(hdrdir)/ruby/encoding.h +psych_yaml_tree.o: $(hdrdir)/ruby/intern.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/abi.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/anyargs.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/char.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/double.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/fixnum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/gid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/int.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/intptr_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/long.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/long_long.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/mode_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/off_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/pid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/short.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/size_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/st_data_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/arithmetic/uid_t.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/assume.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/alloc_size.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/artificial.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/cold.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/const.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/constexpr.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/deprecated.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/diagnose_if.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/enum_extensibility.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/flag_enum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/forceinline.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/format.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/maybe_unused.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noalias.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nodiscard.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noexcept.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noinline.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/nonnull.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/noreturn.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/packed_struct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/pure.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/restrict.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/returns_nonnull.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/warning.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/attr/weakref.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/cast.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/apple.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/clang.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/gcc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/intel.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/msvc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_is/sunpro.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/compiler_since.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/config.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/constant_p.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rarray.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rbasic.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rbignum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rclass.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rdata.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rfile.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rhash.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/robject.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rregexp.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rstring.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rstruct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/core/rtypeddata.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/ctype.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/dllexport.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/dosish.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/coderange.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/ctype.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/encoding.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/pathname.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/re.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/sprintf.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/string.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/symbol.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/encoding/transcode.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/eval.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/event.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/fl_type.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/gc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/glob.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/globals.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/builtin.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/c_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/cpp_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/declspec_attribute.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/extension.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/feature.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/has/warning.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/array.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/bignum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/class.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/compar.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/complex.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/cont.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/dir.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enum.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/enumerator.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/error.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/eval.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/file.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/hash.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/io.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/load.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/marshal.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/numeric.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/object.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/parse.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/proc.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/process.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/random.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/range.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/rational.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/re.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/select/largesize.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/set.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/signal.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/sprintf.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/string.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/struct.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/thread.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/time.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/variable.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/intern/vm.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/interpreter.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/iterator.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/memory.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/method.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/module.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/newobj.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/scan_args.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/special_consts.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/static_assert.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdalign.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdbool.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/stdckdint.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/symbol.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/value.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/value_type.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/variable.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/warning_push.h +psych_yaml_tree.o: $(hdrdir)/ruby/internal/xmalloc.h +psych_yaml_tree.o: $(hdrdir)/ruby/missing.h +psych_yaml_tree.o: $(hdrdir)/ruby/onigmo.h +psych_yaml_tree.o: $(hdrdir)/ruby/oniguruma.h +psych_yaml_tree.o: $(hdrdir)/ruby/ruby.h +psych_yaml_tree.o: $(hdrdir)/ruby/st.h +psych_yaml_tree.o: $(hdrdir)/ruby/subst.h +psych_yaml_tree.o: psych.h +psych_yaml_tree.o: psych_emitter.h +psych_yaml_tree.o: psych_parser.h +psych_yaml_tree.o: psych_to_ruby.h +psych_yaml_tree.o: psych_yaml_tree.c +psych_yaml_tree.o: psych_yaml_tree.h +# AUTOGENERATED DEPENDENCIES END diff --git a/ext/psych/extconf.rb b/ext/psych/extconf.rb index ccc8c9c304..589e201c1c 100644 --- a/ext/psych/extconf.rb +++ b/ext/psych/extconf.rb @@ -1,16 +1,56 @@ +# -*- coding: us-ascii -*- +# frozen_string_literal: true require 'mkmf' -# :stopdoc: +if $mswin or $mingw or $cygwin + $CPPFLAGS << " -DYAML_DECLARE_STATIC" +end -dir_config 'libyaml' +yaml_source = with_config("libyaml-source-dir") +if yaml_source + yaml_source = yaml_source.gsub(/\$\((\w+)\)|\$\{(\w+)\}/) {ENV[$1||$2]} + yaml_source = yaml_source.chomp("/") + yaml_configure = "#{File.expand_path(yaml_source)}/configure" + unless File.exist?(yaml_configure) + raise "Configure script not found in #{yaml_source.quote}" + end -def asplode missing - raise "#{missing} is missing. Please install libyaml." -end + puts("Configuring libyaml source in #{yaml_source.quote}") + yaml = "libyaml" + Dir.mkdir(yaml) unless File.directory?(yaml) + shared = $enable_shared || !$static + args = [ + yaml_configure, + "--enable-#{shared ? 'shared' : 'static'}", + "--host=#{RbConfig::CONFIG['host'].sub(/-unknown-/, '-').sub(/arm64/, 'arm')}", + "CC=#{RbConfig::CONFIG['CC']}", + *(["CFLAGS=-w"] if RbConfig::CONFIG["GCC"] == "yes"), + ] + puts(args.quote.join(' ')) + unless system(*args, chdir: yaml) + raise "failed to configure libyaml" + end + inc = yaml_source.start_with?("#$srcdir/") ? "$(srcdir)#{yaml_source[$srcdir.size..-1]}" : yaml_source + $INCFLAGS << " -I#{yaml}/include -I#{inc}/include" + puts("INCFLAGS=#$INCFLAGS") + libyaml = "libyaml.#$LIBEXT" + $cleanfiles << libyaml + $LOCAL_LIBS.prepend("$(LIBYAML) ") -asplode('yaml.h') unless find_header 'yaml.h' -asplode('libyaml') unless find_library 'yaml', 'yaml_get_version' + # default to pre-installed libyaml +elsif pkg_config('yaml-0.1') + # found with pkg-config +else + dir_config('libyaml') + find_header('yaml.h') or abort "yaml.h not found" + find_library('yaml', 'yaml_get_version') or abort "libyaml not found" +end -create_makefile 'psych' +create_makefile 'psych' do |mk| + mk << "LIBYAML = #{libyaml}".strip << "\n" + mk << "LIBYAML_OBJDIR = libyaml/src#{shared ? '/.libs' : ''}\n" + mk << "OBJEXT = #$OBJEXT" + mk << "RANLIB = #{config_string('RANLIB') || config_string('NULLCMD')}\n" +end # :startdoc: diff --git a/ext/psych/lib/psych.rb b/ext/psych/lib/psych.rb index 19d8b2bc12..850a6d1937 100644 --- a/ext/psych/lib/psych.rb +++ b/ext/psych/lib/psych.rb @@ -1,27 +1,43 @@ -require 'psych.so' -require 'psych/nodes' -require 'psych/streaming' -require 'psych/visitors' -require 'psych/handler' -require 'psych/tree_builder' -require 'psych/parser' -require 'psych/omap' -require 'psych/set' -require 'psych/coder' -require 'psych/core_ext' -require 'psych/deprecated' -require 'psych/stream' -require 'psych/json/tree_builder' -require 'psych/json/stream' -require 'psych/handlers/document_stream' +# frozen_string_literal: true +require 'date' + +require_relative 'psych/versions' +case RUBY_ENGINE +when 'jruby' + require_relative 'psych_jars' + if JRuby::Util.respond_to?(:load_ext) + JRuby::Util.load_ext('org.jruby.ext.psych.PsychLibrary') + else + require 'java'; require 'jruby' + org.jruby.ext.psych.PsychLibrary.new.load(JRuby.runtime, false) + end +else + require 'psych.so' +end +require_relative 'psych/nodes' +require_relative 'psych/streaming' +require_relative 'psych/visitors' +require_relative 'psych/handler' +require_relative 'psych/tree_builder' +require_relative 'psych/parser' +require_relative 'psych/omap' +require_relative 'psych/set' +require_relative 'psych/coder' +require_relative 'psych/stream' +require_relative 'psych/json/tree_builder' +require_relative 'psych/json/stream' +require_relative 'psych/handlers/document_stream' +require_relative 'psych/class_loader' ### # = Overview # -# Psych is a YAML parser and emitter. Psych leverages -# libyaml[http://libyaml.org] for it's YAML parsing and emitting capabilities. -# In addition to wrapping libyaml, Psych also knows how to serialize and -# de-serialize most Ruby objects to and from the YAML format. +# Psych is a YAML parser and emitter. +# Psych leverages libyaml [Home page: https://pyyaml.org/wiki/LibYAML] +# or [git repo: https://github.com/yaml/libyaml] for its YAML parsing +# and emitting capabilities. In addition to wrapping libyaml, Psych also +# knows how to serialize and de-serialize most Ruby objects to and from +# the YAML format. # # = I NEED TO PARSE OR EMIT YAML RIGHT NOW! # @@ -39,16 +55,77 @@ require 'psych/handlers/document_stream' # Psych provides a range of interfaces for parsing a YAML document ranging from # low level to high level, depending on your parsing needs. At the lowest # level, is an event based parser. Mid level is access to the raw YAML AST, -# and at the highest level is the ability to unmarshal YAML to ruby objects. +# and at the highest level is the ability to unmarshal YAML to Ruby objects. # -# === Low level parsing +# == YAML Emitting # -# The lowest level parser should be used when the YAML input is already known, -# and the developer does not want to pay the price of building an AST or -# automatic detection and conversion to ruby objects. See Psych::Parser for -# more information on using the event based parser. +# Psych provides a range of interfaces ranging from low to high level for +# producing YAML documents. Very similar to the YAML parsing interfaces, Psych +# provides at the lowest level, an event based system, mid-level is building +# a YAML AST, and the highest level is converting a Ruby object straight to +# a YAML document. +# +# == High-level API +# +# === Parsing +# +# The high level YAML parser provided by Psych simply takes YAML as input and +# returns a Ruby data structure. For information on using the high level parser +# see Psych.load +# +# ==== Reading from a string +# +# Psych.safe_load("--- a") # => 'a' +# Psych.safe_load("---\n - a\n - b") # => ['a', 'b'] +# # From a trusted string: +# Psych.load("--- !ruby/range\nbegin: 0\nend: 42\nexcl: false\n") # => 0..42 +# +# ==== Reading from a file +# +# Psych.safe_load_file("data.yml", permitted_classes: [Date]) +# Psych.load_file("trusted_database.yml") +# +# ==== \Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# === Emitting +# +# The high level emitter has the easiest interface. Psych simply takes a Ruby +# data structure and converts it to a YAML document. See Psych.dump for more +# information on dumping a Ruby data structure. +# +# ==== Writing to a string +# +# # Dump an array, get back a YAML string +# Psych.dump(['a', 'b']) # => "---\n- a\n- b\n" +# +# # Dump an array to an IO object +# Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> +# +# # Dump an array with indentation set +# Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" +# +# # Dump an array to an IO with indentation set +# Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) # -# === Mid level parsing +# ==== Writing to a file +# +# Currently there is no direct API for dumping Ruby structure to file: +# +# File.open('database.yml', 'w') do |file| +# file.write(Psych.dump(['a', 'b'])) +# end +# +# == Mid-level API +# +# === Parsing # # Psych provides access to an AST produced from parsing a YAML document. This # tree is built using the Psych::Parser and Psych::TreeBuilder. The AST can @@ -56,28 +133,33 @@ require 'psych/handlers/document_stream' # Psych::Nodes, and Psych::Nodes::Node for more information on dealing with # YAML syntax trees. # -# === High level parsing +# ==== Reading from a string # -# The high level YAML parser provided by Psych simply takes YAML as input and -# returns a Ruby data structure. For information on using the high level parser -# see Psych.load +# # Returns Psych::Nodes::Stream +# Psych.parse_stream("---\n - a\n - b") # -# == YAML Emitting +# # Returns Psych::Nodes::Document +# Psych.parse("---\n - a\n - b") # -# Psych provides a range of interfaces ranging from low to high level for -# producing YAML documents. Very similar to the YAML parsing interfaces, Psych -# provides at the lowest level, an event based system, mid-level is building -# a YAML AST, and the highest level is converting a Ruby object straight to -# a YAML document. +# ==== Reading from a file # -# === Low level emitting +# # Returns Psych::Nodes::Stream +# Psych.parse_stream(File.read('database.yml')) # -# The lowest level emitter is an event based system. Events are sent to a -# Psych::Emitter object. That object knows how to convert the events to a YAML -# document. This interface should be used when document format is known in -# advance or speed is a concern. See Psych::Emitter for more information. +# # Returns Psych::Nodes::Document +# Psych.parse_file('database.yml') # -# === Mid level emitting +# ==== \Exception handling +# +# begin +# # The second argument changes only the exception contents +# Psych.parse("--- `", "file.txt") +# rescue Psych::SyntaxError => ex +# ex.file # => 'file.txt' +# ex.message # => "(file.txt): found character that cannot start any token" +# end +# +# === Emitting # # At the mid level is building an AST. This AST is exactly the same as the AST # used when parsing a YAML document. Users can build an AST by hand and the @@ -85,30 +167,181 @@ require 'psych/handlers/document_stream' # Psych::Nodes::Node, and Psych::TreeBuilder for more information on building # a YAML AST. # -# === High level emitting +# ==== Writing to a string # -# The high level emitter has the easiest interface. Psych simply takes a Ruby -# data structure and converts it to a YAML document. See Psych.dump for more -# information on dumping a Ruby data structure. +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream("---\n - a\n - b") +# +# stream.to_yaml # => "---\n- a\n- b\n" +# +# ==== Writing to a file +# +# # We need Psych::Nodes::Stream (not Psych::Nodes::Document) +# stream = Psych.parse_stream(File.read('database.yml')) +# +# File.open('database.yml', 'w') do |file| +# file.write(stream.to_yaml) +# end +# +# == Low-level API +# +# === Parsing +# +# The lowest level parser should be used when the YAML input is already known, +# and the developer does not want to pay the price of building an AST or +# automatic detection and conversion to Ruby objects. See Psych::Parser for +# more information on using the event based parser. +# +# ==== Reading to Psych::Nodes::Stream structure +# +# parser = Psych::Parser.new(TreeBuilder.new) # => #<Psych::Parser> +# parser = Psych.parser # it's an alias for the above +# +# parser.parse("---\n - a\n - b") # => #<Psych::Parser> +# parser.handler # => #<Psych::TreeBuilder> +# parser.handler.root # => #<Psych::Nodes::Stream> +# +# ==== Receiving an events stream +# +# recorder = Psych::Handlers::Recorder.new +# parser = Psych::Parser.new(recorder) +# +# parser.parse("---\n - a\n - b") +# recorder.events # => [list of [event, args] lists] +# # event is one of: Psych::Handler::EVENTS +# # args are the arguments passed to the event +# +# === Emitting +# +# The lowest level emitter is an event based system. Events are sent to a +# Psych::Emitter object. That object knows how to convert the events to a YAML +# document. This interface should be used when document format is known in +# advance or speed is a concern. See Psych::Emitter for more information. +# +# ==== Writing to a Ruby structure +# +# Psych.parser.parse("--- a") # => #<Psych::Parser> +# +# parser.handler.first # => #<Psych::Nodes::Stream> +# parser.handler.first.to_ruby # => ["a"] +# +# parser.handler.root.first # => #<Psych::Nodes::Document> +# parser.handler.root.first.to_ruby # => "a" +# +# # You can instantiate an Emitter manually +# Psych::Visitors::ToRuby.new.accept(parser.handler.root.first) +# # => "a" module Psych - # The version is Psych you're using - VERSION = '1.3.4' - # The version of libyaml Psych is using - LIBYAML_VERSION = Psych.libyaml_version.join '.' + LIBYAML_VERSION = Psych.libyaml_version.join('.').freeze - class Exception < RuntimeError + ### + # Load +yaml+ in to a Ruby data structure. If multiple documents are + # provided, the object contained in the first document will be returned. + # +filename+ will be used in the exception message if any exception + # is raised while parsing. If +yaml+ is empty, it returns + # the specified +fallback+ return value, which defaults to +false+. + # + # Raises a Psych::SyntaxError when a YAML syntax error is detected. + # + # Example: + # + # Psych.unsafe_load("--- a") # => 'a' + # Psych.unsafe_load("---\n - a\n - b") # => ['a', 'b'] + # + # begin + # Psych.unsafe_load("--- `", filename: "file.txt") + # rescue Psych::SyntaxError => ex + # ex.file # => 'file.txt' + # ex.message # => "(file.txt): found character that cannot start any token" + # end + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.unsafe_load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.unsafe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + # Raises a TypeError when `yaml` parameter is NilClass + # + # NOTE: This method *should not* be used to parse untrusted documents, such as + # YAML documents that are supplied via user input. Instead, please use the + # load method or the safe_load method. + # + def self.unsafe_load yaml, filename: nil, fallback: false, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + result = parse(yaml, filename: filename) + return fallback unless result + result.to_ruby(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols) end - class BadAlias < Exception + ### + # Safely load the yaml string in +yaml+. By default, only the following + # classes are allowed to be deserialized: + # + # * TrueClass + # * FalseClass + # * NilClass + # * Integer + # * Float + # * String + # * Array + # * Hash + # + # Recursive data structures are not allowed by default. Arbitrary classes + # can be allowed by adding those classes to the +permitted_classes+ keyword argument. They are + # additive. For example, to allow Date deserialization: + # + # Psych.safe_load(yaml, permitted_classes: [Date]) + # + # Now the Date class can be loaded in addition to the classes listed above. + # + # Aliases can be explicitly allowed by changing the +aliases+ keyword argument. + # For example: + # + # x = [] + # x << x + # yaml = Psych.dump x + # Psych.safe_load yaml # => raises an exception + # Psych.safe_load yaml, aliases: true # => loads the aliases + # + # A Psych::DisallowedClass exception will be raised if the yaml contains a + # class that isn't in the +permitted_classes+ list. + # + # A Psych::AliasesNotEnabled exception will be raised if the yaml contains aliases + # but the +aliases+ keyword argument is set to false. + # + # +filename+ will be used in the exception message if any exception is raised + # while parsing. + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.safe_load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.safe_load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + def self.safe_load yaml, permitted_classes: [], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + result = parse(yaml, filename: filename) + return fallback unless result + + class_loader = ClassLoader::Restricted.new(permitted_classes.map(&:to_s), + permitted_symbols.map(&:to_s)) + scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols + visitor = if aliases + Visitors::ToRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze + else + Visitors::NoAliasRuby.new scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze + end + result = visitor.accept result + result end ### # Load +yaml+ in to a Ruby data structure. If multiple documents are # provided, the object contained in the first document will be returned. - # +filename+ will be used in the exception message if any exception is raised - # while parsing. + # +filename+ will be used in the exception message if any exception + # is raised while parsing. If +yaml+ is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. # @@ -118,18 +351,35 @@ module Psych # Psych.load("---\n - a\n - b") # => ['a', 'b'] # # begin - # Psych.load("--- `", "file.txt") + # Psych.load("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' - # ex.message # => "(foo.txt): found character that cannot start any token" + # ex.message # => "(file.txt): found character that cannot start any token" # end - def self.load yaml, filename = nil - result = parse(yaml, filename) - result ? result.to_ruby : result + # + # When the optional +symbolize_names+ keyword argument is set to a + # true value, returns symbols for keys in Hash objects (default: strings). + # + # Psych.load("---\n foo: bar") # => {"foo"=>"bar"} + # Psych.load("---\n foo: bar", symbolize_names: true) # => {:foo=>"bar"} + # + # Raises a TypeError when `yaml` parameter is NilClass. This method is + # similar to `safe_load` except that `Symbol` objects are allowed by default. + # + def self.load yaml, permitted_classes: [Symbol], permitted_symbols: [], aliases: false, filename: nil, fallback: nil, symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true + safe_load yaml, permitted_classes: permitted_classes, + permitted_symbols: permitted_symbols, + aliases: aliases, + filename: filename, + fallback: fallback, + symbolize_names: symbolize_names, + freeze: freeze, + strict_integer: strict_integer, + parse_symbols: parse_symbols end ### - # Parse a YAML string in +yaml+. Returns the first object of a YAML AST. + # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Document. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. # @@ -137,31 +387,33 @@ module Psych # # Example: # - # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Sequence:0x00> + # Psych.parse("---\n - a\n - b") # => #<Psych::Nodes::Document:0x00> # # begin - # Psych.parse("--- `", "file.txt") + # Psych.parse("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' - # ex.message # => "(foo.txt): found character that cannot start any token" + # ex.message # => "(file.txt): found character that cannot start any token" # end # # See Psych::Nodes for more information about YAML AST. - def self.parse yaml, filename = nil - parse_stream(yaml, filename) do |node| + def self.parse yaml, filename: nil + parse_stream(yaml, filename: filename) do |node| return node end + false end ### - # Parse a file at +filename+. Returns the YAML AST. + # Parse a file at +filename+. Returns the Psych::Nodes::Document. # # Raises a Psych::SyntaxError when a YAML syntax error is detected. - def self.parse_file filename - File.open filename, 'r:bom|utf-8' do |f| - parse f, filename + def self.parse_file filename, fallback: false + result = File.open filename, 'r:bom|utf-8' do |f| + parse f, filename: filename end + result || fallback end ### @@ -171,7 +423,7 @@ module Psych end ### - # Parse a YAML string in +yaml+. Returns the full AST for the YAML document. + # Parse a YAML string in +yaml+. Returns the Psych::Nodes::Stream. # This method can handle multiple YAML documents contained in +yaml+. # +filename+ is used in the exception message if a Psych::SyntaxError is # raised. @@ -190,14 +442,16 @@ module Psych # end # # begin - # Psych.parse_stream("--- `", "file.txt") + # Psych.parse_stream("--- `", filename: "file.txt") # rescue Psych::SyntaxError => ex # ex.file # => 'file.txt' - # ex.message # => "(foo.txt): found character that cannot start any token" + # ex.message # => "(file.txt): found character that cannot start any token" # end # + # Raises a TypeError when NilClass is passed. + # # See Psych::Nodes for more information about YAML AST. - def self.parse_stream yaml, filename = nil, &block + def self.parse_stream yaml, filename: nil, &block if block_given? parser = Psych::Parser.new(Handlers::DocumentStream.new(&block)) parser.parse yaml, filename @@ -219,6 +473,29 @@ module Psych # to control the output format. If an IO object is passed in, the YAML will # be dumped to that IO object. # + # Currently supported options are: + # + # [<tt>:indentation</tt>] Number of space characters used to indent. + # Acceptable value should be in <tt>0..9</tt> range, + # otherwise option is ignored. + # + # Default: <tt>2</tt>. + # [<tt>:line_width</tt>] Max character to wrap line at. + # For unlimited line width use <tt>-1</tt>. + # + # Default: <tt>0</tt> (meaning "wrap at 81"). + # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet + # strictly formal). + # + # Default: <tt>false</tt>. + # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document. + # + # Default: <tt>false</tt>. + # + # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string. + # + # Default: <tt>false</tt>. + # # Example: # # # Dump an array, get back a YAML string @@ -228,17 +505,101 @@ module Psych # Psych.dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> # # # Dump an array with indentation set - # Psych.dump(['a', ['b']], :indentation => 3) # => "---\n- a\n- - b\n" + # Psych.dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" # # # Dump an array to an IO with indentation set - # Psych.dump(['a', ['b']], StringIO.new, :indentation => 3) + # Psych.dump(['a', ['b']], StringIO.new, indentation: 3) + # + # # Dump hash with symbol keys as string + # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n" def self.dump o, io = nil, options = {} if Hash === io options = io io = nil end - visitor = Psych::Visitors::YAMLTree.new options + visitor = Psych::Visitors::YAMLTree.create options + visitor << o + visitor.tree.yaml io, options + end + + ### + # call-seq: + # Psych.safe_dump(o) -> string of yaml + # Psych.safe_dump(o, options) -> string of yaml + # Psych.safe_dump(o, io) -> io object passed in + # Psych.safe_dump(o, io, options) -> io object passed in + # + # Safely dump Ruby object +o+ to a YAML string. Optional +options+ may be passed in + # to control the output format. If an IO object is passed in, the YAML will + # be dumped to that IO object. By default, only the following + # classes are allowed to be serialized: + # + # * TrueClass + # * FalseClass + # * NilClass + # * Integer + # * Float + # * String + # * Array + # * Hash + # + # Arbitrary classes can be allowed by adding those classes to the +permitted_classes+ + # keyword argument. They are additive. For example, to allow Date serialization: + # + # Psych.safe_dump(yaml, permitted_classes: [Date]) + # + # Now the Date class can be dumped in addition to the classes listed above. + # + # A Psych::DisallowedClass exception will be raised if the object contains a + # class that isn't in the +permitted_classes+ list. + # + # Currently supported options are: + # + # [<tt>:indentation</tt>] Number of space characters used to indent. + # Acceptable value should be in <tt>0..9</tt> range, + # otherwise option is ignored. + # + # Default: <tt>2</tt>. + # [<tt>:line_width</tt>] Max character to wrap line at. + # For unlimited line width use <tt>-1</tt>. + # + # Default: <tt>0</tt> (meaning "wrap at 81"). + # [<tt>:canonical</tt>] Write "canonical" YAML form (very verbose, yet + # strictly formal). + # + # Default: <tt>false</tt>. + # [<tt>:header</tt>] Write <tt>%YAML [version]</tt> at the beginning of document. + # + # Default: <tt>false</tt>. + # + # [<tt>:stringify_names</tt>] Dump symbol keys in Hash objects as string. + # + # Default: <tt>false</tt>. + # + # Example: + # + # # Dump an array, get back a YAML string + # Psych.safe_dump(['a', 'b']) # => "---\n- a\n- b\n" + # + # # Dump an array to an IO object + # Psych.safe_dump(['a', 'b'], StringIO.new) # => #<StringIO:0x000001009d0890> + # + # # Dump an array with indentation set + # Psych.safe_dump(['a', ['b']], indentation: 3) # => "---\n- a\n- - b\n" + # + # # Dump an array to an IO with indentation set + # Psych.safe_dump(['a', ['b']], StringIO.new, indentation: 3) + # + # # Dump hash with symbol keys as string + # Psych.dump({a: "b"}, stringify_names: true) # => "---\na: b\n" + def self.safe_dump o, io = nil, options = {} + if Hash === io + options = io + io = nil + end + + visitor = Psych::Visitors::RestrictedYAMLTree.create options visitor << o visitor.tree.yaml io, options end @@ -250,7 +611,7 @@ module Psych # # Psych.dump_stream("foo\n ", {}) # => "--- ! \"foo\\n \"\n--- {}\n" def self.dump_stream *objects - visitor = Psych::Visitors::YAMLTree.new {} + visitor = Psych::Visitors::YAMLTree.create({}) objects.each do |o| visitor << o end @@ -258,16 +619,16 @@ module Psych end ### - # Dump Ruby object +o+ to a JSON string. - def self.to_json o - visitor = Psych::Visitors::JSONTree.new - visitor << o + # Dump Ruby +object+ to a JSON string. + def self.to_json object + visitor = Psych::Visitors::JSONTree.create + visitor << object visitor.tree.yaml end ### # Load multiple documents given in +yaml+. Returns the parsed documents - # as a list. If a block is given, each document will be converted to ruby + # as a list. If a block is given, each document will be converted to Ruby # and passed to the block during parsing # # Example: @@ -280,52 +641,154 @@ module Psych # end # list # => ['foo', 'bar'] # - def self.load_stream yaml, filename = nil + def self.load_stream yaml, filename: nil, fallback: [], **kwargs + result = if block_given? + parse_stream(yaml, filename: filename) do |node| + yield node.to_ruby(**kwargs) + end + else + parse_stream(yaml, filename: filename).children.map { |node| node.to_ruby(**kwargs) } + end + + return fallback if result.is_a?(Array) && result.empty? + result + end + + ### + # Load multiple documents given in +yaml+. Returns the parsed documents + # as a list. + # + # Example: + # + # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") # => ['foo', 'bar'] + # + # list = [] + # Psych.safe_load_stream("--- foo\n...\n--- bar\n...") do |ruby| + # list << ruby + # end + # list # => ['foo', 'bar'] + # + def self.safe_load_stream yaml, filename: nil, permitted_classes: [], aliases: false + documents = parse_stream(yaml, filename: filename).children.map do |child| + stream = Psych::Nodes::Stream.new + stream.children << child + safe_load(stream.to_yaml, permitted_classes: permitted_classes, aliases: aliases) + end + if block_given? - parse_stream(yaml, filename) do |node| - yield node.to_ruby - end + documents.each { |doc| yield doc } + nil else - parse_stream(yaml, filename).children.map { |child| child.to_ruby } + documents end end ### # Load the document contained in +filename+. Returns the yaml contained in - # +filename+ as a ruby object - def self.load_file filename - File.open(filename, 'r:bom|utf-8') { |f| self.load f, filename } + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +false+. + # + # NOTE: This method *should not* be used to parse untrusted documents, such as + # YAML documents that are supplied via user input. Instead, please use the + # safe_load_file method. + def self.unsafe_load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.unsafe_load f, filename: filename, **kwargs + } + end + + ### + # Safely loads the document contained in +filename+. Returns the yaml contained in + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. + # See safe_load for options. + def self.safe_load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.safe_load f, filename: filename, **kwargs + } + end + + ### + # Loads the document contained in +filename+. Returns the yaml contained in + # +filename+ as a Ruby object, or if the file is empty, it returns + # the specified +fallback+ return value, which defaults to +nil+. + # See load for options. + def self.load_file filename, **kwargs + File.open(filename, 'r:bom|utf-8') { |f| + self.load f, filename: filename, **kwargs + } end # :stopdoc: - @domain_types = {} def self.add_domain_type domain, type_tag, &block key = ['tag', domain, type_tag].join ':' - @domain_types[key] = [key, block] - @domain_types["tag:#{type_tag}"] = [key, block] + domain_types[key] = [key, block] + domain_types["tag:#{type_tag}"] = [key, block] end def self.add_builtin_type type_tag, &block domain = 'yaml.org,2002' key = ['tag', domain, type_tag].join ':' - @domain_types[key] = [key, block] + domain_types[key] = [key, block] end def self.remove_type type_tag - @domain_types.delete type_tag + domain_types.delete type_tag end - @load_tags = {} - @dump_tags = {} def self.add_tag tag, klass - @load_tags[tag] = klass - @dump_tags[klass] = tag + load_tags[tag] = klass.name + dump_tags[klass] = tag end class << self - attr_accessor :load_tags - attr_accessor :dump_tags - attr_accessor :domain_types + if defined?(Ractor) + class Config + attr_accessor :load_tags, :dump_tags, :domain_types + def initialize + @load_tags = {} + @dump_tags = {} + @domain_types = {} + end + end + + def config + Ractor.current[:PsychConfig] ||= Config.new + end + + def load_tags + config.load_tags + end + + def dump_tags + config.dump_tags + end + + def domain_types + config.domain_types + end + + def load_tags=(value) + config.load_tags = value + end + + def dump_tags=(value) + config.dump_tags = value + end + + def domain_types=(value) + config.domain_types = value + end + else + attr_accessor :load_tags + attr_accessor :dump_tags + attr_accessor :domain_types + end end + self.load_tags = {} + self.dump_tags = {} + self.domain_types = {} # :startdoc: end + +require_relative 'psych/core_ext' diff --git a/ext/psych/lib/psych/class_loader.rb b/ext/psych/lib/psych/class_loader.rb new file mode 100644 index 0000000000..c8f509720a --- /dev/null +++ b/ext/psych/lib/psych/class_loader.rb @@ -0,0 +1,105 @@ +# frozen_string_literal: true +require_relative 'omap' +require_relative 'set' + +module Psych + class ClassLoader # :nodoc: + BIG_DECIMAL = 'BigDecimal' + COMPLEX = 'Complex' + DATA = 'Data' unless RUBY_VERSION < "3.2" + DATE = 'Date' + DATE_TIME = 'DateTime' + EXCEPTION = 'Exception' + OBJECT = 'Object' + PSYCH_OMAP = 'Psych::Omap' + PSYCH_SET = 'Psych::Set' + RANGE = 'Range' + RATIONAL = 'Rational' + REGEXP = 'Regexp' + STRUCT = 'Struct' + SYMBOL = 'Symbol' + + def initialize + @cache = CACHE.dup + end + + def load klassname + return nil if !klassname || klassname.empty? + + find klassname + end + + def symbolize sym + symbol + sym.to_sym + end + + constants.each do |const| + konst = const_get const + class_eval <<~RUBY, __FILE__, __LINE__ + 1 + def #{const.to_s.downcase} + load #{konst.inspect} + end + RUBY + end + + private + + def find klassname + @cache[klassname] ||= resolve(klassname) + end + + def resolve klassname + name = klassname + retried = false + + begin + path2class(name) + rescue ArgumentError, NameError => ex + unless retried + name = "Struct::#{name}" + retried = ex + retry + end + raise retried + end + end + + CACHE = Hash[constants.map { |const| + val = const_get const + begin + [val, ::Object.const_get(val)] + rescue + nil + end + }.compact].freeze + + class Restricted < ClassLoader + def initialize classes, symbols + @classes = classes + @symbols = symbols + super() + end + + def symbolize sym + return super if @symbols.empty? + + if @symbols.include? sym + super + else + raise DisallowedClass.new('load', 'Symbol') + end + end + + private + + def find klassname + if @classes.include? klassname + super + else + raise DisallowedClass.new('load', klassname) + end + end + end + end +end diff --git a/ext/psych/lib/psych/coder.rb b/ext/psych/lib/psych/coder.rb index 2b830d2b21..96a9c3fbad 100644 --- a/ext/psych/lib/psych/coder.rb +++ b/ext/psych/lib/psych/coder.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych ### # If an object defines +encode_with+, then an instance of Psych::Coder will diff --git a/ext/psych/lib/psych/core_ext.rb b/ext/psych/lib/psych/core_ext.rb index 4a04c2d128..6dfd0f1696 100644 --- a/ext/psych/lib/psych/core_ext.rb +++ b/ext/psych/lib/psych/core_ext.rb @@ -1,42 +1,36 @@ +# frozen_string_literal: true class Object def self.yaml_tag url Psych.add_tag(url, self) end - # FIXME: rename this to "to_yaml" when syck is removed - ### # call-seq: to_yaml(options = {}) # # Convert an object to YAML. See Psych.dump for more information on the # available +options+. - def psych_to_yaml options = {} + def to_yaml options = {} Psych.dump self, options end - remove_method :to_yaml rescue nil - alias :to_yaml :psych_to_yaml end -class Module - def psych_yaml_as url - return if caller[0].end_with?('rubytypes.rb') - if $VERBOSE - warn "#{caller[0]}: yaml_as is deprecated, please use yaml_tag" +# Up to Ruby 3.4, Set was a regular object and was dumped as such +# by Pysch. +# Starting from Ruby 4.0 it's a core class written in C, so we have to implement +# #encode_with / #init_with to preserve backward compatibility. +if defined?(::Set) && Set.new.instance_variables.empty? + class Set + def encode_with(coder) + hash = {} + each do |m| + hash[m] = true + end + coder["hash"] = hash + coder end - Psych.add_tag(url, self) - end - remove_method :yaml_as rescue nil - alias :yaml_as :psych_yaml_as -end - -if defined?(::IRB) -module Kernel - def psych_y *objects - puts Psych.dump_stream(*objects) + def init_with(coder) + replace(coder["hash"].keys) + end end - remove_method :y rescue nil - alias y psych_y - private :y -end end diff --git a/ext/psych/lib/psych/deprecated.rb b/ext/psych/lib/psych/deprecated.rb deleted file mode 100644 index 333c3a1016..0000000000 --- a/ext/psych/lib/psych/deprecated.rb +++ /dev/null @@ -1,83 +0,0 @@ -require 'date' - -module Psych - DEPRECATED = __FILE__ # :nodoc: - - module DeprecatedMethods # :nodoc: - attr_accessor :taguri - attr_accessor :to_yaml_style - end - - def self.quick_emit thing, opts = {}, &block # :nodoc: - warn "#{caller[0]}: YAML.quick_emit is deprecated" if $VERBOSE && !caller[0].start_with?(File.dirname(__FILE__)) - target = eval 'self', block.binding - target.extend DeprecatedMethods - metaclass = class << target; self; end - metaclass.send(:define_method, :encode_with) do |coder| - target.taguri = coder.tag - target.to_yaml_style = coder.style - block.call coder - end - target.psych_to_yaml unless opts[:nodump] - end - - def self.load_documents yaml, &block - if $VERBOSE - warn "#{caller[0]}: load_documents is deprecated, use load_stream" - end - list = load_stream yaml - return list unless block_given? - list.each(&block) - end - - def self.detect_implicit thing - warn "#{caller[0]}: detect_implicit is deprecated" if $VERBOSE - return '' unless String === thing - return 'null' if '' == thing - ScalarScanner.new.tokenize(thing).class.name.downcase - end - - def self.add_ruby_type type_tag, &block - warn "#{caller[0]}: add_ruby_type is deprecated, use add_domain_type" if $VERBOSE - domain = 'ruby.yaml.org,2002' - key = ['tag', domain, type_tag].join ':' - @domain_types[key] = [key, block] - end - - def self.add_private_type type_tag, &block - warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE - domain = 'x-private' - key = [domain, type_tag].join ':' - @domain_types[key] = [key, block] - end - - def self.tagurize thing - warn "#{caller[0]}: add_private_type is deprecated, use add_domain_type" if $VERBOSE - return thing unless String === thing - "tag:yaml.org,2002:#{thing}" - end - - def self.read_type_class type, reference - warn "#{caller[0]}: read_type_class is deprecated" if $VERBOSE - _, _, type, name = type.split ':', 4 - - reference = name.split('::').inject(reference) do |k,n| - k.const_get(n.to_sym) - end if name - [type, reference] - end - - def self.object_maker klass, hash - warn "#{caller[0]}: object_maker is deprecated" if $VERBOSE - klass.allocate.tap do |obj| - hash.each { |k,v| obj.instance_variable_set(:"@#{k}", v) } - end - end -end - -class Object - undef :to_yaml_properties rescue nil - def to_yaml_properties # :nodoc: - instance_variables - end -end diff --git a/ext/psych/lib/psych/exception.rb b/ext/psych/lib/psych/exception.rb new file mode 100644 index 0000000000..d7469a4b30 --- /dev/null +++ b/ext/psych/lib/psych/exception.rb @@ -0,0 +1,28 @@ +# frozen_string_literal: true +module Psych + class Exception < RuntimeError + end + + class BadAlias < Exception + end + + # Subclasses `BadAlias` for backwards compatibility + class AliasesNotEnabled < BadAlias + def initialize + super "Alias parsing was not enabled. To enable it, pass `aliases: true` to `Psych::load` or `Psych::safe_load`." + end + end + + # Subclasses `BadAlias` for backwards compatibility + class AnchorNotDefined < BadAlias + def initialize anchor_name + super "An alias referenced an unknown anchor: #{anchor_name}" + end + end + + class DisallowedClass < Exception + def initialize action, klass_name + super "Tried to #{action} unspecified class: #{klass_name}" + end + end +end diff --git a/ext/psych/lib/psych/handler.rb b/ext/psych/lib/psych/handler.rb index d3b99636c4..ad7249ff77 100644 --- a/ext/psych/lib/psych/handler.rb +++ b/ext/psych/lib/psych/handler.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych ### # Psych::Handler is an abstract base class that defines the events used @@ -25,6 +26,19 @@ module Psych # Default dumping options OPTIONS = DumperOptions.new + # Events that a Handler should respond to. + EVENTS = [ :alias, + :empty, + :end_document, + :end_mapping, + :end_sequence, + :end_stream, + :scalar, + :start_document, + :start_mapping, + :start_sequence, + :start_stream ] + ### # Called with +encoding+ when the YAML stream starts. This method is # called once per stream. A stream may contain multiple documents. @@ -91,7 +105,7 @@ module Psych # - first element # - *ponies # - # &ponies is the achor, *ponies is the alias. In this case, alias is + # &ponies is the anchor, *ponies is the alias. In this case, alias is # called with "ponies". def alias anchor end @@ -105,7 +119,7 @@ module Psych # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value - # +style+ is an integer idicating the string style + # +style+ is an integer indicating the string style # # See the constants in Psych::Nodes::Scalar for the possible values of # +style+ @@ -228,6 +242,11 @@ module Psych end ### + # Called before each event with line/column information. + def event_location(start_line, start_column, end_line, end_column) + end + + ### # Is this handler a streaming handler? def streaming? false diff --git a/ext/psych/lib/psych/handlers/document_stream.rb b/ext/psych/lib/psych/handlers/document_stream.rb index e429993c1c..b77115d074 100644 --- a/ext/psych/lib/psych/handlers/document_stream.rb +++ b/ext/psych/lib/psych/handlers/document_stream.rb @@ -1,4 +1,5 @@ -require 'psych/tree_builder' +# frozen_string_literal: true +require_relative '../tree_builder' module Psych module Handlers diff --git a/ext/psych/lib/psych/handlers/recorder.rb b/ext/psych/lib/psych/handlers/recorder.rb new file mode 100644 index 0000000000..c98724cb76 --- /dev/null +++ b/ext/psych/lib/psych/handlers/recorder.rb @@ -0,0 +1,40 @@ +# frozen_string_literal: true +require_relative '../handler' + +module Psych + module Handlers + ### + # This handler will capture an event and record the event. Recorder events + # are available vial Psych::Handlers::Recorder#events. + # + # For example: + # + # recorder = Psych::Handlers::Recorder.new + # parser = Psych::Parser.new recorder + # parser.parse '--- foo' + # + # recorder.events # => [list of events] + # + # # Replay the events + # + # emitter = Psych::Emitter.new $stdout + # recorder.events.each do |m, args| + # emitter.send m, *args + # end + + class Recorder < Psych::Handler + attr_reader :events + + def initialize + @events = [] + super + end + + EVENTS.each do |event| + define_method event do |*args| + @events << [event, args] + end + end + end + end +end diff --git a/ext/psych/lib/psych/json/ruby_events.rb b/ext/psych/lib/psych/json/ruby_events.rb index 6b73249c06..17b7ddc386 100644 --- a/ext/psych/lib/psych/json/ruby_events.rb +++ b/ext/psych/lib/psych/json/ruby_events.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module JSON module RubyEvents # :nodoc: diff --git a/ext/psych/lib/psych/json/stream.rb b/ext/psych/lib/psych/json/stream.rb index be1a0a8a82..24dd4b9baf 100644 --- a/ext/psych/lib/psych/json/stream.rb +++ b/ext/psych/lib/psych/json/stream.rb @@ -1,11 +1,13 @@ -require 'psych/json/ruby_events' -require 'psych/json/yaml_events' +# frozen_string_literal: true +require_relative 'ruby_events' +require_relative 'yaml_events' module Psych module JSON class Stream < Psych::Visitors::JSONTree include Psych::JSON::RubyEvents include Psych::Streaming + extend Psych::Streaming::ClassMethods class Emitter < Psych::Stream::Emitter # :nodoc: include Psych::JSON::YAMLEvents diff --git a/ext/psych/lib/psych/json/tree_builder.rb b/ext/psych/lib/psych/json/tree_builder.rb index b799c93f58..9a45f6b94c 100644 --- a/ext/psych/lib/psych/json/tree_builder.rb +++ b/ext/psych/lib/psych/json/tree_builder.rb @@ -1,4 +1,5 @@ -require 'psych/json/yaml_events' +# frozen_string_literal: true +require_relative 'yaml_events' module Psych module JSON diff --git a/ext/psych/lib/psych/json/yaml_events.rb b/ext/psych/lib/psych/json/yaml_events.rb index d054d9b458..eb973f5361 100644 --- a/ext/psych/lib/psych/json/yaml_events.rb +++ b/ext/psych/lib/psych/json/yaml_events.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module JSON module YAMLEvents # :nodoc: diff --git a/ext/psych/lib/psych/nodes.rb b/ext/psych/lib/psych/nodes.rb index f3b33fe975..2fa52e0055 100644 --- a/ext/psych/lib/psych/nodes.rb +++ b/ext/psych/lib/psych/nodes.rb @@ -1,10 +1,11 @@ -require 'psych/nodes/node' -require 'psych/nodes/stream' -require 'psych/nodes/document' -require 'psych/nodes/sequence' -require 'psych/nodes/scalar' -require 'psych/nodes/mapping' -require 'psych/nodes/alias' +# frozen_string_literal: true +require_relative 'nodes/node' +require_relative 'nodes/stream' +require_relative 'nodes/document' +require_relative 'nodes/sequence' +require_relative 'nodes/scalar' +require_relative 'nodes/mapping' +require_relative 'nodes/alias' module Psych ### diff --git a/ext/psych/lib/psych/nodes/alias.rb b/ext/psych/lib/psych/nodes/alias.rb index 5bd4df13d1..6da655f0fd 100644 --- a/ext/psych/lib/psych/nodes/alias.rb +++ b/ext/psych/lib/psych/nodes/alias.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -13,6 +14,8 @@ module Psych def initialize anchor @anchor = anchor end + + def alias?; true; end end end end diff --git a/ext/psych/lib/psych/nodes/document.rb b/ext/psych/lib/psych/nodes/document.rb index 32014d60dc..f57410d636 100644 --- a/ext/psych/lib/psych/nodes/document.rb +++ b/ext/psych/lib/psych/nodes/document.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -55,6 +56,8 @@ module Psych def root children.first end + + def document?; true; end end end end diff --git a/ext/psych/lib/psych/nodes/mapping.rb b/ext/psych/lib/psych/nodes/mapping.rb index 5ba95ce4b6..d49678cb0e 100644 --- a/ext/psych/lib/psych/nodes/mapping.rb +++ b/ext/psych/lib/psych/nodes/mapping.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -51,6 +52,8 @@ module Psych @implicit = implicit @style = style end + + def mapping?; true; end end end end diff --git a/ext/psych/lib/psych/nodes/node.rb b/ext/psych/lib/psych/nodes/node.rb index 0cefe44e44..fc27448f2e 100644 --- a/ext/psych/lib/psych/nodes/node.rb +++ b/ext/psych/lib/psych/nodes/node.rb @@ -1,4 +1,6 @@ -require 'stringio' +# frozen_string_literal: true +require_relative '../class_loader' +require_relative '../scalar_scanner' module Psych module Nodes @@ -14,6 +16,18 @@ module Psych # An associated tag attr_reader :tag + # The line number where this node start + attr_accessor :start_line + + # The column number where this node start + attr_accessor :start_column + + # The line number where this node ends + attr_accessor :end_line + + # The column number where this node ends + attr_accessor :end_column + # Create a new Psych::Nodes::Node def initialize @children = [] @@ -31,8 +45,8 @@ module Psych # Convert this node to Ruby. # # See also Psych::Visitors::ToRuby - def to_ruby - Visitors::ToRuby.new.accept self + def to_ruby(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true) + Visitors::ToRuby.create(symbolize_names: symbolize_names, freeze: freeze, strict_integer: strict_integer, parse_symbols: parse_symbols).accept(self) end alias :transform :to_ruby @@ -41,6 +55,8 @@ module Psych # # See also Psych::Visitors::Emitter def yaml io = nil, options = {} + require "stringio" unless defined?(StringIO) + real_io = io || StringIO.new(''.encode('utf-8')) Visitors::Emitter.new(real_io, options).accept self @@ -48,6 +64,13 @@ module Psych io end alias :to_yaml :yaml + + def alias?; false; end + def document?; false; end + def mapping?; false; end + def scalar?; false; end + def sequence?; false; end + def stream?; false; end end end end diff --git a/ext/psych/lib/psych/nodes/scalar.rb b/ext/psych/lib/psych/nodes/scalar.rb index 1b1b25b98a..5550b616a3 100644 --- a/ext/psych/lib/psych/nodes/scalar.rb +++ b/ext/psych/lib/psych/nodes/scalar.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -49,7 +50,7 @@ module Psych # +tag+ is an associated tag or nil # +plain+ is a boolean value # +quoted+ is a boolean value - # +style+ is an integer idicating the string style + # +style+ is an integer indicating the string style # # == See Also # @@ -62,6 +63,8 @@ module Psych @quoted = quoted @style = style end + + def scalar?; true; end end end end diff --git a/ext/psych/lib/psych/nodes/sequence.rb b/ext/psych/lib/psych/nodes/sequence.rb index e4b833d330..740f1938a4 100644 --- a/ext/psych/lib/psych/nodes/sequence.rb +++ b/ext/psych/lib/psych/nodes/sequence.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -56,7 +57,7 @@ module Psych # Is this sequence started implicitly? attr_accessor :implicit - # The sequece style used + # The sequence style used attr_accessor :style ### @@ -76,6 +77,8 @@ module Psych @implicit = implicit @style = style end + + def sequence?; true; end end end end diff --git a/ext/psych/lib/psych/nodes/stream.rb b/ext/psych/lib/psych/nodes/stream.rb index 7cf5e033ec..b525217821 100644 --- a/ext/psych/lib/psych/nodes/stream.rb +++ b/ext/psych/lib/psych/nodes/stream.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Nodes ### @@ -32,6 +33,8 @@ module Psych super() @encoding = encoding end + + def stream?; true; end end end end diff --git a/ext/psych/lib/psych/omap.rb b/ext/psych/lib/psych/omap.rb index 6286270616..29cde0be50 100644 --- a/ext/psych/lib/psych/omap.rb +++ b/ext/psych/lib/psych/omap.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych class Omap < ::Hash end diff --git a/ext/psych/lib/psych/parser.rb b/ext/psych/lib/psych/parser.rb index 84085f1fb0..2181c730e5 100644 --- a/ext/psych/lib/psych/parser.rb +++ b/ext/psych/lib/psych/parser.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych ### # YAML event parser class. This class parses a YAML document and calls @@ -47,5 +48,18 @@ module Psych @handler = handler @external_encoding = ANY end + + ### + # call-seq: + # parser.parse(yaml) + # + # Parse the YAML document contained in +yaml+. Events will be called on + # the handler set on the parser instance. + # + # See Psych::Parser and Psych::Parser#handler + + def parse yaml, path = yaml.respond_to?(:path) ? yaml.path : "<unknown>" + _native_parse @handler, yaml, path + end end end diff --git a/ext/psych/lib/psych/scalar_scanner.rb b/ext/psych/lib/psych/scalar_scanner.rb index fa2d385a63..6a556fb3b8 100644 --- a/ext/psych/lib/psych/scalar_scanner.rb +++ b/ext/psych/lib/psych/scalar_scanner.rb @@ -1,117 +1,131 @@ -require 'strscan' +# frozen_string_literal: true module Psych ### # Scan scalars for built in types class ScalarScanner # Taken from http://yaml.org/type/timestamp.html - TIME = /^\d{4}-\d{1,2}-\d{1,2}([Tt]|\s+)\d{1,2}:\d\d:\d\d(\.\d*)?(\s*Z|[-+]\d{1,2}(:\d\d)?)?/ + TIME = /^-?\d{4}-\d{1,2}-\d{1,2}(?:[Tt]|\s+)\d{1,2}:\d\d:\d\d(?:\.\d*)?(?:\s*(?:Z|[-+]\d{1,2}:?(?:\d\d)?))?$/ # Taken from http://yaml.org/type/float.html - FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9.]*([eE][-+][0-9]+)?(?# base 10) - |[-+]?[0-9][0-9_,]*(:[0-5]?[0-9])+\.[0-9_]*(?# base 60) - |[-+]?\.(inf|Inf|INF)(?# infinity) - |\.(nan|NaN|NAN)(?# not a number))$/x + # Base 60, [-+]inf and NaN are handled separately + FLOAT = /^(?:[-+]?([0-9][0-9_,]*)?\.[0-9]*([eE][-+][0-9]+)?(?# base 10))$/x + + # Taken from http://yaml.org/type/int.html and modified to ensure at least one numerical symbol exists + INTEGER_STRICT = /^(?:[-+]?0b[_]*[0-1][0-1_]* (?# base 2) + |[-+]?0[_]*[0-7][0-7_]* (?# base 8) + |[-+]?(0|[1-9][0-9_]*) (?# base 10) + |[-+]?0x[_]*[0-9a-fA-F][0-9a-fA-F_]* (?# base 16))$/x + + # Same as above, but allows commas. + # Not to YML spec, but kept for backwards compatibility + INTEGER_LEGACY = /^(?:[-+]?0b[_,]*[0-1][0-1_,]* (?# base 2) + |[-+]?0[_,]*[0-7][0-7_,]* (?# base 8) + |[-+]?(?:0|[1-9](?:[0-9]|,[0-9]|_[0-9])*) (?# base 10) + |[-+]?0x[_,]*[0-9a-fA-F][0-9a-fA-F_,]* (?# base 16))$/x + + attr_reader :class_loader # Create a new scanner - def initialize - @string_cache = {} + def initialize class_loader, strict_integer: false, parse_symbols: true + @symbol_cache = {} + @class_loader = class_loader + @strict_integer = strict_integer + @parse_symbols = parse_symbols end - # Tokenize +string+ returning the ruby object + # Tokenize +string+ returning the Ruby object def tokenize string return nil if string.empty? - return string if @string_cache.key?(string) + return @symbol_cache[string] if @symbol_cache.key?(string) + integer_regex = @strict_integer ? INTEGER_STRICT : INTEGER_LEGACY + # Check for a String type, being careful not to get caught by hash keys, hex values, and + # special floats (e.g., -.inf). + if string.match?(%r{^[^\d.:-]?[[:alpha:]_\s!@#$%\^&*(){}<>|/\\~;=]+}) || string.match?(/\n/) + return string if string.length > 5 - case string - when /^[A-Za-z~]/ - if string.length > 5 - @string_cache[string] = true - return string - end - - case string - when /^[^ytonf~]/i - @string_cache[string] = true + if string.match?(/^[^ytonf~]/i) string - when '~', /^null$/i + elsif string == '~' || string.match?(/^null$/i) nil - when /^(yes|true|on)$/i + elsif string.match?(/^(yes|true|on)$/i) true - when /^(no|false|off)$/i + elsif string.match?(/^(no|false|off)$/i) false else - @string_cache[string] = true string end - when TIME - parse_time string - when /^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/ - require 'date' + elsif string.match?(TIME) begin - Date.strptime(string, '%Y-%m-%d') + parse_time string rescue ArgumentError string end - when /^\.inf$/i - 1 / 0.0 - when /^-\.inf$/i - -1 / 0.0 - when /^\.nan$/i - 0.0 / 0.0 - when /^:./ + elsif string.match?(/^\d{4}-(?:1[012]|0\d|\d)-(?:[12]\d|3[01]|0\d|\d)$/) + begin + class_loader.date.strptime(string, '%F', Date::GREGORIAN) + rescue ArgumentError + string + end + elsif string.match?(/^\+?\.inf$/i) + Float::INFINITY + elsif string.match?(/^-\.inf$/i) + -Float::INFINITY + elsif string.match?(/^\.nan$/i) + Float::NAN + elsif @parse_symbols && string.match?(/^:./) if string =~ /^:(["'])(.*)\1/ - $2.sub(/^:/, '').to_sym + @symbol_cache[string] = class_loader.symbolize($2.sub(/^:/, '')) else - string.sub(/^:/, '').to_sym + @symbol_cache[string] = class_loader.symbolize(string.sub(/^:/, '')) end - when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+$/ + elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_i * 60 ** (e - 2).abs) end i - when /^[-+]?[0-9][0-9_]*(:[0-5]?[0-9])+\.[0-9_]*$/ + elsif string.match?(/^[-+]?[0-9][0-9_]*(:[0-5]?[0-9]){1,2}\.[0-9_]*$/) i = 0 string.split(':').each_with_index do |n,e| i += (n.to_f * 60 ** (e - 2).abs) end i - when FLOAT - begin - return Float(string.gsub(/[,_]/, '')) - rescue ArgumentError + elsif string.match?(FLOAT) + if string.match?(/\A[-+]?\.\Z/) + string + else + Float(string.delete(',_').gsub(/\.([Ee]|$)/, '\1')) end - - @string_cache[string] = true - string + elsif string.match?(integer_regex) + parse_int string else - if string.count('.') < 2 - begin - return Integer(string.gsub(/[,_]/, '')) - rescue ArgumentError - end - end - - @string_cache[string] = true string end end ### + # Parse and return an int from +string+ + def parse_int string + Integer(string.delete(',_')) + end + + ### # Parse and return a Time from +string+ def parse_time string + klass = class_loader.load 'Time' + date, time = *(string.split(/[ tT]/, 2)) - (yy, m, dd) = date.split('-').map { |x| x.to_i } + (yy, m, dd) = date.match(/^(-?\d{4})-(\d{1,2})-(\d{1,2})/).captures.map { |x| x.to_i } md = time.match(/(\d+:\d+:\d+)(?:\.(\d*))?\s*(Z|[-+]\d+(:\d\d)?)?/) (hh, mm, ss) = md[1].split(':').map { |x| x.to_i } us = (md[2] ? Rational("0.#{md[2]}") : 0) * 1000000 - time = Time.utc(yy, m, dd, hh, mm, ss, us) + time = klass.utc(yy, m, dd, hh, mm, ss, us) return time if 'Z' == md[3] - return Time.at(time.to_i, us) unless md[3] + return klass.at(time.to_i, us) unless md[3] tz = md[3].match(/^([+\-]?\d{1,2})\:?(\d{1,2})?$/)[1..-1].compact.map { |digit| Integer(digit, 10) } offset = tz.first * 3600 @@ -122,7 +136,7 @@ module Psych offset += ((tz[1] || 0) * 60) end - Time.at((time - offset).to_i, us) + klass.new(yy, m, dd, hh, mm, ss+us/(1_000_000r), offset) end end end diff --git a/ext/psych/lib/psych/set.rb b/ext/psych/lib/psych/set.rb index 6793a8ed1b..760d217098 100644 --- a/ext/psych/lib/psych/set.rb +++ b/ext/psych/lib/psych/set.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych class Set < ::Hash end diff --git a/ext/psych/lib/psych/stream.rb b/ext/psych/lib/psych/stream.rb index 567c1bb790..24e45afc3b 100644 --- a/ext/psych/lib/psych/stream.rb +++ b/ext/psych/lib/psych/stream.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych ### # Psych::Stream is a streaming YAML emitter. It will not buffer your YAML, @@ -32,5 +33,6 @@ module Psych end include Psych::Streaming + extend Psych::Streaming::ClassMethods end end diff --git a/ext/psych/lib/psych/streaming.rb b/ext/psych/lib/psych/streaming.rb index c6fa109d5a..eb19792ad0 100644 --- a/ext/psych/lib/psych/streaming.rb +++ b/ext/psych/lib/psych/streaming.rb @@ -1,10 +1,16 @@ +# frozen_string_literal: true module Psych module Streaming - ### - # Create a new streaming emitter. Emitter will print to +io+. See - # Psych::Stream for an example. - def initialize io - super({}, self.class.const_get(:Emitter).new(io)) + module ClassMethods + ### + # Create a new streaming emitter. Emitter will print to +io+. See + # Psych::Stream for an example. + def new io + emitter = const_get(:Emitter).new(io) + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + super(emitter, ss, {}) + end end ### diff --git a/ext/psych/lib/psych/syntax_error.rb b/ext/psych/lib/psych/syntax_error.rb index f79743dba4..a4c9c4a376 100644 --- a/ext/psych/lib/psych/syntax_error.rb +++ b/ext/psych/lib/psych/syntax_error.rb @@ -1,5 +1,8 @@ +# frozen_string_literal: true +require_relative 'exception' + module Psych - class SyntaxError < ::SyntaxError + class SyntaxError < Psych::Exception attr_reader :file, :line, :column, :offset, :problem, :context def initialize file, line, col, offset, problem, context diff --git a/ext/psych/lib/psych/tree_builder.rb b/ext/psych/lib/psych/tree_builder.rb index c8f344787c..83115bd721 100644 --- a/ext/psych/lib/psych/tree_builder.rb +++ b/ext/psych/lib/psych/tree_builder.rb @@ -1,4 +1,5 @@ -require 'psych/handler' +# frozen_string_literal: true +require_relative 'handler' module Psych ### @@ -22,23 +23,38 @@ module Psych @stack = [] @last = nil @root = nil + + @start_line = nil + @start_column = nil + @end_line = nil + @end_column = nil + end + + def event_location(start_line, start_column, end_line, end_column) + @start_line = start_line + @start_column = start_column + @end_line = end_line + @end_column = end_column end %w{ Sequence Mapping }.each do |node| - class_eval %{ + class_eval <<~RUBY, __FILE__, __LINE__ + 1 def start_#{node.downcase}(anchor, tag, implicit, style) n = Nodes::#{node}.new(anchor, tag, implicit, style) + set_start_location(n) @last.children << n push n end def end_#{node.downcase} - pop + n = pop + set_end_location(n) + n end - } + RUBY end ### @@ -48,6 +64,7 @@ module Psych # See Psych::Handler#start_document def start_document version, tag_directives, implicit n = Nodes::Document.new version, tag_directives, implicit + set_start_location(n) @last.children << n push n end @@ -59,26 +76,35 @@ module Psych # See Psych::Handler#start_document def end_document implicit_end = !streaming? @last.implicit_end = implicit_end - pop + n = pop + set_end_location(n) + n end def start_stream encoding @root = Nodes::Stream.new(encoding) + set_start_location(@root) push @root end def end_stream - pop + n = pop + set_end_location(n) + n end def scalar value, anchor, tag, plain, quoted, style s = Nodes::Scalar.new(value,anchor,tag,plain,quoted,style) + set_location(s) @last.children << s s end def alias anchor - @last.children << Nodes::Alias.new(anchor) + a = Nodes::Alias.new(anchor) + set_location(a) + @last.children << a + a end private @@ -92,5 +118,20 @@ module Psych @last = @stack.last x end + + def set_location(node) + set_start_location(node) + set_end_location(node) + end + + def set_start_location(node) + node.start_line = @start_line + node.start_column = @start_column + end + + def set_end_location(node) + node.end_line = @end_line + node.end_column = @end_column + end end end diff --git a/ext/psych/lib/psych/versions.rb b/ext/psych/lib/psych/versions.rb new file mode 100644 index 0000000000..6c1679bf65 --- /dev/null +++ b/ext/psych/lib/psych/versions.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true + +module Psych + # The version of Psych you are using + VERSION = '5.4.0' + + if RUBY_ENGINE == 'jruby' + DEFAULT_SNAKEYAML_VERSION = '2.10'.freeze + end +end diff --git a/ext/psych/lib/psych/visitors.rb b/ext/psych/lib/psych/visitors.rb index cc98b103f1..508290d862 100644 --- a/ext/psych/lib/psych/visitors.rb +++ b/ext/psych/lib/psych/visitors.rb @@ -1,6 +1,7 @@ -require 'psych/visitors/visitor' -require 'psych/visitors/to_ruby' -require 'psych/visitors/emitter' -require 'psych/visitors/yaml_tree' -require 'psych/visitors/json_tree' -require 'psych/visitors/depth_first' +# frozen_string_literal: true +require_relative 'visitors/visitor' +require_relative 'visitors/to_ruby' +require_relative 'visitors/emitter' +require_relative 'visitors/yaml_tree' +require_relative 'visitors/json_tree' +require_relative 'visitors/depth_first' diff --git a/ext/psych/lib/psych/visitors/depth_first.rb b/ext/psych/lib/psych/visitors/depth_first.rb index c6eb814ac0..b4ff9e40e7 100644 --- a/ext/psych/lib/psych/visitors/depth_first.rb +++ b/ext/psych/lib/psych/visitors/depth_first.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Visitors class DepthFirst < Psych::Visitors::Visitor diff --git a/ext/psych/lib/psych/visitors/emitter.rb b/ext/psych/lib/psych/visitors/emitter.rb index c886e5092e..e3b92b7d03 100644 --- a/ext/psych/lib/psych/visitors/emitter.rb +++ b/ext/psych/lib/psych/visitors/emitter.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Visitors class Emitter < Psych::Visitors::Visitor diff --git a/ext/psych/lib/psych/visitors/json_tree.rb b/ext/psych/lib/psych/visitors/json_tree.rb index 0350dd1faa..979fc100bd 100644 --- a/ext/psych/lib/psych/visitors/json_tree.rb +++ b/ext/psych/lib/psych/visitors/json_tree.rb @@ -1,12 +1,16 @@ -require 'psych/json/ruby_events' +# frozen_string_literal: true +require_relative '../json/ruby_events' module Psych module Visitors class JSONTree < YAMLTree include Psych::JSON::RubyEvents - def initialize options = {}, emitter = Psych::JSON::TreeBuilder.new - super + def self.create options = {} + emitter = Psych::JSON::TreeBuilder.new + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + new(emitter, ss, options) end def accept target diff --git a/ext/psych/lib/psych/visitors/to_ruby.rb b/ext/psych/lib/psych/visitors/to_ruby.rb index 088301ac14..475444e589 100644 --- a/ext/psych/lib/psych/visitors/to_ruby.rb +++ b/ext/psych/lib/psych/visitors/to_ruby.rb @@ -1,4 +1,7 @@ -require 'psych/scalar_scanner' +# frozen_string_literal: true +require_relative '../scalar_scanner' +require_relative '../class_loader' +require_relative '../exception' unless defined?(Regexp::NOENCODING) Regexp::NOENCODING = 32 @@ -7,32 +10,50 @@ end module Psych module Visitors ### - # This class walks a YAML AST, converting each node to ruby + # This class walks a YAML AST, converting each node to Ruby class ToRuby < Psych::Visitors::Visitor - def initialize ss = ScalarScanner.new + unless RUBY_VERSION < "3.2" + DATA_INITIALIZE = Data.instance_method(:initialize) + end + + def self.create(symbolize_names: false, freeze: false, strict_integer: false, parse_symbols: true) + class_loader = ClassLoader.new + scanner = ScalarScanner.new class_loader, strict_integer: strict_integer, parse_symbols: parse_symbols + new(scanner, class_loader, symbolize_names: symbolize_names, freeze: freeze) + end + + attr_reader :class_loader + + def initialize ss, class_loader, symbolize_names: false, freeze: false super() @st = {} @ss = ss + @load_tags = Psych.load_tags @domain_types = Psych.domain_types + @class_loader = class_loader + @symbolize_names = symbolize_names + @freeze = freeze end def accept target result = super - return result if @domain_types.empty? || !target.tag - key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:') - key = "tag:#{key}" unless key =~ /^(tag:|x-private)/ + unless @domain_types.empty? || !target.tag + key = target.tag.sub(/^[!\/]*/, '').sub(/(,\d+)\//, '\1:') + key = "tag:#{key}" unless key.match?(/^(?:tag:|x-private)/) - if @domain_types.key? key - value, block = @domain_types[key] - return block.call value, result + if @domain_types.key? key + value, block = @domain_types[key] + result = block.call value, result + end end + result = deduplicate(result).freeze if @freeze result end def deserialize o - if klass = Psych.load_tags[o.tag] + if klass = resolve_class(@load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) @@ -50,7 +71,7 @@ module Psych case o.tag when '!binary', 'tag:yaml.org,2002:binary' o.value.unpack('m').first - when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str' + when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' klass = resolve_class($1) if klass klass.allocate.replace o.value @@ -58,25 +79,32 @@ module Psych o.value end when '!ruby/object:BigDecimal' - require 'bigdecimal' - BigDecimal._load o.value + require 'bigdecimal' unless defined? BigDecimal + class_loader.big_decimal._load o.value when "!ruby/object:DateTime" - require 'date' - @ss.parse_time(o.value).to_datetime + class_loader.date_time + t = @ss.parse_time(o.value) + DateTime.civil(*t.to_a[0, 6].reverse, Rational(t.utc_offset, 86400)) + + (t.subsec/86400) + when '!ruby/encoding' + ::Encoding.find o.value when "!ruby/object:Complex" + class_loader.complex Complex(o.value) when "!ruby/object:Rational" + class_loader.rational Rational(o.value) when "!ruby/class", "!ruby/module" resolve_class o.value when "tag:yaml.org,2002:float", "!float" Float(@ss.tokenize(o.value)) when "!ruby/regexp" - o.value =~ /^\/(.*)\/([mixn]*)$/ - source = $1 + klass = class_loader.regexp + matches = /^\/(?<string>.*)\/(?<options>[mixn]*)$/m.match(o.value) + source = matches[:string].gsub('\/', '/') options = 0 lang = nil - ($2 || '').split('').each do |option| + matches[:options].each_char do |option| case option when 'x' then options |= Regexp::EXTENDED when 'i' then options |= Regexp::IGNORECASE @@ -85,15 +113,16 @@ module Psych else lang = option end end - Regexp.new(*[source, options, lang].compact) + klass.new(*[source, options, lang].compact) when "!ruby/range" + klass = class_loader.range args = o.value.split(/([.]{2,3})/, 2).map { |s| accept Nodes::Scalar.new(s) } args.push(args.delete_at(1) == '...') - Range.new(*args) + klass.new(*args) when /^!ruby\/sym(bol)?:?(.*)?$/ - o.value.to_sym + class_loader.symbolize o.value else @ss.tokenize o.value end @@ -105,7 +134,7 @@ module Psych end def visit_Psych_Nodes_Sequence o - if klass = Psych.load_tags[o.tag] + if klass = resolve_class(@load_tags[o.tag]) instance = klass.allocate if instance.respond_to?(:init_with) @@ -118,6 +147,8 @@ module Psych end case o.tag + when nil + register_empty(o) when '!omap', 'tag:yaml.org,2002:omap' map = register(o, Psych::Omap.new) o.children.each { |a| @@ -130,51 +161,29 @@ module Psych o.children.each { |c| list.push accept c } list else - list = register(o, []) - o.children.each { |c| list.push accept c } - list + register_empty(o) end end def visit_Psych_Nodes_Mapping o - return revive(Psych.load_tags[o.tag], o) if Psych.load_tags[o.tag] - return revive_hash({}, o) unless o.tag + if @load_tags[o.tag] + return revive(resolve_class(@load_tags[o.tag]), o) + end + return revive_hash(register(o, {}), o) unless o.tag case o.tag - when /^!(?:str|ruby\/string)(?::(.*))?/, 'tag:yaml.org,2002:str' - klass = resolve_class($1) - members = Hash[*o.children.map { |c| accept c }] - string = members.delete 'str' - - if klass - string = klass.allocate.replace string - register(o, string) - end - - init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) - when /^!ruby\/array:(.*)$/ - klass = resolve_class($1) - list = register(o, klass.allocate) - - members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] - list.replace members['internal'] - - members['ivars'].each do |ivar, v| - list.instance_variable_set ivar, v - end - list when /^!ruby\/struct:?(.*)?$/ - klass = resolve_class($1) + klass = resolve_class($1) if $1 if klass s = register(o, klass.allocate) members = {} - struct_members = s.members.map { |x| x.to_sym } + struct_members = s.members.map { |x| class_loader.symbolize x } o.children.each_slice(2) do |k,v| member = accept(k) value = accept(v) - if struct_members.include?(member.to_sym) + if struct_members.include?(class_loader.symbolize(member)) s.send("#{member}=", value) else members[member.to_s.sub(/^@/, '')] = value @@ -182,55 +191,157 @@ module Psych end init_with(s, members, o) else + klass = class_loader.struct members = o.children.map { |c| accept c } h = Hash[*members] - Struct.new(*h.map { |k,v| k.to_sym }).new(*h.map { |k,v| v }) + s = klass.new(*h.map { |k,v| + class_loader.symbolize k + }).new(*h.map { |k,v| v }) + register(o, s) + s + end + + when /^!ruby\/data(-with-ivars)?(?::(.*))?$/ + data = register(o, resolve_class($2).allocate) if $2 + members = {} + + if $1 # data-with-ivars + ivars = {} + o.children.each_slice(2) do |type, vars| + case accept(type) + when 'members' + revive_data_members(members, vars) + data ||= allocate_anon_data(o, members) + when 'ivars' + revive_hash(ivars, vars) + end + end + ivars.each do |ivar, v| + data.instance_variable_set ivar, v + end + else + revive_data_members(members, o) + end + data ||= allocate_anon_data(o, members) + DATA_INITIALIZE.bind_call(data, **members) + data.freeze + data + + when /^!ruby\/object:?(.*)?$/ + name = $1 || 'Object' + + if name == 'Complex' + class_loader.complex + h = Hash[*o.children.map { |c| accept c }] + register o, Complex(h['real'], h['image']) + elsif name == 'Rational' + class_loader.rational + h = Hash[*o.children.map { |c| accept c }] + register o, Rational(h['numerator'], h['denominator']) + elsif name == 'Hash' + revive_hash(register(o, {}), o) + else + obj = revive((resolve_class(name) || class_loader.object), o) + obj + end + + when /^!(?:str|ruby\/string)(?::(.*))?$/, 'tag:yaml.org,2002:str' + klass = resolve_class($1) + members = {} + string = nil + + o.children.each_slice(2) do |k,v| + key = accept k + value = accept v + + if key == 'str' + if klass + string = klass.allocate.replace value + else + string = value + end + register(o, string) + else + members[key] = value + end + end + init_with(string, members.map { |k,v| [k.to_s.sub(/^@/, ''),v] }, o) + when /^!ruby\/array:(.*)$/ + klass = resolve_class($1) + list = register(o, klass.allocate) + + members = Hash[o.children.map { |c| accept c }.each_slice(2).to_a] + list.replace members['internal'] + + members['ivars'].each do |ivar, v| + list.instance_variable_set ivar, v end + list when '!ruby/range' + klass = class_loader.range h = Hash[*o.children.map { |c| accept c }] - register o, Range.new(h['begin'], h['end'], h['excl']) + register o, klass.new(h['begin'], h['end'], h['excl']) when /^!ruby\/exception:?(.*)?$/ h = Hash[*o.children.map { |c| accept c }] - e = build_exception((resolve_class($1) || Exception), + e = build_exception((resolve_class($1) || class_loader.exception), h.delete('message')) + + e.set_backtrace h.delete('backtrace') if h.key? 'backtrace' init_with(e, h, o) when '!set', 'tag:yaml.org,2002:set' - set = Psych::Set.new + set = class_loader.psych_set.new @st[o.anchor] = set if o.anchor o.children.each_slice(2) do |k,v| set[accept(k)] = accept(v) end set - when '!ruby/object:Complex' - h = Hash[*o.children.map { |c| accept c }] - register o, Complex(h['real'], h['image']) - - when '!ruby/object:Rational' - h = Hash[*o.children.map { |c| accept c }] - register o, Rational(h['numerator'], h['denominator']) - - when /^!ruby\/object:?(.*)?$/ - name = $1 || 'Object' - obj = revive((resolve_class(name) || Object), o) - obj + when /^!ruby\/hash-with-ivars(?::(.*))?$/ + hash = $1 ? resolve_class($1).allocate : {} + register o, hash + o.children.each_slice(2) do |key, value| + case key.value + when 'elements' + revive_hash hash, value + when 'ivars' + value.children.each_slice(2) do |k,v| + hash.instance_variable_set accept(k), accept(v) + end + end + end + hash when /^!map:(.*)$/, /^!ruby\/hash:(.*)$/ - revive_hash resolve_class($1).new, o + revive_hash register(o, resolve_class($1).allocate), o when '!omap', 'tag:yaml.org,2002:omap' - map = register(o, Psych::Omap.new) + map = register(o, class_loader.psych_omap.new) o.children.each_slice(2) do |l,r| map[accept(l)] = accept r end map + when /^!ruby\/marshalable:(.*)$/ + name = $1 + klass = resolve_class(name) + obj = register(o, klass.allocate) + + if obj.respond_to?(:init_with) + init_with(obj, revive_hash({}, o), o) + elsif obj.respond_to?(:marshal_load) + marshal_data = o.children.map(&method(:accept)) + obj.marshal_load(marshal_data) + obj + else + raise ArgumentError, "Cannot deserialize #{name}" + end + else - revive_hash({}, o) + revive_hash(register(o, {}), o) end end @@ -243,45 +354,102 @@ module Psych end def visit_Psych_Nodes_Alias o - @st.fetch(o.anchor) { raise BadAlias, "Unknown alias: #{o.anchor}" } + @st.fetch(o.anchor) { raise AnchorNotDefined, o.anchor } end private + def register node, object @st[node.anchor] = object if node.anchor object end - def revive_hash hash, o - @st[o.anchor] = hash if o.anchor + def register_empty object + list = register(object, []) + object.children.each { |c| list.push accept c } + list + end - o.children.each_slice(2) { |k,v| + def allocate_anon_data node, members + klass = class_loader.data.define(*members.keys) + register(node, klass.allocate) + end + + def revive_data_members hash, o + o.children.each_slice(2) do |k,v| + name = accept(k) + value = accept(v) + hash[class_loader.symbolize(name)] = value + end + hash + end + + def revive_hash hash, o, tagged= false + o.children.each_slice(2) { |k,v| key = accept(k) + val = accept(v) - if key == '<<' + if key == '<<' && k.tag != "tag:yaml.org,2002:str" case v - when Nodes::Alias - hash.merge! accept(v) + when Nodes::Alias, Nodes::Mapping + begin + hash.merge! val + rescue TypeError + hash[key] = val + end when Nodes::Sequence - accept(v).reverse_each do |value| - hash.merge! value + begin + h = {} + val.reverse_each do |value| + h.merge! value + end + hash.merge! h + rescue TypeError + hash[key] = val end else - hash[key] = accept(v) + hash[key] = val end else - hash[key] = accept(v) + if !tagged && @symbolize_names && key.is_a?(String) + key = key.to_sym + elsif !@freeze + key = deduplicate(key) + end + + hash[key] = val end } hash end + if RUBY_VERSION < '2.7' + def deduplicate key + if key.is_a?(String) + # It is important to untaint the string, otherwise it won't + # be deduplicated into an fstring, but simply frozen. + -(key.untaint) + else + key + end + end + else + def deduplicate key + if key.is_a?(String) + -key + else + key + end + end + end + + def merge_key hash, key, val + end + def revive klass, node - s = klass.allocate - @st[node.anchor] = s if node.anchor - h = Hash[*node.children.map { |c| accept c }] - init_with(s, h, node) + s = register(node, klass.allocate) + init_with(s, revive_hash({}, node, true), node) end def init_with o, h, node @@ -290,11 +458,6 @@ module Psych if o.respond_to?(:init_with) o.init_with c - elsif o.respond_to?(:yaml_initialize) - if $VERBOSE - warn "Implementing #{o.class}#yaml_initialize is deprecated, please implement \"init_with(coder)\"" - end - o.yaml_initialize c.tag, c.map else h.each { |k,v| o.instance_variable_set(:"@#{k}", v) } end @@ -303,21 +466,13 @@ module Psych # Convert +klassname+ to a Class def resolve_class klassname - return nil unless klassname and not klassname.empty? - - name = klassname - retried = false - - begin - path2class(name) - rescue ArgumentError, NameError => ex - unless retried - name = "Struct::#{name}" - retried = ex - retry - end - raise retried - end + class_loader.load klassname + end + end + + class NoAliasRuby < ToRuby + def visit_Psych_Nodes_Alias o + raise AliasesNotEnabled end end end diff --git a/ext/psych/lib/psych/visitors/visitor.rb b/ext/psych/lib/psych/visitors/visitor.rb index 4d7772f428..21052aa66f 100644 --- a/ext/psych/lib/psych/visitors/visitor.rb +++ b/ext/psych/lib/psych/visitors/visitor.rb @@ -1,3 +1,4 @@ +# frozen_string_literal: true module Psych module Visitors class Visitor @@ -7,12 +8,26 @@ module Psych private - DISPATCH = Hash.new do |hash, klass| - hash[klass] = "visit_#{klass.name.gsub('::', '_')}" + # @api private + def self.dispatch_cache + Hash.new do |hash, klass| + hash[klass] = :"visit_#{klass.name.gsub('::', '_')}" + end.compare_by_identity + end + + if defined?(Ractor) + def dispatch + @dispatch_cache ||= (Ractor.current[:Psych_Visitors_Visitor] ||= Visitor.dispatch_cache) + end + else + DISPATCH = dispatch_cache + def dispatch + DISPATCH + end end def visit target - send DISPATCH[target.class], target + send dispatch[target.class], target end end end diff --git a/ext/psych/lib/psych/visitors/yaml_tree.rb b/ext/psych/lib/psych/visitors/yaml_tree.rb index 948a976dd1..b6c86f4c94 100644 --- a/ext/psych/lib/psych/visitors/yaml_tree.rb +++ b/ext/psych/lib/psych/visitors/yaml_tree.rb @@ -1,36 +1,82 @@ +# frozen_string_literal: true +require_relative '../tree_builder' +require_relative '../scalar_scanner' +require_relative '../class_loader' + module Psych module Visitors ### - # YAMLTree builds a YAML ast given a ruby object. For example: + # YAMLTree builds a YAML ast given a Ruby object. For example: # # builder = Psych::Visitors::YAMLTree.new # builder << { :foo => 'bar' } # builder.tree # => #<Psych::Nodes::Stream .. } # class YAMLTree < Psych::Visitors::Visitor + class Registrar # :nodoc: + def initialize + @obj_to_id = {}.compare_by_identity + @obj_to_node = {}.compare_by_identity + @counter = 0 + end + + def register target, node + @obj_to_node[target] = node + end + + def key? target + @obj_to_node.key? target + end + + def id_for target + @obj_to_id[target] ||= (@counter += 1) + end + + def node_for target + @obj_to_node[target] + end + end + attr_reader :started, :finished alias :finished? :finished alias :started? :started - def initialize options = {}, emitter = TreeBuilder.new, ss = ScalarScanner.new + def self.create options = {}, emitter = nil + emitter ||= TreeBuilder.new + class_loader = ClassLoader.new + ss = ScalarScanner.new class_loader + new(emitter, ss, options) + end + + def initialize emitter, ss, options super() - @started = false - @finished = false - @emitter = emitter - @st = {} - @ss = ss - @options = options - @coders = [] + @started = false + @finished = false + @emitter = emitter + @st = Registrar.new + @ss = ss + @options = options + @line_width = options[:line_width] + if @line_width && @line_width < 0 + if @line_width == -1 + # Treat -1 as unlimited line-width, same as libyaml does. + @line_width = nil + else + fail(ArgumentError, "Invalid line_width #{@line_width}, must be non-negative or -1 for unlimited.") + end + end + @stringify_names = options[:stringify_names] + @coders = [] @dispatch_cache = Hash.new do |h,klass| method = "visit_#{(klass.name || '').split('::').join('_')}" method = respond_to?(method) ? method : h[klass.superclass] - raise(TypeError, "Can't dump #{target.class}") unless method + raise(TypeError, "can't dump #{klass.name}") unless method h[klass] = method - end + end.compare_by_identity end def start encoding = Nodes::Stream::UTF8 @@ -47,6 +93,7 @@ module Psych def tree finish unless finished? + @emitter.root end def push object @@ -65,38 +112,20 @@ module Psych @emitter.start_document version, [], false accept object - @emitter.end_document + @emitter.end_document !@emitter.streaming? end alias :<< :push def accept target # return any aliases we find - if @st.key? target.object_id - oid = target.object_id - node = @st[oid] + if @st.key? target + oid = @st.id_for target + node = @st.node_for target anchor = oid.to_s node.anchor = anchor return @emitter.alias anchor end - if target.respond_to?(:to_yaml) - begin - loc = target.method(:to_yaml).source_location.first - if loc !~ /(syck\/rubytypes.rb|psych\/core_ext.rb)/ - unless target.respond_to?(:encode_with) - if $VERBOSE - warn "implementing to_yaml is deprecated, please implement \"encode_with\"" - end - - target.to_yaml(:nodump => true) - end - end - rescue - # public_method or source_location might be overridden, - # and it's OK to skip it since it's only to emit a warning - end - end - if target.respond_to?(:encode_with) dump_coder target else @@ -105,13 +134,18 @@ module Psych end def visit_Psych_Omap o - seq = @emitter.start_sequence(nil, '!omap', false, Nodes::Sequence::BLOCK) + seq = @emitter.start_sequence(nil, 'tag:yaml.org,2002:omap', false, Nodes::Sequence::BLOCK) register(o, seq) o.each { |k,v| visit_Hash k => v } @emitter.end_sequence end + def visit_Encoding o + tag = "!ruby/encoding" + @emitter.scalar o.name, nil, tag, false, false, Nodes::Scalar::ANY + end + def visit_Object o tag = Psych.dump_tags[o.class] unless tag @@ -126,6 +160,46 @@ module Psych @emitter.end_mapping end + alias :visit_Delegator :visit_Object + + def visit_Data o + ivars = o.instance_variables + if ivars.empty? + tag = ['!ruby/data', o.class.name].compact.join(':') + register o, @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + else + tag = ['!ruby/data-with-ivars', o.class.name].compact.join(':') + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + + # Dump the members + accept 'members' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.members.each do |member| + @emitter.scalar member.to_s, nil, nil, true, false, Nodes::Scalar::ANY + accept o.send member + end + @emitter.end_mapping + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + ivars.each do |ivar| + accept ivar.to_s + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end unless RUBY_VERSION < "3.2" + def visit_Struct o tag = ['!ruby/struct', o.class.name].compact.join(':') @@ -141,37 +215,32 @@ module Psych end def visit_Exception o - tag = ['!ruby/exception', o.class.name].join ':' - - @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK - - { - 'message' => private_iv_get(o, 'mesg'), - 'backtrace' => private_iv_get(o, 'backtrace'), - }.each do |k,v| - next unless v - @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY - accept v - end - - dump_ivars o + dump_exception o, o.message.to_s + end - @emitter.end_mapping + def visit_NameError o + dump_exception o, o.message.to_s end def visit_Regexp o register o, @emitter.scalar(o.inspect, nil, '!ruby/regexp', false, false, Nodes::Scalar::ANY) end + def visit_Date o + formatted = format_date o + register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) + end + def visit_DateTime o - formatted = format_time o.to_time + t = o.italy + formatted = format_time t, t.offset.zero? tag = '!ruby/object:DateTime' register o, @emitter.scalar(formatted, nil, tag, false, false, Nodes::Scalar::ANY) end def visit_Time o formatted = format_time o - @emitter.scalar formatted, nil, nil, true, false, Nodes::Scalar::ANY + register o, @emitter.scalar(formatted, nil, nil, true, false, Nodes::Scalar::ANY) end def visit_Rational o @@ -202,7 +271,6 @@ module Psych end alias :visit_TrueClass :visit_Integer alias :visit_FalseClass :visit_Integer - alias :visit_Date :visit_Integer def visit_Float o if o.nan? @@ -219,44 +287,53 @@ module Psych @emitter.scalar o._dump, nil, '!ruby/object:BigDecimal', false, false, Nodes::Scalar::ANY end - def binary? string - string.encoding == Encoding::ASCII_8BIT || - string.index("\x00") || - string.count("\x00-\x7F", "^ -~\t\r\n").fdiv(string.length) > 0.3 - end - private :binary? - def visit_String o - plain = false - quote = false - style = Nodes::Scalar::ANY + plain = true + quote = true + style = Nodes::Scalar::PLAIN + tag = nil if binary?(o) - str = [o].pack('m').chomp + o = [o].pack('m0') tag = '!binary' # FIXME: change to below when syck is removed #tag = 'tag:yaml.org,2002:binary' style = Nodes::Scalar::LITERAL - else - str = o - tag = nil - quote = !(String === @ss.tokenize(o)) - plain = !quote + plain = false + quote = false + elsif o.match?(/\n(?!\Z)/) # match \n except blank line at the end of string + style = Nodes::Scalar::LITERAL + elsif o == '<<' + style = Nodes::Scalar::SINGLE_QUOTED + tag = 'tag:yaml.org,2002:str' + plain = false + quote = false + elsif o == 'y' || o == 'Y' || o == 'n' || o == 'N' + style = Nodes::Scalar::DOUBLE_QUOTED + elsif @line_width && o.length > @line_width + style = Nodes::Scalar::FOLDED + elsif o.match?(/^[^[:word:]][^"]*$/) + style = Nodes::Scalar::DOUBLE_QUOTED + elsif not String === @ss.tokenize(o) or /\A0[0-7]*[89]/.match?(o) + style = Nodes::Scalar::SINGLE_QUOTED end - ivars = find_ivars o + is_primitive = o.class == ::String + ivars = is_primitive ? [] : o.instance_variables if ivars.empty? - unless o.class == ::String + unless is_primitive tag = "!ruby/string:#{o.class}" + plain = false + quote = false end - @emitter.scalar str, nil, tag, plain, quote, style + @emitter.scalar o, nil, tag, plain, quote, style else - maptag = '!ruby/string' + maptag = '!ruby/string'.dup maptag << ":#{o.class}" unless o.class == ::String register o, @emitter.start_mapping(nil, maptag, false, Nodes::Mapping::BLOCK) @emitter.scalar 'str', nil, nil, true, false, Nodes::Scalar::ANY - @emitter.scalar str, nil, tag, plain, quote, style + @emitter.scalar o, nil, tag, plain, quote, style dump_ivars o @@ -283,24 +360,23 @@ module Psych end def visit_Hash o - tag = o.class == ::Hash ? nil : "!ruby/hash:#{o.class}" - implicit = !tag - - register(o, @emitter.start_mapping(nil, tag, implicit, Psych::Nodes::Mapping::BLOCK)) - - o.each do |k,v| - accept k - accept v + if o.class == ::Hash + register(o, @emitter.start_mapping(nil, nil, true, Psych::Nodes::Mapping::BLOCK)) + o.each do |k,v| + accept(@stringify_names && Symbol === k ? k.to_s : k) + accept v + end + @emitter.end_mapping + else + visit_hash_subclass o end - - @emitter.end_mapping end def visit_Psych_Set o register(o, @emitter.start_mapping(nil, '!set', false, Psych::Nodes::Mapping::BLOCK)) o.each do |k,v| - accept k + accept(@stringify_names && Symbol === k ? k.to_s : k) accept v end @@ -309,26 +385,52 @@ module Psych def visit_Array o if o.class == ::Array - register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) - o.each { |c| accept c } - @emitter.end_sequence + visit_Enumerator o else visit_array_subclass o end end + def visit_Enumerator o + register o, @emitter.start_sequence(nil, nil, true, Nodes::Sequence::BLOCK) + o.each { |c| accept c } + @emitter.end_sequence + end + def visit_NilClass o @emitter.scalar('', nil, 'tag:yaml.org,2002:null', true, false, Nodes::Scalar::ANY) end def visit_Symbol o - @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY + if o.empty? + @emitter.scalar "", nil, '!ruby/symbol', false, false, Nodes::Scalar::ANY + else + @emitter.scalar ":#{o}", nil, nil, true, false, Nodes::Scalar::ANY + end + end + + def visit_BasicObject o + tag = Psych.dump_tags[o.class] + tag ||= "!ruby/marshalable:#{o.class.name}" + + map = @emitter.start_mapping(nil, tag, false, Nodes::Mapping::BLOCK) + register(o, map) + + o.marshal_dump.each(&method(:accept)) + + @emitter.end_mapping end private + + def binary? string + string.encoding == Encoding::ASCII_8BIT && !string.ascii_only? + end + def visit_array_subclass o tag = "!ruby/array:#{o.class}" - if o.instance_variables.empty? + ivars = o.instance_variables + if ivars.empty? node = @emitter.start_sequence(nil, tag, false, Nodes::Sequence::BLOCK) register o, node o.each { |c| accept c } @@ -346,12 +448,50 @@ module Psych # Dump the ivars accept 'ivars' @emitter.start_mapping(nil, nil, true, Nodes::Sequence::BLOCK) + ivars.each do |ivar| + accept ivar + accept o.instance_variable_get ivar + end + @emitter.end_mapping + + @emitter.end_mapping + end + end + + def visit_hash_subclass o + ivars = o.instance_variables + if ivars.any? + tag = "!ruby/hash-with-ivars:#{o.class}" + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + + # Dump the ivars + accept 'ivars' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK o.instance_variables.each do |ivar| accept ivar accept o.instance_variable_get ivar end @emitter.end_mapping + # Dump the elements + accept 'elements' + @emitter.start_mapping nil, nil, true, Nodes::Mapping::BLOCK + o.each do |k,v| + accept k + accept v + end + @emitter.end_mapping + + @emitter.end_mapping + else + tag = "!ruby/hash:#{o.class}" + node = @emitter.start_mapping(nil, tag, false, Psych::Nodes::Mapping::BLOCK) + register(o, node) + o.each do |k,v| + accept k + accept v + end @emitter.end_mapping end end @@ -359,50 +499,38 @@ module Psych def dump_list o end - # '%:z' was no defined until 1.9.3 - if RUBY_VERSION < '1.9.3' - def format_time time - formatted = time.strftime("%Y-%m-%d %H:%M:%S.%9N") + def dump_exception o, msg + tag = ['!ruby/exception', o.class.name].join ':' - if time.utc? - formatted += " Z" - else - zone = time.strftime('%z') - formatted += " #{zone[0,3]}:#{zone[3,5]}" - end + @emitter.start_mapping nil, tag, false, Nodes::Mapping::BLOCK - formatted - end - else - def format_time time - if time.utc? - time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") - else - time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") - end + if msg + @emitter.scalar 'message', nil, nil, true, false, Nodes::Scalar::ANY + accept msg end + + @emitter.scalar 'backtrace', nil, nil, true, false, Nodes::Scalar::ANY + accept o.backtrace + + dump_ivars o + + @emitter.end_mapping end - # FIXME: remove this method once "to_yaml_properties" is removed - def find_ivars target - begin - loc = target.method(:to_yaml_properties).source_location.first - unless loc.start_with?(Psych::DEPRECATED) || loc.end_with?('rubytypes.rb') - if $VERBOSE - warn "#{loc}: to_yaml_properties is deprecated, please implement \"encode_with(coder)\"" - end - return target.to_yaml_properties - end - rescue - # public_method or source_location might be overridden, - # and it's OK to skip it since it's only to emit a warning. + def format_time time, utc = time.utc? + if utc + time.strftime("%Y-%m-%d %H:%M:%S.%9N Z") + else + time.strftime("%Y-%m-%d %H:%M:%S.%9N %:z") end + end - target.instance_variables + def format_date date + date.strftime("%Y-%m-%d") end def register target, yaml_obj - @st[target.object_id] = yaml_obj + @st.register target, yaml_obj yaml_obj end @@ -416,23 +544,23 @@ module Psych c = Psych::Coder.new(tag) o.encode_with(c) - emit_coder c + emit_coder c, o end - def emit_coder c + def emit_coder c, o case c.type when :scalar - @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, Nodes::Scalar::ANY + @emitter.scalar c.scalar, nil, c.tag, c.tag.nil?, false, c.style when :seq - @emitter.start_sequence nil, c.tag, c.tag.nil?, Nodes::Sequence::BLOCK + @emitter.start_sequence nil, c.tag, c.tag.nil?, c.style c.seq.each do |thing| accept thing end @emitter.end_sequence when :map - @emitter.start_mapping nil, c.tag, c.implicit, c.style + register o, @emitter.start_mapping(nil, c.tag, c.implicit, c.style) c.map.each do |k,v| - @emitter.scalar k, nil, nil, true, false, Nodes::Scalar::ANY + accept k accept v end @emitter.end_mapping @@ -442,13 +570,57 @@ module Psych end def dump_ivars target - ivars = find_ivars target - - ivars.each do |iv| + target.instance_variables.each do |iv| @emitter.scalar("#{iv.to_s.sub(/^@/, '')}", nil, nil, true, false, Nodes::Scalar::ANY) accept target.instance_variable_get(iv) end end end + + class RestrictedYAMLTree < YAMLTree + DEFAULT_PERMITTED_CLASSES = { + TrueClass => true, + FalseClass => true, + NilClass => true, + Integer => true, + Float => true, + String => true, + Array => true, + Hash => true, + }.compare_by_identity.freeze + + def initialize emitter, ss, options + super + @permitted_classes = DEFAULT_PERMITTED_CLASSES.dup + Array(options[:permitted_classes]).each do |klass| + @permitted_classes[klass] = true + end + @permitted_symbols = {}.compare_by_identity + Array(options[:permitted_symbols]).each do |symbol| + @permitted_symbols[symbol] = true + end + @aliases = options.fetch(:aliases, false) + end + + def accept target + if !@aliases && @st.key?(target) + raise BadAlias, "Tried to dump an aliased object" + end + + unless Symbol === target || @permitted_classes[target.class] + raise DisallowedClass.new('dump', target.class.name || target.class.inspect) + end + + super + end + + def visit_Symbol sym + unless @permitted_classes[Symbol] || @permitted_symbols[sym] + raise DisallowedClass.new('dump', "Symbol(#{sym.inspect})") + end + + super + end + end end end diff --git a/ext/psych/lib/psych/y.rb b/ext/psych/lib/psych/y.rb new file mode 100644 index 0000000000..e857953c04 --- /dev/null +++ b/ext/psych/lib/psych/y.rb @@ -0,0 +1,10 @@ +# frozen_string_literal: true +module Kernel + ### + # An alias for Psych.dump_stream meant to be used with IRB. + def y *objects + puts Psych.dump_stream(*objects) + end + private :y +end + diff --git a/ext/psych/parser.c b/ext/psych/parser.c deleted file mode 100644 index 0908a1b49f..0000000000 --- a/ext/psych/parser.c +++ /dev/null @@ -1,579 +0,0 @@ -#include <psych.h> - -VALUE cPsychParser; -VALUE ePsychSyntaxError; - -static ID id_read; -static ID id_path; -static ID id_empty; -static ID id_start_stream; -static ID id_end_stream; -static ID id_start_document; -static ID id_end_document; -static ID id_alias; -static ID id_scalar; -static ID id_start_sequence; -static ID id_end_sequence; -static ID id_start_mapping; -static ID id_end_mapping; - -#define PSYCH_TRANSCODE(_str, _yaml_enc, _internal_enc) \ - do { \ - rb_enc_associate_index((_str), (_yaml_enc)); \ - if(_internal_enc) \ - (_str) = rb_str_export_to_enc((_str), (_internal_enc)); \ - } while (0) - -static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read) -{ - VALUE io = (VALUE)data; - VALUE string = rb_funcall(io, id_read, 1, INT2NUM(size)); - - *read = 0; - - if(! NIL_P(string)) { - void * str = (void *)StringValuePtr(string); - *read = (size_t)RSTRING_LEN(string); - memcpy(buf, str, *read); - } - - return 1; -} - -static void dealloc(void * ptr) -{ - yaml_parser_t * parser; - - parser = (yaml_parser_t *)ptr; - yaml_parser_delete(parser); - xfree(parser); -} - -static VALUE allocate(VALUE klass) -{ - yaml_parser_t * parser; - - parser = xmalloc(sizeof(yaml_parser_t)); - yaml_parser_initialize(parser); - - return Data_Wrap_Struct(klass, 0, dealloc, parser); -} - -static VALUE make_exception(yaml_parser_t * parser, VALUE path) -{ - size_t line, column; - - line = parser->context_mark.line + 1; - column = parser->context_mark.column + 1; - - return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6, - path, - INT2NUM(line), - INT2NUM(column), - INT2NUM(parser->problem_offset), - parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil, - parser->context ? rb_usascii_str_new2(parser->context) : Qnil); -} - -#ifdef HAVE_RUBY_ENCODING_H -static VALUE transcode_string(VALUE src, int * parser_encoding) -{ - int utf8 = rb_utf8_encindex(); - int utf16le = rb_enc_find_index("UTF-16LE"); - int utf16be = rb_enc_find_index("UTF-16BE"); - int source_encoding = rb_enc_get_index(src); - - if (source_encoding == utf8) { - *parser_encoding = YAML_UTF8_ENCODING; - return src; - } - - if (source_encoding == utf16le) { - *parser_encoding = YAML_UTF16LE_ENCODING; - return src; - } - - if (source_encoding == utf16be) { - *parser_encoding = YAML_UTF16BE_ENCODING; - return src; - } - - src = rb_str_export_to_enc(src, rb_utf8_encoding()); - RB_GC_GUARD(src); - - *parser_encoding = YAML_UTF8_ENCODING; - return src; -} - -static VALUE transcode_io(VALUE src, int * parser_encoding) -{ - VALUE io_external_encoding; - int io_external_enc_index; - - io_external_encoding = rb_funcall(src, rb_intern("external_encoding"), 0); - - /* if no encoding is returned, assume ascii8bit. */ - if (NIL_P(io_external_encoding)) { - io_external_enc_index = rb_ascii8bit_encindex(); - } else { - io_external_enc_index = rb_to_encoding_index(io_external_encoding); - } - - /* Treat US-ASCII as utf_8 */ - if (io_external_enc_index == rb_usascii_encindex()) { - *parser_encoding = YAML_UTF8_ENCODING; - return src; - } - - if (io_external_enc_index == rb_utf8_encindex()) { - *parser_encoding = YAML_UTF8_ENCODING; - return src; - } - - if (io_external_enc_index == rb_enc_find_index("UTF-16LE")) { - *parser_encoding = YAML_UTF16LE_ENCODING; - return src; - } - - if (io_external_enc_index == rb_enc_find_index("UTF-16BE")) { - *parser_encoding = YAML_UTF16BE_ENCODING; - return src; - } - - /* Just guess on ASCII-8BIT */ - if (io_external_enc_index == rb_ascii8bit_encindex()) { - *parser_encoding = YAML_ANY_ENCODING; - return src; - } - - /* If the external encoding is something we don't know how to handle, - * fall back to YAML_ANY_ENCODING. */ - *parser_encoding = YAML_ANY_ENCODING; - - return src; -} - -#endif - -static VALUE protected_start_stream(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall(args[0], id_start_stream, 1, args[1]); -} - -static VALUE protected_start_document(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall3(args[0], id_start_document, 3, args + 1); -} - -static VALUE protected_end_document(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall(args[0], id_end_document, 1, args[1]); -} - -static VALUE protected_alias(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall(args[0], id_alias, 1, args[1]); -} - -static VALUE protected_scalar(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall3(args[0], id_scalar, 6, args + 1); -} - -static VALUE protected_start_sequence(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall3(args[0], id_start_sequence, 4, args + 1); -} - -static VALUE protected_end_sequence(VALUE handler) -{ - return rb_funcall(handler, id_end_sequence, 0); -} - -static VALUE protected_start_mapping(VALUE pointer) -{ - VALUE *args = (VALUE *)pointer; - return rb_funcall3(args[0], id_start_mapping, 4, args + 1); -} - -static VALUE protected_end_mapping(VALUE handler) -{ - return rb_funcall(handler, id_end_mapping, 0); -} - -static VALUE protected_empty(VALUE handler) -{ - return rb_funcall(handler, id_empty, 0); -} - -static VALUE protected_end_stream(VALUE handler) -{ - return rb_funcall(handler, id_end_stream, 0); -} - -/* - * call-seq: - * parser.parse(yaml) - * - * Parse the YAML document contained in +yaml+. Events will be called on - * the handler set on the parser instance. - * - * See Psych::Parser and Psych::Parser#handler - */ -static VALUE parse(int argc, VALUE *argv, VALUE self) -{ - VALUE yaml, path; - yaml_parser_t * parser; - yaml_event_t event; - int done = 0; - int tainted = 0; - int state = 0; - int parser_encoding = YAML_ANY_ENCODING; -#ifdef HAVE_RUBY_ENCODING_H - int encoding = rb_utf8_encindex(); - rb_encoding * internal_enc = rb_default_internal_encoding(); -#endif - VALUE handler = rb_iv_get(self, "@handler"); - - if (rb_scan_args(argc, argv, "11", &yaml, &path) == 1) { - if(rb_respond_to(yaml, id_path)) - path = rb_funcall(yaml, id_path, 0); - else - path = rb_str_new2("<unknown>"); - } - - Data_Get_Struct(self, yaml_parser_t, parser); - - yaml_parser_delete(parser); - yaml_parser_initialize(parser); - - if (OBJ_TAINTED(yaml)) tainted = 1; - - if (rb_respond_to(yaml, id_read)) { -#ifdef HAVE_RUBY_ENCODING_H - yaml = transcode_io(yaml, &parser_encoding); - yaml_parser_set_encoding(parser, parser_encoding); -#endif - yaml_parser_set_input(parser, io_reader, (void *)yaml); - if (RTEST(rb_obj_is_kind_of(yaml, rb_cIO))) tainted = 1; - } else { - StringValue(yaml); -#ifdef HAVE_RUBY_ENCODING_H - yaml = transcode_string(yaml, &parser_encoding); - yaml_parser_set_encoding(parser, parser_encoding); -#endif - yaml_parser_set_input_string( - parser, - (const unsigned char *)RSTRING_PTR(yaml), - (size_t)RSTRING_LEN(yaml) - ); - } - - while(!done) { - if(!yaml_parser_parse(parser, &event)) { - VALUE exception; - - exception = make_exception(parser, path); - yaml_parser_delete(parser); - yaml_parser_initialize(parser); - - rb_exc_raise(exception); - } - - switch(event.type) { - case YAML_STREAM_START_EVENT: - { - VALUE args[2]; - - args[0] = handler; - args[1] = INT2NUM((long)event.data.stream_start.encoding); - rb_protect(protected_start_stream, (VALUE)args, &state); - } - break; - case YAML_DOCUMENT_START_EVENT: - { - VALUE args[4]; - /* Get a list of tag directives (if any) */ - VALUE tag_directives = rb_ary_new(); - /* Grab the document version */ - VALUE version = event.data.document_start.version_directive ? - rb_ary_new3( - (long)2, - INT2NUM((long)event.data.document_start.version_directive->major), - INT2NUM((long)event.data.document_start.version_directive->minor) - ) : rb_ary_new(); - - if(event.data.document_start.tag_directives.start) { - yaml_tag_directive_t *start = - event.data.document_start.tag_directives.start; - yaml_tag_directive_t *end = - event.data.document_start.tag_directives.end; - for(; start != end; start++) { - VALUE handle = Qnil; - VALUE prefix = Qnil; - if(start->handle) { - handle = rb_str_new2((const char *)start->handle); - if (tainted) OBJ_TAINT(handle); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(handle, encoding, internal_enc); -#endif - } - - if(start->prefix) { - prefix = rb_str_new2((const char *)start->prefix); - if (tainted) OBJ_TAINT(prefix); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(prefix, encoding, internal_enc); -#endif - } - - rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix)); - } - } - args[0] = handler; - args[1] = version; - args[2] = tag_directives; - args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse; - rb_protect(protected_start_document, (VALUE)args, &state); - } - break; - case YAML_DOCUMENT_END_EVENT: - { - VALUE args[2]; - - args[0] = handler; - args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse; - rb_protect(protected_end_document, (VALUE)args, &state); - } - break; - case YAML_ALIAS_EVENT: - { - VALUE args[2]; - VALUE alias = Qnil; - if(event.data.alias.anchor) { - alias = rb_str_new2((const char *)event.data.alias.anchor); - if (tainted) OBJ_TAINT(alias); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(alias, encoding, internal_enc); -#endif - } - - args[0] = handler; - args[1] = alias; - rb_protect(protected_alias, (VALUE)args, &state); - } - break; - case YAML_SCALAR_EVENT: - { - VALUE args[7]; - VALUE anchor = Qnil; - VALUE tag = Qnil; - VALUE plain_implicit, quoted_implicit, style; - VALUE val = rb_str_new( - (const char *)event.data.scalar.value, - (long)event.data.scalar.length - ); - if (tainted) OBJ_TAINT(val); - -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(val, encoding, internal_enc); -#endif - - if(event.data.scalar.anchor) { - anchor = rb_str_new2((const char *)event.data.scalar.anchor); - if (tainted) OBJ_TAINT(anchor); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(anchor, encoding, internal_enc); -#endif - } - - if(event.data.scalar.tag) { - tag = rb_str_new2((const char *)event.data.scalar.tag); - if (tainted) OBJ_TAINT(tag); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(tag, encoding, internal_enc); -#endif - } - - plain_implicit = - event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue; - - quoted_implicit = - event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue; - - style = INT2NUM((long)event.data.scalar.style); - - args[0] = handler; - args[1] = val; - args[2] = anchor; - args[3] = tag; - args[4] = plain_implicit; - args[5] = quoted_implicit; - args[6] = style; - rb_protect(protected_scalar, (VALUE)args, &state); - } - break; - case YAML_SEQUENCE_START_EVENT: - { - VALUE args[5]; - VALUE anchor = Qnil; - VALUE tag = Qnil; - VALUE implicit, style; - if(event.data.sequence_start.anchor) { - anchor = rb_str_new2((const char *)event.data.sequence_start.anchor); - if (tainted) OBJ_TAINT(anchor); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(anchor, encoding, internal_enc); -#endif - } - - tag = Qnil; - if(event.data.sequence_start.tag) { - tag = rb_str_new2((const char *)event.data.sequence_start.tag); - if (tainted) OBJ_TAINT(tag); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(tag, encoding, internal_enc); -#endif - } - - implicit = - event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue; - - style = INT2NUM((long)event.data.sequence_start.style); - - args[0] = handler; - args[1] = anchor; - args[2] = tag; - args[3] = implicit; - args[4] = style; - - rb_protect(protected_start_sequence, (VALUE)args, &state); - } - break; - case YAML_SEQUENCE_END_EVENT: - rb_protect(protected_end_sequence, handler, &state); - break; - case YAML_MAPPING_START_EVENT: - { - VALUE args[5]; - VALUE anchor = Qnil; - VALUE tag = Qnil; - VALUE implicit, style; - if(event.data.mapping_start.anchor) { - anchor = rb_str_new2((const char *)event.data.mapping_start.anchor); - if (tainted) OBJ_TAINT(anchor); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(anchor, encoding, internal_enc); -#endif - } - - if(event.data.mapping_start.tag) { - tag = rb_str_new2((const char *)event.data.mapping_start.tag); - if (tainted) OBJ_TAINT(tag); -#ifdef HAVE_RUBY_ENCODING_H - PSYCH_TRANSCODE(tag, encoding, internal_enc); -#endif - } - - implicit = - event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue; - - style = INT2NUM((long)event.data.mapping_start.style); - - args[0] = handler; - args[1] = anchor; - args[2] = tag; - args[3] = implicit; - args[4] = style; - - rb_protect(protected_start_mapping, (VALUE)args, &state); - } - break; - case YAML_MAPPING_END_EVENT: - rb_protect(protected_end_mapping, handler, &state); - break; - case YAML_NO_EVENT: - rb_protect(protected_empty, handler, &state); - break; - case YAML_STREAM_END_EVENT: - rb_protect(protected_end_stream, handler, &state); - done = 1; - break; - } - yaml_event_delete(&event); - if (state) rb_jump_tag(state); - } - - return self; -} - -/* - * call-seq: - * parser.mark # => #<Psych::Parser::Mark> - * - * Returns a Psych::Parser::Mark object that contains line, column, and index - * information. - */ -static VALUE mark(VALUE self) -{ - VALUE mark_klass; - VALUE args[3]; - yaml_parser_t * parser; - - Data_Get_Struct(self, yaml_parser_t, parser); - mark_klass = rb_const_get_at(cPsychParser, rb_intern("Mark")); - args[0] = INT2NUM(parser->mark.index); - args[1] = INT2NUM(parser->mark.line); - args[2] = INT2NUM(parser->mark.column); - - return rb_class_new_instance(3, args, mark_klass); -} - -void Init_psych_parser() -{ -#if 0 - mPsych = rb_define_module("Psych"); -#endif - - cPsychParser = rb_define_class_under(mPsych, "Parser", rb_cObject); - rb_define_alloc_func(cPsychParser, allocate); - - /* Any encoding: Let the parser choose the encoding */ - rb_define_const(cPsychParser, "ANY", INT2NUM(YAML_ANY_ENCODING)); - - /* UTF-8 Encoding */ - rb_define_const(cPsychParser, "UTF8", INT2NUM(YAML_UTF8_ENCODING)); - - /* UTF-16-LE Encoding with BOM */ - rb_define_const(cPsychParser, "UTF16LE", INT2NUM(YAML_UTF16LE_ENCODING)); - - /* UTF-16-BE Encoding with BOM */ - rb_define_const(cPsychParser, "UTF16BE", INT2NUM(YAML_UTF16BE_ENCODING)); - - rb_require("psych/syntax_error"); - ePsychSyntaxError = rb_define_class_under(mPsych, "SyntaxError", rb_eSyntaxError); - - rb_define_method(cPsychParser, "parse", parse, -1); - rb_define_method(cPsychParser, "mark", mark, 0); - - id_read = rb_intern("read"); - id_path = rb_intern("path"); - id_empty = rb_intern("empty"); - id_start_stream = rb_intern("start_stream"); - id_end_stream = rb_intern("end_stream"); - id_start_document = rb_intern("start_document"); - id_end_document = rb_intern("end_document"); - id_alias = rb_intern("alias"); - id_scalar = rb_intern("scalar"); - id_start_sequence = rb_intern("start_sequence"); - id_end_sequence = rb_intern("end_sequence"); - id_start_mapping = rb_intern("start_mapping"); - id_end_mapping = rb_intern("end_mapping"); -} -/* vim: set noet sws=4 sw=4: */ diff --git a/ext/psych/psych.c b/ext/psych/psych.c index 69ff1d8dfc..afbd7a3571 100644 --- a/ext/psych/psych.c +++ b/ext/psych/psych.c @@ -11,17 +11,20 @@ static VALUE libyaml_version(VALUE module) yaml_get_version(&major, &minor, &patch); - list[0] = INT2NUM((long)major); - list[1] = INT2NUM((long)minor); - list[2] = INT2NUM((long)patch); + list[0] = INT2NUM(major); + list[1] = INT2NUM(minor); + list[2] = INT2NUM(patch); return rb_ary_new4((long)3, list); } VALUE mPsych; -void Init_psych() +void Init_psych(void) { + #ifdef HAVE_RB_EXT_RACTOR_SAFE + RB_EXT_RACTOR_SAFE(true); + #endif mPsych = rb_define_module("Psych"); rb_define_singleton_method(mPsych, "libyaml_version", libyaml_version, 0); @@ -31,4 +34,3 @@ void Init_psych() Init_psych_to_ruby(); Init_psych_yaml_tree(); } -/* vim: set noet sws=4 sw=4: */ diff --git a/ext/psych/psych.gemspec b/ext/psych/psych.gemspec new file mode 100644 index 0000000000..a32f79bc16 --- /dev/null +++ b/ext/psych/psych.gemspec @@ -0,0 +1,82 @@ +# -*- encoding: utf-8 -*- +# frozen_string_literal: true + +version_module = Module.new do + version_rb = File.join(__dir__, "lib/psych/versions.rb") + module_eval(File.read(version_rb), version_rb) +end + +Gem::Specification.new do |s| + s.name = "psych" + s.version = version_module::Psych::VERSION + s.authors = ["Aaron Patterson", "SHIBATA Hiroshi", "Charles Oliver Nutter"] + s.email = ["aaron@tenderlovemaking.com", "hsbt@ruby-lang.org", "headius@headius.com"] + s.summary = "Psych is a YAML parser and emitter" + s.description = <<-DESCRIPTION +Psych is a YAML parser and emitter. Psych leverages libyaml[https://pyyaml.org/wiki/LibYAML] +for its YAML parsing and emitting capabilities. In addition to wrapping libyaml, +Psych also knows how to serialize and de-serialize most Ruby objects to and from the YAML format. +DESCRIPTION + s.homepage = "https://github.com/ruby/psych" + s.licenses = ["MIT"] + s.require_paths = ["lib"] + + # for ruby core repository. + # It was generated by + # `git ls-files -z`.split("\x0").reject { |f| + # f.match(%r{^\.git|^(test|spec|features|bin|tool)/|^[A-Z]\w+file$|/extlibs$|\.(gemspec|java)$|jar}) + # } + s.files = [ + "CONTRIBUTING.md", "LICENSE", "README.md", "ext/psych/depend", + "ext/psych/extconf.rb", "ext/psych/psych.c", "ext/psych/psych.h", + "ext/psych/psych_emitter.c", "ext/psych/psych_emitter.h", + "ext/psych/psych_parser.c", "ext/psych/psych_parser.h", + "ext/psych/psych_to_ruby.c", "ext/psych/psych_to_ruby.h", + "ext/psych/psych_yaml_tree.c", "ext/psych/psych_yaml_tree.h", + "lib/psych.rb", "lib/psych/class_loader.rb", "lib/psych/coder.rb", + "lib/psych/core_ext.rb", "lib/psych/exception.rb", "lib/psych/handler.rb", + "lib/psych/handlers/document_stream.rb", "lib/psych/handlers/recorder.rb", + "lib/psych/json/ruby_events.rb", "lib/psych/json/stream.rb", + "lib/psych/json/tree_builder.rb", "lib/psych/json/yaml_events.rb", + "lib/psych/nodes.rb", "lib/psych/nodes/alias.rb", + "lib/psych/nodes/document.rb", "lib/psych/nodes/mapping.rb", + "lib/psych/nodes/node.rb", "lib/psych/nodes/scalar.rb", + "lib/psych/nodes/sequence.rb", "lib/psych/nodes/stream.rb", + "lib/psych/omap.rb", "lib/psych/parser.rb", "lib/psych/scalar_scanner.rb", + "lib/psych/set.rb", "lib/psych/stream.rb", "lib/psych/streaming.rb", + "lib/psych/syntax_error.rb", "lib/psych/tree_builder.rb", + "lib/psych/versions.rb", "lib/psych/visitors.rb", + "lib/psych/visitors/depth_first.rb", "lib/psych/visitors/emitter.rb", + "lib/psych/visitors/json_tree.rb", "lib/psych/visitors/to_ruby.rb", + "lib/psych/visitors/visitor.rb", "lib/psych/visitors/yaml_tree.rb", + "lib/psych/y.rb" + ] + + s.rdoc_options = ["--main", "README.md"] + s.extra_rdoc_files = ["README.md"] + + s.required_ruby_version = Gem::Requirement.new(">= 2.5.0") + s.required_rubygems_version = Gem::Requirement.new(">= 0") + + if RUBY_ENGINE == 'jruby' + s.platform = 'java' + s.files.concat [ + "ext/java/org/jruby/ext/psych/PsychEmitter.java", + "ext/java/org/jruby/ext/psych/PsychLibrary.java", + "ext/java/org/jruby/ext/psych/PsychParser.java", + "ext/java/org/jruby/ext/psych/PsychToRuby.java", + "lib/psych_jars.rb", + "lib/psych.jar" + ] + s.requirements = "jar org.snakeyaml:snakeyaml-engine, #{version_module::Psych::DEFAULT_SNAKEYAML_VERSION}" + s.add_dependency 'jar-dependencies', '>= 0.1.7' + else + s.extensions = ["ext/psych/extconf.rb"] + s.add_dependency 'stringio' + end + + s.add_dependency 'date' + + s.metadata['msys2_mingw_dependencies'] = 'libyaml' + s.metadata['changelog_uri'] = s.homepage + '/releases' +end diff --git a/ext/psych/psych.h b/ext/psych/psych.h index 9f1be449a2..6b3d63f246 100644 --- a/ext/psych/psych.h +++ b/ext/psych/psych.h @@ -2,17 +2,14 @@ #define PSYCH_H #include <ruby.h> - -#ifdef HAVE_RUBY_ENCODING_H #include <ruby/encoding.h> -#endif #include <yaml.h> -#include <parser.h> -#include <emitter.h> -#include <to_ruby.h> -#include <yaml_tree.h> +#include <psych_parser.h> +#include <psych_emitter.h> +#include <psych_to_ruby.h> +#include <psych_yaml_tree.h> extern VALUE mPsych; diff --git a/ext/psych/emitter.c b/ext/psych/psych_emitter.c index f0d032649c..624ab7c528 100644 --- a/ext/psych/emitter.c +++ b/ext/psych/psych_emitter.c @@ -1,6 +1,14 @@ #include <psych.h> +#if !defined(RARRAY_CONST_PTR) +#define RARRAY_CONST_PTR(s) (const VALUE *)RARRAY_PTR(s) +#endif +#if !defined(RARRAY_AREF) +#define RARRAY_AREF(a, i) RARRAY_CONST_PTR(a)[i] +#endif + VALUE cPsychEmitter; +static ID id_io; static ID id_write; static ID id_line_width; static ID id_indentation; @@ -9,13 +17,13 @@ static ID id_canonical; static void emit(yaml_emitter_t * emitter, yaml_event_t * event) { if(!yaml_emitter_emit(emitter, event)) - rb_raise(rb_eRuntimeError, "%s", emitter->problem); + rb_raise(rb_eRuntimeError, "%s", emitter->problem); } static int writer(void *ctx, unsigned char *buffer, size_t size) { - VALUE io = (VALUE)ctx; - VALUE str = rb_str_new((const char *)buffer, (long)size); + VALUE self = (VALUE)ctx, io = rb_attr_get(self, id_io); + VALUE str = rb_enc_str_new((const char *)buffer, (long)size, rb_utf8_encoding()); VALUE wrote = rb_funcall(io, id_write, 1, str); return (int)NUM2INT(wrote); } @@ -29,17 +37,34 @@ static void dealloc(void * ptr) xfree(emitter); } +#if 0 +static size_t memsize(const void *ptr) +{ + const yaml_emitter_t *emitter = ptr; + /* TODO: calculate emitter's size */ + return 0; +} +#endif + +static const rb_data_type_t psych_emitter_type = { + "Psych/emitter", + {0, dealloc, 0,}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; + static VALUE allocate(VALUE klass) { yaml_emitter_t * emitter; - - emitter = xmalloc(sizeof(yaml_emitter_t)); + VALUE obj = TypedData_Make_Struct(klass, yaml_emitter_t, &psych_emitter_type, emitter); yaml_emitter_initialize(emitter); yaml_emitter_set_unicode(emitter, 1); yaml_emitter_set_indent(emitter, 2); - return Data_Wrap_Struct(klass, 0, dealloc, emitter); + return obj; } /* call-seq: Psych::Emitter.new(io, options = Psych::Emitter::OPTIONS) @@ -54,19 +79,20 @@ static VALUE initialize(int argc, VALUE *argv, VALUE self) VALUE indent; VALUE canonical; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); if (rb_scan_args(argc, argv, "11", &io, &options) == 2) { - line_width = rb_funcall(options, id_line_width, 0); - indent = rb_funcall(options, id_indentation, 0); - canonical = rb_funcall(options, id_canonical, 0); + line_width = rb_funcall(options, id_line_width, 0); + indent = rb_funcall(options, id_indentation, 0); + canonical = rb_funcall(options, id_canonical, 0); - yaml_emitter_set_width(emitter, NUM2INT(line_width)); - yaml_emitter_set_indent(emitter, NUM2INT(indent)); - yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0); + yaml_emitter_set_width(emitter, NUM2INT(line_width)); + yaml_emitter_set_indent(emitter, NUM2INT(indent)); + yaml_emitter_set_canonical(emitter, Qtrue == canonical ? 1 : 0); } - yaml_emitter_set_output(emitter, writer, (void *)io); + rb_ivar_set(self, id_io, io); + yaml_emitter_set_output(emitter, writer, (void *)self); return self; } @@ -81,7 +107,7 @@ static VALUE start_stream(VALUE self, VALUE encoding) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); Check_Type(encoding, T_FIXNUM); yaml_stream_start_event_initialize(&event, (yaml_encoding_t)NUM2INT(encoding)); @@ -101,7 +127,7 @@ static VALUE end_stream(VALUE self) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_stream_end_event_initialize(&event); @@ -110,84 +136,118 @@ static VALUE end_stream(VALUE self) return self; } -/* call-seq: emitter.start_document(version, tags, implicit) - * - * Start a document emission with YAML +version+, +tags+, and an +implicit+ - * start. - * - * See Psych::Handler#start_document - */ -static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp) +struct start_document_data { + VALUE self; + VALUE version; + VALUE tags; + VALUE imp; + + yaml_tag_directive_t * head; +}; + +static VALUE start_document_try(VALUE d) { + struct start_document_data * data = (struct start_document_data *)d; + VALUE self = data->self; + VALUE version = data->version; + VALUE tags = data->tags; + VALUE imp = data->imp; + yaml_emitter_t * emitter; - yaml_tag_directive_t * head = NULL; yaml_tag_directive_t * tail = NULL; yaml_event_t event; yaml_version_directive_t version_directive; - Data_Get_Struct(self, yaml_emitter_t, emitter); - + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); Check_Type(version, T_ARRAY); if(RARRAY_LEN(version) > 0) { - VALUE major = rb_ary_entry(version, (long)0); - VALUE minor = rb_ary_entry(version, (long)1); + VALUE major = rb_ary_entry(version, (long)0); + VALUE minor = rb_ary_entry(version, (long)1); - version_directive.major = NUM2INT(major); - version_directive.minor = NUM2INT(minor); + version_directive.major = NUM2INT(major); + version_directive.minor = NUM2INT(minor); } if(RTEST(tags)) { - int i = 0; -#ifdef HAVE_RUBY_ENCODING_H - rb_encoding * encoding = rb_utf8_encoding(); -#endif + long i = 0; + long len; + rb_encoding * encoding = rb_utf8_encoding(); - Check_Type(tags, T_ARRAY); + Check_Type(tags, T_ARRAY); - head = xcalloc((size_t)RARRAY_LEN(tags), sizeof(yaml_tag_directive_t)); - tail = head; + len = RARRAY_LEN(tags); + data->head = xcalloc((size_t)len, sizeof(yaml_tag_directive_t)); + tail = data->head; - for(i = 0; i < RARRAY_LEN(tags); i++) { - VALUE tuple = RARRAY_PTR(tags)[i]; - VALUE name; - VALUE value; + for(i = 0; i < len && i < RARRAY_LEN(tags); i++) { + VALUE tuple = RARRAY_AREF(tags, i); + VALUE name; + VALUE value; - Check_Type(tuple, T_ARRAY); + Check_Type(tuple, T_ARRAY); - if(RARRAY_LEN(tuple) < 2) { - xfree(head); - rb_raise(rb_eRuntimeError, "tag tuple must be of length 2"); - } - name = RARRAY_PTR(tuple)[0]; - value = RARRAY_PTR(tuple)[1]; -#ifdef HAVE_RUBY_ENCODING_H - name = rb_str_export_to_enc(name, encoding); - value = rb_str_export_to_enc(value, encoding); -#endif + if(RARRAY_LEN(tuple) < 2) { + rb_raise(rb_eRuntimeError, "tag tuple must be of length 2"); + } + + name = RARRAY_AREF(tuple, 0); + value = RARRAY_AREF(tuple, 1); + StringValue(name); + StringValue(value); + name = rb_str_export_to_enc(name, encoding); + value = rb_str_export_to_enc(value, encoding); - tail->handle = (yaml_char_t *)StringValuePtr(name); - tail->prefix = (yaml_char_t *)StringValuePtr(value); + tail->handle = (yaml_char_t *)StringValueCStr(name); + tail->prefix = (yaml_char_t *)StringValueCStr(value); - tail++; - } + tail++; + } } yaml_document_start_event_initialize( - &event, - (RARRAY_LEN(version) > 0) ? &version_directive : NULL, - head, - tail, - imp ? 1 : 0 - ); + &event, + (RARRAY_LEN(version) > 0) ? &version_directive : NULL, + data->head, + tail, + imp ? 1 : 0 + ); emit(emitter, &event); - if(head) xfree(head); - return self; } +static VALUE start_document_ensure(VALUE d) +{ + struct start_document_data * data = (struct start_document_data *)d; + + xfree(data->head); + + return Qnil; +} + +/* call-seq: emitter.start_document(version, tags, implicit) + * + * Start a document emission with YAML +version+, +tags+, and an +implicit+ + * start. + * + * See Psych::Handler#start_document + */ +static VALUE start_document(VALUE self, VALUE version, VALUE tags, VALUE imp) +{ + struct start_document_data data = { + .self = self, + .version = version, + .tags = tags, + .imp = imp, + + .head = NULL, + }; + + return rb_ensure(start_document_try, (VALUE)&data, start_document_ensure, (VALUE)&data); +} + /* call-seq: emitter.end_document(implicit) * * End a document emission with an +implicit+ ending. @@ -198,7 +258,7 @@ static VALUE end_document(VALUE self, VALUE imp) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_document_end_event_initialize(&event, imp ? 1 : 0); @@ -215,49 +275,46 @@ static VALUE end_document(VALUE self, VALUE imp) * See Psych::Handler#scalar */ static VALUE scalar( - VALUE self, - VALUE value, - VALUE anchor, - VALUE tag, - VALUE plain, - VALUE quoted, - VALUE style - ) { + VALUE self, + VALUE value, + VALUE anchor, + VALUE tag, + VALUE plain, + VALUE quoted, + VALUE style + ) { yaml_emitter_t * emitter; yaml_event_t event; -#ifdef HAVE_RUBY_ENCODING_H rb_encoding *encoding; -#endif - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); Check_Type(value, T_STRING); -#ifdef HAVE_RUBY_ENCODING_H encoding = rb_utf8_encoding(); value = rb_str_export_to_enc(value, encoding); if(!NIL_P(anchor)) { - Check_Type(anchor, T_STRING); - anchor = rb_str_export_to_enc(anchor, encoding); + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); } if(!NIL_P(tag)) { - Check_Type(tag, T_STRING); - tag = rb_str_export_to_enc(tag, encoding); + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); } -#endif + const char *value_ptr = StringValuePtr(value); yaml_scalar_event_initialize( - &event, - (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)), - (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)), - (yaml_char_t*)StringValuePtr(value), - (int)RSTRING_LEN(value), - plain ? 1 : 0, - quoted ? 1 : 0, - (yaml_scalar_style_t)NUM2INT(style) - ); + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + (yaml_char_t*)value_ptr, + (int)RSTRING_LEN(value), + plain ? 1 : 0, + quoted ? 1 : 0, + (yaml_scalar_style_t)NUM2INT(style) + ); emit(emitter, &event); @@ -272,38 +329,36 @@ static VALUE scalar( * See Psych::Handler#start_sequence */ static VALUE start_sequence( - VALUE self, - VALUE anchor, - VALUE tag, - VALUE implicit, - VALUE style - ) { + VALUE self, + VALUE anchor, + VALUE tag, + VALUE implicit, + VALUE style + ) { yaml_emitter_t * emitter; yaml_event_t event; -#ifdef HAVE_RUBY_ENCODING_H rb_encoding * encoding = rb_utf8_encoding(); if(!NIL_P(anchor)) { - Check_Type(anchor, T_STRING); - anchor = rb_str_export_to_enc(anchor, encoding); + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); } if(!NIL_P(tag)) { - Check_Type(tag, T_STRING); - tag = rb_str_export_to_enc(tag, encoding); + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); } -#endif - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_sequence_start_event_initialize( - &event, - (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)), - (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)), - implicit ? 1 : 0, - (yaml_sequence_style_t)NUM2INT(style) - ); + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + implicit ? 1 : 0, + (yaml_sequence_style_t)NUM2INT(style) + ); emit(emitter, &event); @@ -320,7 +375,7 @@ static VALUE end_sequence(VALUE self) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_sequence_end_event_initialize(&event); @@ -337,40 +392,37 @@ static VALUE end_sequence(VALUE self) * See Psych::Handler#start_mapping */ static VALUE start_mapping( - VALUE self, - VALUE anchor, - VALUE tag, - VALUE implicit, - VALUE style - ) { + VALUE self, + VALUE anchor, + VALUE tag, + VALUE implicit, + VALUE style + ) { yaml_emitter_t * emitter; yaml_event_t event; -#ifdef HAVE_RUBY_ENCODING_H rb_encoding *encoding; -#endif - Data_Get_Struct(self, yaml_emitter_t, emitter); -#ifdef HAVE_RUBY_ENCODING_H + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); + encoding = rb_utf8_encoding(); if(!NIL_P(anchor)) { - Check_Type(anchor, T_STRING); - anchor = rb_str_export_to_enc(anchor, encoding); + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, encoding); } if(!NIL_P(tag)) { - Check_Type(tag, T_STRING); - tag = rb_str_export_to_enc(tag, encoding); + Check_Type(tag, T_STRING); + tag = rb_str_export_to_enc(tag, encoding); } -#endif yaml_mapping_start_event_initialize( - &event, - (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)), - (yaml_char_t *)(NIL_P(tag) ? NULL : StringValuePtr(tag)), - implicit ? 1 : 0, - (yaml_mapping_style_t)NUM2INT(style) - ); + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)), + (yaml_char_t *)(NIL_P(tag) ? NULL : StringValueCStr(tag)), + implicit ? 1 : 0, + (yaml_mapping_style_t)NUM2INT(style) + ); emit(emitter, &event); @@ -387,7 +439,7 @@ static VALUE end_mapping(VALUE self) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_mapping_end_event_initialize(&event); @@ -406,19 +458,17 @@ static VALUE alias(VALUE self, VALUE anchor) { yaml_emitter_t * emitter; yaml_event_t event; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); -#ifdef HAVE_RUBY_ENCODING_H if(!NIL_P(anchor)) { - Check_Type(anchor, T_STRING); - anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding()); + Check_Type(anchor, T_STRING); + anchor = rb_str_export_to_enc(anchor, rb_utf8_encoding()); } -#endif yaml_alias_event_initialize( - &event, - (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValuePtr(anchor)) - ); + &event, + (yaml_char_t *)(NIL_P(anchor) ? NULL : StringValueCStr(anchor)) + ); emit(emitter, &event); @@ -432,7 +482,7 @@ static VALUE alias(VALUE self, VALUE anchor) static VALUE set_canonical(VALUE self, VALUE style) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_emitter_set_canonical(emitter, Qtrue == style ? 1 : 0); @@ -446,7 +496,7 @@ static VALUE set_canonical(VALUE self, VALUE style) static VALUE canonical(VALUE self) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); return (emitter->canonical == 0) ? Qfalse : Qtrue; } @@ -459,7 +509,7 @@ static VALUE canonical(VALUE self) static VALUE set_indentation(VALUE self, VALUE level) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_emitter_set_indent(emitter, NUM2INT(level)); @@ -473,7 +523,7 @@ static VALUE set_indentation(VALUE self, VALUE level) static VALUE indentation(VALUE self) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); return INT2NUM(emitter->best_indent); } @@ -485,7 +535,7 @@ static VALUE indentation(VALUE self) static VALUE line_width(VALUE self) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); return INT2NUM(emitter->best_width); } @@ -497,15 +547,16 @@ static VALUE line_width(VALUE self) static VALUE set_line_width(VALUE self, VALUE width) { yaml_emitter_t * emitter; - Data_Get_Struct(self, yaml_emitter_t, emitter); + TypedData_Get_Struct(self, yaml_emitter_t, &psych_emitter_type, emitter); yaml_emitter_set_width(emitter, NUM2INT(width)); return width; } -void Init_psych_emitter() +void Init_psych_emitter(void) { +#undef rb_intern VALUE psych = rb_define_module("Psych"); VALUE handler = rb_define_class_under(psych, "Handler", rb_cObject); cPsychEmitter = rb_define_class_under(psych, "Emitter", handler); @@ -530,9 +581,9 @@ void Init_psych_emitter() rb_define_method(cPsychEmitter, "line_width", line_width, 0); rb_define_method(cPsychEmitter, "line_width=", set_line_width, 1); + id_io = rb_intern("io"); id_write = rb_intern("write"); id_line_width = rb_intern("line_width"); id_indentation = rb_intern("indentation"); id_canonical = rb_intern("canonical"); } -/* vim: set noet sws=4 sw=4: */ diff --git a/ext/psych/emitter.h b/ext/psych/psych_emitter.h index 560451ef31..4c1482a78b 100644 --- a/ext/psych/emitter.h +++ b/ext/psych/psych_emitter.h @@ -3,6 +3,6 @@ #include <psych.h> -void Init_psych_emitter(); +void Init_psych_emitter(void); #endif diff --git a/ext/psych/psych_parser.c b/ext/psych/psych_parser.c new file mode 100644 index 0000000000..00a2207b58 --- /dev/null +++ b/ext/psych/psych_parser.c @@ -0,0 +1,575 @@ +#include <psych.h> + +VALUE cPsychParser; + +static ID id_read; +static ID id_path; +static ID id_empty; +static ID id_start_stream; +static ID id_end_stream; +static ID id_start_document; +static ID id_end_document; +static ID id_alias; +static ID id_scalar; +static ID id_start_sequence; +static ID id_end_sequence; +static ID id_start_mapping; +static ID id_end_mapping; +static ID id_event_location; + +#define PSYCH_TRANSCODE(_str, _yaml_enc, _internal_enc) \ + do { \ + rb_enc_associate_index((_str), (_yaml_enc)); \ + if(_internal_enc) \ + (_str) = rb_str_export_to_enc((_str), (_internal_enc)); \ + } while (0) + +static int io_reader(void * data, unsigned char *buf, size_t size, size_t *read) +{ + VALUE io = (VALUE)data; + VALUE string = rb_funcall(io, id_read, 1, SIZET2NUM(size)); + + *read = 0; + + if(! NIL_P(string)) { + char * str = StringValuePtr(string); + size_t len = (size_t)RSTRING_LEN(string); + + /* IO#read(size) is documented to return at most `size` bytes, but a + * misbehaving IO-like object may return more. Clamp the copy to the + * buffer libyaml gave us to avoid writing past its end, rounding down + * to a character boundary so a multibyte character is never split. */ + if(len > size) { + rb_encoding * enc = rb_enc_get(string); + len = (size_t)(rb_enc_left_char_head(str, str + size, str + len, enc) - str); + } + + *read = len; + memcpy(buf, str, len); + } + + return 1; +} + +static void dealloc(void * ptr) +{ + yaml_parser_t * parser; + + parser = (yaml_parser_t *)ptr; + yaml_parser_delete(parser); + xfree(parser); +} + +#if 0 +static size_t memsize(const void *ptr) +{ + const yaml_parser_t *parser = ptr; + /* TODO: calculate parser's size */ + return 0; +} +#endif + +static const rb_data_type_t psych_parser_type = { + "Psych/parser", + {0, dealloc, 0,}, + 0, 0, +#ifdef RUBY_TYPED_FREE_IMMEDIATELY + RUBY_TYPED_FREE_IMMEDIATELY, +#endif +}; + +static VALUE allocate(VALUE klass) +{ + yaml_parser_t * parser; + VALUE obj = TypedData_Make_Struct(klass, yaml_parser_t, &psych_parser_type, parser); + + yaml_parser_initialize(parser); + + return obj; +} + +static VALUE make_exception(yaml_parser_t * parser, VALUE path) +{ + if (parser->error == YAML_MEMORY_ERROR) { + return rb_eNoMemError; + } else { + size_t line, column; + VALUE ePsychSyntaxError; + + line = parser->context_mark.line + 1; + column = parser->context_mark.column + 1; + + ePsychSyntaxError = rb_const_get(mPsych, rb_intern("SyntaxError")); + + return rb_funcall(ePsychSyntaxError, rb_intern("new"), 6, + path, + SIZET2NUM(line), + SIZET2NUM(column), + SIZET2NUM(parser->problem_offset), + parser->problem ? rb_usascii_str_new2(parser->problem) : Qnil, + parser->context ? rb_usascii_str_new2(parser->context) : Qnil); + } +} + +static VALUE transcode_string(VALUE src, int * parser_encoding) +{ + int utf8 = rb_utf8_encindex(); + int utf16le = rb_enc_find_index("UTF-16LE"); + int utf16be = rb_enc_find_index("UTF-16BE"); + int source_encoding = rb_enc_get_index(src); + + if (source_encoding == utf8) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (source_encoding == utf16le) { + *parser_encoding = YAML_UTF16LE_ENCODING; + return src; + } + + if (source_encoding == utf16be) { + *parser_encoding = YAML_UTF16BE_ENCODING; + return src; + } + + src = rb_str_export_to_enc(src, rb_utf8_encoding()); + RB_GC_GUARD(src); + + *parser_encoding = YAML_UTF8_ENCODING; + return src; +} + +static VALUE transcode_io(VALUE src, int * parser_encoding) +{ + VALUE io_external_encoding; + int io_external_enc_index; + + io_external_encoding = rb_funcall(src, rb_intern("external_encoding"), 0); + + /* if no encoding is returned, assume ascii8bit. */ + if (NIL_P(io_external_encoding)) { + io_external_enc_index = rb_ascii8bit_encindex(); + } else { + io_external_enc_index = rb_to_encoding_index(io_external_encoding); + } + + /* Treat US-ASCII as utf_8 */ + if (io_external_enc_index == rb_usascii_encindex()) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (io_external_enc_index == rb_utf8_encindex()) { + *parser_encoding = YAML_UTF8_ENCODING; + return src; + } + + if (io_external_enc_index == rb_enc_find_index("UTF-16LE")) { + *parser_encoding = YAML_UTF16LE_ENCODING; + return src; + } + + if (io_external_enc_index == rb_enc_find_index("UTF-16BE")) { + *parser_encoding = YAML_UTF16BE_ENCODING; + return src; + } + + /* Just guess on ASCII-8BIT */ + if (io_external_enc_index == rb_ascii8bit_encindex()) { + *parser_encoding = YAML_ANY_ENCODING; + return src; + } + + /* If the external encoding is something we don't know how to handle, + * fall back to YAML_ANY_ENCODING. */ + *parser_encoding = YAML_ANY_ENCODING; + + return src; +} + +static VALUE protected_start_stream(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_start_stream, 1, args[1]); +} + +static VALUE protected_start_document(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_document, 3, args + 1); +} + +static VALUE protected_end_document(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_end_document, 1, args[1]); +} + +static VALUE protected_alias(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall(args[0], id_alias, 1, args[1]); +} + +static VALUE protected_scalar(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_scalar, 6, args + 1); +} + +static VALUE protected_start_sequence(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_sequence, 4, args + 1); +} + +static VALUE protected_end_sequence(VALUE handler) +{ + return rb_funcall(handler, id_end_sequence, 0); +} + +static VALUE protected_start_mapping(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_start_mapping, 4, args + 1); +} + +static VALUE protected_end_mapping(VALUE handler) +{ + return rb_funcall(handler, id_end_mapping, 0); +} + +static VALUE protected_empty(VALUE handler) +{ + return rb_funcall(handler, id_empty, 0); +} + +static VALUE protected_end_stream(VALUE handler) +{ + return rb_funcall(handler, id_end_stream, 0); +} + +static VALUE protected_event_location(VALUE pointer) +{ + VALUE *args = (VALUE *)pointer; + return rb_funcall3(args[0], id_event_location, 4, args + 1); +} + +static VALUE parse(VALUE self, VALUE handler, VALUE yaml, VALUE path) +{ + yaml_parser_t * parser; + yaml_event_t event; + int done = 0; + int state = 0; + int parser_encoding = YAML_ANY_ENCODING; + int encoding = rb_utf8_encindex(); + rb_encoding * internal_enc = rb_default_internal_encoding(); + + TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser); + + yaml_parser_delete(parser); + yaml_parser_initialize(parser); + + if (rb_respond_to(yaml, id_read)) { + yaml = transcode_io(yaml, &parser_encoding); + yaml_parser_set_encoding(parser, parser_encoding); + yaml_parser_set_input(parser, io_reader, (void *)yaml); + } else { + StringValue(yaml); + yaml = transcode_string(yaml, &parser_encoding); + yaml_parser_set_encoding(parser, parser_encoding); + yaml_parser_set_input_string( + parser, + (const unsigned char *)RSTRING_PTR(yaml), + (size_t)RSTRING_LEN(yaml) + ); + } + + while(!done) { + VALUE event_args[5]; + VALUE start_line, start_column, end_line, end_column; + + if(parser->error || !yaml_parser_parse(parser, &event)) { + VALUE exception; + + exception = make_exception(parser, path); + yaml_parser_delete(parser); + yaml_parser_initialize(parser); + + rb_exc_raise(exception); + } + + start_line = SIZET2NUM(event.start_mark.line); + start_column = SIZET2NUM(event.start_mark.column); + end_line = SIZET2NUM(event.end_mark.line); + end_column = SIZET2NUM(event.end_mark.column); + + event_args[0] = handler; + event_args[1] = start_line; + event_args[2] = start_column; + event_args[3] = end_line; + event_args[4] = end_column; + rb_protect(protected_event_location, (VALUE)event_args, &state); + + switch(event.type) { + case YAML_STREAM_START_EVENT: + { + VALUE args[2]; + + args[0] = handler; + args[1] = INT2NUM(event.data.stream_start.encoding); + rb_protect(protected_start_stream, (VALUE)args, &state); + } + break; + case YAML_DOCUMENT_START_EVENT: + { + VALUE args[4]; + /* Get a list of tag directives (if any) */ + VALUE tag_directives = rb_ary_new(); + /* Grab the document version */ + VALUE version = event.data.document_start.version_directive ? + rb_ary_new3( + (long)2, + INT2NUM(event.data.document_start.version_directive->major), + INT2NUM(event.data.document_start.version_directive->minor) + ) : rb_ary_new(); + + if(event.data.document_start.tag_directives.start) { + yaml_tag_directive_t *start = + event.data.document_start.tag_directives.start; + yaml_tag_directive_t *end = + event.data.document_start.tag_directives.end; + for(; start != end; start++) { + VALUE handle = Qnil; + VALUE prefix = Qnil; + if(start->handle) { + handle = rb_str_new2((const char *)start->handle); + PSYCH_TRANSCODE(handle, encoding, internal_enc); + } + + if(start->prefix) { + prefix = rb_str_new2((const char *)start->prefix); + PSYCH_TRANSCODE(prefix, encoding, internal_enc); + } + + rb_ary_push(tag_directives, rb_ary_new3((long)2, handle, prefix)); + } + } + args[0] = handler; + args[1] = version; + args[2] = tag_directives; + args[3] = event.data.document_start.implicit == 1 ? Qtrue : Qfalse; + rb_protect(protected_start_document, (VALUE)args, &state); + } + break; + case YAML_DOCUMENT_END_EVENT: + { + VALUE args[2]; + + args[0] = handler; + args[1] = event.data.document_end.implicit == 1 ? Qtrue : Qfalse; + rb_protect(protected_end_document, (VALUE)args, &state); + } + break; + case YAML_ALIAS_EVENT: + { + VALUE args[2]; + VALUE alias = Qnil; + if(event.data.alias.anchor) { + alias = rb_str_new2((const char *)event.data.alias.anchor); + PSYCH_TRANSCODE(alias, encoding, internal_enc); + } + + args[0] = handler; + args[1] = alias; + rb_protect(protected_alias, (VALUE)args, &state); + } + break; + case YAML_SCALAR_EVENT: + { + VALUE args[7]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE plain_implicit, quoted_implicit, style; + VALUE val = rb_str_new( + (const char *)event.data.scalar.value, + (long)event.data.scalar.length + ); + + PSYCH_TRANSCODE(val, encoding, internal_enc); + + if(event.data.scalar.anchor) { + anchor = rb_str_new2((const char *)event.data.scalar.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + if(event.data.scalar.tag) { + tag = rb_str_new2((const char *)event.data.scalar.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + plain_implicit = + event.data.scalar.plain_implicit == 0 ? Qfalse : Qtrue; + + quoted_implicit = + event.data.scalar.quoted_implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.scalar.style); + + args[0] = handler; + args[1] = val; + args[2] = anchor; + args[3] = tag; + args[4] = plain_implicit; + args[5] = quoted_implicit; + args[6] = style; + rb_protect(protected_scalar, (VALUE)args, &state); + } + break; + case YAML_SEQUENCE_START_EVENT: + { + VALUE args[5]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE implicit, style; + if(event.data.sequence_start.anchor) { + anchor = rb_str_new2((const char *)event.data.sequence_start.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + tag = Qnil; + if(event.data.sequence_start.tag) { + tag = rb_str_new2((const char *)event.data.sequence_start.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + implicit = + event.data.sequence_start.implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.sequence_start.style); + + args[0] = handler; + args[1] = anchor; + args[2] = tag; + args[3] = implicit; + args[4] = style; + + rb_protect(protected_start_sequence, (VALUE)args, &state); + } + break; + case YAML_SEQUENCE_END_EVENT: + rb_protect(protected_end_sequence, handler, &state); + break; + case YAML_MAPPING_START_EVENT: + { + VALUE args[5]; + VALUE anchor = Qnil; + VALUE tag = Qnil; + VALUE implicit, style; + if(event.data.mapping_start.anchor) { + anchor = rb_str_new2((const char *)event.data.mapping_start.anchor); + PSYCH_TRANSCODE(anchor, encoding, internal_enc); + } + + if(event.data.mapping_start.tag) { + tag = rb_str_new2((const char *)event.data.mapping_start.tag); + PSYCH_TRANSCODE(tag, encoding, internal_enc); + } + + implicit = + event.data.mapping_start.implicit == 0 ? Qfalse : Qtrue; + + style = INT2NUM(event.data.mapping_start.style); + + args[0] = handler; + args[1] = anchor; + args[2] = tag; + args[3] = implicit; + args[4] = style; + + rb_protect(protected_start_mapping, (VALUE)args, &state); + } + break; + case YAML_MAPPING_END_EVENT: + rb_protect(protected_end_mapping, handler, &state); + break; + case YAML_NO_EVENT: + rb_protect(protected_empty, handler, &state); + break; + case YAML_STREAM_END_EVENT: + rb_protect(protected_end_stream, handler, &state); + done = 1; + break; + } + yaml_event_delete(&event); + if (state) rb_jump_tag(state); + } + + return self; +} + +/* + * call-seq: + * parser.mark # => #<Psych::Parser::Mark> + * + * Returns a Psych::Parser::Mark object that contains line, column, and index + * information. + */ +static VALUE mark(VALUE self) +{ + VALUE mark_klass; + VALUE args[3]; + yaml_parser_t * parser; + + TypedData_Get_Struct(self, yaml_parser_t, &psych_parser_type, parser); + mark_klass = rb_const_get_at(cPsychParser, rb_intern("Mark")); + args[0] = SIZET2NUM(parser->mark.index); + args[1] = SIZET2NUM(parser->mark.line); + args[2] = SIZET2NUM(parser->mark.column); + + return rb_class_new_instance(3, args, mark_klass); +} + +void Init_psych_parser(void) +{ +#undef rb_intern +#if 0 + mPsych = rb_define_module("Psych"); +#endif + + cPsychParser = rb_define_class_under(mPsych, "Parser", rb_cObject); + rb_define_alloc_func(cPsychParser, allocate); + + /* Any encoding: Let the parser choose the encoding */ + rb_define_const(cPsychParser, "ANY", INT2NUM(YAML_ANY_ENCODING)); + + /* UTF-8 Encoding */ + rb_define_const(cPsychParser, "UTF8", INT2NUM(YAML_UTF8_ENCODING)); + + /* UTF-16-LE Encoding with BOM */ + rb_define_const(cPsychParser, "UTF16LE", INT2NUM(YAML_UTF16LE_ENCODING)); + + /* UTF-16-BE Encoding with BOM */ + rb_define_const(cPsychParser, "UTF16BE", INT2NUM(YAML_UTF16BE_ENCODING)); + + rb_require("psych/syntax_error"); + + rb_define_private_method(cPsychParser, "_native_parse", parse, 3); + rb_define_method(cPsychParser, "mark", mark, 0); + + id_read = rb_intern("read"); + id_path = rb_intern("path"); + id_empty = rb_intern("empty"); + id_start_stream = rb_intern("start_stream"); + id_end_stream = rb_intern("end_stream"); + id_start_document = rb_intern("start_document"); + id_end_document = rb_intern("end_document"); + id_alias = rb_intern("alias"); + id_scalar = rb_intern("scalar"); + id_start_sequence = rb_intern("start_sequence"); + id_end_sequence = rb_intern("end_sequence"); + id_start_mapping = rb_intern("start_mapping"); + id_end_mapping = rb_intern("end_mapping"); + id_event_location = rb_intern("event_location"); +} diff --git a/ext/psych/parser.h b/ext/psych/psych_parser.h index 25e896f01d..beb3dd0709 100644 --- a/ext/psych/parser.h +++ b/ext/psych/psych_parser.h @@ -1,6 +1,6 @@ #ifndef PSYCH_PARSER_H #define PSYCH_PARSER_H -void Init_psych_parser(); +void Init_psych_parser(void); #endif diff --git a/ext/psych/to_ruby.c b/ext/psych/psych_to_ruby.c index ed5245e12e..3ab0138b52 100644 --- a/ext/psych/to_ruby.c +++ b/ext/psych/psych_to_ruby.c @@ -10,7 +10,11 @@ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg) { VALUE e = rb_obj_alloc(klass); +#ifdef TRUFFLERUBY + rb_exc_set_message(e, mesg); +#else rb_iv_set(e, "mesg", mesg); +#endif return e; } @@ -21,21 +25,18 @@ static VALUE build_exception(VALUE self, VALUE klass, VALUE mesg) */ static VALUE path2class(VALUE self, VALUE path) { -#ifdef HAVE_RUBY_ENCODING_H return rb_path_to_class(path); -#else - return rb_path2class(StringValuePtr(path)); -#endif } void Init_psych_to_ruby(void) { VALUE psych = rb_define_module("Psych"); + VALUE class_loader = rb_define_class_under(psych, "ClassLoader", rb_cObject); + VALUE visitors = rb_define_module_under(psych, "Visitors"); VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); cPsychVisitorsToRuby = rb_define_class_under(visitors, "ToRuby", visitor); rb_define_private_method(cPsychVisitorsToRuby, "build_exception", build_exception, 2); - rb_define_private_method(cPsychVisitorsToRuby, "path2class", path2class, 1); + rb_define_private_method(class_loader, "path2class", path2class, 1); } -/* vim: set noet sws=4 sw=4: */ diff --git a/ext/psych/to_ruby.h b/ext/psych/psych_to_ruby.h index 7b8e757a45..7b8e757a45 100644 --- a/ext/psych/to_ruby.h +++ b/ext/psych/psych_to_ruby.h diff --git a/ext/psych/psych_yaml_tree.c b/ext/psych/psych_yaml_tree.c new file mode 100644 index 0000000000..bbd93f874d --- /dev/null +++ b/ext/psych/psych_yaml_tree.c @@ -0,0 +1,11 @@ +#include <psych.h> + +VALUE cPsychVisitorsYamlTree; + +void Init_psych_yaml_tree(void) +{ + VALUE psych = rb_define_module("Psych"); + VALUE visitors = rb_define_module_under(psych, "Visitors"); + VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); + cPsychVisitorsYamlTree = rb_define_class_under(visitors, "YAMLTree", visitor); +} diff --git a/ext/psych/yaml_tree.h b/ext/psych/psych_yaml_tree.h index 4628a69d71..4628a69d71 100644 --- a/ext/psych/yaml_tree.h +++ b/ext/psych/psych_yaml_tree.h diff --git a/ext/psych/yaml_tree.c b/ext/psych/yaml_tree.c deleted file mode 100644 index bcf24d2070..0000000000 --- a/ext/psych/yaml_tree.c +++ /dev/null @@ -1,24 +0,0 @@ -#include <psych.h> - -VALUE cPsychVisitorsYamlTree; - -/* - * call-seq: private_iv_get(target, prop) - * - * Get the private instance variable +prop+ from +target+ - */ -static VALUE private_iv_get(VALUE self, VALUE target, VALUE prop) -{ - return rb_attr_get(target, rb_intern(StringValuePtr(prop))); -} - -void Init_psych_yaml_tree(void) -{ - VALUE psych = rb_define_module("Psych"); - VALUE visitors = rb_define_module_under(psych, "Visitors"); - VALUE visitor = rb_define_class_under(visitors, "Visitor", rb_cObject); - cPsychVisitorsYamlTree = rb_define_class_under(visitors, "YAMLTree", visitor); - - rb_define_private_method(cPsychVisitorsYamlTree, "private_iv_get", private_iv_get, 2); -} -/* vim: set noet sws=4 sw=4: */ |
