--[[
* Ashita - Copyright ( c ) 2014 - 2017 atom0s [ atom0s @ live.com ]
*
* This work is licensed under the Creative Commons Attribution - NonCommercial - NoDerivatives 4.0 International License .
* To view a copy of this license , visit http : // creativecommons.org / licenses / by - nc - nd / 4.0 / or send a letter to
* Creative Commons , PO Box 1866 , Mountain View , CA 94042 , USA .
*
* By using Ashita , you agree to the above license and its terms .
*
* Attribution - You must give appropriate credit , provide a link to the license and indicate if changes were
* made . You must do so in any reasonable manner , but not in any way that suggests the licensor
* endorses you or your use .
*
* Non - Commercial - You may not use the material ( Ashita ) for commercial purposes .
*
* No - Derivatives - If you remix , transform , or build upon the material ( Ashita ) , you may not distribute the
* modified material . You are , however , allowed to submit the modified works back to the original
* Ashita project in attempt to have it added to the original project .
*
* You may not apply legal terms or technological measures that legally restrict others
* from doing anything the license permits .
*
* No warranties are given .
] ] --
----------------------------------------------------------------------------------------------------
-- func: string.contains
-- desc: Determines if a string contains the given sub-string.
----------------------------------------------------------------------------------------------------
function string . contains ( s , v )
return s : find ( v , nil , true ) ~= nil ;
end
----------------------------------------------------------------------------------------------------
-- func: string.startswith
-- desc: Determines if a string begins with a specific string.
----------------------------------------------------------------------------------------------------
function string . startswith ( s , v )
return s : sub ( 1 , # v ) == v ;
end
----------------------------------------------------------------------------------------------------
-- func: string.endswith
-- desc: Determines if a string ends with a specific string.
----------------------------------------------------------------------------------------------------
function string . endswith ( s , v )
return s : sub ( -# v ) == v ;
end
----------------------------------------------------------------------------------------------------
-- func: string.upperfirst
-- desc: Uppercases the first letter of a string.
----------------------------------------------------------------------------------------------------
function string . upperfirst ( s )
return s : sub ( 1 , 1 ) : upper ( ) .. s : sub ( 2 ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.toproper
-- desc: Converts a string to proper casing.
----------------------------------------------------------------------------------------------------
function string . toproper ( s )
local ret = ' ' ;
local t = { } ;
for x = 1 , s : len ( ) do
t [ x ] = s : sub ( x , x ) ;
if ( t [ x - 1 ] == ' ' or x == 1 ) then
t [ x ] = t [ x ] : upperfirst ( ) ;
end
ret = ret .. t [ x ] ;
end
return ret ;
end
----------------------------------------------------------------------------------------------------
-- func: string.insert
-- desc: Inserts data into the current string at the given position.
----------------------------------------------------------------------------------------------------
function string . insert ( s , p , v )
local part = s : sub ( 1 , p - 1 ) ;
return part .. v .. s : sub ( # part + 1 ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.remove
-- desc: Removes the character at the given index.
----------------------------------------------------------------------------------------------------
function string . remove ( s , index )
return s : sub ( 0 , index - 1 ) .. s : sub ( index + 1 ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.lpad
-- desc: Pads a string 'n' times with the given string.
----------------------------------------------------------------------------------------------------
function string . lpad ( s , v , n )
return ( v : rep ( n ) .. s ) : sub ( - ( n > # s and n or # s ) ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.rpad
-- desc: Pads a string 'n' times with the given string.
----------------------------------------------------------------------------------------------------
function string . rpad ( s , v , n )
return ( s .. v : rep ( n ) ) : sub ( 1 , - ( n > # s and n or # s ) ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.hex
-- desc: Converts a strings value to a hex string.
----------------------------------------------------------------------------------------------------
function string . hex ( s , sep )
sep = sep or ' ' ;
local ret = ' ' ;
for _ , v in pairs ( s : totable ( ) ) do
ret = ret .. string.format ( ' %02X ' , v ) .. sep ;
end
return ret : trim ( ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.fromhex
-- desc: Converts a hex value to a string.
----------------------------------------------------------------------------------------------------
function string . fromhex ( s )
s = s : gsub ( ' %s*0x ' , ' ' ) : gsub ( ' [^%w] ' , ' ' ) ;
return ( s : gsub ( ' %w%w ' , function ( c ) return string.char ( tonumber ( c , 16 ) ) ; end ) ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.totable
-- desc: Converts the characters of a string to a table.
----------------------------------------------------------------------------------------------------
function string . totable ( s )
local ret = { } ;
for x = 1 , string.len ( s ) do
ret [ x ] = string.byte ( s , x ) ;
end
return ret ;
end
----------------------------------------------------------------------------------------------------
-- func: string.clean
-- desc: Cleans a string of whitespace.
----------------------------------------------------------------------------------------------------
function string . clean ( s , trimend )
if ( trimend == nil ) then trimend = true ; end
if ( trimend ) then
return s : gsub ( ' %s+ ' , ' ' ) : trim ( ) ;
else
return ( s : gsub ( ' %s+ ' , ' ' ) ) ;
end
end
----------------------------------------------------------------------------------------------------
-- func: string.trimstart
-- desc: Trims the start of a string for whitespace.
----------------------------------------------------------------------------------------------------
function string . trimstart ( s , c )
if ( not c ) then c = ' ' ; end
s = string.reverse ( s ) ;
s = string.trimend ( s , c ) ;
return string.reverse ( s ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.trimend
-- desc: Trims the end of a string for whitespace.
----------------------------------------------------------------------------------------------------
function string . trimend ( s , c )
if ( not c ) then c = ' ' ; end
if ( string.sub ( s , - 1 ) == c ) then
s = string.sub ( s , 0 , - 2 ) ;
s = string.trimend ( s , c ) ;
end
return s ;
end
----------------------------------------------------------------------------------------------------
-- func: string.trim
-- desc: Trims a string of whitespace.
----------------------------------------------------------------------------------------------------
function string . trim ( s , c )
if ( not c ) then c = ' ' ; end
s = string.trimstart ( s , c ) ;
s = string.trimend ( s , c ) ;
return s ;
end
----------------------------------------------------------------------------------------------------
-- func: string.args
-- desc: Returns a table of arguments parsed from a string.
----------------------------------------------------------------------------------------------------
function string : args ( )
local STATE_NONE = 0 ; -- Currently within nothing..
local STATE_WORD = 1 ; -- Currently within a word..
local STATE_QUOTE = 2 ; -- Currently within a quote..
local currentState = STATE_NONE ;
local currentChar = nil ;
local nextChar = nil ;
local stringStart = nil ;
local args = { } ;
-- Loop the string and self any arguments..
for x = 1 , string.len ( self ) do
-- Read the current characters..
currentChar = string.sub ( self , x , x ) ;
nextChar = string.sub ( self , x + 1 , x + 1 ) ;
-- Handle non-state..
if ( currentState == STATE_NONE ) then
if ( currentChar == ' " ' ) then
stringStart = x + 1 ;
currentState = STATE_QUOTE ;
else
if ( currentChar ~= ' ' ) then
stringStart = x ;
currentState = STATE_WORD ;
end
end
-- Handle quoted string state..
elseif ( currentState == STATE_QUOTE ) then
if ( currentChar == ' " ' ) then
currentState = STATE_NONE ;
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x - 1 ) ) ;
end
-- Handle word string state..
elseif ( currentState == STATE_WORD ) then
if ( currentChar == ' ' or nextChar == nil or nextChar == ' \0 ' ) then
currentState = STATE_NONE ;
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x - 1 ) ) ;
end
else
print ( ' args - Unknown state. ' ) ;
end
end
-- If in a word insert into the args table..
if ( currentState == STATE_WORD ) then
table.insert ( args , # args + 1 , string.sub ( self , stringStart , # self + 1 ) ) ;
end
-- Return the found arguments..
return args ;
end
----------------------------------------------------------------------------------------------------
-- func: string.is_quoted_arg
-- desc: Determines if the string is quoted.
----------------------------------------------------------------------------------------------------
function string . is_quoted_arg ( )
local arg = string.match ( self , " ^ \" (.*) \" $ " ) ;
return ( arg ~= nil ) , arg ;
end
----------------------------------------------------------------------------------------------------
-- func: string.parseargs
-- desc: Returns a table of arguments parsed from a string.
----------------------------------------------------------------------------------------------------
function string : parseargs ( )
local STATE_NONE = 0 ; -- Currently within nothing..
local STATE_WORD = 1 ; -- Currently within a word..
local STATE_QUOTE = 2 ; -- Currently within a quote..
local currentState = STATE_NONE ;
local currentChar = nil ;
local nextChar = nil ;
local stringStart = nil ;
local prefix = nil ;
local args = { } ;
-- Loop the string and self any arguments..
for x = 1 , string.len ( self ) do
-- Read the current characters..
currentChar = string.sub ( self , x , x ) ;
nextChar = string.sub ( self , x + 1 , x + 1 ) ;
-- Ensure the command starts with a slash..
if ( x == 1 and currentChar ~= ' / ' ) then
return nil ;
end
-- Handle non-state..
if ( currentState == STATE_NONE ) then
if ( currentChar == ' " ' ) then
stringStart = x ;
currentState = STATE_QUOTE ;
elseif ( currentChar ~= ' ' ) then
stringStart = x ;
currentState = STATE_WORD ;
end
-- Handle quoted string state..
elseif ( currentState == STATE_QUOTE ) then
if ( currentChar == ' " ' ) then
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x ) ) ;
currentState = STATE_NONE ;
end
-- Handle word string state..
elseif ( currentState == STATE_WORD ) then
if ( currentChar == ' ' ) then
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x - 1 ) ) ;
if ( prefix == nil ) then
prefix = args [ # args ] ;
end
currentState = STATE_NONE ;
elseif ( nextChar == nil or nextChar == ' \0 ' ) then
-- This section never actually seems to get hit during processing.
-- Regardless, it needs to use a different endpoint than the block above.
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x ) ) ;
if ( prefix == nil ) then
prefix = args [ # args ] ;
end
currentState = STATE_NONE ;
elseif ( prefix == nil and currentChar == ' / ' and x == ( stringStart + 1 ) ) then
-- If command line starts with //, put that in its own argument field
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x ) ) ;
prefix = args [ # args ] ;
currentState = STATE_NONE ;
elseif ( currentChar == ' " ' ) then
-- A quote mark should start a new quote arg, even if there is no space delimiter.
table.insert ( args , # args + 1 , string.sub ( self , stringStart , x - 1 ) ) ;
currentState = STATE_QUOTE ;
stringStart = x ;
end
else
print ( ' parseargs - Unknown state. ' ) ;
end
end
-- If in a word insert into the args table..
if ( currentState == STATE_WORD ) then
table.insert ( args , # args + 1 , string.sub ( self , stringStart , # self ) ) ;
end
-- Return the found arguments..
return args ;
end
----------------------------------------------------------------------------------------------------
-- func: string.strip_colors
-- desc: Strips FFXi based colors from a string.
----------------------------------------------------------------------------------------------------
function string . strip_colors ( s )
return ( s : gsub ( ' [ ' .. string.char ( 0x1E , 0x1F , 0x7F ) .. ' ]. ' , ' ' ) ) ;
end
----------------------------------------------------------------------------------------------------
-- func: string.strip_translate
-- desc: Strips FFXi based auto-translate tags from a string.
----------------------------------------------------------------------------------------------------
function string . strip_translate ( s )
return ( s : gsub ( string.char ( 0xEF ) .. ' [ ' .. string.char ( 0x27 , 0x28 ) .. ' ] ' , ' ' ) ) ;
end