* tables:again(again)again

For users to report plugin bugs and request plugin enhancements; and for authors to test new/new versions of plugins, and to discuss plugin development (in the Programming Technicalities sub-forum). If you want advice on choosing or using a plugin, please ask in General Usage or an appropriate sub-forum.
Post Reply
User avatar
Ron Melby
Megastar
Posts: 878
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

tables:again(again)again

Post by Ron Melby » 08 Feb 2023 01:29

I have cut this code to essentials, it is somewhat more elaborate than this.
the file qwcsysval will be loaded from disk thru the SAVRST operations.

the file can only be modified by an approved interface.
that is yet to be done, I will finally be working on iup.GridBox to do this.
(that endeavor, I don't wonder; will be threads among millions.

essentially it is a complement of working constants used by my programs.
I 'unroll' it from the table into standalone values.

The code works fine, and does create global variables, but has a problem.
since at present, I am declaring them individually in the require(s), my code all works
as I decide on names and values and so on, I can go into the saved table with an editor,
and fix things or add things to test. I think during normal save restores the problem that I am creating would manifest itself differently. And this is a rather artificial but not impossible happenstance.

However, trying to bulletproof it and handle errors at the earliest step, this is giving me fits:

["qwc_GPS_time_ERR"] = y8600,

it really should be just the number 8600.

however, it must resolve to null and the key does not even enter my for do
is my code not correct or is there some clever way to get this keyval pair?


(the issue here is one of program timing) that key could be used 3 or 4 require "levels" deep in my code and only under such conditions that processing is almost finished before it becomes a problem)

Ideas?

Code: Select all

--[[
    require 'QSYS'
      require 'QSYS_PTH'
      __ipath = rtvpath()
      qgdp = __ipath.global()
      require 'QSYS_SAVRST'
        rtvTBL()

** in QSYS:         
local qcwp, qwcsysval = rtvTBL(('%s%s'):format(qgdp, 'qwcsysval.dat'))
that gets the table that is provided here as qwcsysval
  ]]

qwcsysval =

{
  ["qwc_GPS_BASE_LATI"]      = 46.23997959960783,
  ["qwc_GPS_BASE_LONG"]      = -95.95777396029047,
  ["qwc_GPS_time_ERR"]       = y8600,
  ["qwc_GPS_miles_ERR"]      = '',
  ["qwc_GPS_direction_ERR"]  = '****',
  ["qwc_GPS_duration_ERR"]   = 8686,
  ["qprt_spool_browser"]     = 'EditPadLite8.exe',
}

--[[unroll table entries into program]]
local function reflect(_source)
  local _sink = ''
  local _var

  for _key, _val in pairs(_source) do
    _keytyp = type(_key)
    _valtyp = type(_val)

    if type(_val) == 'string' then _val = ("'%q'"):format(_val) end
    _var = ('%s = %s\n'):format(_key, _val)
    _sink = ('%s%s'):format(_sink, _var)
  end
  local _rc, _mat, _err = pcall(loadstring, _sink)
  if _err then

    error(('QSYS.reflect: sysval:\n %s\n  %s\n corrupt'):format(_err, type(_mat))) end
    _mat()
    return
  end -- fn reflect
  
  --[[
      see header comments
        table provided in QSYS by file load
        rtvTBL(qwcp)
  ]]
  
  reflect(qwcsysval)
  return
FH V.6.2.7 Win 10 64 bit

User avatar
tatewise
Megastar
Posts: 27075
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: tables:again(again)again

Post by tatewise » 08 Feb 2023 13:00

Ron Melby wrote:
08 Feb 2023 01:29
["qwc_GPS_time_ERR"] = y8600,

it really should be just the number 8600.

however, it must resolve to null and the key does not even enter my for do
is my code not correct or is there some clever way to get this keyval pair?
y8600 is the name of a variable, which if it does not exist will resolve to nil so no key will be created.
So that is working exactly as expected in Lua terms.

If just the number 8600 is used instead (as you say it really should be) then the code below works fine for me.
The subsequent for _key, _val in pairs(_source) do unpacks the table correctly including the 8600 value.
It is just like the very similar ["qwc_GPS_duration_ERR"] = 8686,

Code: Select all

qwcsysval =
{
  ["qwc_GPS_BASE_LATI"]      = 46.23997959960783,
  ["qwc_GPS_BASE_LONG"]      = -95.95777396029047,
  ["qwc_GPS_time_ERR"]       = 8600,
  ["qwc_GPS_miles_ERR"]      = '',
  ["qwc_GPS_direction_ERR"]  = '****',
  ["qwc_GPS_duration_ERR"]   = 8686,
  ["qprt_spool_browser"]     = 'EditPadLite8.exe',
}
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry

User avatar
Ron Melby
Megastar
Posts: 878
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: tables:again(again)again

Post by Ron Melby » 08 Feb 2023 14:53

Mike,

yes-- agreed.

while I may be dealing with an arcane error, I am trying to defeat standard lua behavior somehow in this case, and find that nil key somehow and raise the error right there on the spot.

In the perfect world I would somehow like to create a situation where running thru my for-pairs-do-enddo I could see

_key ["qwc_GPS_time_ERR"]
y8600,
_valtyp== 'nil'

as I have said that is an artifical error, but I can do an astonishing amount of stupid that I would like to protect myself from up front.

if I index them [1]...to [n] and ipairs doesnt work, that would tell me the file is in error but not when or where, and would load added complexity to its use (read time, program size, and cpu)
FH V.6.2.7 Win 10 64 bit

User avatar
tatewise
Megastar
Posts: 27075
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: tables:again(again)again

Post by tatewise » 08 Feb 2023 15:39

The way I cope with possible nil values is to use or with some special value.
e.g.
["qwc_GPS_time_ERR"] = y8600 or '!?'

Then if y8600 yields nil it is replaced by '!?' which can be tested in your unpack for loop.
You can choose whatever special value can never naturally occur in your data set.
It can be either an unusual text string or an unusual number or even a function.
Consider the following code:

Code: Select all

function null()
    return nil
end

qwcsysval =
{
  ["qwc_GPS_BASE_LATI"]      = 46.23997959960783 or null,
  ["qwc_GPS_BASE_LONG"]      = -95.95777396029047 or null,
  ["qwc_GPS_time_ERR"]       = y8600 or null,
  ["qwc_GPS_miles_ERR"]      = '' or null,
  ["qwc_GPS_direction_ERR"]  = '****' or null,
  ["qwc_GPS_duration_ERR"]   = 8686 or null,
  ["qprt_spool_browser"]     = 'EditPadLite8.exe' or null,
}

 for _key, _val in pairs(qwcsysval) do
   if type(_val) == 'function' and not _val() then
        -- error detected here
   end
 end
The function can have any name you like but must return nil or false.
If any value assigned to a key has a nil or false value then the null function is substituted.
That is detected in the for loop but assumes that no legitimate value is a function that returns nil or false.
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry

User avatar
Ron Melby
Megastar
Posts: 878
Joined: 15 Nov 2016 15:40
Family Historian: V6.2

Re: tables:again(again)again

Post by Ron Melby » 09 Feb 2023 02:20

I dont think your chillcode save and restore tables nor my QSYS_SAVRST functions (which are quite different) could save or restore that table from disk in that state without horrific custom coding setup to front end it. and it doesn't cure my problem that someong goes in and changes the value with a text editor from or null to y8600. its the only vulnerability, when it is on disk.
FH V.6.2.7 Win 10 64 bit

User avatar
tatewise
Megastar
Posts: 27075
Joined: 25 May 2010 11:00
Family Historian: V7
Location: Torbay, Devon, UK
Contact:

Re: tables:again(again)again

Post by tatewise » 09 Feb 2023 12:14

If you use the same technique as the load/save library then the 'function' option would work to disk.
The only gotcha is that it relies on the loadstring function which is deprecated to the load function in Lua v5.3.
But since you are still using FH V6.2 and Lua v5.1 that is not a problem, but there is a simple workaround.

But the unique special text string value such as '!?' would also work in that scenario.
e.g.
["qwc_GPS_time_ERR"] = y8600 or '!?'
You can choose whatever text string you like to ensure it is unique among all genuine table values.
If you ever need to revise that text string then it is easy to use a global search & replace operation.

If someone changes a key value on disk to an invalid value then surely they get what they deserve!
Mike Tate ~ researching the Tate and Scott family history ~ tatewise ancestry

Post Reply