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