1 // -*- mode: c++; c-file-style: "linux"; c-basic-offset: 2; indent-tabs-mode: nil -*-
2 //  Copyright (C) 2004-2015 Andrej Vodopivec <andrej.vodopivec@gmail.com>
3 //            (C) 2015-2018 Gunter Königsmann <wxMaxima@physikbuch.de>
4 //            (C) 2008-2009 Ziga Lenarcic <zigalenarcic@users.sourceforge.net>
5 //            (C) 2011-2011 cw.ahbong <cw.ahbong@gmail.com>
6 //            (C) 2012-2013 Doug Ilijev <doug.ilijev@gmail.com>
7 //
8 //  This program is free software; you can redistribute it and/or modify
9 //  it under the terms of the GNU General Public License as published by
10 //  the Free Software Foundation; either version 2 of the License, or
11 //  (at your option) any later version.
12 //
13 //  This program is distributed in the hope that it will be useful,
14 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
15 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16 //  GNU General Public License for more details.
17 //
18 //
19 //  You should have received a copy of the GNU General Public License
20 //  along with this program; if not, write to the Free Software
21 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
22 //
23 //  SPDX-License-Identifier: GPL-2.0+
24 
25 
26 /*! \file
27   This file defines the class DirStructure
28 
29   DirStructure informs about what directory is to be found where on the current system.
30 */
31 
32 #include "Dirstructure.h"
33 #include <wx/filename.h>
34 #include <wx/dir.h>
35 #include "Version.h"
36 
37 // This macro is used to mark the macports prefix, so that it can be easily patched
38 // The MacPorts port file for wxMaxima uses this, so don't remove this!
39 // Note: this is not done with a define passed through cmake because I didn't find a way
40 // to pass paths which need quoting through cmake.
41 #define OSX_MACPORTS_PREFIX "/opt/local"
42 // If set to 1, the macports path is put first into the search path (after app package paths).
43 // This could be done with a define but then it doesn't make sense to use a different method.
44 #define OSX_MACPORTS_PREFER 0
45 
Dirstructure()46 Dirstructure::Dirstructure()
47 {
48   m_dirStructure = this;
49   m_helpDir = ResourcesDir();
50 
51   // The path Gentoo hides the manual at
52   if(wxDirExists(m_helpDir + wxString::Format("/doc/wxmaxima-%s",GITVERSION)))
53     m_helpDir += wxString::Format("/doc/wxmaxima-%s",GITVERSION);
54   if(wxDirExists(m_helpDir + wxT("/doc/wxmaxima")))
55     m_helpDir += wxT("/doc/wxmaxima");
56 
57   if(wxDirExists(m_helpDir + wxT("/html")))
58     m_helpDir += wxT("/html");
59 
60   if(wxDirExists(m_helpDir + wxT("/info")))
61     m_helpDir += wxT("/info");
62 
63   if(wxDirExists(m_helpDir + wxT("/help")))
64     m_helpDir += wxT("/help");
65 
66   if(!wxGetEnv(wxT("MAXIMA_USERDIR"),&m_userConfDir))
67     m_userConfDir = wxGetHomeDir();
68   m_userConfDir += "/";
69 
70 #ifndef __WXMSW__
71   m_userConfDir += wxT(".");
72 #endif
73 
74   m_userConfDir += wxT("maxima");
75 
76   if(!wxDirExists(m_userConfDir))
77     wxMkDir(m_userConfDir, wxS_DIR_DEFAULT);
78 
79   m_userConfDir += "/";
80 
81 }
82 
ResourcesDir() const83 wxString Dirstructure::ResourcesDir() const
84 {
85   wxString exepath = wxStandardPaths::Get().GetExecutablePath();
86   if(!exepath.IsEmpty())
87   {
88     // Our resources dir is somewhere near to the dir the binary can be found.
89     wxFileName exe(exepath);
90 
91     // We only need the drive and the directory part of the path to the binary
92     exe.ClearExt();
93     exe.SetName(wxEmptyString);
94 
95     // If the binary is in a source or bin folder the resources dir is one level above
96     wxArrayString dirs = exe.GetDirs();
97     if((dirs.Last().Upper() == wxT("SRC")) || (dirs.Last().Upper() == wxT("BIN")))
98     {
99       exe.RemoveLastDir();
100       dirs = exe.GetDirs();
101     }
102 
103     // If the binary is in the wxMaxima folder the resources dir is two levels above as we
104     // are in MacOS/wxmaxima
105     if((dirs.Last().Upper() == wxT("MACOS")))
106       exe.RemoveLastDir();
107 
108     // If there is a Resources folder the resources are there
109     if(wxDirExists(exe.GetPath() + wxT("/Resources")))
110       exe.AppendDir("Resources");
111 
112     // If there is a share folder the resources are there
113     if(wxDirExists(exe.GetPath() + wxT("/share")))
114       exe.AppendDir("share");
115 
116 
117     exepath = exe.GetPath();
118   }
119   else
120   {
121     exepath = CMAKE_INSTALL_PREFIX;
122   }
123   return exepath;
124 }
125 
DataDir() const126 wxString Dirstructure::DataDir() const
127 {
128   wxString dir = ResourcesDir();
129   if(wxDirExists(dir + wxT("/data")))
130     dir += wxT("/data");
131   if(wxDirExists(dir + wxT("/wxMaxima")))
132     dir += wxT("/wxMaxima");
133 
134   return dir;
135 }
136 
ArtDir() const137 wxString Dirstructure::ArtDir() const
138 {
139   wxString dir = ResourcesDir();
140   if(wxDirExists(dir + wxT("/wxMaxima")))
141     dir += wxT("/wxMaxima");
142 
143   if(wxDirExists(dir + wxT("/art")))
144     dir += wxT("/art");
145 
146   return dir;
147 }
148 
MaximaDefaultLocation()149 wxString Dirstructure::MaximaDefaultLocation()
150 {
151   wxString maximaLocation;
152   wxFileName exe = wxStandardPaths::Get().GetExecutablePath();
153   exe.MakeAbsolute();
154   wxFileName maxima;
155 #if defined __WXMSW__ || defined __WXOSX__
156   wxString notFound = _("Maxima not found as %s");
157 #endif
158 #if defined __WXMSW__
159   wxString exeDir = exe.GetPathWithSep();
160   maxima = exeDir + "../bin/maxima.bat";
161   maxima.MakeAbsolute();
162   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
163     return maximaLocation;
164 
165   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
166   maxima = exeDir + "maxima.bat";
167   maxima.MakeAbsolute();
168   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
169     return maximaLocation;
170 
171   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
172   maxima = exeDir + "bin/maxima.bat";
173   maxima.MakeAbsolute();
174   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
175     return maximaLocation;
176 
177   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
178   maxima = exeDir + "../maxima.bat";
179   maxima.MakeAbsolute();
180   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
181     return maximaLocation;
182 
183   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
184   maxima = exeDir + "maxima";
185   maxima.MakeAbsolute();
186   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
187     return maximaLocation;
188 
189   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
190   maxima = exeDir + "bin/maxima";
191   maxima.MakeAbsolute();
192   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
193     return maximaLocation;
194 
195   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
196   maxima = exeDir + "../maxima";
197   maxima.MakeAbsolute();
198   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
199     return maximaLocation;
200 
201   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
202   maxima = exeDir + "../bin/maxima";
203   maxima.MakeAbsolute();
204   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
205     return maximaLocation;
206 
207   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
208 #elif defined __WXOSX__
209   wxString exeDir = exe.GetPathWithSep();
210   maximaLocation =  "/Applications/Maxima.app";
211   if (wxFileExists(maximaLocation))
212     return maximaLocation;
213 
214   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
215   maximaLocation = "/Applications/maxima.app";
216   if (wxFileExists(maximaLocation))
217     return maximaLocation;
218 
219   // The Macports path (if it is prefered over homebrew)
220 #if OSX_MACPORTS_PREFER
221   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
222   maximaLocation = OSX_MACPORTS_PREFIX "/bin/maxima";
223   if (wxFileExists(maximaLocation))
224     return maximaLocation;
225 #endif
226 
227   // The homebrew path
228   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
229   maximaLocation = "/usr/local/bin/maxima";
230   if (wxFileExists(maximaLocation))
231     return maximaLocation;
232 
233   // The Macports path (if it is not prefered over homebrew)
234 #if !OSX_MACPORTS_PREFER
235   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
236   maximaLocation = OSX_MACPORTS_PREFIX "/bin/maxima";
237   if (wxFileExists(maximaLocation))
238     return maximaLocation;
239 #endif
240 
241   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
242   maximaLocation = "/usr/bin/maxima";
243   if (wxFileExists(maximaLocation))
244     return maximaLocation;
245 
246   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
247   maxima = exeDir + "maxima";
248   maxima.MakeAbsolute();
249   if(wxFileExists(maximaLocation = maxima.GetFullPath()))
250     return maximaLocation;
251 
252   wxLogMessage(wxString::Format(notFound,maximaLocation.utf8_str()));
253 #endif
254   return wxT("maxima");
255 }
256 
GnuplotDefaultLocation(wxString pathguess)257 wxString Dirstructure::GnuplotDefaultLocation(wxString pathguess)
258 {
259   wxString gnuplot_binary;
260 
261   if(wxFileName(pathguess).IsAbsolute())
262     gnuplot_binary = pathguess;
263   else
264   {
265     wxPathList pathlist;
266 
267     // Add paths relative to the path of the wxMaxima executable
268     pathlist.Add(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath());
269     pathlist.Add(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath()+"/../");
270     pathlist.Add(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath()+"/../gnuplot");
271     pathlist.Add(wxFileName(wxStandardPaths::Get().GetExecutablePath()).GetPath()+"/../gnuplot/bin");
272 
273     // Add paths from the PATH environment variable
274     pathlist.AddEnvList(wxT("PATH"));
275 
276     // Add OSX specific paths
277 #ifdef __WXOSX__
278     // MacPorts:
279     // The MacPorts default binary path /opt/local/bin/ is not in the PATH for applications.
280     // It is added to .profile, but this is only used by shells.
281     // => Add the default MacPorts binary path /opt/local/bin/ to our search path list.
282     //
283     // Homebrew:
284     // Homebrew installs binaries in /usr/local/bin, which is in the PATH by default.
285     //
286     // Application packages including gnuplot:
287     // The above wxMaxima executable relative logic should work
288     //
289     // If gnuplot is somewhere else (e.g. non default MacPort or Homebrew path), the command
290     //   gnuplot_command:"/opt/local/bin/gnuplot"$
291     // must be added manually to ~/.maxima/wxmaxima-init.mac
292     // This should be documented for the installer packages, e.g. as MacPorts "notes" field.
293     pathlist.Add(OSX_MACPORTS_PREFIX "/bin");
294 #endif
295 
296     // Find executable "gnuplot" in our list of paths
297     gnuplot_binary = pathlist.FindAbsoluteValidPath(pathguess);
298     // If not successful, Find executable "gnuplot.exe" in our list of paths
299     if(gnuplot_binary == wxEmptyString)
300       gnuplot_binary = pathlist.FindAbsoluteValidPath(pathguess + wxT(".exe"));
301     // If not successful, use the original command (better than empty for error messages)
302     if(gnuplot_binary == wxEmptyString)
303     {
304       wxLogMessage(_("Gnuplot not found, using the default: ") + pathguess);
305       gnuplot_binary = pathguess;
306     }
307     else
308     {
309       wxLogMessage(_("Gnuplot found at: ") + gnuplot_binary);
310     }
311   }
312 
313   return gnuplot_binary;
314 }
315 
UserAutocompleteFile()316 wxString Dirstructure::UserAutocompleteFile()
317 {
318   wxString newFileName = UserConfDir() + wxT("wxmaxima.ac");
319   if(!wxFileExists(newFileName))
320   {
321     wxString potentialOldFile = UserConfDir() + wxT(".wxmaxima.ac");
322     if(wxFileExists(potentialOldFile))
323       wxRenameFile(potentialOldFile, newFileName);
324     potentialOldFile = UserConfDir() + wxT(".wxmax.ac");
325     if(wxFileExists(potentialOldFile))
326       wxRenameFile(potentialOldFile, newFileName);
327   }
328   return newFileName;
329 }
330 
331 Dirstructure *Dirstructure::m_dirStructure;
332