1 ////////////////////////////////////////////////////////////////////////
2 //
3 // Copyright (C) 2008-2021 The Octave Project Developers
4 //
5 // See the file COPYRIGHT.md in the top-level directory of this
6 // distribution or <https://octave.org/copyright/>.
7 //
8 // This file is part of Octave.
9 //
10 // Octave is free software: you can redistribute it and/or modify it
11 // under the terms of the GNU General Public License as published by
12 // the Free Software Foundation, either version 3 of the License, or
13 // (at your option) any later version.
14 //
15 // Octave is distributed in the hope that it will be useful, but
16 // WITHOUT ANY WARRANTY; without even the implied warranty of
17 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 // GNU General Public License for more details.
19 //
20 // You should have received a copy of the GNU General Public License
21 // along with Octave; see the file COPYING.  If not, see
22 // <https://www.gnu.org/licenses/>.
23 //
24 ////////////////////////////////////////////////////////////////////////
25 
26 // These functions are also defined in liboctave or libinterp.  They
27 // are repeated here to avoid having to link the main Octave program
28 // with the Octave libraries.
29 
30 #if ! defined (octave_shared_fcns_h)
31 #define octave_shared_fcns_h 1
32 
33 #include <cctype>
34 
35 #if defined (OCTAVE_USE_WINDOWS_API)
36 
37 #include <windows.h>
38 #include <tlhelp32.h>
39 
40 #if defined (_MSC_VER)
41 #  define popen _popen
42 #  define pclose _pclose
43 #endif
44 
45 static std::string
w32_get_octave_home(void)46 w32_get_octave_home (void)
47 {
48   std::string retval;
49 
50   std::string bin_dir;
51 
52   char namebuf[MAX_PATH+1];
53   if (GetModuleFileName (GetModuleHandle (nullptr), namebuf, MAX_PATH))
54     {
55       namebuf[MAX_PATH] = '\0';
56 
57       std::string exe_name = namebuf;
58       std::size_t pos = exe_name.rfind ('\\');
59 
60       if (pos != std::string::npos)
61         bin_dir = exe_name.substr (0, pos + 1);
62     }
63 
64   if (! bin_dir.empty ())
65     {
66       std::size_t pos = bin_dir.rfind (R"(\bin\)");
67 
68       if (pos != std::string::npos)
69         retval = bin_dir.substr (0, pos);
70     }
71 
72   return retval;
73 }
74 
75 #endif
76 
77 // Find the directory where the octave binary is supposed to be
78 // installed.
79 
80 #if (defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)           \
81      && ! defined (OCTAVE_HAVE_POSIX_FILESYSTEM))
82 static const char dir_sep_char = '\\';
83 #else
84 static const char dir_sep_char = '/';
85 #endif
86 
87 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
88 static std::string dir_sep_chars = R"(/\)";
89 #else
90 static std::string dir_sep_chars = "/";
91 #endif
92 
93 static std::string
octave_getenv(const std::string & name)94 octave_getenv (const std::string& name)
95 {
96   char *value = ::getenv (name.c_str ());
97 
98   return value ? value : "";
99 }
100 
101 static std::string Voctave_home;
102 static std::string Voctave_exec_home;
103 
104 static void
set_octave_home(void)105 set_octave_home (void)
106 {
107   std::string op = OCTAVE_PREFIX;
108   std::string oep = OCTAVE_EXEC_PREFIX;
109 
110   std::string oh = octave_getenv ("OCTAVE_HOME");
111   std::string oeh = octave_getenv ("OCTAVE_EXEC_HOME");
112 
113 #if defined (OCTAVE_USE_WINDOWS_API)
114   if (oh.empty ())
115     oh = w32_get_octave_home ();
116 #endif
117 
118   // If OCTAVE_HOME is set in the environment, use that.  Otherwise,
119   // default to ${prefix} from configure.
120 
121   Voctave_home = (oh.empty () ? op : oh);
122 
123   // If OCTAVE_EXEC_HOME is set in the environment, use that.
124   // Otherwise, if ${prefix} and ${exec_prefix} from configure are set
125   // to the same value, use OCTAVE_HOME from the environment if it is set.
126   // Otherwise, default to ${exec_prefix} from configure.
127 
128   if (! oeh.empty ())
129     Voctave_exec_home = oeh;
130   else if (op == oep && ! oh.empty ())
131     Voctave_exec_home = oh;
132   else
133     Voctave_exec_home = oep;
134 }
135 
is_dir_sep(char c)136 static bool is_dir_sep (char c)
137 {
138   return dir_sep_chars.find (c) != std::string::npos;
139 }
140 
141 static bool
absolute_pathname(const std::string & s)142 absolute_pathname (const std::string& s)
143 {
144   std::size_t len = s.length ();
145 
146   if (len == 0)
147     return false;
148 
149   if (is_dir_sep (s[0]))
150     return true;
151 
152 #if defined (OCTAVE_HAVE_WINDOWS_FILESYSTEM)
153   if ((len == 2 && isalpha (s[0]) && s[1] == ':')
154       || (len > 2 && isalpha (s[0]) && s[1] == ':'
155           && is_dir_sep (s[2])))
156     return true;
157 #endif
158 
159   return false;
160 }
161 
162 static std::string
prepend_home_dir(const std::string & hd,const std::string & s)163 prepend_home_dir (const std::string& hd, const std::string& s)
164 {
165   std::string retval = s;
166 
167   if (! absolute_pathname (retval))
168     retval = hd + dir_sep_char + s;
169 
170   if (dir_sep_char != '/')
171     std::replace (retval.begin (), retval.end (), '/', dir_sep_char);
172 
173   return retval;
174 }
175 
176 // prepend_octave_home is used in mkoctfile.in.cc and
177 // octave-config.in.cc but not in main.in.cc.  Tagging it as unused
178 // avoids warnings from GCC about an unused function but should not
179 // cause trouble in the event that it actually is used.
180 
181 OCTAVE_UNUSED
182 static std::string
prepend_octave_home(const std::string & s)183 prepend_octave_home (const std::string& s)
184 {
185   return prepend_home_dir (Voctave_home, s);
186 }
187 
188 static std::string
prepend_octave_exec_home(const std::string & s)189 prepend_octave_exec_home (const std::string& s)
190 {
191   return prepend_home_dir (Voctave_exec_home, s);
192 }
193 
194 #endif
195