e37b9a7ef252486e1f5b0fb8e9bf33486ce402ed
[blender.git] / source / blender / blenkernel / intern / appdir.c
1 /*
2  * ***** BEGIN GPL LICENSE BLOCK *****
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License
6  * as published by the Free Software Foundation; either version 2
7  * of the License, or (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17  *
18  */
19
20 /** \file blender/blenlib/intern/appdir.c
21  *  \ingroup bke
22  *
23  * Access to application level directories.
24  */
25
26 #include <stdlib.h>
27 #include <string.h>
28 #include <stdio.h>
29
30 #include "BLI_utildefines.h"
31 #include "BLI_string.h"
32 #include "BLI_fileops.h"
33 #include "BLI_path_util.h"
34
35 #include "BKE_appdir.h"  /* own include */
36
37 #include "GHOST_Path-api.h"
38
39 #include "../blenkernel/BKE_blender.h"  /* BLENDER_VERSION, bad level include (no function call) */
40
41 #include "MEM_guardedalloc.h"
42
43 #ifdef WIN32
44 #  include "utf_winfunc.h"
45 #  include "utfconv.h"
46 #  include <io.h>
47 #  ifdef _WIN32_IE
48 #    undef _WIN32_IE
49 #  endif
50 #  define _WIN32_IE 0x0501
51 #  include <windows.h>
52 #  include <shlobj.h>
53 #  include "BLI_winstuff.h"
54 #else /* non windows */
55 #  ifdef WITH_BINRELOC
56 #    include "binreloc.h"
57 #  endif
58 #  include <unistd.h>  /* mkdtemp on OSX (and probably all *BSD?), not worth making specific check for this OS. */
59 #endif /* WIN32 */
60
61 /* local */
62 static char bprogname[FILE_MAX];    /* full path to program executable */
63 static char bprogdir[FILE_MAX];     /* full path to directory in which executable is located */
64 static char btempdir_base[FILE_MAX];          /* persistent temporary directory */
65 static char btempdir_session[FILE_MAX] = "";  /* volatile temporary directory */
66
67 /* This is now only used to really get the user's default document folder */
68 /* On Windows I chose the 'Users/<MyUserName>/Documents' since it's used
69  * as default location to save documents */
70 const char *BKE_appdir_folder_default(void)
71 {
72 #ifndef WIN32
73         const char * const xdg_documents_dir = getenv("XDG_DOCUMENTS_DIR");
74
75         if (xdg_documents_dir)
76                 return xdg_documents_dir;
77
78         return getenv("HOME");
79 #else /* Windows */
80         static char documentfolder[MAXPATHLEN];
81         HRESULT hResult;
82
83         /* Check for %HOME% env var */
84         if (uput_getenv("HOME", documentfolder, MAXPATHLEN)) {
85                 if (BLI_is_dir(documentfolder)) return documentfolder;
86         }
87                                 
88         /* add user profile support for WIN 2K / NT.
89          * This is %APPDATA%, which translates to either
90          * %USERPROFILE%\Application Data or since Vista
91          * to %USERPROFILE%\AppData\Roaming
92          */
93         hResult = SHGetFolderPath(NULL, CSIDL_PERSONAL, NULL, SHGFP_TYPE_CURRENT, documentfolder);
94                 
95         if (hResult == S_OK) {
96                 if (BLI_is_dir(documentfolder)) return documentfolder;
97         }
98                 
99         return NULL;
100 #endif /* WIN32 */
101 }
102
103
104 // #define PATH_DEBUG
105
106 /* returns a formatted representation of the specified version number. Non-reentrant! */
107 static char *blender_version_decimal(const int ver)
108 {
109         static char version_str[5];
110         sprintf(version_str, "%d.%02d", ver / 100, ver % 100);
111         return version_str;
112 }
113
114 /**
115  * Concatenates path_base, (optional) path_sep and (optional) folder_name into targetpath,
116  * returning true if result points to a directory.
117  */
118 static bool test_path(char *targetpath, const char *path_base, const char *path_sep, const char *folder_name)
119 {
120         char tmppath[FILE_MAX];
121         
122         if (path_sep) BLI_join_dirfile(tmppath, sizeof(tmppath), path_base, path_sep);
123         else BLI_strncpy(tmppath, path_base, sizeof(tmppath));
124
125         /* rare cases folder_name is omitted (when looking for ~/.blender/2.xx dir only) */
126         if (folder_name)
127                 BLI_make_file_string("/", targetpath, tmppath, folder_name);
128         else
129                 BLI_strncpy(targetpath, tmppath, sizeof(tmppath));
130         /* FIXME: why is "//" on front of tmppath expanded to "/" (by BLI_join_dirfile)
131          * if folder_name is specified but not otherwise? */
132
133         if (BLI_is_dir(targetpath)) {
134 #ifdef PATH_DEBUG
135                 printf("\t%s found: %s\n", __func__, targetpath);
136 #endif
137                 return true;
138         }
139         else {
140 #ifdef PATH_DEBUG
141                 printf("\t%s missing: %s\n", __func__, targetpath);
142 #endif
143                 //targetpath[0] = '\0';
144                 return false;
145         }
146 }
147
148 /**
149  * Puts the value of the specified environment variable into *path if it exists
150  * and points at a directory. Returns true if this was done.
151  */
152 static bool test_env_path(char *path, const char *envvar)
153 {
154         const char *env = envvar ? getenv(envvar) : NULL;
155         if (!env) return false;
156         
157         if (BLI_is_dir(env)) {
158                 BLI_strncpy(path, env, FILE_MAX);
159 #ifdef PATH_DEBUG
160                 printf("\t%s env %s found: %s\n", __func__, envvar, env);
161 #endif
162                 return true;
163         }
164         else {
165                 path[0] = '\0';
166 #ifdef PATH_DEBUG
167                 printf("\t%s env %s missing: %s\n", __func__, envvar, env);
168 #endif
169                 return false;
170         }
171 }
172
173 /**
174  * Constructs in \a targetpath the name of a directory relative to a version-specific
175  * subdirectory in the parent directory of the Blender executable.
176  *
177  * \param targetpath  String to return path
178  * \param folder_name  Optional folder name within version-specific directory
179  * \param subfolder_name  Optional subfolder name within folder_name
180  * \param ver  To construct name of version-specific directory within bprogdir
181  * \return true if such a directory exists.
182  */
183 static bool get_path_local(char *targetpath, const char *folder_name, const char *subfolder_name, const int ver)
184 {
185         char relfolder[FILE_MAX];
186         
187 #ifdef PATH_DEBUG
188         printf("%s...\n", __func__);
189 #endif
190
191         if (folder_name) {
192                 if (subfolder_name) {
193                         BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
194                 }
195                 else {
196                         BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
197                 }
198         }
199         else {
200                 relfolder[0] = '\0';
201         }
202
203         /* try EXECUTABLE_DIR/2.5x/folder_name - new default directory for local blender installed files */
204 #ifdef __APPLE__
205         static char osx_resourses[FILE_MAX]; /* due new codesign situation in OSX > 10.9.5 we must move the blender_version dir with contents to Resources */
206         sprintf(osx_resourses, "%s../Resources", bprogdir);
207         return test_path(targetpath, osx_resourses, blender_version_decimal(ver), relfolder);
208 #else
209         return test_path(targetpath, bprogdir, blender_version_decimal(ver), relfolder);
210 #endif
211 }
212
213 /**
214  * Is this an install with user files kept together with the Blender executable and its
215  * installation files.
216  */
217 static bool is_portable_install(void)
218 {
219         /* detect portable install by the existence of config folder */
220         const int ver = BLENDER_VERSION;
221         char path[FILE_MAX];
222
223         return get_path_local(path, "config", NULL, ver);
224 }
225
226 /**
227  * Returns the path of a folder within the user-files area.
228  *
229  *
230  * \param targetpath  String to return path
231  * \param folder_name  default name of folder within user area
232  * \param subfolder_name  optional name of subfolder within folder
233  * \param envvar  name of environment variable which, if defined, overrides folder_name
234  * \param ver  Blender version, used to construct a subdirectory name
235  * \return true if it was able to construct such a path.
236  */
237 static bool get_path_user(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
238 {
239         char user_path[FILE_MAX];
240         const char *user_base_path;
241
242         /* for portable install, user path is always local */
243         if (is_portable_install())
244                 return get_path_local(targetpath, folder_name, subfolder_name, ver);
245         
246         user_path[0] = '\0';
247
248         if (test_env_path(user_path, envvar)) {
249                 if (subfolder_name) {
250                         return test_path(targetpath, user_path, NULL, subfolder_name);
251                 }
252                 else {
253                         BLI_strncpy(targetpath, user_path, FILE_MAX);
254                         return true;
255                 }
256         }
257
258         user_base_path = (const char *)GHOST_getUserDir(ver, blender_version_decimal(ver));
259         if (user_base_path)
260                 BLI_strncpy(user_path, user_base_path, FILE_MAX);
261
262         if (!user_path[0])
263                 return false;
264         
265 #ifdef PATH_DEBUG
266         printf("%s: %s\n", __func__, user_path);
267 #endif
268         
269         if (subfolder_name) {
270                 return test_path(targetpath, user_path, folder_name, subfolder_name);
271         }
272         else {
273                 return test_path(targetpath, user_path, NULL, folder_name);
274         }
275 }
276
277 /**
278  * Returns the path of a folder within the Blender installation directory.
279  *
280  * \param targetpath  String to return path
281  * \param folder_name  default name of folder within installation area
282  * \param subfolder_name  optional name of subfolder within folder
283  * \param envvar  name of environment variable which, if defined, overrides folder_name
284  * \param ver  Blender version, used to construct a subdirectory name
285  * \return  true if it was able to construct such a path.
286  */
287 static bool get_path_system(char *targetpath, const char *folder_name, const char *subfolder_name, const char *envvar, const int ver)
288 {
289         char system_path[FILE_MAX];
290         const char *system_base_path;
291         char cwd[FILE_MAX];
292         char relfolder[FILE_MAX];
293
294         if (folder_name) {
295                 if (subfolder_name) {
296                         BLI_join_dirfile(relfolder, sizeof(relfolder), folder_name, subfolder_name);
297                 }
298                 else {
299                         BLI_strncpy(relfolder, folder_name, sizeof(relfolder));
300                 }
301         }
302         else {
303                 relfolder[0] = '\0';
304         }
305
306         /* first allow developer only overrides to the system path
307          * these are only used when running blender from source */
308
309         /* try CWD/release/folder_name */
310         if (BLI_current_working_dir(cwd, sizeof(cwd))) {
311                 if (test_path(targetpath, cwd, "release", relfolder)) {
312                         return true;
313                 }
314         }
315
316         /* try EXECUTABLE_DIR/release/folder_name */
317         if (test_path(targetpath, bprogdir, "release", relfolder))
318                 return true;
319
320         /* end developer overrides */
321
322
323
324         system_path[0] = '\0';
325
326         if (test_env_path(system_path, envvar)) {
327                 if (subfolder_name) {
328                         return test_path(targetpath, system_path, NULL, subfolder_name);
329                 }
330                 else {
331                         BLI_strncpy(targetpath, system_path, FILE_MAX);
332                         return true;
333                 }
334         }
335
336         system_base_path = (const char *)GHOST_getSystemDir(ver, blender_version_decimal(ver));
337         if (system_base_path)
338                 BLI_strncpy(system_path, system_base_path, FILE_MAX);
339         
340         if (!system_path[0])
341                 return false;
342         
343 #ifdef PATH_DEBUG
344         printf("%s: %s\n", __func__, system_path);
345 #endif
346         
347         if (subfolder_name) {
348                 /* try $BLENDERPATH/folder_name/subfolder_name */
349                 return test_path(targetpath, system_path, folder_name, subfolder_name);
350         }
351         else {
352                 /* try $BLENDERPATH/folder_name */
353                 return test_path(targetpath, system_path, NULL, folder_name);
354         }
355 }
356
357 /* get a folder out of the 'folder_id' presets for paths */
358 /* returns the path if found, NULL string if not */
359 const char *BKE_appdir_folder_id(const int folder_id, const char *subfolder)
360 {
361         const int ver = BLENDER_VERSION;
362         static char path[FILE_MAX] = "";
363         
364         switch (folder_id) {
365                 case BLENDER_DATAFILES:     /* general case */
366                         if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
367                         if (get_path_local(path, "datafiles", subfolder, ver)) break;
368                         if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
369                         return NULL;
370                         
371                 case BLENDER_USER_DATAFILES:
372                         if (get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
373                         return NULL;
374                         
375                 case BLENDER_SYSTEM_DATAFILES:
376                         if (get_path_local(path, "datafiles", subfolder, ver)) break;
377                         if (get_path_system(path, "datafiles", subfolder, "BLENDER_SYSTEM_DATAFILES", ver)) break;
378                         return NULL;
379                         
380                 case BLENDER_USER_AUTOSAVE:
381                         if (get_path_user(path, "autosave", subfolder, "BLENDER_USER_DATAFILES", ver)) break;
382                         return NULL;
383
384                 case BLENDER_USER_CONFIG:
385                         if (get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver)) break;
386                         return NULL;
387                         
388                 case BLENDER_USER_SCRIPTS:
389                         if (get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver)) break;
390                         return NULL;
391                         
392                 case BLENDER_SYSTEM_SCRIPTS:
393                         if (get_path_local(path, "scripts", subfolder, ver)) break;
394                         if (get_path_system(path, "scripts", subfolder, "BLENDER_SYSTEM_SCRIPTS", ver)) break;
395                         return NULL;
396                         
397                 case BLENDER_SYSTEM_PYTHON:
398                         if (get_path_local(path, "python", subfolder, ver)) break;
399                         if (get_path_system(path, "python", subfolder, "BLENDER_SYSTEM_PYTHON", ver)) break;
400                         return NULL;
401
402                 default:
403                         BLI_assert(0);
404                         break;
405         }
406         
407         return path;
408 }
409
410 /**
411  * Returns the path to a folder in the user area without checking that it actually exists first.
412  */
413 const char *BKE_appdir_folder_id_user_notest(const int folder_id, const char *subfolder)
414 {
415         const int ver = BLENDER_VERSION;
416         static char path[FILE_MAX] = "";
417
418         switch (folder_id) {
419                 case BLENDER_USER_DATAFILES:
420                         get_path_user(path, "datafiles", subfolder, "BLENDER_USER_DATAFILES", ver);
421                         break;
422                 case BLENDER_USER_CONFIG:
423                         get_path_user(path, "config", subfolder, "BLENDER_USER_CONFIG", ver);
424                         break;
425                 case BLENDER_USER_AUTOSAVE:
426                         get_path_user(path, "autosave", subfolder, "BLENDER_USER_AUTOSAVE", ver);
427                         break;
428                 case BLENDER_USER_SCRIPTS:
429                         get_path_user(path, "scripts", subfolder, "BLENDER_USER_SCRIPTS", ver);
430                         break;
431                 default:
432                         BLI_assert(0);
433                         break;
434         }
435
436         if ('\0' == path[0]) {
437                 return NULL;
438         }
439         return path;
440 }
441
442 /**
443  * Returns the path to a folder in the user area, creating it if it doesn't exist.
444  */
445 const char *BKE_appdir_folder_id_create(int folder_id, const char *subfolder)
446 {
447         const char *path;
448
449         /* only for user folders */
450         if (!ELEM(folder_id, BLENDER_USER_DATAFILES, BLENDER_USER_CONFIG, BLENDER_USER_SCRIPTS, BLENDER_USER_AUTOSAVE))
451                 return NULL;
452         
453         path = BKE_appdir_folder_id(folder_id, subfolder);
454         
455         if (!path) {
456                 path = BKE_appdir_folder_id_user_notest(folder_id, subfolder);
457                 if (path) BLI_dir_create_recursive(path);
458         }
459         
460         return path;
461 }
462
463 /**
464  * Returns the path of the top-level version-specific local, user or system directory.
465  * If do_check, then the result will be NULL if the directory doesn't exist.
466  */
467 const char *BKE_appdir_folder_id_version(const int folder_id, const int ver, const bool do_check)
468 {
469         static char path[FILE_MAX] = "";
470         bool ok;
471         switch (folder_id) {
472                 case BLENDER_RESOURCE_PATH_USER:
473                         ok = get_path_user(path, NULL, NULL, NULL, ver);
474                         break;
475                 case BLENDER_RESOURCE_PATH_LOCAL:
476                         ok = get_path_local(path, NULL, NULL, ver);
477                         break;
478                 case BLENDER_RESOURCE_PATH_SYSTEM:
479                         ok = get_path_system(path, NULL, NULL, NULL, ver);
480                         break;
481                 default:
482                         path[0] = '\0'; /* in case do_check is false */
483                         ok = false;
484                         BLI_assert(!"incorrect ID");
485                         break;
486         }
487
488         if (!ok && do_check) {
489                 return NULL;
490         }
491
492         return path;
493 }
494
495 #ifdef PATH_DEBUG
496 #  undef PATH_DEBUG
497 #endif
498
499
500
501
502 /* -------------------------------------------------------------------- */
503 /* Preset paths */
504
505 /**
506  * Tries appending each of the semicolon-separated extensions in the PATHEXT
507  * environment variable (Windows-only) onto *name in turn until such a file is found.
508  * Returns success/failure.
509  */
510 static int add_win32_extension(char *name)
511 {
512         int retval = 0;
513         int type;
514
515         type = BLI_exists(name);
516         if ((type == 0) || S_ISDIR(type)) {
517 #ifdef _WIN32
518                 char filename[FILE_MAX];
519                 char ext[FILE_MAX];
520                 const char *extensions = getenv("PATHEXT");
521                 if (extensions) {
522                         char *temp;
523                         do {
524                                 strcpy(filename, name);
525                                 temp = strstr(extensions, ";");
526                                 if (temp) {
527                                         strncpy(ext, extensions, temp - extensions);
528                                         ext[temp - extensions] = 0;
529                                         extensions = temp + 1;
530                                         strcat(filename, ext);
531                                 }
532                                 else {
533                                         strcat(filename, extensions);
534                                 }
535
536                                 type = BLI_exists(filename);
537                                 if (type && (!S_ISDIR(type))) {
538                                         retval = 1;
539                                         strcpy(name, filename);
540                                         break;
541                                 }
542                         } while (temp);
543                 }
544 #endif
545         }
546         else {
547                 retval = 1;
548         }
549
550         return (retval);
551 }
552
553 /**
554  * Checks if name is a fully qualified filename to an executable.
555  * If not it searches $PATH for the file. On Windows it also
556  * adds the correct extension (.com .exe etc) from
557  * $PATHEXT if necessary. Also on Windows it translates
558  * the name to its 8.3 version to prevent problems with
559  * spaces and stuff. Final result is returned in fullname.
560  *
561  * \param fullname The full path and full name of the executable
562  * (must be FILE_MAX minimum)
563  * \param name The name of the executable (usually argv[0]) to be checked
564  */
565 static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
566 {
567         char filename[FILE_MAX];
568         const char *path = NULL, *temp;
569
570 #ifdef _WIN32
571         const char *separator = ";";
572 #else
573         const char *separator = ":";
574 #endif
575
576         
577 #ifdef WITH_BINRELOC
578         /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
579         path = br_find_exe(NULL);
580         if (path) {
581                 BLI_strncpy(fullname, path, maxlen);
582                 free((void *)path);
583                 return;
584         }
585 #endif
586
587 #ifdef _WIN32
588         wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
589         if (GetModuleFileNameW(0, fullname_16, maxlen)) {
590                 conv_utf_16_to_8(fullname_16, fullname, maxlen);
591                 if (!BLI_exists(fullname)) {
592                         printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
593                         MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
594                 }
595                 MEM_freeN(fullname_16);
596                 return;
597         }
598
599         MEM_freeN(fullname_16);
600 #endif
601
602         /* unix and non linux */
603         if (name && name[0]) {
604
605                 BLI_strncpy(fullname, name, maxlen);
606                 if (name[0] == '.') {
607                         char wdir[FILE_MAX] = "";
608                         BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
609
610                         // not needed but avoids annoying /./ in name
611                         if (name[1] == SEP)
612                                 BLI_join_dirfile(fullname, maxlen, wdir, name + 2);
613                         else
614                                 BLI_join_dirfile(fullname, maxlen, wdir, name);
615
616                         add_win32_extension(fullname); /* XXX, doesnt respect length */
617                 }
618                 else if (BLI_last_slash(name)) {
619                         // full path
620                         BLI_strncpy(fullname, name, maxlen);
621                         add_win32_extension(fullname);
622                 }
623                 else {
624                         // search for binary in $PATH
625                         path = getenv("PATH");
626                         if (path) {
627                                 do {
628                                         temp = strstr(path, separator);
629                                         if (temp) {
630                                                 strncpy(filename, path, temp - path);
631                                                 filename[temp - path] = 0;
632                                                 path = temp + 1;
633                                         }
634                                         else {
635                                                 strncpy(filename, path, sizeof(filename));
636                                         }
637                                         BLI_path_append(fullname, maxlen, name);
638                                         if (add_win32_extension(filename)) {
639                                                 BLI_strncpy(fullname, filename, maxlen);
640                                                 break;
641                                         }
642                                 } while (temp);
643                         }
644                 }
645 #if defined(DEBUG)
646                 if (strcmp(name, fullname)) {
647                         printf("guessing '%s' == '%s'\n", name, fullname);
648                 }
649 #endif
650         }
651 }
652
653 void BKE_appdir_program_path_init(const char *argv0)
654 {
655         bli_where_am_i(bprogname, sizeof(bprogname), argv0);
656         BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
657 }
658
659 /**
660  * Path to executable
661  */
662 const char *BKE_appdir_program_path(void)
663 {
664         return bprogname;
665 }
666
667 /**
668  * Path to directory of executable
669  */
670 const char *BKE_appdir_program_dir(void)
671 {
672         return bprogdir;
673 }
674
675 /**
676  * Gets the temp directory when blender first runs.
677  * If the default path is not found, use try $TEMP
678  * 
679  * Also make sure the temp dir has a trailing slash
680  *
681  * \param fullname The full path to the temporary temp directory
682  * \param basename The full path to the persistent temp directory (may be NULL)
683  * \param maxlen The size of the fullname buffer
684  * \param userdir Directory specified in user preferences 
685  */
686 static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
687 {
688         /* Clear existing temp dir, if needed. */
689         BKE_tempdir_session_purge();
690
691         fullname[0] = '\0';
692         if (basename) {
693                 basename[0] = '\0';
694         }
695
696         if (userdir && BLI_is_dir(userdir)) {
697                 BLI_strncpy(fullname, userdir, maxlen);
698         }
699         
700         
701 #ifdef WIN32
702         if (fullname[0] == '\0') {
703                 const char *tmp = getenv("TEMP"); /* Windows */
704                 if (tmp && BLI_is_dir(tmp)) {
705                         BLI_strncpy(fullname, tmp, maxlen);
706                 }
707         }
708 #else
709         /* Other OS's - Try TMP and TMPDIR */
710         if (fullname[0] == '\0') {
711                 const char *tmp = getenv("TMP");
712                 if (tmp && BLI_is_dir(tmp)) {
713                         BLI_strncpy(fullname, tmp, maxlen);
714                 }
715         }
716         
717         if (fullname[0] == '\0') {
718                 const char *tmp = getenv("TMPDIR");
719                 if (tmp && BLI_is_dir(tmp)) {
720                         BLI_strncpy(fullname, tmp, maxlen);
721                 }
722         }
723 #endif
724         
725         if (fullname[0] == '\0') {
726                 BLI_strncpy(fullname, "/tmp/", maxlen);
727         }
728         else {
729                 /* add a trailing slash if needed */
730                 BLI_add_slash(fullname);
731 #ifdef WIN32
732                 if (userdir && userdir != fullname) {
733                         BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
734                 }
735 #endif
736         }
737
738         /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
739         if (basename) {
740                 /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
741                 char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
742                 const size_t ln = strlen(tmp_name) + 1;
743                 if (ln <= maxlen) {
744 #ifdef WIN32
745                         if (_mktemp_s(tmp_name, ln) == 0) {
746                                 BLI_dir_create_recursive(tmp_name);
747                         }
748 #else
749                         mkdtemp(tmp_name);
750 #endif
751                 }
752                 if (BLI_is_dir(tmp_name)) {
753                         BLI_strncpy(basename, fullname, maxlen);
754                         BLI_strncpy(fullname, tmp_name, maxlen);
755                         BLI_add_slash(fullname);
756                 }
757                 else {
758                         printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname);
759                 }
760
761                 MEM_freeN(tmp_name);
762         }
763 }
764
765 /**
766  * Sets btempdir_base to userdir if specified and is a valid directory, otherwise
767  * chooses a suitable OS-specific temporary directory.
768  * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base.
769  *
770  * \note On Window userdir will be set to the temporary directory!
771  */
772 void BKE_tempdir_init(char *userdir)
773 {
774         BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
775 ;
776 }
777
778 /**
779  * Path to temporary directory (with trailing slash)
780  */
781 const char *BKE_tempdir_session(void)
782 {
783         return btempdir_session[0] ? btempdir_session : BKE_tempdir_base();
784 }
785
786 /**
787  * Path to persistent temporary directory (with trailing slash)
788  */
789 const char *BKE_tempdir_base(void)
790 {
791         return btempdir_base;
792 }
793
794 /**
795  * Path to the system temporary directory (with trailing slash)
796  */
797 void BKE_tempdir_system_init(char *dir)
798 {
799         BLI_where_is_temp(dir, NULL, FILE_MAX, NULL);
800 }
801
802 /**
803  * Delete content of this instance's temp dir.
804  */
805 void BKE_tempdir_session_purge(void)
806 {
807         if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
808                 BLI_delete(btempdir_session, true, true);
809         }
810 }