Cleanup: warnings & space
[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 /* Preset paths */
502
503 /**
504  * Tries appending each of the semicolon-separated extensions in the PATHEXT
505  * environment variable (Windows-only) onto *name in turn until such a file is found.
506  * Returns success/failure.
507  */
508 static int add_win32_extension(char *name)
509 {
510         int retval = 0;
511         int type;
512
513         type = BLI_exists(name);
514         if ((type == 0) || S_ISDIR(type)) {
515 #ifdef _WIN32
516                 char filename[FILE_MAX];
517                 char ext[FILE_MAX];
518                 const char *extensions = getenv("PATHEXT");
519                 if (extensions) {
520                         char *temp;
521                         do {
522                                 strcpy(filename, name);
523                                 temp = strstr(extensions, ";");
524                                 if (temp) {
525                                         strncpy(ext, extensions, temp - extensions);
526                                         ext[temp - extensions] = 0;
527                                         extensions = temp + 1;
528                                         strcat(filename, ext);
529                                 }
530                                 else {
531                                         strcat(filename, extensions);
532                                 }
533
534                                 type = BLI_exists(filename);
535                                 if (type && (!S_ISDIR(type))) {
536                                         retval = 1;
537                                         strcpy(name, filename);
538                                         break;
539                                 }
540                         } while (temp);
541                 }
542 #endif
543         }
544         else {
545                 retval = 1;
546         }
547
548         return (retval);
549 }
550
551 /**
552  * Checks if name is a fully qualified filename to an executable.
553  * If not it searches $PATH for the file. On Windows it also
554  * adds the correct extension (.com .exe etc) from
555  * $PATHEXT if necessary. Also on Windows it translates
556  * the name to its 8.3 version to prevent problems with
557  * spaces and stuff. Final result is returned in fullname.
558  *
559  * \param fullname The full path and full name of the executable
560  * (must be FILE_MAX minimum)
561  * \param name The name of the executable (usually argv[0]) to be checked
562  */
563 static void bli_where_am_i(char *fullname, const size_t maxlen, const char *name)
564 {
565         char filename[FILE_MAX];
566         const char *path = NULL, *temp;
567
568 #ifdef _WIN32
569         const char *separator = ";";
570 #else
571         const char *separator = ":";
572 #endif
573
574         
575 #ifdef WITH_BINRELOC
576         /* linux uses binreloc since argv[0] is not reliable, call br_init( NULL ) first */
577         path = br_find_exe(NULL);
578         if (path) {
579                 BLI_strncpy(fullname, path, maxlen);
580                 free((void *)path);
581                 return;
582         }
583 #endif
584
585 #ifdef _WIN32
586         wchar_t *fullname_16 = MEM_mallocN(maxlen * sizeof(wchar_t), "ProgramPath");
587         if (GetModuleFileNameW(0, fullname_16, maxlen)) {
588                 conv_utf_16_to_8(fullname_16, fullname, maxlen);
589                 if (!BLI_exists(fullname)) {
590                         printf("path can't be found: \"%.*s\"\n", (int)maxlen, fullname);
591                         MessageBox(NULL, "path contains invalid characters or is too long (see console)", "Error", MB_OK);
592                 }
593                 MEM_freeN(fullname_16);
594                 return;
595         }
596
597         MEM_freeN(fullname_16);
598 #endif
599
600         /* unix and non linux */
601         if (name && name[0]) {
602
603                 BLI_strncpy(fullname, name, maxlen);
604                 if (name[0] == '.') {
605                         char wdir[FILE_MAX] = "";
606                         BLI_current_working_dir(wdir, sizeof(wdir));     /* backup cwd to restore after */
607
608                         // not needed but avoids annoying /./ in name
609                         if (name[1] == SEP)
610                                 BLI_join_dirfile(fullname, maxlen, wdir, name + 2);
611                         else
612                                 BLI_join_dirfile(fullname, maxlen, wdir, name);
613
614                         add_win32_extension(fullname); /* XXX, doesnt respect length */
615                 }
616                 else if (BLI_last_slash(name)) {
617                         // full path
618                         BLI_strncpy(fullname, name, maxlen);
619                         add_win32_extension(fullname);
620                 }
621                 else {
622                         // search for binary in $PATH
623                         path = getenv("PATH");
624                         if (path) {
625                                 do {
626                                         temp = strstr(path, separator);
627                                         if (temp) {
628                                                 strncpy(filename, path, temp - path);
629                                                 filename[temp - path] = 0;
630                                                 path = temp + 1;
631                                         }
632                                         else {
633                                                 strncpy(filename, path, sizeof(filename));
634                                         }
635                                         BLI_path_append(fullname, maxlen, name);
636                                         if (add_win32_extension(filename)) {
637                                                 BLI_strncpy(fullname, filename, maxlen);
638                                                 break;
639                                         }
640                                 } while (temp);
641                         }
642                 }
643 #if defined(DEBUG)
644                 if (strcmp(name, fullname)) {
645                         printf("guessing '%s' == '%s'\n", name, fullname);
646                 }
647 #endif
648         }
649 }
650
651 void BKE_appdir_program_path_init(const char *argv0)
652 {
653         bli_where_am_i(bprogname, sizeof(bprogname), argv0);
654         BLI_split_dir_part(bprogname, bprogdir, sizeof(bprogdir));
655 }
656
657 /**
658  * Path to executable
659  */
660 const char *BKE_appdir_program_path(void)
661 {
662         return bprogname;
663 }
664
665 /**
666  * Path to directory of executable
667  */
668 const char *BKE_appdir_program_dir(void)
669 {
670         return bprogdir;
671 }
672
673 /**
674  * Gets the temp directory when blender first runs.
675  * If the default path is not found, use try $TEMP
676  * 
677  * Also make sure the temp dir has a trailing slash
678  *
679  * \param fullname The full path to the temporary temp directory
680  * \param basename The full path to the persistent temp directory (may be NULL)
681  * \param maxlen The size of the fullname buffer
682  * \param userdir Directory specified in user preferences 
683  */
684 static void BLI_where_is_temp(char *fullname, char *basename, const size_t maxlen, char *userdir)
685 {
686         /* Clear existing temp dir, if needed. */
687         BKE_tempdir_session_purge();
688
689         fullname[0] = '\0';
690         if (basename) {
691                 basename[0] = '\0';
692         }
693
694         if (userdir && BLI_is_dir(userdir)) {
695                 BLI_strncpy(fullname, userdir, maxlen);
696         }
697         
698         
699 #ifdef WIN32
700         if (fullname[0] == '\0') {
701                 const char *tmp = getenv("TEMP"); /* Windows */
702                 if (tmp && BLI_is_dir(tmp)) {
703                         BLI_strncpy(fullname, tmp, maxlen);
704                 }
705         }
706 #else
707         /* Other OS's - Try TMP and TMPDIR */
708         if (fullname[0] == '\0') {
709                 const char *tmp = getenv("TMP");
710                 if (tmp && BLI_is_dir(tmp)) {
711                         BLI_strncpy(fullname, tmp, maxlen);
712                 }
713         }
714         
715         if (fullname[0] == '\0') {
716                 const char *tmp = getenv("TMPDIR");
717                 if (tmp && BLI_is_dir(tmp)) {
718                         BLI_strncpy(fullname, tmp, maxlen);
719                 }
720         }
721 #endif
722         
723         if (fullname[0] == '\0') {
724                 BLI_strncpy(fullname, "/tmp/", maxlen);
725         }
726         else {
727                 /* add a trailing slash if needed */
728                 BLI_add_slash(fullname);
729 #ifdef WIN32
730                 if (userdir && userdir != fullname) {
731                         BLI_strncpy(userdir, fullname, maxlen); /* also set user pref to show %TEMP%. /tmp/ is just plain confusing for Windows users. */
732                 }
733 #endif
734         }
735
736         /* Now that we have a valid temp dir, add system-generated unique sub-dir. */
737         if (basename) {
738                 /* 'XXXXXX' is kind of tag to be replaced by mktemp-familly by an uuid. */
739                 char *tmp_name = BLI_strdupcat(fullname, "blender_XXXXXX");
740                 const size_t ln = strlen(tmp_name) + 1;
741                 if (ln <= maxlen) {
742 #ifdef WIN32
743                         if (_mktemp_s(tmp_name, ln) == 0) {
744                                 BLI_dir_create_recursive(tmp_name);
745                         }
746 #else
747                         mkdtemp(tmp_name);
748 #endif
749                 }
750                 if (BLI_is_dir(tmp_name)) {
751                         BLI_strncpy(basename, fullname, maxlen);
752                         BLI_strncpy(fullname, tmp_name, maxlen);
753                         BLI_add_slash(fullname);
754                 }
755                 else {
756                         printf("Warning! Could not generate a temp file name for '%s', falling back to '%s'\n", tmp_name, fullname);
757                 }
758
759                 MEM_freeN(tmp_name);
760         }
761 }
762
763 /**
764  * Sets btempdir_base to userdir if specified and is a valid directory, otherwise
765  * chooses a suitable OS-specific temporary directory.
766  * Sets btempdir_session to a mkdtemp-generated sub-dir of btempdir_base.
767  *
768  * \note On Window userdir will be set to the temporary directory!
769  */
770 void BKE_tempdir_init(char *userdir)
771 {
772         BLI_where_is_temp(btempdir_session, btempdir_base, FILE_MAX, userdir);
773 ;
774 }
775
776 /**
777  * Path to temporary directory (with trailing slash)
778  */
779 const char *BKE_tempdir_session(void)
780 {
781         return btempdir_session[0] ? btempdir_session : BKE_tempdir_base();
782 }
783
784 /**
785  * Path to persistent temporary directory (with trailing slash)
786  */
787 const char *BKE_tempdir_base(void)
788 {
789         return btempdir_base;
790 }
791
792 /**
793  * Path to the system temporary directory (with trailing slash)
794  */
795 void BKE_tempdir_system_init(char *dir)
796 {
797         BLI_where_is_temp(dir, NULL, FILE_MAX, NULL);
798 }
799
800 /**
801  * Delete content of this instance's temp dir.
802  */
803 void BKE_tempdir_session_purge(void)
804 {
805         if (btempdir_session[0] && BLI_is_dir(btempdir_session)) {
806                 BLI_delete(btempdir_session, true, true);
807         }
808 }