{"id":11787,"date":"2020-12-14T10:36:24","date_gmt":"2020-12-14T10:36:24","guid":{"rendered":"https:\/\/fhug.org.uk\/kb\/?post_type=kb_article&#038;p=11787"},"modified":"2022-11-06T17:45:29","modified_gmt":"2022-11-06T17:45:29","slug":"writing-plugins-compatible-with-versions-5-6-7","status":"publish","type":"kb_article","link":"https:\/\/www.fhug.org.uk\/kb\/kb-article\/writing-plugins-compatible-with-versions-5-6-7\/","title":{"rendered":"Writing and Maintaining Plugins Compatible with Versions 5, 6 &#038; 7"},"content":{"rendered":"<h2>Introduction<\/h2>\n<p>The changes from Lua 5.1 to 5.3 in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7 and from Gedcom 5.5 to Gedcom 5.5.1, the introduction of new features in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7 and the updating of many of the Lua libraries available for writing plugins poses some challenges to plugin authors who wish to write or update plugins for use across <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> versions 5, 6 and 7. This article explores those challenges and offers advice on overcoming them.<\/p>\n<p>If you&#8217;re a plugin author who wishes to migrate a plugin from V6 to V7 and are not concerned with backward compatibility, first consult <code>Converting Lua 5.1 Plugins to Lua 5.3<\/code> within the Family Historian Plugin Help. This article may also be useful to identify other considerations to take into account during the migration, depending on how complex your plugin is.<\/p>\n<h2>General Guidance on Software Versions<\/h2>\n<p>Check that any facilities you&#8217;re using in Lua, <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Library Modules <\/a>or the <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> API are available in all the versions of <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> that you intend to support.<\/p>\n<p>To test for the version of <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> in use, for example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">if fhGetAppVersion () &gt; 5 then\r\n  --do something here\r\nend<\/pre>\n<p>This should usually be sufficient to determine what version of Lua and Lua libraries are available to you, but you can also check the Lua version using:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">if _VERSION == \"Lua 5.3\" then --FH 7\r\n  --do something\r\nelse -- FH 5 or 6\r\n --do something else\r\nend\r\n<\/pre>\n<p>Some but not all libraries will allow you to check their version, for example:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">luasql = require \"luasql\"\r\nver = luasql._VERSION\r\nprint (ver)<\/pre>\n<p>If necessary, these checks will let you include coding for different versions of <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>, Lua, and the libraries, should you (for example) want to make basic functionality available to all users but enhance the functionality where you can.<\/p>\n<h2>Lua 5.1\/5.3 Compatibility<\/h2>\n<h3>Plugins that Originated in Version 5 or 6<\/h3>\n<p>Some functions in Lua 5.1 have been renamed or deprecated in 5.3., and some additional functions have been added in Lua 5.3.<\/p>\n<p>If relevant, this code block must be positioned near the beginning of any plugin written originally in Lua 5.1 to enable it to run in Lua 5.3 with the minimum of changes.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">if _VERSION == \"Lua 5.3\" then\r\n  -- handle changes to table library\r\n  unpack = table.unpack --function moved in 5.3\r\n  function table.getn(t) --function removed in 5.3\r\n    local count = 0\r\n    for _, __ in ipairs(t) do\r\n      count = count + 1\r\n    end\r\n    return count\r\n  end\r\n  function table.maxn(t) --function removed in 5.3\r\n    local max = 0\r\n    for j,k in pairs (t) do\r\n      if type(j) == \"number\" then\r\n        max = j\r\n      end\r\n    end\r\n    return max\r\n  end\r\n  --handle changes to string library\r\n  loadstring   = load -- function removed in 5.3\r\n  string.gfind = string.gmatch --function renamed in 5.3\r\nend\r\n<\/pre>\n<p>There are also changes that need to be made wherever particular Lua features have been used. The most common include:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">--[[Byte zero pattern %z was deprecated in Lua 5.2 to be replaced by \\0. %z still works in Lua 5.3 as well as 5.1, but there is no guarantee it will work in future versions of Lua.\r\nA alternative for those who are concerned about future compatibility is to specify byte0 and use it with this code in patterns instead of %z or \\0 .\r\nPatterns will need to be edited manually to include byte0 instead of %z or \\0\r\n--]]\r\nlocal byte0 = \"%z\" --Byte zero pattern %z was deprecated in Lua 5.2 to be replaced by \\0\r\nif _VERSION == \"Lua 5.3\" then\t\t\t \r\n  byte0 = \"\\0\"\r\nend\r\n\r\n--[[in Family Historian 5 and 6 both % and the slash character were permitted as escape characters. Now only % is allowed]]--\r\n\r\n--[[handle changes to OS.TMPNAME\r\n--In 5.3 the os.temp variable now returns the full file name with thepath.  The following will make the call backwardly compatible with 5.1\r\n--]]\r\nlocal temp = os.tmpname()..'.html'\r\nif _VERSION ~= 'Lua 5.1' then\r\n  temp = os.getenv('TEMP')..filename\r\nend\r\n\r\n--[[Pseudo-argument arg\r\nPseudo-argument arg was deprecated in Lua 5.1 and removed in Lua 5.2.\r\nInsert the following code into functions which use the ... argument\r\narg = {...}\r\narg['n'] = #arg\r\n--]]\r\n\r\n-- Example \r\nlocal function test(...)\r\n  local arg = {...}\r\n  arg['n'] = #arg\r\n  for i,v in ipairs(arg) do\r\n    print(i,v)\r\n  end\r\nend\r\n\r\n--[[String formatting for numbers\r\n\r\nstring.format(\"%d\",number) won't work if number is not an integer. It needs string.format(\"%d\",math.floor(number)) or similar to ensure the parameter is an integer. That solution works for all Lua versions.\r\n\r\n]]--\r\n\r\n<\/pre>\n<p>There are also changes in areas that are less commonly used. See the relevant Lua documentation to understand the cumulative changes from 5.1 to 5.3:<\/p>\n<ul>\n<li><a href=\"http:\/\/www.lua.org\/manual\/5.2\/readme.html#changes\">Changes between Lua 5.1 and Lua 5.2<\/a> and <a href=\"http:\/\/www.lua.org\/manual\/5.2\/manual.html#8\">Incompatibilities between 5.1 and 5.2<\/a><\/li>\n<li><a href=\"http:\/\/www.lua.org\/manual\/5.3\/readme.html#changes\">Changes between Lua 5.2 and Lua 5.3<\/a> and <a href=\"http:\/\/www.lua.org\/manual\/5.3\/manual.html#8\">Incompatibilities between 5.2 and 5.3<\/a><\/li>\n<\/ul>\n<h3>Plugins Created in FH7<\/h3>\n<p>If you are writing a new plugin and want it to run in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>5, 6 and 7, you should investigate the <a href=\"https:\/\/github.com\/keplerproject\/lua-compat-5.3\">compat53<\/a> module for Lua 5.1:<\/p>\n<blockquote><p>This is a small module that aims to make it easier to write code in a Lua-5.3-style that is compatible with Lua 5.1, Lua 5.2, and Lua 5.3. This does\u00a0<em>not<\/em>\u00a0make Lua 5.2 (or even Lua 5.1) entirely compatible with Lua 5.3, but it brings the API closer to that of Lua 5.3.<\/p><\/blockquote>\n<p>Instructions for loading the module are at <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Lua References and Library Modules<\/a>.<\/p>\n<h2>Library Changes<\/h2>\n<p>There are numerous changes in the libraries available between <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6 and [<span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7. See <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Lua References and Library Modules<\/a>\u00a0for details of the library versions supported in each version.<\/p>\n<h3>IUP<\/h3>\n<p>IUP is the most commonly used library, and the following code block <strong>must<\/strong> be included before IUP is used to make a plugin compatible with the changing versions of IUP.\u00a0 It tests for the version of IUP and enables some special handling for later versions.<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">require (\"iuplua\") -- this was optional before Family Historian 7\r\nif tonumber(iup._VERSION) &gt;= 3.28 then\r\n  iup.SetGlobal(\"CUSTOMQUITMESSAGE\",\"YES\") --if you don't include this, FH will exit when the plugin exits and you may get other unpredictable behaviour\r\nend\r\n<\/pre>\n<p>A popular simple dialogue involves <strong class=\"text-strong\">iup.GetParam(..)<\/strong>\u00a0but a bug prevents the button labels being changed from\u00a0<strong class=\"text-strong\">OK<\/strong>\u00a0and\u00a0<strong class=\"text-strong\">Cancel<\/strong>. The workaround is:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">function paramAction(iupDialog,intIndex)\r\n  if intIndex == iup.GETPARAM_MAP then\t\t-- Correct button labels needed for IUP 3.28 bug\r\n    iupDialog.Button1.Title = \"Edit\"\t-- Otherwise remain as OK and Cancel\r\n    iupDialog.Button2.Title = \"Exit\"\r\n  end\r\n  return 1\r\nend\r\nlocal isAns,strAns = iup.GetParam(\"Test\",paramAction,\"%u[Edit,Exit]\")\t-- Displays dialogue with buttons Edit and Exit\r\n\r\nfunction paramAction(iupDialog,intIndex)\r\n  if intIndex == iup.GETPARAM_MAP then\t\t-- Correct button labels needed for IUP 3.28 bug\r\n    iupDialog.Button1.Title = \"Apply Rules\"\r\n    iupDialog.Button2.Title = \"Cancel Plugin\"\r\n  elseif intIndex == (iup.GETPARAM_HELP or -4) then\t-- FH V5 needs -4\r\n    fhShellExecute(\"https:\/\/pluginstore.family-historian.co.uk\/page\/help\/main-help-page\",\"\",\"\",\"open\")\r\n  end\r\n  return 1\r\nend -- function paramAction\r\n\r\n<\/pre>\n<p>Again, there are more changes than can be addressed here, and different plugin authors will have used different facilities. Consult the IUP <a href=\"https:\/\/www.tecgraf.puc-rio.br\/iup\/\">History<\/a> to understand what has changed and when.<\/p>\n<h3>Require and Loadrequire<\/h3>\n<p>In <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>5 and 6, some library modules had to be downloaded before they could be required for the first time, via the <a href=\"https:\/\/fhug.org.uk\/kb\/code-snippet\/module-require-with-load\/\">Module Require with Load function<\/a>; in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7 these libraries are installed with [FH] and can simple be required.\u00a0 See <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Lua References and Library Modules<\/a> for details of the modules affected.\u00a0 If writing for versions 5, 6, and 7 you should include the loadrequire snippet (which was updated when <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>7 was released, so make sure you are using the latest version) and code like:<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">if fhGetAppVersion () &gt;= 7 then \r\n  socket = require (\"socket\")\r\nelse\r\n  socket = loadrequire(\"socket\")\r\nend<\/pre>\n<p>Note: the utf8 library for <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6 needs special handling and you should follow the instructions in <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules\/\">Lua References and Library Modules<\/a> exactly.<\/p>\n<h2>User Written Modules<\/h2>\n<p>In Lua 5.3, user-written modules need to be created using tables (this was optional in Lua 5.1). For example,<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">function myModule()\r\n  local x = 0 --private module constant\r\n  local function myFunc1 (a,b)\r\n    x = a+b\r\n  end\r\n  local function myGetX()\r\n    return x\r\n  end\r\n  return{\r\n    myFunc1 = myFunc1,\r\n    myGetX = myGetX\r\n  }\r\nend\r\n\r\nlocal M = myModule()\r\nM.myFunc1(1,2)\r\nprint (M.myGetX()) -- '3'<\/pre>\n<p>Note: it is a requirement of the Plugin that each plugin can be run independently, without dependencies, so any modules must be included inline within the plugin.<\/p>\n<h2>Character Encoding<\/h2>\n<span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>5 only supports ANSI whereas <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6+ supports Unicode UTF-8, and there are three options&#8230;<br \/>\n1. Use plugin File &gt; Encoding &gt; UTF-8 and only support <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6+<br \/>\n2. Use plugin File &gt; Encoding &gt; ANSI for all versions where Unicode UTF-8 fields are not involved<br \/>\n3. Use plugin File &gt; Encoding &gt; ANSI for all versions but with the code block below to support Unicode UTF-8 in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>6+<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">if fhGetAppVersion() &gt; 5 then -- Cater for Unicode UTF-8 for FH v6+\r\n\u00a0 fhSetStringEncoding(\"UTF-8\")\r\n\u00a0 iup.SetGlobal(\"UTF8MODE\",\"YES\") -- These two only needed with require \"iuplua\"\r\n\u00a0 iup.SetGlobal(\"UTF8MODE_FILE\",\"NO\")\r\nend<\/pre>\n<h2>Gedcom Data Format Changes<\/h2>\n<p>The change from Gedcom 5.5 to 5.5.1 brings with it some data format changes, including:<\/p>\n<ul>\n<li>The structure for Media objects has tag FILE (was _FILE) and the level for FORM &amp; TITL tags has changed<\/li>\n<li>Custom attributes now use FACT tag although the API still uses _ATTR<\/li>\n<li>Changes to the GEDCOM tags for EMAIL (was _EMAIL), and WWW (was _WEB)<\/li>\n<li>New GEDCOM tags FAX, FONE, ROMN, et<\/li>\n<\/ul>\n<p>There&#8217;s a useful comparison of the two formats at <a href=\"https:\/\/fire-eggs.github.io\/gedcom_55_vs_551.html\">GEDCOM Grammars : 5.5 vs 5.5.1<\/a><\/p>\n<p>Whether these changes affect a plugin is highly dependent on what the plugin does, but if your plugin is affected you will need to write code for &#8216;old&#8217; (versions 5 &amp;6) and &#8216;new&#8217; (version 7) and test the version of FH to determine which one applies.<\/p>\n<h2>New Family Historian Features<\/h2>\n<p>The changes due to new features in <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> include:<\/p>\n<ul>\n<li>The structure for Media objects for _KEYS, _AREA, _CAPT, _NOTA, _SEQ instead of _ASID, etc<\/li>\n<li>Rich text in Note (NOTE2) and Text From Source (TEXT) fields that have new data type &#8216;richtext&#8217; and tags _FMT, _LINK_? &amp; _LNK plus many new API functions<\/li>\n<li>Research Notes with new tag _RNOT that support rich text formats<\/li>\n<li>Templated source citation meta-fields that require shortcuts and new tag _SRCT<\/li>\n<li>Updates to some Plugin\u00a0<a class=\"postlink\" href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-code-snippets\/\">Code Snippets<\/a><\/li>\n<\/ul>\n<p>If your plugin interacts with these new features, you will have to decide whether to restrict it to <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> version 7 only, or include alternative code for earlier versions.<\/p>\n","protected":false},"template":"","fh_version":[14,15,739],"skill_level":[18],"topic":[73],"class_list":["post-11787","kb_article","type-kb_article","status-publish","hentry","fh_version-v5","fh_version-v6","fh_version-v7","skill_level-advanced","topic-writing-plugins"],"_links":{"self":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article\/11787","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article"}],"about":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/types\/kb_article"}],"wp:attachment":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/media?parent=11787"}],"wp:term":[{"taxonomy":"fh_version","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/fh_version?post=11787"},{"taxonomy":"skill_level","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/skill_level?post=11787"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/topic?post=11787"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}