about summary refs log tree commit homepage
path: root/lib/dtas
diff options
context:
space:
mode:
Diffstat (limited to 'lib/dtas')
-rw-r--r--lib/dtas/buffer.rb1
-rw-r--r--lib/dtas/buffer/read_write.rb1
-rw-r--r--lib/dtas/buffer/splice.rb1
-rw-r--r--lib/dtas/command.rb1
-rw-r--r--lib/dtas/compat_onenine.rb1
-rw-r--r--lib/dtas/disclaimer.rb1
-rw-r--r--lib/dtas/edit_client.rb1
-rw-r--r--lib/dtas/format.rb6
-rw-r--r--lib/dtas/pipe.rb1
-rw-r--r--lib/dtas/player.rb5
-rw-r--r--lib/dtas/player/client_handler.rb5
-rw-r--r--lib/dtas/process.rb10
-rw-r--r--lib/dtas/replaygain.rb1
-rw-r--r--lib/dtas/rg_state.rb1
-rw-r--r--lib/dtas/serialize.rb1
-rw-r--r--lib/dtas/sigevent.rb1
-rw-r--r--lib/dtas/sigevent/efd.rb1
-rw-r--r--lib/dtas/sigevent/pipe.rb1
-rw-r--r--lib/dtas/sink.rb1
-rw-r--r--lib/dtas/source.rb1
-rw-r--r--lib/dtas/source/av.rb1
-rw-r--r--lib/dtas/source/av_ff_common.rb19
-rw-r--r--lib/dtas/source/cmd.rb1
-rw-r--r--lib/dtas/source/common.rb1
-rw-r--r--lib/dtas/source/ff.rb1
-rw-r--r--lib/dtas/source/file.rb1
-rw-r--r--lib/dtas/source/mp3gain.rb3
-rw-r--r--lib/dtas/source/sox.rb11
-rw-r--r--lib/dtas/state_file.rb1
-rw-r--r--lib/dtas/unix_accepted.rb1
-rw-r--r--lib/dtas/unix_client.rb8
-rw-r--r--lib/dtas/unix_server.rb1
-rw-r--r--lib/dtas/util.rb1
-rw-r--r--lib/dtas/writable_iter.rb1
-rw-r--r--lib/dtas/xs.rb14
35 files changed, 48 insertions, 59 deletions
diff --git a/lib/dtas/buffer.rb b/lib/dtas/buffer.rb
index 6ae3cfc..c9f096c 100644
--- a/lib/dtas/buffer.rb
+++ b/lib/dtas/buffer.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../dtas'
diff --git a/lib/dtas/buffer/read_write.rb b/lib/dtas/buffer/read_write.rb
index 5e816b2..1f1e4a7 100644
--- a/lib/dtas/buffer/read_write.rb
+++ b/lib/dtas/buffer/read_write.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'io/wait'
diff --git a/lib/dtas/buffer/splice.rb b/lib/dtas/buffer/splice.rb
index 2cbd16d..18dfd82 100644
--- a/lib/dtas/buffer/splice.rb
+++ b/lib/dtas/buffer/splice.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'io/wait'
diff --git a/lib/dtas/command.rb b/lib/dtas/command.rb
index b1b52ce..91b3c6f 100644
--- a/lib/dtas/command.rb
+++ b/lib/dtas/command.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 # common code for wrapping SoX/ecasound/... commands
diff --git a/lib/dtas/compat_onenine.rb b/lib/dtas/compat_onenine.rb
index f8040a5..d031252 100644
--- a/lib/dtas/compat_onenine.rb
+++ b/lib/dtas/compat_onenine.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 
diff --git a/lib/dtas/disclaimer.rb b/lib/dtas/disclaimer.rb
index 9a02a28..558bb19 100644
--- a/lib/dtas/disclaimer.rb
+++ b/lib/dtas/disclaimer.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # :enddoc:
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
diff --git a/lib/dtas/edit_client.rb b/lib/dtas/edit_client.rb
index 50c8444..45300c1 100644
--- a/lib/dtas/edit_client.rb
+++ b/lib/dtas/edit_client.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'tempfile'
diff --git a/lib/dtas/format.rb b/lib/dtas/format.rb
index 35682a7..690a21f 100644
--- a/lib/dtas/format.rb
+++ b/lib/dtas/format.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 # class represents an audio format (type/bits/channels/sample rate/...)
@@ -9,6 +8,7 @@ require_relative 'serialize'
 class DTAS::Format # :nodoc:
   include DTAS::Process
   include DTAS::Serialize
+
   NATIVE_ENDIAN = [1].pack("l") == [1].pack("l>") ? "big" : "little"
 
   attr_accessor :type # s32, f32, f64 ... any point in others?
@@ -63,10 +63,6 @@ class DTAS::Format # :nodoc:
     %W(-f #{@type}_#{endian2},#@channels,#@rate)
   end
 
-  def inspect
-    "<#{self.class}(#{Shellwords.join(to_sox_arg)})>"
-  end
-
   def to_hsh
     to_hash.delete_if { |k,v| v == FORMAT_DEFAULTS[k] }
   end
diff --git a/lib/dtas/pipe.rb b/lib/dtas/pipe.rb
index c3cebca..cd3ac46 100644
--- a/lib/dtas/pipe.rb
+++ b/lib/dtas/pipe.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 begin
diff --git a/lib/dtas/player.rb b/lib/dtas/player.rb
index 73342bb..ba42490 100644
--- a/lib/dtas/player.rb
+++ b/lib/dtas/player.rb
@@ -1,9 +1,9 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'yaml'
 require 'shellwords'
 require_relative '../dtas'
+require_relative 'xs'
 require_relative 'source'
 require_relative 'source/sox'
 require_relative 'source/av'
@@ -18,6 +18,7 @@ require_relative 'state_file'
 
 class DTAS::Player # :nodoc:
   require_relative 'player/client_handler'
+  include DTAS::XS
   include DTAS::Player::ClientHandler
   attr_accessor :state_file
   attr_accessor :socket
@@ -52,7 +53,7 @@ class DTAS::Player # :nodoc:
   end
 
   def echo(msg)
-    msg = Shellwords.join(msg) if Array === msg
+    msg = xs(Array(msg))
     @watchers.delete_if do |io, _|
       if io.closed?
         true
diff --git a/lib/dtas/player/client_handler.rb b/lib/dtas/player/client_handler.rb
index f29db36..f601d46 100644
--- a/lib/dtas/player/client_handler.rb
+++ b/lib/dtas/player/client_handler.rb
@@ -1,7 +1,8 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require_relative '../xs'
 module DTAS::Player::ClientHandler # :nodoc:
+  include DTAS::XS
 
   # returns true on success, wait_ctl arg on error
   def set_bool(io, kv, v)
@@ -116,7 +117,7 @@ module DTAS::Player::ClientHandler # :nodoc:
     name = msg[1]
     case msg[0]
     when "ls"
-      io.emit(Shellwords.join(@sinks.keys.sort))
+      io.emit(xs(@sinks.keys.sort))
     when "rm"
       sink = @sinks.delete(name) or return io.emit("ERR #{name} not found")
       drop_sink(sink)
diff --git a/lib/dtas/process.rb b/lib/dtas/process.rb
index 5b11f14..b90b318 100644
--- a/lib/dtas/process.rb
+++ b/lib/dtas/process.rb
@@ -1,11 +1,12 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
-require 'shellwords'
 require 'io/wait'
 require_relative '../dtas'
+require_relative 'xs'
+
 module DTAS::Process # :nodoc:
   PIDS = {}
+  include DTAS::XS
 
   def self.reaper
     begin
@@ -60,7 +61,7 @@ module DTAS::Process # :nodoc:
     w.close
     if err_str
       we.close
-      res = ""
+      res = "".b
       want = { r => res, re => err_str }
       begin
         readable = IO.select(want.keys) or next
@@ -82,7 +83,6 @@ module DTAS::Process # :nodoc:
     _, status = Process.waitpid2(pid)
     return res if status.success?
     return status if no_raise
-    raise RuntimeError,
-          "`#{Shellwords.join(Array(cmd))}' failed: #{status.inspect}"
+    raise RuntimeError, "`#{xs(Array(cmd))}' failed: #{status.inspect}"
   end
 end
diff --git a/lib/dtas/replaygain.rb b/lib/dtas/replaygain.rb
index 8845b90..d3fa8ad 100644
--- a/lib/dtas/replaygain.rb
+++ b/lib/dtas/replaygain.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 #
diff --git a/lib/dtas/rg_state.rb b/lib/dtas/rg_state.rb
index bf6f972..a6c56f5 100644
--- a/lib/dtas/rg_state.rb
+++ b/lib/dtas/rg_state.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 #
diff --git a/lib/dtas/serialize.rb b/lib/dtas/serialize.rb
index 449c8d3..ceba005 100644
--- a/lib/dtas/serialize.rb
+++ b/lib/dtas/serialize.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 module DTAS::Serialize # :nodoc:
diff --git a/lib/dtas/sigevent.rb b/lib/dtas/sigevent.rb
index 282dad9..3800f4b 100644
--- a/lib/dtas/sigevent.rb
+++ b/lib/dtas/sigevent.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 begin
diff --git a/lib/dtas/sigevent/efd.rb b/lib/dtas/sigevent/efd.rb
index 1fef013..b108b89 100644
--- a/lib/dtas/sigevent/efd.rb
+++ b/lib/dtas/sigevent/efd.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 class DTAS::Sigevent < SleepyPenguin::EventFD # :nodoc:
diff --git a/lib/dtas/sigevent/pipe.rb b/lib/dtas/sigevent/pipe.rb
index d85a81b..bf2ba00 100644
--- a/lib/dtas/sigevent/pipe.rb
+++ b/lib/dtas/sigevent/pipe.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 class DTAS::Sigevent # :nodoc:
diff --git a/lib/dtas/sink.rb b/lib/dtas/sink.rb
index 0ce6237..9ccd8ea 100644
--- a/lib/dtas/sink.rb
+++ b/lib/dtas/sink.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'yaml'
diff --git a/lib/dtas/source.rb b/lib/dtas/source.rb
index 4608150..d8f0170 100644
--- a/lib/dtas/source.rb
+++ b/lib/dtas/source.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../dtas'
diff --git a/lib/dtas/source/av.rb b/lib/dtas/source/av.rb
index 6005344..d44b1a9 100644
--- a/lib/dtas/source/av.rb
+++ b/lib/dtas/source/av.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
diff --git a/lib/dtas/source/av_ff_common.rb b/lib/dtas/source/av_ff_common.rb
index 666adbd..bcb8a0a 100644
--- a/lib/dtas/source/av_ff_common.rb
+++ b/lib/dtas/source/av_ff_common.rb
@@ -1,9 +1,9 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
 require_relative '../source'
 require_relative '../replaygain'
+require_relative '../xs'
 require_relative 'file'
 
 # Common code for libav (avconv/avprobe) and ffmpeg (and ffprobe)
@@ -12,6 +12,7 @@ require_relative 'file'
 # support JSON, so we have an ugly parser...
 module DTAS::Source::AvFfCommon # :nodoc:
   include DTAS::Source::File
+  include DTAS::XS
   AStream = Struct.new(:duration, :channels, :rate)
   AV_FF_TRYORDER = 1
 
@@ -35,16 +36,16 @@ module DTAS::Source::AvFfCommon # :nodoc:
     s = qx(@env, cmd, err_str: err, no_raise: true)
     return false if Process::Status === s
     return false if err =~ /Unable to find a suitable output format for/
-    s.scan(%r{^\[STREAM\]\n(.*?)\n\[/STREAM\]\n}m) do |_|
+    s.scan(%r{^\[STREAM\]\n(.*?)\n\[/STREAM\]\n}mn) do |_|
       stream = $1
       if stream =~ /^codec_type=audio$/
         as = AStream.new
         index = nil
-        stream =~ /^index=(\d+)\s*$/m and index = $1.to_i
-        stream =~ /^duration=([\d\.]+)\s*$/m and as.duration = $1.to_f
-        stream =~ /^channels=(\d)\s*$/m and as.channels = $1.to_i
-        stream =~ /^sample_rate=([\d\.]+)\s*$/m and as.rate = $1.to_i
-        index or raise "BUG: no audio index from #{Shellwords.join(cmd)}"
+        stream =~ /^index=(\d+)\s*$/nm and index = $1.to_i
+        stream =~ /^duration=([\d\.]+)\s*$/nm and as.duration = $1.to_f
+        stream =~ /^channels=(\d)\s*$/nm and as.channels = $1.to_i
+        stream =~ /^sample_rate=([\d\.]+)\s*$/nm and as.rate = $1.to_i
+        index or raise "BUG: no audio index from #{xs(cmd)}"
 
         # some streams have zero channels
         @astreams[index] = as if as.channels > 0 && as.rate > 0
@@ -52,9 +53,9 @@ module DTAS::Source::AvFfCommon # :nodoc:
     end
     s.scan(%r{^\[FORMAT\]\n(.*?)\n\[/FORMAT\]\n}m) do |_|
       f = $1
-      f =~ /^duration=([\d\.]+)\s*$/m and @duration = $1.to_f
+      f =~ /^duration=([\d\.]+)\s*$/nm and @duration = $1.to_f
       # TODO: multi-line/multi-value/repeated tags
-      f.gsub!(/^TAG:([^=]+)=(.*)$/i) { |_| @comments[$1.upcase] = $2 }
+      f.gsub!(/^TAG:([^=]+)=(.*)$/ni) { |_| @comments[$1.upcase] = $2 }
     end
     ! @astreams.empty?
   end
diff --git a/lib/dtas/source/cmd.rb b/lib/dtas/source/cmd.rb
index 3ea2049..3c409e9 100644
--- a/lib/dtas/source/cmd.rb
+++ b/lib/dtas/source/cmd.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
diff --git a/lib/dtas/source/common.rb b/lib/dtas/source/common.rb
index 7cc5f7c..03d1562 100644
--- a/lib/dtas/source/common.rb
+++ b/lib/dtas/source/common.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 module DTAS::Source::Common # :nodoc:
diff --git a/lib/dtas/source/ff.rb b/lib/dtas/source/ff.rb
index b8e6f6b..fa4bbf7 100644
--- a/lib/dtas/source/ff.rb
+++ b/lib/dtas/source/ff.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
diff --git a/lib/dtas/source/file.rb b/lib/dtas/source/file.rb
index d79dd88..3dadc67 100644
--- a/lib/dtas/source/file.rb
+++ b/lib/dtas/source/file.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
diff --git a/lib/dtas/source/mp3gain.rb b/lib/dtas/source/mp3gain.rb
index fe0b642..b48c759 100644
--- a/lib/dtas/source/mp3gain.rb
+++ b/lib/dtas/source/mp3gain.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../process'
@@ -15,7 +14,7 @@ module DTAS::Source::Mp3gain # :nodoc:
     tmp = {}
     case @infile
     when String
-      @infile =~ /\.mp[g23]\z/i or return
+      @infile =~ /\.mp[g23]\z/in or return
       qx(%W(mp3gain -s c #@infile)).split(/\n/).each do |line|
         case line
         when /^Recommended "(Track|Album)" dB change:\s*(\S+)/
diff --git a/lib/dtas/source/sox.rb b/lib/dtas/source/sox.rb
index d030628..0001689 100644
--- a/lib/dtas/source/sox.rb
+++ b/lib/dtas/source/sox.rb
@@ -1,15 +1,16 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../../dtas'
 require_relative '../source'
 require_relative '../replaygain'
+require_relative '../xs'
 
 # this is usually one input file
 class DTAS::Source::Sox # :nodoc:
   require_relative 'file'
 
   include DTAS::Source::File
+  include DTAS::XS
 
   SOX_DEFAULTS = COMMAND_DEFAULTS.merge(
     "command" => 'exec sox "$INFILE" $SOXFMT - $TRIMFX $RGFX',
@@ -27,7 +28,7 @@ class DTAS::Source::Sox # :nodoc:
     if msg
       return if @last_failed == infile
       @last_failed = infile
-      return warn("`#{Shellwords.join(cmd)}' #{msg}")
+      return warn("`#{xs(cmd)}' #{msg}")
     end
     true
   end
@@ -49,7 +50,7 @@ class DTAS::Source::Sox # :nodoc:
     qx(@env, %W(soxi -p #@infile), err: "/dev/null").to_i # sox.git f4562efd0aa3
   rescue # fallback to parsing the whole output
     s = qx(@env, %W(soxi #@infile), err: "/dev/null")
-    s =~ /Precision\s+:\s*(\d+)-bit/
+    s =~ /Precision\s+:\s*(\d+)-bit/n
     v = $1.to_i
     return v if v > 0
     raise TypeError, "could not determine precision for #@infile"
@@ -81,8 +82,8 @@ class DTAS::Source::Sox # :nodoc:
     tmp = {}
     case @infile
     when String
-      qx(@env, %W(soxi -a #@infile)).split(/\n/).each do |line|
-        key, value = line.split(/=/, 2)
+      qx(@env, %W(soxi -a #@infile)).split(/\n/n).each do |line|
+        key, value = line.split(/=/n, 2)
         key && value or next
         # TODO: multi-line/multi-value/repeated tags
         tmp[key.upcase] = value
diff --git a/lib/dtas/state_file.rb b/lib/dtas/state_file.rb
index 05015ae..c009797 100644
--- a/lib/dtas/state_file.rb
+++ b/lib/dtas/state_file.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'yaml'
diff --git a/lib/dtas/unix_accepted.rb b/lib/dtas/unix_accepted.rb
index c995364..be344c7 100644
--- a/lib/dtas/unix_accepted.rb
+++ b/lib/dtas/unix_accepted.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'socket'
diff --git a/lib/dtas/unix_client.rb b/lib/dtas/unix_client.rb
index 1a0de90..fa94bbf 100644
--- a/lib/dtas/unix_client.rb
+++ b/lib/dtas/unix_client.rb
@@ -1,7 +1,7 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
-require 'dtas'
+require_relative '../dtas'
+require_relative 'xs'
 require 'socket'
 require 'io/wait'
 require 'shellwords'
@@ -9,6 +9,8 @@ require 'shellwords'
 class DTAS::UNIXClient # :nodoc:
   attr_reader :to_io
 
+  include DTAS::XS
+
   def self.default_path
     (ENV["DTAS_PLAYER_SOCK"] || File.expand_path("~/.dtas/player.sock")).b
   end
@@ -19,7 +21,7 @@ class DTAS::UNIXClient # :nodoc:
   end
 
   def req_start(args)
-    args = Shellwords.join(args) if Array === args
+    args = xs(args) if Array === args
     @to_io.send(args, Socket::MSG_EOR)
   end
 
diff --git a/lib/dtas/unix_server.rb b/lib/dtas/unix_server.rb
index 07e16b4..bccfad5 100644
--- a/lib/dtas/unix_server.rb
+++ b/lib/dtas/unix_server.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require 'socket'
diff --git a/lib/dtas/util.rb b/lib/dtas/util.rb
index f785b37..b235b0e 100644
--- a/lib/dtas/util.rb
+++ b/lib/dtas/util.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../dtas'
diff --git a/lib/dtas/writable_iter.rb b/lib/dtas/writable_iter.rb
index 0694085..1fd65eb 100644
--- a/lib/dtas/writable_iter.rb
+++ b/lib/dtas/writable_iter.rb
@@ -1,4 +1,3 @@
-# -*- encoding: binary -*-
 # Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
 # License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
 require_relative '../dtas'
diff --git a/lib/dtas/xs.rb b/lib/dtas/xs.rb
new file mode 100644
index 0000000..968865d
--- /dev/null
+++ b/lib/dtas/xs.rb
@@ -0,0 +1,14 @@
+# Copyright (C) 2013, Eric Wong <normalperson@yhbt.net> and all contributors
+# License: GPLv3 or later (https://www.gnu.org/licenses/gpl-3.0.txt)
+require_relative '../dtas'
+require 'shellwords'
+
+# We always escape binary strings because paths on POSIX filesystems are
+# encoding agnostic.  Shellwords.split does give UTF-8 strings, but nothing
+# cares at that point if the encoding isn't valid (and it's right to not care,
+# again, filesystems can use any byte value in names except '\0'.
+module DTAS::XS # :nodoc:
+  def xs(ary)
+    Shellwords.join(ary.map { |s| s.b })
+  end
+end