shelljoin

function shelljoin( args ) --> line

Description

Builds a command line string from an array table with the arguments. All elements are joined into a single string with fields separated by a space, where each element is escaped with escapeshellarg.html[escapeshellarg].

Parameters

argtab

Array table with the single arguments.

Return Values

line

A safe command line string.

Code

--ZFUNC-shelljoin-v1
local function shelljoin( args ) --> line
   --ZFUNC-escapeshellarg-v1
   local function escapeshellarg( str )
      return '"'..str:gsub( '"', '\\"' )..'"'
   end

   --ZFUNC-isoneshellarg-v1
   local function isoneshellarg( str )
      --ZFUNC-utf8codes-v1
      local function utf8codes( str )
         return str:gmatch( "[%z\1-\127\194-\244][\128-\191]*" )
      end

      local function isspace( str )
         return str == " " or str == "\t" or str == "\r" or str == "\n"
      end

      local inbuff = false
      local escaped, doubleQ, singleQ, backQ = false, false, false, false

      for r in utf8codes( str ) do
         if escaped then--------------------------------------------------------
            inbuff = true
            escaped = false

         elseif r == '\\' then--------------------------------------------------
            if singleQ then inbuff = true
            else escaped = true
            end

         elseif isspace( r ) then-----------------------------------------------
            if singleQ or doubleQ or backQ then inbuff = true
            else return false
            end

         elseif r == "`" then---------------------------------------------------
            if singleQ or doubleQ then inbuff = true
            else backQ = not backQ
            end

         elseif r == '"' then---------------------------------------------------
            if singleQ or backQ then inbuff = true
            else doubleQ = not doubleQ
            end

         elseif r == "'" then---------------------------------------------------
            if doubleQ or backQ then inbuff = true
            else singleQ = not singleQ
            end

         else-------------------------------------------------------------------
            inbuff = true

         end
      end

      if escaped or doubleQ or singleQ or backQ then return false end

      if inbuff then return true end

      return false --no argument
   end

   local tmp = {}

   for _, a in ipairs( args ) do
      if not isoneshellarg( a ) then
         a = escapeshellarg( a )
      end
      table.insert( tmp, a )
   end

   return table.concat( tmp, " " )
end

return shelljoin

Examples

local t = require( "tapered" )
local shelljoin = require( "shelljoin" )

line = shelljoin{ "here", "are", "two words" }
t.is( 'here are "two words"', line )

line = shelljoin{ "John", "says", 'Hello"s World' }
t.is( 'John says "Hello\\"s World"', line )

t.done()

See also