1 /*
2  * This program source code file is part of KiCad, a free EDA CAD application.
3  *
4  * Copyright (C) 2021 KiCad Developers, see AUTHORS.txt for contributors.
5  *
6  * This program is free software: you can redistribute it and/or modify it
7  * under the terms of the GNU General Public License as published by the
8  * Free Software Foundation, either version 3 of the License, or (at your
9  * option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful, but
12  * WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License along
17  * with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include <wx/filename.h>
21 #include <wx/stdpaths.h>
22 #include <wx/string.h>
23 #include <wx/utils.h>
24 
25 #include <kiplatform/environment.h>
26 #include <paths.h>
27 #include <pgm_base.h>
28 #include <settings/settings_manager.h>
29 #include <config.h>
30 
31 // lowercase or pretty case depending on platform
32 #if defined( __WXMAC__ ) || defined( __WXMSW__ )
33 #define KICAD_PATH_STR "KiCad"
34 #else
35 #define KICAD_PATH_STR "kicad"
36 #endif
37 
38 
getUserDocumentPath(wxFileName & aPath)39 void PATHS::getUserDocumentPath( wxFileName& aPath )
40 {
41     wxString envPath;
42 
43     if( wxGetEnv( wxT( "KICAD_DOCUMENTS_HOME" ), &envPath ) )
44         aPath.AssignDir( envPath );
45     else
46         aPath.AssignDir( KIPLATFORM::ENV::GetDocumentsPath() );
47 
48     aPath.AppendDir( KICAD_PATH_STR );
49     aPath.AppendDir( SETTINGS_MANAGER::GetSettingsVersion() );
50 }
51 
52 
GetUserPluginsPath()53 wxString PATHS::GetUserPluginsPath()
54 {
55     wxFileName tmp;
56     getUserDocumentPath( tmp );
57 
58     tmp.AppendDir( "plugins" );
59 
60     return tmp.GetPath();
61 }
62 
63 
GetUserPlugins3DPath()64 wxString PATHS::GetUserPlugins3DPath()
65 {
66     wxFileName tmp;
67 
68     tmp.AssignDir( PATHS::GetUserPluginsPath() );
69     tmp.AppendDir( "3d" );
70 
71     return tmp.GetPath();
72 }
73 
74 
GetUserScriptingPath()75 wxString PATHS::GetUserScriptingPath()
76 {
77     wxFileName tmp;
78     getUserDocumentPath( tmp );
79 
80     tmp.AppendDir( "scripting" );
81 
82     return tmp.GetPath();
83 }
84 
85 
GetUserTemplatesPath()86 wxString PATHS::GetUserTemplatesPath()
87 {
88     wxFileName tmp;
89     getUserDocumentPath( tmp );
90 
91     tmp.AppendDir( "template" );
92 
93     return tmp.GetPathWithSep();
94 }
95 
96 
GetDefaultUserSymbolsPath()97 wxString PATHS::GetDefaultUserSymbolsPath()
98 {
99     wxFileName tmp;
100     getUserDocumentPath( tmp );
101 
102     tmp.AppendDir( "symbols" );
103 
104     return tmp.GetPath();
105 }
106 
107 
GetDefaultUserFootprintsPath()108 wxString PATHS::GetDefaultUserFootprintsPath()
109 {
110     wxFileName tmp;
111     getUserDocumentPath( tmp );
112 
113     tmp.AppendDir( "footprints" );
114 
115     return tmp.GetPath();
116 }
117 
118 
GetDefaultUser3DModelsPath()119 wxString PATHS::GetDefaultUser3DModelsPath()
120 {
121     wxFileName tmp;
122     getUserDocumentPath( tmp );
123 
124     tmp.AppendDir( "3dmodels" );
125 
126     return tmp.GetPath();
127 }
128 
GetDefault3rdPartyPath()129 wxString PATHS::GetDefault3rdPartyPath()
130 {
131     wxFileName tmp;
132     getUserDocumentPath( tmp );
133 
134     tmp.AppendDir( "3rdparty" );
135 
136     return tmp.GetPath();
137 }
138 
GetDefaultUserProjectsPath()139 wxString PATHS::GetDefaultUserProjectsPath()
140 {
141     wxFileName tmp;
142     getUserDocumentPath( tmp );
143 
144     tmp.AppendDir( "projects" );
145 
146     return tmp.GetPath();
147 }
148 
149 
GetStockDataPath(bool aRespectRunFromBuildDir)150 wxString PATHS::GetStockDataPath( bool aRespectRunFromBuildDir )
151 {
152     wxString path;
153 
154     if( aRespectRunFromBuildDir && wxGetEnv( wxT( "KICAD_RUN_FROM_BUILD_DIR" ), nullptr ) )
155     {
156         // Allow debugging from build dir by placing relevant files/folders in the build root
157 #if defined( __WXMAC__ )
158         wxFileName fn = wxStandardPaths::Get().GetExecutablePath();
159 
160         fn.RemoveLastDir();
161         fn.RemoveLastDir();
162         fn.RemoveLastDir();
163         fn.RemoveLastDir();
164         path = fn.GetPath();
165 #elif defined( __WXMSW__ )
166         path = getWindowsKiCadRoot();
167 #else
168         path = Pgm().GetExecutablePath() + wxT( ".." );
169 #endif
170     }
171     else
172     {
173 #if defined( __WXMAC__ )
174         path = GetOSXKicadDataDir();
175 #elif defined( __WXMSW__ )
176         path = getWindowsKiCadRoot() + wxT( "share/kicad" );
177 #else
178         path = wxString::FromUTF8Unchecked( KICAD_DATA );
179 #endif
180     }
181 
182     return path;
183 }
184 
185 
GetStockEDALibraryPath()186 wxString PATHS::GetStockEDALibraryPath()
187 {
188     wxString path;
189 
190 #if defined( __WXMAC__ )
191     path = GetOSXKicadMachineDataDir();
192 #elif defined( __WXMSW__ )
193     path = GetStockDataPath( false );
194 #else
195     path = wxString::FromUTF8Unchecked( KICAD_LIBRARY_DATA );
196 #endif
197 
198     return path;
199 }
200 
201 
GetStockSymbolsPath()202 wxString PATHS::GetStockSymbolsPath()
203 {
204     wxString path;
205 
206     path = GetStockDataPath() + wxT( "/symbols" );
207 
208     return path;
209 }
210 
211 
GetStockFootprintsPath()212 wxString PATHS::GetStockFootprintsPath()
213 {
214     wxString path;
215 
216     path = GetStockDataPath() + wxT( "/footprints" );
217 
218     return path;
219 }
220 
221 
GetStock3dmodelsPath()222 wxString PATHS::GetStock3dmodelsPath()
223 {
224     wxString path;
225 
226     path = GetStockDataPath() + wxT( "/3dmodels" );
227 
228     return path;
229 }
230 
231 
GetStockScriptingPath()232 wxString PATHS::GetStockScriptingPath()
233 {
234     wxString path;
235 
236     path = GetStockDataPath() + wxT( "/scripting" );
237 
238     return path;
239 }
240 
241 
GetStockPluginsPath()242 wxString PATHS::GetStockPluginsPath()
243 {
244     wxFileName fn;
245 
246 #if defined( __WXMSW__ )
247     fn.AssignDir( Pgm().GetExecutablePath() );
248     fn.AppendDir( wxT( "scripting" ) );
249 #else
250     fn.AssignDir( PATHS::GetStockDataPath( false ) );
251 #endif
252     fn.AppendDir( wxT( "plugins" ) );
253 
254     return fn.GetPathWithSep();
255 }
256 
257 
GetStockPlugins3DPath()258 wxString PATHS::GetStockPlugins3DPath()
259 {
260     wxFileName fn;
261 
262 #ifdef __WXGTK__
263     // KICAD_PLUGINDIR = CMAKE_INSTALL_FULL_LIBDIR path is the absolute path
264     // corresponding to the install path used for constructing KICAD_USER_PLUGIN
265     wxString tfname = wxString::FromUTF8Unchecked( KICAD_PLUGINDIR );
266     fn.Assign( tfname, "" );
267     fn.AppendDir( wxT( "kicad" ) );
268     fn.AppendDir( wxT( "plugins" ) );
269 #elif defined( __WXMAC__ )
270     fn.Assign( wxStandardPaths::Get().GetPluginsDir(), wxEmptyString );
271 #else
272     fn.AssignDir( Pgm().GetExecutablePath() );
273     fn.AppendDir( wxT( "plugins" ) );
274 #endif
275 
276     fn.AppendDir( "3d" );
277 
278     return fn.GetPathWithSep();
279 }
280 
281 
GetStockDemosPath()282 wxString PATHS::GetStockDemosPath()
283 {
284     wxFileName fn;
285 
286     fn.AssignDir( PATHS::GetStockDataPath( false ) );
287     fn.AppendDir( wxT( "demos" ) );
288 
289     return fn.GetPathWithSep();
290 }
291 
292 
GetUserCachePath()293 wxString PATHS::GetUserCachePath()
294 {
295     wxFileName tmp;
296 
297     tmp.AssignDir( KIPLATFORM::ENV::GetUserCachePath() );
298     tmp.AppendDir( KICAD_PATH_STR );
299     tmp.AppendDir( SETTINGS_MANAGER::GetSettingsVersion() );
300 
301     return tmp.GetPathWithSep();
302 }
303 
304 
GetDocumentationPath()305 wxString PATHS::GetDocumentationPath()
306 {
307     wxString path;
308 
309 #if defined( __WXMAC__ )
310     path = GetOSXKicadDataDir();
311 #elif defined( __WXMSW__ )
312     path = getWindowsKiCadRoot() + "share/doc/kicad";
313 #else
314     path = wxString::FromUTF8Unchecked( KICAD_DOCS );
315 #endif
316 
317     return path;
318 }
319 
320 
EnsurePathExists(const wxString & aPath)321 bool PATHS::EnsurePathExists( const wxString& aPath )
322 {
323     wxFileName path( aPath );
324     if( !path.Normalize() )
325     {
326         return false;
327     }
328 
329     if( !wxFileName::DirExists( aPath ) )
330     {
331         if( !wxFileName::Mkdir( aPath, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL ) )
332         {
333             return false;
334         }
335     }
336 
337     return true;
338 }
339 
340 
EnsureUserPathsExist()341 void PATHS::EnsureUserPathsExist()
342 {
343     EnsurePathExists( GetUserPluginsPath() );
344     EnsurePathExists( GetUserPlugins3DPath() );
345     EnsurePathExists( GetUserScriptingPath() );
346     EnsurePathExists( GetUserTemplatesPath() );
347     EnsurePathExists( GetDefaultUserProjectsPath() );
348     EnsurePathExists( GetDefaultUserSymbolsPath() );
349     EnsurePathExists( GetDefaultUserFootprintsPath() );
350     EnsurePathExists( GetDefaultUser3DModelsPath() );
351     EnsurePathExists( GetDefault3rdPartyPath() );
352 }
353 
354 
355 #ifdef __WXMAC__
GetOSXKicadUserDataDir()356 wxString PATHS::GetOSXKicadUserDataDir()
357 {
358     // According to wxWidgets documentation for GetUserDataDir:
359     // Mac: ~/Library/Application Support/appname
360     wxFileName udir( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
361 
362     // Since appname is different if started via launcher or standalone binary
363     // map all to "kicad" here
364     udir.RemoveLastDir();
365     udir.AppendDir( "kicad" );
366 
367     return udir.GetPath();
368 }
369 
370 
GetOSXKicadMachineDataDir()371 wxString PATHS::GetOSXKicadMachineDataDir()
372 {
373     // 6.0 forward:  Same as the main data dir
374     return GetOSXKicadDataDir();
375 }
376 
377 
GetOSXKicadDataDir()378 wxString PATHS::GetOSXKicadDataDir()
379 {
380     // According to wxWidgets documentation for GetDataDir:
381     // Mac: appname.app/Contents/SharedSupport bundle subdirectory
382     wxFileName ddir( wxStandardPaths::Get().GetDataDir(), wxEmptyString );
383 
384     // This must be mapped to main bundle for everything but kicad.app
385     const wxArrayString dirs = ddir.GetDirs();
386 
387     // Check if we are the main kicad binary.  in this case, the path will be
388     //     /path/to/bundlename.app/Contents/SharedSupport
389     // If we are an aux binary, the path will be something like
390     //     /path/to/bundlename.app/Contents/Applications/<standalone>.app/Contents/SharedSupport
391     if( dirs.GetCount() >= 6 &&
392         dirs[dirs.GetCount() - 4] == wxT( "Applications" ) &&
393         dirs[dirs.GetCount() - 6].Lower().EndsWith( wxT( "app" ) ) )
394     {
395         ddir.RemoveLastDir();
396         ddir.RemoveLastDir();
397         ddir.RemoveLastDir();
398         ddir.RemoveLastDir();
399         ddir.AppendDir( wxT( "SharedSupport" ) );
400     }
401 
402     return ddir.GetPath();
403 }
404 #endif
405 
406 
407 #ifdef __WXWINDOWS__
getWindowsKiCadRoot()408 wxString PATHS::getWindowsKiCadRoot()
409 {
410     wxFileName root( Pgm().GetExecutablePath() + "/../" );
411     root.Normalize();
412 
413     return root.GetPathWithSep();
414 }
415 #endif
416