diff libinterp/corefcn/load-path.cc @ 28953:dff830c84726

Add function "dir_encoding" to set a file encoding per directory (bug #49685). * corefcn/load-path.h (load_path::read_dir_config): Add new function. * corefcn/load-path.cc (load_path::read_dir_config): Add new function. (load_path::add): Call read_dir_config on adding a new directory to the load path. * corefcn/input.h (input_system::dir_encoding, input_system::set_dir_encoding): Add new functions. Add private unordered_map "m_dir_encoding". * corefcn/input.cc (input_system::dir_encoding, input_system::set_dir_encoding): Add new functions. (base_reader, file_reader, input_reader): Add new constructors that accept an encoding (use mfile_encoding by default). Add private property "m_encoding". (load_path_dir): Static function to get the part of the directory that would be added to the load path. (Fdir_encoding): New function. * corefcn/interpreter.cc (interpreter::chdir): Call load_path::read_dir_config. * parse-tree/lex.h (lexer): Add new constructor that accepts an encoding. * parse-tree/parse.h (parser): Add new constructor that accepts an encoding. * parse-tree/oct-parse.yy (parse_fcn_file): Pass dir_encoding to parser. * doc/interpreter/func.txi: Add docstring of function "dir_encoding" to manual.
author Markus Mützel <markus.muetzel@gmx.de>
date Fri, 18 Sep 2020 17:15:32 +0200
parents 43ad651cf5a0
children 02b97abbc6fc
line wrap: on
line diff
--- a/libinterp/corefcn/load-path.cc	Sat Oct 17 02:13:39 2020 -0700
+++ b/libinterp/corefcn/load-path.cc	Fri Sep 18 17:15:32 2020 +0200
@@ -28,6 +28,7 @@
 #endif
 
 #include <algorithm>
+#include <cctype>
 
 #include "dir-ops.h"
 #include "file-ops.h"
@@ -1084,6 +1085,8 @@
           {
             if (fs.is_dir ())
               {
+                read_dir_config (dir);
+
                 dir_info di (dir);
 
                 if (at_end)
@@ -1134,6 +1137,78 @@
       }
   }
 
+  void
+  load_path::read_dir_config (const std::string& dir) const
+  {
+    // read file with directory configuration
+    std::string conf_file = dir + sys::file_ops::dir_sep_str ()
+                            + ".oct_config";
+
+    FILE* cfile = sys::fopen (conf_file, "rb");
+
+    if (! cfile)
+      {
+        // reset directory encoding
+        input_system& input_sys
+          = __get_input_system__ ("load_path::read_dir_config");
+
+        std::string enc_val = "delete";
+        input_sys.set_dir_encoding (dir, enc_val);
+        return;
+      }
+
+    unwind_action close_file ([cfile] (void) { fclose (cfile); });
+
+    // find line with character encoding and read it
+    bool eof = false;
+    const std::string enc_prop = "encoding";
+    while (! eof)
+      {
+        std::string conf_str = octave_fgets (cfile, eof);
+
+        // delete any preceeding whitespace
+        auto it = std::find_if_not (conf_str.begin (), conf_str.end (),
+                                    [] (unsigned char c)
+                                    { return std::isblank (c); });
+        conf_str.erase (conf_str.begin (), it);
+
+        // match identifier
+        if (conf_str.compare (0, enc_prop.size (), enc_prop) == 0)
+          {
+            // skip delimiter characters
+            size_t pos = conf_str.find_first_not_of (" \t=:",
+                                                     enc_prop.size ());
+            if (pos == std::string::npos)
+              continue;
+
+            std::string enc_val = conf_str.substr (pos);
+
+            // take alphanumeric and '-' characters
+            it = std::find_if_not (enc_val.begin (), enc_val.end (),
+                                   [] (unsigned char c)
+                                   { return std::isalnum (c) || c == '-'; });
+            enc_val.erase(it, enc_val.end ());
+
+            if (enc_val.empty ())
+              continue;
+
+            // set encoding for this directory in input system
+            input_system& input_sys
+              = __get_input_system__ ("load_path::read_dir_config");
+            input_sys.set_dir_encoding (dir, enc_val);
+            return;
+          }
+      }
+
+    // reset directory encoding
+    input_system& input_sys
+      = __get_input_system__ ("load_path::read_dir_config");
+
+    std::string enc_val = "delete";
+    input_sys.set_dir_encoding (dir, enc_val);
+
+  }
+
   bool
   load_path::is_package (const std::string& name) const
   {