{"id":12132,"date":"2022-02-28T14:12:49","date_gmt":"2022-02-28T14:12:49","guid":{"rendered":"https:\/\/fhug.org.uk\/kb\/?post_type=kb_article&#038;p=12132"},"modified":"2022-08-23T09:54:46","modified_gmt":"2022-08-23T09:54:46","slug":"character-handling-for-plugin-authors","status":"publish","type":"kb_article","link":"https:\/\/www.fhug.org.uk\/kb\/kb-article\/character-handling-for-plugin-authors\/","title":{"rendered":"International Character Handling for Plugin Authors"},"content":{"rendered":"<h3>Introduction<\/h3>\n<p>Many plugin authors encounter problems handing unexpected characters.<\/p>\nProblems due to mismatched <a href=\"https:\/\/en.wikipedia.org\/wiki\/Character_encoding\">character encodings<\/a> can include:\n<ul>\n<li>file names in the Windows Filing System not being recognised<\/li>\n<li>string manipulations yielding unexpected results<\/li>\n<li>text displayed to the user being completely unintelligible, or sprinkled with \ufffd<\/li>\n<\/ul>\n<p>This article sets out the background, describes the problems and recommends solutions. It is aimed as authors working with <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; as of 2022, most new plugins are likely to be written 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>7 only, and the language pack facility 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 makes it more likely that unexpected characters will be encountered.<\/p>\n<p>Developers of plugins aimed at multiple users (typically published via the Plugin Store) should assume that they need to cater for all possible characters. Authors of plugins for private use may encounter fewer problems but might still find the recommendations helpful.<\/p>\n<div class=\"lightweight-accordion\"><details><summary class=\"lightweight-accordion-title\"><h3>Character Encodings Relevant to Plugin Authors<\/h3><\/summary><div class=\"lightweight-accordion-body\"><p>There are a number of character encodings relevant to plugin authors (in roughly historical order):<\/p>\n<h4><a href=\"https:\/\/en.wikipedia.org\/wiki\/ASCII\">ASCII<\/a><\/h4>\n<p>ASCII supports unaccented English characters, digits 0-9, plus some punctuation and other symbols, and control characters such as Tab or Line Feed (New Line), to a total of 128 codes (the bottom 7 bits of a single byte). Not coincidentally (as many later encodings chose to align with ASCII), ASCII maps the same single byte codes to the same characters as some encodings that came later, which has the useful effect that if all you need is the upper- and lower-case English alphabet, you probably won&#8217;t see any problems. But once you wander outside the English walled garden, more characters are needed, and things get more complicated.<\/p>\n<h4>&#8216;ANSI&#8217;\/<a href=\"https:\/\/en.wikipedia.org\/wiki\/Windows_code_page\">Windows Code Pages<\/a><\/h4>\n<p>&#8216;ANSI&#8217; is not a character encoding. Rather, it is a misnomer used to refer to the collection of Windows code pages introduced by Microsoft and others during the 1980s and 1990s to support more languages than English, and still supported (more or less) today.<\/p>\n<p>Each character in a code page is encoded using a single byte. The first 128 character codes mirror ASCII; then (up to) another 128 locale-specific characters are added. One major consequence of the approach is that the same byte value represents many different characters or none.<\/p>\n<p>For example:<\/p>\n<ul>\n<li><a href=\"https:\/\/en.wikipedia.org\/wiki\/Windows-1252\">Windows-1252<\/a> (the Latin alphabet), which is is the most-used single-byte character encoding in the world (and confusingly is also often called &#8216;ANSI&#8217;) uses byte value DE for the letter <strong>\u00de\u00a0<\/strong>(because we all need a <a href=\"https:\/\/en.wikipedia.org\/wiki\/Thorn_(letter)\">thorn<\/a>, right, especially if our ancestors ran \u00dee Olde Cake Shoppe?)<\/li>\n<li>Windows-1253 (Greek) uses byte value DE for <strong>\u03ae<\/strong>.<\/li>\n<li>Windows-1255 (Hebrew) doesn&#8217;t use byte value DE at all.<\/li>\n<\/ul>\n<p>These characters may not seem to you to be particularly useful, but they illustrate the point that text encoded using one code page may yield unexpected results if it&#8217;s decoded using another.<\/p>\n<p>Another problem arises because there are languages (e.g. Thai) for which 128 characters are not enough. Thai may not be a huge issue for plugin authors, but there are places in Europe whose alphabet is not wholly supported by e.g. Windows 1252, for example the Dutch <strong>ij<\/strong> or the Polish <strong>\u0142<\/strong>.<\/p>\n<p>So, code pages aren&#8217;t an entirely satisfactory solution to handling characters from multiple languages.<\/p>\n<h4><a href=\"https:\/\/en.wikipedia.org\/wiki\/Unicode\">Unicode<\/a><\/h4>\n<p>Unicode is a character encoding <i>standard <\/i>that sets out to cover every reasonable writing system in the world (and a few unreasonable ones as well, like Klingon) without ambiguity. It defines unique &#8216;code points&#8217; for every character in every language, and it can be implemented by various character encodings (Unicode Transformation Formats or UTFs) that map code points (and thus characters) to unique byte sequences. Two UTFs are relevant to plugin authors: UTF-16 and UTF-8.<\/p>\n<h4><a href=\"https:\/\/en.wikipedia.org\/wiki\/UTF-16\">UTF-16<\/a><\/h4>\n<p>UTF-16 encodes all characters in either 2 or 4 bytes. It is the only popular character encoding that is incompatible with ASCII (e.g. the English character X coded in ASCII is NOT the same code as character X coded in UTF-16.) It comes in 2 variants, depending on the underlying architecture or <a href=\"https:\/\/en.wikipedia.org\/wiki\/Endianness\">Endianness<\/a> of the computer system involved: UTF16-LE and UTF16-BE. Windows uses UTF-16LE, with a BOM (byte order mark) <code>0xFF 0xFE<\/code> at the start of a character stream to signify which variant is in use.<\/p>\n<p>Microsoft was an early adopter of Unicode. They used UTF-16 widely within their operating and filing systems, and sometimes for plain text and word processing files, and recommended it to application developers. (A word of caution: when reading Microsoft library documentation in your idle moments, any reference you find to &#8216;Unicode&#8217; should almost always be interpreted as a reference to &#8216;UTF-16LE&#8217;).<\/p>\n<p>Almost all of the computing and Internet world adopted <a href=\"#UTF8\">UTF-8<\/a>, not UTF-16, and in 2019 Microsoft changed their stance and started recommending UTF-8 to application developers; however, changing all their existing system code to use UTF-8 would be a huge endeavour, so many Microsoft libraries etc. still assume UTF-16 (or Windows Code Pages\/&#8217;ANSI&#8217;).<\/p>\n<h4><a id=\"UTF8\"><\/a><a href=\"https:\/\/en.wikipedia.org\/wiki\/UTF-8\">UTF-8<\/a><\/h4>\n<p>UTF-8 is now the dominant character encoding in computing and the Internet. It encodes all characters in 1,2,3 or 4 bytes. The first 128 characters of UTF-8 correspond one-to-one with ASCII, so that valid ASCII text is also valid UTF-8 text.\u00a0UTF-8 does not require a BOM, nor is one recommended, but it is sometimes added at the start of a character stream in the form <code>0xEF 0xBB 0xBF<\/code>. (If a BOM is added, it stops text from being backwards compatible with ASCII.) Where <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> uses UTF-8 it often includes a BOM.<\/p>\n<\/div><\/details><\/div>\n<h3>Where Might Encoding Issues Occur?<\/h3>\n<p>Encoding issues may occur anywhere that a plugin\u00a0interacts with external entities\/resources, or within the plugin\u00a0when manipulating strings.<\/p>\n<p><img decoding=\"async\" class=\"aligncenter wp-image-12100 size-large lazyload\" data-src=\"https:\/\/fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding-1024x593.jpg\" alt=\"\" width=\"640\" height=\"371\" data-srcset=\"https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding-1024x593.jpg 1024w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding-300x174.jpg 300w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding-150x87.jpg 150w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding-768x445.jpg 768w, https:\/\/www.fhug.org.uk\/kb\/wp-content\/uploads\/2022\/01\/Character-encoding.jpg 1478w\" data-sizes=\"(max-width: 640px) 100vw, 640px\" src=\"data:image\/svg+xml;base64,PHN2ZyB3aWR0aD0iMSIgaGVpZ2h0PSIxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciPjwvc3ZnPg==\" style=\"--smush-placeholder-width: 640px; --smush-placeholder-aspect-ratio: 640\/371;\" \/><\/p>\n<p>Most issues can be avoided by adopting UTF-8 wherever possible, and the steps to do this are detailed in <a href=\"#Recommendations\">Recommendations<\/a> below, following detailed explanations of the issues involved.<\/p>\n<div class=\"lightweight-accordion\" id=\"ProjectAccess\"><details><summary class=\"lightweight-accordion-title\"><h3>Accessing Project Data<\/h3><\/summary><div class=\"lightweight-accordion-body\"><p>The following encodings are supported for project\u00a0GEDCOM\u00a0files and plugins\u00a0in <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.<\/p>\n<table style=\"border-collapse: collapse; width: 50%;\">\n<tbody>\n<tr>\n<td style=\"width: 10%; text-align: left;\"><strong>GEDCOM\u00a0Default<\/strong><\/td>\n<td style=\"width: 5%; text-align: left;\"><strong>GEDCOM\u00a0Alternative\u00a0<\/strong><\/td>\n<td style=\"width: 10%; text-align: left;\"><strong>Plugin\u00a0Preferred<\/strong><\/td>\n<td style=\"width: 10%; text-align: left;\"><strong>Plugin\u00a0<\/strong><strong>Alternative<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 10%; text-align: left;\">UTF-8<\/td>\n<td style=\"width: 5%; text-align: left;\">UTF-16<\/td>\n<td style=\"width: 10%; text-align: left;\">UTF-8<\/td>\n<td style=\"width: 10%; text-align: left;\">&#8216;ANSI&#8217;<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>If you access project data via 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 , you are insulated from the GEDCOM encoding. Strings on 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 passed in the \u2018current string encoding\u2019, which defaults to the encoding of the plugin file. <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> handles the conversion if any between the current string encoding and the GEDCOM file encoding.<\/p>\n<p>The current string encoding can be changed via the <code>fhSetStringEncoding\u00a0<\/code>function, or interrogated using the <code>fhGetStringEncoding<\/code> function.<\/p>\n<p>Note: if the current string encoding is \u2018ANSI\u2019 and the GEDCOM file is encoded in UTF-8 or UTF-16, there is a possibility that text will be corrupted or lost because not all UTF characters are supported in \u2018ANSI\u2019. <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> will set a \u2018Conversion Loss Flag\u2019 flag to tell you that data has been lost. You can interrogate it using the <code>fhIsConversionLossFlagSet<\/code> function, but encoding your plugins as UTF-8 or setting the current string encoding to UTF-8 avoids this issue.<\/p>\n<p>See the <a href=\"https:\/\/www.family-historian.co.uk\/help\/fh7-plugins\/hh_start.htm#api\/string_encoding_and_unicode.htm\">Plugin Help file<\/a> for more on this subject.<\/p>\n<p><strong>RECOMMENDATION 1<\/strong>: Use UTF-8 for your plugin encoding and current string encoding.<\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\" id=\"String-Manipulation\"><details><summary class=\"lightweight-accordion-title\"><h3>String Manipulation<\/h3><\/summary><div class=\"lightweight-accordion-body\"><h4>Handling UTF-8 strings<\/h4>\n<p>If you follow the recommendations in this article for <a href=\"#ProjectAccess\">accessing project data<\/a>, <a href=\"#File-Handling\">handling files<\/a> and <a href=\"#user-interface\">gathering user input<\/a>, any string manipulation you do within a plugin will be operating on UTF-8 text.<\/p>\n<p>However, the Lua <code>string<\/code> library treats a string as simply a sequence of (single) bytes, which works for ASCII and &#8216;ANSI&#8217; but not for UTF-8. There are some limited techniques for manipulating UTF-8 using the <code>string<\/code> library\u00a0outlined at &#8220;Unicode UTF-8 Encoding&#8221; in <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/understanding-lua-patterns\/\">Understanding Lua Patterns<\/a> but a better solution is to use two UTF-8 libraries:<\/p>\n<ul>\n<li>The Lua <code>utf8<\/code> library within Lua 5.3 provides a basic set of functions for handling UTF-8 strings.<\/li>\n<li>The <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules#utf8\">additional <code>utf8<\/code> library<\/a> installed with <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 can be used to perform all standard string operations on UTF-8 strings.<\/li>\n<\/ul>\n<p>You can overlay the additional <code>utf8<\/code> library on the <code>string<\/code> library (and invoke its functions as e.g.\u00a0 <code>string.find<\/code>) or\u00a0load it alongside the string library (and invoke its functions as <code>utf8.find<\/code>). Be aware that overlaying it on the string library can cause performance problems and unexpected behaviour in 3rd party libraries that rely on the string library, so test throroughly if you take this option.<\/p>\n<p><strong>RECOMMENDATION 2: <\/strong>Use the inbuilt Lua <code>utf8<\/code> library and the additional <code>utf8<\/code> library to manipulate strings.<\/p>\n<h4>String Handling in Other Libraries<\/h4>\n<p>The <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules#penlight\"><code>Penlight<\/code> <\/a>third-party library includes many modules that rely on the Lua <code>string<\/code> library, and assume that &#8216;ANSI&#8217; is the encoding in use. \u00a0(You should test the <code>Penlight<\/code> functions you intend to use with UTF-8 strings.) This applies to the following commonly used <code>Penlight<\/code> libraries:<\/p>\n<ul>\n<li><code>stringx<\/code><\/li>\n<li><code>text<\/code><\/li>\n<li><code>utils<\/code><\/li>\n<\/ul>\n<p>but may affect other <code>Penlight<\/code> libraries as well.<\/p>\n<p>The <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules#fhutils\"><code>fhUtils<\/code> <\/a>library also relies on <code>Penlight<\/code> and the Lua <code>string<\/code> library for string handling.<\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\" id=\"user-interface\"><details><summary class=\"lightweight-accordion-title\"><h3>User Interface<\/h3><\/summary><div class=\"lightweight-accordion-body\"><p>The <a href=\"https:\/\/fhug.org.uk\/kb\/kb-article\/lua-references-and-library-modules#iup\">IUP<\/a> library (for constructing user interfaces) works by default in &#8216;ANSI&#8217; , but can be configured to use UTF-8:<\/p>\n<p style=\"padding-left: 40px;\"><code>iup.SetGlobal(\"UTF8MODE\", \"YES\")<\/code><\/p>\n<p><strong>RECOMMENDATION 3<\/strong>: Configure IUP to use UTF-8 on the user interface.<\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\" id=\"File-Handling\"><details><summary class=\"lightweight-accordion-title\"><h3>File Access and Manipulation<\/h3><\/summary><div class=\"lightweight-accordion-body\"><h4>File Access Problems<\/h4>\n<p>There are a lot of options for file handling in Lua and the libraries made available with <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span>, which work to a greater or lesser extent with the Windows Filing System.<\/p>\n<p>The Windows Filing System (except on very old systems) stores file and folder names in UTF-16.<\/p>\n<p>The Lua <code>io<\/code> and <code>os<\/code> libraries expect file paths and names in the local code page (&#8216;ANSI&#8217;).<\/p>\n<p>So, it is possible to encounter a file path that the <code>io<\/code> and <code>os<\/code> libraries can&#8217;t deal with, because it includes UTF-16 characters that can&#8217;t be converted (by Windows) into the local code page. If this happens, the <code>io<\/code> and <code>os<\/code> libraries will fail to find the file. The Lua File System (<code>lfs<\/code>) library will encounter the same problem, as will file operations in other third party libraries that depend on <code>lfs<\/code> , <code>io<\/code> or <code>os<\/code> such as <code>Penlight<\/code>.<\/p>\n<p>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 functions <code>fhLoadTextFile<\/code> and <code>fhSaveTextFile<\/code> will read and write UTF-8, UTF-16 and &#8216;ANSI&#8217; encoded text files, and handle all characters in the file path. A plugin receives the content of any text file read encoded in the current string encoding (ideally UTF-8 to avoid conversion loss). However:<\/p>\n<ul>\n<li>in the event of failure, these functions don&#8217;t return error messages explaining what went wrong<\/li>\n<li><code>fhSaveTextFile<\/code> will overwrite an existing file with no warning<\/li>\n<li><code>fhLoadTextFile<\/code> makes no checks that the encoding specified for the file matches the text string involved, so can return garbage (without any indication that it has done so)<\/li>\n<\/ul>\n<p>The <code>fhFileUtils<\/code> library supplied with <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> contains a variety of functions for accessing and manipulating (e.g. copy, move, delete, rename) files that will handle all characters in the file path. It uses <code>fhLoadTextFile<\/code> and <code>fhSaveTextFile<\/code> for accessing text files, but supplements them with additional error handling. However, it will still return garbage when reading a file that does not match the encoding specified.<\/p>\n<p><strong>RECOMMENDATION 4: <\/strong>Use <code>fhLoadTextFile<\/code> and <code>fhSaveTextFile<\/code> if you simply need to read and\/or write text files stored in UTF-8, UTF-16 or &#8216;ANSI&#8217; encoding, and you are happy with their lack of of error reporting.<\/p>\n<p><strong>RECOMMENDATION 5<\/strong>: Use the <code>fhFileUtils<\/code> library for file access and manipulation if your needs are more complex.<\/p>\n<h4>Determining a File&#8217;s Character Encoding<\/h4>\n<p>If you don&#8217;t know the encoding of a file, read it as a binary file (using <code>fileGetContents<\/code> from the <code>fhFileUtils<\/code> library), and use the snippet <a href=\"https:\/\/fhug.org.uk\/kb\/code-snippet\/determine-the-character-encoding-of-a-file\/\">Determine the Character Encoding of a File.<\/a>\u00a0You can then use 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 or <code>fhFileUtils<\/code> to read it as text in the correct format.<\/p>\n<h4>File Handling Within IUP and Associated Libraries CD and IM<\/h4>\n<p>IUP supports &#8216;ANSI&#8217; paths by default in <code>iup.filedlg<\/code> (a file selection dialog), and the <code>DROPFILE_CB<\/code> callback (supporting file drag-and-drop onto an IUP dialog).<\/p>\n<p>To support UTF-8 file paths in these contexts:<\/p>\n<p style=\"padding-left: 40px;\"><code>iup.SetGlobal(\"UTF8MODE_FILE\", \"YES\")<br \/>\n<\/code><\/p>\n<p>However, this will not allow the CD or IM libraries (supporting graphics and digital images) to read or save files with Unicode characters in their path. If you can&#8217;t be certain that a file path doesn&#8217;t contain Unicode characters you should create a temporary file copy with an ANSI-encoded path (using <code>os.tmpname)<\/code> while working with those libraries, and copy the results to the target file when done.<\/p>\n<p><strong>RECOMMENDATION 6:<\/strong> Configure IUP to use UTF-8 file names.<\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\"><details><summary class=\"lightweight-accordion-title\"><h3>Accessing Configuration Data<\/h3><\/summary><div class=\"lightweight-accordion-body\"><h4><span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> Configuration Data<\/h4>\n<p>Much <span class=\"fh\" style=\"font-size: 17px !important; line-height: 21.4286px !important;\">\u0192<span style=\"color:#73B262; font-weight: bold;\">h<\/span><\/span> configuration data is available via 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. However, there are some items that are not supported in the API, and are occasionally used by plugin authors. The relevant encodings for Version 7 are:<\/p>\n<table style=\"border-collapse: collapse; width: 30%;\">\n<tbody>\n<tr>\n<td style=\"width: 10%;\"><strong>Data<\/strong><\/td>\n<td style=\"width: 10%;\"><strong>Encoding<\/strong><\/td>\n<\/tr>\n<tr>\n<td style=\"width: 10%;\">Autotext<\/td>\n<td style=\"width: 10%;\">UTF-8 BOM<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 10%;\">Fact Sets<\/td>\n<td style=\"width: 10%;\">UTF-16LE<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 10%;\">Queries<\/td>\n<td style=\"width: 10%;\">UTF-16LE<\/td>\n<\/tr>\n<tr>\n<td style=\"width: 10%;\">Source Templates<\/td>\n<td style=\"width: 10%;\">UTF-8 BOM<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p>This list is not an exhaustive list 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> configuration data.<\/p>\n<p>Follow the advice in <a href=\"#File-Handling\">File Access and Manipulation<\/a> to access these files, and in <a href=\"#String_Manipulation\">String Manipulation<\/a> to handle their contents.<\/p>\n<h4>Plugin Configuration Data<\/h4>\n<p>Many authors manipulate plugin configuration data directly as simple text; in which case it is recommended that the configuration data is encoded in UTF-8 files.<\/p>\n<p>However, <code>fhGetIniFileValue<\/code> and <code>fhSetIniFileValue<\/code> support the commonly-used <em>Inifile<\/em> format, and cope with non-&#8216;ANSI&#8217; characters in the file path, albeit with a lack of error messages when they fail, so are a simpler option.\u00a0 \u00a0If you wish to store Unicode values in the ini file, you must crreate it as an empty UTF-16LE text file before using it, using <code>fhSaveTextFile(strFilePath,\"\", \"UTF-16LE\").<\/code><\/p>\n<p>The Penlight <code>config<\/code> library does not cope with non-&#8216;ANSI&#8217; file paths.<\/p>\n<p><strong>RECOMMENDATION 7:<\/strong> Use <code>fhGetIniFileValue<\/code> and <code>fhSetIniFileValue<\/code> to manipulate Plugin Configuration Data for new plugins. Initialise the Ini file as an empty UTF-16 file using <code>fhSaveTextFile(strFilePath,\"\", \"UTF-16LE\").<\/code><\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\"><details><summary class=\"lightweight-accordion-title\"><h3>Running System Commands<\/h3><\/summary><div class=\"lightweight-accordion-body\"><p>The Lua <code>os<\/code> library (e.g. <code>os.getenv<\/code>, <code>os.execute<\/code>) supports &#8216;ANSI&#8217; as does <code>io.popen.<\/code> If a call to these functions involves UTF-8 or UTF-16 strings they may fail (depending on the characteristics of the command being executed.)<\/p>\n<p>So, for example, this will fail:<\/p>\n<p><code>bOK, strresult, iresult = os.execute(\"D:\\\\Documents\\\\\u0446\u043e\u043d\u0446\u043b\u0443\u0434\u0430\u0442\u0443\u0440\u044f\u0443\u0435.html\")<\/code><\/p>\n<p>The fhShellExecute function handles UTF-8 characters, so this will work, and returns similar information to <code>os.execute:<\/code><\/p>\n<p><code>bOK, iErrorCode, strErrorText = fhShellExecute(\"D:\\\\Documents\\\\\u0446\u043e\u043d\u0446\u043b\u0443\u0434\u0430\u0442\u0443\u0440\u044f\u0443\u0435.html\")<\/code><\/p>\n<p><strong>RECOMMENDATION 8:<\/strong>\u00a0Use <code>fhShellExecute<\/code> to execute system commands.<\/p>\n<\/div><\/details><\/div>\n<div class=\"lightweight-accordion\"><details><summary class=\"lightweight-accordion-title\"><h3>Debugging<\/h3><\/summary><div class=\"lightweight-accordion-body\"><p>The <code>print<\/code> function only supports &#8216;ANSI&#8217; (and the ASCII-compatible element of UTF-8) so you can&#8217;t rely on it for debugging if you need to check the value of a string in another encoding. Try placing a breakpoint and inspecting a string variable instead.<\/p>\n<\/div><\/details><\/div>\n<h3><a id=\"Recommendations\"><\/a>Recommendations Summarised<\/h3>\n<p><strong>RECOMMENDATION 1<\/strong>: Use UTF-8 for your plugin encoding and current string encoding.<\/p>\n<p><strong>RECOMMENDATION 2: <\/strong>Use the inbuilt Lua <code>utf8<\/code> library and the additional <code>utf8<\/code> library to manipulate strings.<\/p>\n<p><strong>RECOMMENDATION 3<\/strong>: Configure IUP to use UTF-8 on the user interface.<\/p>\n<p><strong>RECOMMENDATION 4: <\/strong>Use <code>fhLoadTextFile<\/code> and <code>fhSaveTextFile<\/code> if you simply need to read and\/or write text files stored in UTF-8, UTF-16 or &#8216;ANSI&#8217; encoding, and you are happy with their lack of of error reporting.<\/p>\n<p><strong>RECOMMENDATION 5<\/strong>: Use the <code>fhFileUtils<\/code> library for file access and manipulation if your needs are more complex.<\/p>\n<p><strong>RECOMMENDATION 6:<\/strong> Configure IUP to use UTF-8 file names.<\/p>\n<p><strong>RECOMMENDATION 7:<\/strong> Use <code>fhGetIniFileValue<\/code> and <code>fhSetIniFileValue<\/code> to manipulate Plugin Configuration Data for new plugins. Initialise the Ini file as an empty UTF-16 file using <code>fhSaveTextFile(strFilePath,\"\", \"UTF-16LE\").<\/code><\/p>\n<p><strong>RECOMMENDATION 8:<\/strong>\u00a0Use <code>fhShellExecute<\/code> to execute system commands.<\/p>\n<h3>Implementing the Recommendations<\/h3>\n<p>This block of code executed at the beginning of a plugin will either implement the recommendations above, or lay the groundwork to implement them.<\/p>\n<p>&nbsp;<\/p>\n<pre class=\"EnlighterJSRAW\" data-enlighter-language=\"lua\">fhSetStringEncoding(\"UTF-8\") --Use UTF-8 as current string encoding.\r\n\r\n--utf8 library for string manipulation\r\n\r\nrequire ( \"utf8data\" )\r\nutf8 = require ( \".utf8\" )\r\nutf8.config[\"conversion\"] = { uc_lc = utf8_uc_lc; lc_uc = utf8_lc_uc; }\r\nutf8:init()\r\n\r\n--optional libraries (omit any you're not intending to use)\r\n\r\nrequire ('iuplua') \r\nfh = require('fhUtils')\r\nfh.setIupDefaults() --initialise fhUtils\r\niup.SetGlobal(\"CUSTOMQUITMESSAGE\",\"YES\") --initialise IUP\r\niup.SetGlobal(\"UTF8MODE\", \"YES\") -- Configure IUP to use UTF-8 on the user interface.\r\niup.SetGlobal(\"UTF8MODE_FILE\", \"YES\")  --Configure IUP to use UTF-8 file names if you intend to use IUP file selection dialog\r\nfhfu = require('fhFileUtils')\u00a0\r\n<\/pre>\n<p>&nbsp;<\/p>\n<p>&nbsp;<\/p>\n","protected":false},"template":"","fh_version":[739],"skill_level":[18],"topic":[73],"class_list":["post-12132","kb_article","type-kb_article","status-publish","hentry","fh_version-v7","skill_level-advanced","topic-writing-plugins"],"_links":{"self":[{"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/kb_article\/12132","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=12132"}],"wp:term":[{"taxonomy":"fh_version","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/fh_version?post=12132"},{"taxonomy":"skill_level","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/skill_level?post=12132"},{"taxonomy":"topic","embeddable":true,"href":"https:\/\/www.fhug.org.uk\/kb\/wp-json\/wp\/v2\/topic?post=12132"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}