410 lines
7.8 KiB
Lua
410 lines
7.8 KiB
Lua
|
|
-- Copyright (C) 2017-2020 DBotThePony
|
|
|
|
-- Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
-- of this software and associated documentation files (the "Software"), to deal
|
|
-- in the Software without restriction, including without limitation the rights
|
|
-- to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
-- of the Software, and to permit persons to whom the Software is furnished to do so,
|
|
-- subject to the following conditions:
|
|
|
|
-- The above copyright notice and this permission notice shall be included in all copies
|
|
-- or substantial portions of the Software.
|
|
|
|
-- THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
|
|
-- INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
|
|
-- PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
|
|
-- FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
|
-- OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
|
-- DEALINGS IN THE SOFTWARE.
|
|
|
|
local gstring = _G.string
|
|
local string = setmetatable(DLib.string or {}, {__index = string})
|
|
DLib.string = string
|
|
local unpack = unpack
|
|
local os = os
|
|
local select = select
|
|
local math = math
|
|
local table = table
|
|
|
|
--[[
|
|
@doc
|
|
@fname string.formatname
|
|
@args string self
|
|
|
|
@desc
|
|
first character is uppecased
|
|
@enddesc
|
|
|
|
@returns
|
|
string
|
|
]]
|
|
function gstring.formatname(self)
|
|
return self:sub(1, 1):upper() .. self:sub(2)
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname string.formatname2
|
|
@args string self
|
|
|
|
@desc
|
|
first character is uppecased, `_` are replaced with spaces
|
|
@enddesc
|
|
|
|
@returns
|
|
string
|
|
]]
|
|
function gstring.formatname2(self)
|
|
return self:sub(1, 1):upper() .. self:sub(2):replace('_', ' ')
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.tformat
|
|
@args number time
|
|
|
|
@deprecated
|
|
|
|
@desc
|
|
use DLib.i18n.tformat
|
|
@enddesc
|
|
|
|
@returns
|
|
string: formatted time
|
|
]]
|
|
function string.tformat(time)
|
|
if time > 0xFFFFFFFFF then
|
|
return 'Way too long'
|
|
elseif time <= 1 then
|
|
return 'Right now'
|
|
end
|
|
|
|
local str = ''
|
|
|
|
local centuries, years, months, weeks, days, hours, minutes, seconds = math.tformatVararg(time)
|
|
|
|
if seconds ~= 0 then
|
|
str = seconds .. ' seconds'
|
|
end
|
|
|
|
if minutes ~= 0 then
|
|
str = minutes .. ' minutes ' .. str
|
|
end
|
|
|
|
if hours ~= 0 then
|
|
str = hours .. ' hours ' .. str
|
|
end
|
|
|
|
if days ~= 0 then
|
|
str = days .. ' days ' .. str
|
|
end
|
|
|
|
if weeks ~= 0 then
|
|
str = weeks .. ' weeks ' .. str
|
|
end
|
|
|
|
if months ~= 0 then
|
|
str = months .. ' months ' .. str
|
|
end
|
|
|
|
if years ~= 0 then
|
|
str = years .. ' years ' .. str
|
|
end
|
|
|
|
if centuries ~= 0 then
|
|
str = centuries .. ' centuries ' .. str
|
|
end
|
|
|
|
return str
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.qdate
|
|
@args number time = os.time(), boolean isLocal = true, boolean removeTimezone = false
|
|
|
|
@desc
|
|
`isLocal` - time is result of call os.time() or similar
|
|
`removeTimezone` - whenever to sub/add time using operating system's timezone (and don't print timezone in final result)
|
|
@enddesc
|
|
|
|
@returns
|
|
string: quick formatted os.date (Human friendly ISO8601 format)
|
|
]]
|
|
function string.qdate(time, isLocal, removeTimezone)
|
|
if time == nil then time = os.time() end
|
|
if isLocal == nil then isLocal = true end
|
|
|
|
local timezone = os.date('%z', time)
|
|
local timezoneNum = 0
|
|
|
|
if isLocal then
|
|
if #timezone == 0 then
|
|
timezone = '+??:??'
|
|
else
|
|
timezone = timezone:sub(1, 3) .. ':' .. timezone:sub(4)
|
|
timezoneNum = ((tonumber(timezone:sub(2, 3)) or 0) * 3600 + (tonumber(timezone:sub(4)) or 0) * 60) * (timezone[1] == '-' and -1 or 1)
|
|
end
|
|
end
|
|
|
|
if removeTimezone and isLocal then
|
|
time = time - timezoneNum
|
|
end
|
|
|
|
if isLocal and not removeTimezone then
|
|
return os.date('%Y-%m-%d %H:%M:%S', time) .. ' UTC' .. timezone
|
|
else
|
|
return os.date('%Y-%m-%d %H:%M:%S', time) .. ' UTC+00:00'
|
|
end
|
|
end
|
|
|
|
string.HU_IN_M = 40
|
|
string.HU_IN_CM = string.HU_IN_M / 100
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.ddistance
|
|
@args number z, boolean newline, number fromZ
|
|
|
|
@returns
|
|
string: unlocalized Z difference
|
|
]]
|
|
function string.ddistance(z, newline, from)
|
|
if newline == nil then
|
|
newline = true
|
|
end
|
|
|
|
local delta
|
|
|
|
if from then
|
|
delta = from - z
|
|
else
|
|
delta = LocalPlayer():GetPos().z - z
|
|
end
|
|
|
|
if delta > 200 and not newline then
|
|
return string.fdistance(delta) .. ' lower'
|
|
end
|
|
|
|
if delta > 200 and newline then
|
|
return '\n' .. string.fdistance(delta) .. ' lower'
|
|
end
|
|
|
|
if -delta > 200 and not newline then
|
|
return string.fdistance(delta) .. 'upper'
|
|
end
|
|
|
|
if -delta > 200 and newline then
|
|
return '\n' .. string.fdistance(delta) .. 'upper'
|
|
end
|
|
|
|
return ''
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.fdistance
|
|
@args number distanceInHammerUnits
|
|
|
|
@returns
|
|
string: formatted metres
|
|
]]
|
|
function string.fdistance(m)
|
|
return string.format('%.1fm', m / string.HU_IN_M)
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.niceName
|
|
@args Entity ent
|
|
@deprecated
|
|
|
|
@desc
|
|
Use Entity:GetPrintNameDLib()
|
|
@enddesc
|
|
|
|
@returns
|
|
string
|
|
]]
|
|
function string.niceName(ent)
|
|
if not IsValid(ent) then return '' end
|
|
if ent.Nick then return ent:Nick() end
|
|
if ent.PrintName and ent.PrintName ~= '' then return ent.PrintName end
|
|
if ent.GetPrintName then return ent:GetPrintName() end
|
|
return ent:GetClass()
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname string.split
|
|
@args string self, string separator, vararg arguments
|
|
|
|
@desc
|
|
flip of !g:string.Explode
|
|
@enddesc
|
|
|
|
@returns
|
|
table: of strings
|
|
]]
|
|
function string.split(stringIn, explodeIn, ...)
|
|
return string.Explode(explodeIn, stringIn, ...)
|
|
end
|
|
|
|
-- fuck https://github.com/Facepunch/garrysmod/pull/1176
|
|
string.StartsWith = string.StartWith
|
|
|
|
|
|
--[[
|
|
@doc
|
|
@fname string.StartsWith
|
|
@args string self, string check
|
|
|
|
@desc
|
|
[alias](https://github.com/Facepunch/garrysmod/pull/1176) of !g:string.StartWith
|
|
@enddesc
|
|
|
|
@returns
|
|
boolean
|
|
]]
|
|
gstring.StartsWith = gstring.StartWith
|
|
|
|
local funcs = {}
|
|
|
|
for k, v in pairs(gstring) do
|
|
funcs[k:sub(1, 1):lower() .. k:sub(2)] = v
|
|
end
|
|
|
|
for k, v in pairs(funcs) do
|
|
if gstring[k] == nil then
|
|
gstring[k] = v
|
|
end
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.bchar
|
|
@args vararg bytes
|
|
|
|
@desc
|
|
allows to bypass bytes limit of bytes-per-call of !g:string.char transparently
|
|
@enddesc
|
|
|
|
@returns
|
|
string
|
|
]]
|
|
function string.bchar(...)
|
|
local bytes = select('#', ...)
|
|
|
|
if bytes < 800 then
|
|
return string.char(...)
|
|
end
|
|
|
|
local input = {...}
|
|
local output = ''
|
|
local i = -799
|
|
|
|
::loop::
|
|
i = i + 800
|
|
|
|
output = output .. string.char(unpack(input, i, math.min(i + 799, bytes)))
|
|
|
|
if i + 799 < bytes then
|
|
goto loop
|
|
end
|
|
|
|
return output
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.bcharTable
|
|
@args table bytes
|
|
|
|
@desc
|
|
allows to bypass bytes limit of bytes-per-call of !g:string.char transparently
|
|
@enddesc
|
|
|
|
@returns
|
|
string
|
|
]]
|
|
function string.bcharTable(input)
|
|
local bytes = #input
|
|
if bytes == 0 then return '' end
|
|
|
|
if bytes < 800 then
|
|
return string.char(unpack(input))
|
|
end
|
|
|
|
local output = ''
|
|
local i = -799
|
|
|
|
::loop::
|
|
i = i + 800
|
|
|
|
local status, output2 = pcall(string.char, unpack(input, i, math.min(i + 799, bytes)))
|
|
|
|
if not status then
|
|
for i2 = i, math.min(i + 799, bytes) do
|
|
if input[i2] < 0 or input[i2] > 255 then
|
|
error(output2 .. ' (' .. input[i2] .. ')')
|
|
end
|
|
end
|
|
end
|
|
|
|
output = output .. output2
|
|
|
|
if i + 799 < bytes then
|
|
goto loop
|
|
end
|
|
|
|
return output
|
|
end
|
|
|
|
--[[
|
|
@doc
|
|
@fname DLib.string.bbyte
|
|
@args string self, number sliceAt, number sliceEnd
|
|
|
|
@desc
|
|
allows to bypass bytes limit of bytes-per-call of !g:string.byte transparently
|
|
@enddesc
|
|
|
|
@returns
|
|
table: of bytes
|
|
]]
|
|
function string.bbyte(strIn, sliceStart, sliceEnd)
|
|
local strLen = #strIn
|
|
local delta = sliceEnd - sliceStart
|
|
|
|
if delta < 800 then
|
|
local i = sliceStart - 1
|
|
local output = {}
|
|
|
|
::loop1::
|
|
i = i + 1
|
|
|
|
table.insert(output, strIn:byte(i, i))
|
|
|
|
if i < sliceEnd then
|
|
goto loop1
|
|
end
|
|
|
|
return output
|
|
end
|
|
|
|
local output = {}
|
|
|
|
local i = sliceStart - 1
|
|
|
|
::loop::
|
|
i = i + 1
|
|
|
|
table.insert(output, strIn:byte(i, i))
|
|
|
|
if i < sliceEnd then
|
|
goto loop
|
|
end
|
|
|
|
return output
|
|
end
|