diff options
author | Guillermo S. Romero <gsr.b3d@infernal-iceberg.com> | 2009-10-19 22:44:09 +0400 |
---|---|---|
committer | Guillermo S. Romero <gsr.b3d@infernal-iceberg.com> | 2009-10-19 22:44:09 +0400 |
commit | 680e724e37e10a3e6e7e42691d2e07d3dd62b6b7 (patch) | |
tree | b995119ba65d643cc84187085cf6912ff57afcd7 /source/blender/blenlib/intern/BLI_bfile.c | |
parent | 1f4d07fd199041726d2bb77eebe702bf3351b4e8 (diff) |
Continue development of bfile system.
Still not usable, but some parts could be made more portable already.
Help welcome for MacOSX and MSWindows calls and paths.
Diffstat (limited to 'source/blender/blenlib/intern/BLI_bfile.c')
-rw-r--r-- | source/blender/blenlib/intern/BLI_bfile.c | 414 |
1 files changed, 346 insertions, 68 deletions
diff --git a/source/blender/blenlib/intern/BLI_bfile.c b/source/blender/blenlib/intern/BLI_bfile.c index a7ce1df5712..4de1e6ce4a1 100644 --- a/source/blender/blenlib/intern/BLI_bfile.c +++ b/source/blender/blenlib/intern/BLI_bfile.c @@ -25,89 +25,70 @@ */ #include <string.h> - +#include <stdlib.h> #ifndef WIN32 #include <unistd.h> #else #include <io.h> #include "BLI_winstuff.h" #endif - +#include <sys/param.h> #include <sys/types.h> #include <sys/stat.h> #include <fcntl.h> +#include <libgen.h> #include "MEM_guardedalloc.h" - +#include "BKE_utildefines.h" +#include "BKE_blender.h" +#include "BLI_util.h" +#include "BLI_fileops.h" +#include "BLI_storage.h" #include "BLI_bfile.h" -// This would provide config paths and their oldest viable version -// so if there is an uncompatible change, user's old versions are not loaded -//#include "bfile_tables.h" - -/* Internal bfile type flags */ -#define BTF_OPEN (0) -#define BTF_FOPEN (1<<0) -#define BTF_READ (1<<1) -#define BTF_WRITE (1<<2) -#define BTF_AT_END (1<<3) -#define BTF_DISCARD (1<<4) - - -void fill_paths(BFILE *bfile, const char *path) { - char* source_path = NULL; - int bflags = bfile->uflags; - - if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) { -// bfile->fpath is path with // replaced - } - if(bflags & BFILE_TEMP) { -// bfile->fpath is tempdir+path - } - if(bflags & BFILE_CONFIG) { -// bfile->fpath is userdir+version+path -// source_path is first hit in (if using fallback to older versions) -// userdir+curversion+path (... userdir+limitversion+path) sysdir+path -// (limitversion is based in path, using some kind of regex or "tables") - } - - if(bfile->type & BTF_WRITE && !(bflags & BFILE_RAW)) { - /* Generate temp path */ - // bfile->tpath is fpath+randstring - if(!(bfile->type & BTF_DISCARD)) { - /* Copy data to tpath */ - if(source_path) { - // copy it from older version or sys version - } - } - } else { - bfile->tpath = bfile->fpath; - } -} - -BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags) { +/* Internal bfile classification flags */ +#define BCF_OPEN (0) +#define BCF_FOPEN (1<<0) +#define BCF_READ (1<<1) +#define BCF_WRITE (1<<2) +#define BCF_AT_END (1<<3) +#define BCF_DISCARD (1<<4) + +/* Declaration of internal functions */ +void chomp(char* line); +void expand_envvars(char* src, char* dst); +void fill_paths(BFILE *bfile, const char *path); +char* find_in_pathlist(char* filename, char* pathlist); +void init_vars_from_file(const char* path); +void setup_temp(); + +/*** Exported functions ***/ + +BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags, + BEnvVarFam envvars) +{ BFILE *bfile; bfile = MEM_mallocN(sizeof(BFILE), "bfile-fopen"); - bfile->type = BTF_FOPEN; + bfile->classf = BCF_FOPEN; bfile->uflags = bflags; /* From fopen() doc, we can guess some logic: - r BTF_READ - r+ BTF_READ | BTF_WRITE - w BTF_DISCARD | BTF_WRITE - w+ BTF_DISCARD | BTF_WRITE | BTF_READ - a BTF_AT_END | BTF_WRITE - a+ BTF_AT_END | BTF_WRITE | BTF_READ + r BCF_READ + r+ BCF_READ | BCF_WRITE + w BCF_DISCARD | BCF_WRITE + w+ BCF_DISCARD | BCF_WRITE | BCF_READ + a BCF_AT_END | BCF_WRITE + a+ BCF_AT_END | BCF_WRITE | BCF_READ */ if(strchr(mode, 'r')) - bfile->type |= BTF_READ; + bfile->classf |= BCF_READ; if(strchr(mode, 'w')) - bfile->type |= (BTF_DISCARD | BTF_WRITE); + bfile->classf |= (BCF_DISCARD | BCF_WRITE); if(strchr(mode, 'a')) - bfile->type |= (BTF_AT_END | BTF_WRITE); + bfile->classf |= (BCF_AT_END | BCF_WRITE); if(strchr(mode, '+')) - bfile->type |= (BTF_READ | BTF_WRITE); + bfile->classf |= (BCF_READ | BCF_WRITE); fill_paths(bfile, path); @@ -118,24 +99,26 @@ BFILE *BLI_bfile_fopen(const char *path, const char *mode, int bflags) { } -BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags) { +BFILE *BLI_bfile_open(const char *pathname, int flags, int bflags, + BEnvVarFam envvars) +{ BFILE *bfile; bfile = MEM_mallocN(sizeof(BFILE), "bfile-open"); - bfile->type = BTF_OPEN; + bfile->classf = BCF_OPEN; bfile->uflags = bflags; /* Easy mapping for open() */ if(flags & O_RDONLY) - bfile->type |= BTF_READ; + bfile->classf |= BCF_READ; if(flags & O_WRONLY) - bfile->type |= BTF_WRITE; + bfile->classf |= BCF_WRITE; if(flags & O_RDWR) - bfile->type |= (BTF_READ | BTF_WRITE); + bfile->classf |= (BCF_READ | BCF_WRITE); if(flags & O_APPEND) - bfile->type |= BTF_AT_END; + bfile->classf |= BCF_AT_END; if(flags & O_TRUNC) - bfile->type |= BTF_DISCARD; + bfile->classf |= BCF_DISCARD; fill_paths(bfile, pathname); @@ -180,7 +163,9 @@ ssize_t BLI_bfile_read(BFILE *f, void *buf, size_t count) { } -size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, BFILE *f) { +size_t BLI_bfile_fwrite(const void *ptr, size_t size, size_t nmemb, + BFILE *f) +{ size_t ret; ret = fwrite(ptr, size, nmemb, f->stream); @@ -205,7 +190,7 @@ size_t BLI_bfile_fread(void *ptr, size_t size, size_t nmemb, BFILE *f) { void BLI_bfile_close(BFILE *bfile) { - if((bfile->type | BTF_WRITE) && + if((bfile->classf | BCF_WRITE) && !(bfile->uflags | BFILE_RAW)) { /* Make sure data is on disk */ /* Move to final name if no errors */ @@ -234,3 +219,296 @@ void BLI_bfile_set_error(BFILE *bfile, int error) { bfile->error = error; } } + + +#if defined(WIN32) + #define LAST_SESSION_FILE "%HOME%\\Blender\\last-session FIXME FIXME FIXME" + #define ENVIRONMENT_FILE "FIXME" + #define SHARED_DIRECTORY "FIXME TOO" +#elif defined(OSX) + #define LAST_SESSION_FILE "${HOME}/Library/Application Support/Blender/last-session" + #define ENVIRONMENT_FILE "${HOME}/Library/Application Support/Blender/${BLENDER_VERSION}/environment" + #define SHARED_DIRECTORY "/Library/Application Support/Blender" +#else + #define LAST_SESSION_FILE "${HOME}/.blender/last-session" + #define ENVIRONMENT_FILE "${HOME}/.blender/${BLENDER_VERSION}/environment" + #define SHARED_DIRECTORY "/usr/share/blender" +#endif +void BLI_bfile_init_vars() { + char file[MAXPATHLEN]; + char temp[MAXPATHLEN]; + extern char bprogname[]; + FILE* fp; + + /* This one is unconditional */ + sprintf(temp, "%d", BLENDER_VERSION); + BLI_setenv("BLENDER_VERSION", temp); + + /* Is this unpack&run? */ + sprintf(temp, "%s/%d/environment", dirname(bprogname), BLENDER_VERSION); + if(BLI_exist(temp)) { + BLI_setenv_if_new("BLENDER_SHARE", dirname(bprogname)); + } else { + BLI_setenv_if_new("BLENDER_SHARE", SHARED_DIRECTORY); + } + + expand_envvars(LAST_SESSION_FILE, file); + fp = fopen(file, "r"); + /* 1st line, read previous version */ + if (fp && (fscanf(fp, "%3c\n", temp) == 1)) { + temp[3] = '\0'; + BLI_setenv("BLENDER_VERSION_PREV", temp); + /* 2nd line, read previous session path if needed */ + if(!getenv("BLENDER_TEMP")) { + if ((fgets(temp, MAXPATHLEN, fp) != NULL)) { + /* Clean any \n */ + chomp(temp); + /* Check the dir is still there or generate new one */ + if(!BLI_exist(temp)) { + setup_temp(); + } + } else { + /* We have to generate it for sure */ + setup_temp(); + } + } + } else { + /* Probably new user, or only <=249 before */ + BLI_setenv("BLENDER_VERSION_PREV", "0"); + setup_temp(); + } + + if(fp) { + fclose(fp); + } + + /* Load vars from user and system files */ + expand_envvars(ENVIRONMENT_FILE, file); + init_vars_from_file(file); + sprintf(temp, "/%d/environment", BLENDER_VERSION); + BLI_make_file_string("/", file, getenv("BLENDER_SHARE"), temp); + init_vars_from_file(file); +} + + +/*** Internal functions ***/ + +/** + Eliminate trailing EOL by writing a \0 over it. + Name taken from Perl. + */ +void chomp(char* line) { + int len = strlen(line); +#ifndef WIN32 + if (line[len - 1] == '\n') { + line[len - 1] = '\0'; + } +#else + if ((line[len - 2] == '\r' ) && ((line[len - 1] == '\n'))) { + line[len - 2] = '\0'; + } +#endif /* WIN32 */ +} + + +/** + Parse a file with lines like FOO=bar (comment lines have # as first + character) assigning to envvar FOO the value bar if FOO does not + exist yet. + Any white space before FOO, around the = or trailing will be used, + so beware. + */ +#define MAX_LINE 4096 +#define ENV_VAR 256 +#define VAR_LEN 8192 +void init_vars_from_file(const char* path) { + char line[MAX_LINE]; + char name[ENV_VAR]; + FILE *fp; + char* separator; + char expanded[VAR_LEN]; + + fp = fopen(path, "r"); + if (!fp) return; + + while (fgets(line, MAX_LINE, fp) != NULL) { + /* Ignore comment lines */ + if (line[0] == '#') + continue; + + /* Split into envvar name and contents */ + separator = strchr(line, '='); + if(separator && ((separator - line) < ENV_VAR)) { + /* First remove EOL */ + chomp(line); + strncpy(name, line, separator - line); + name[separator - line] = '\0'; + expand_envvars(separator + 1, expanded); + BLI_setenv_if_new(name, expanded); + } + } + fclose(fp); +} + + +/** + Look for ${} (or %%) env vars in src and expand if the var + exists (even if empty value). If not exist, the name is left as is. + The process is done all over src, and nested ${${}} is not supported. + src must be \0 terminated, and dst must be big enough. +*/ +#ifndef WIN32 + #define ENVVAR_PREFFIX "${" + #define ENVVAR_P_SIZE 2 + #define ENVVAR_SUFFIX "}" + #define ENVVAR_S_SIZE 1 +#else + #define ENVVAR_PREFFIX "%" + #define ENVVAR_P_SIZE 1 + #define ENVVAR_SUFFIX "%" + #define ENVVAR_S_SIZE 1 +#endif /* WIN32 */ +void expand_envvars(char* src, char* dst) { + char* hit1; + char* hit2; + char name[ENV_VAR]; + char* value; + int prevlen; + int done = 0; + char* source = src; + + dst[0] = '\0'; + while (!done) { + hit1 = strstr(source, ENVVAR_PREFFIX); + if (hit1) { + hit2 = strstr(hit1 + ENVVAR_P_SIZE, ENVVAR_SUFFIX); + if (hit2) { + /* "Copy" the leading part, if any */ + if (hit1 != source) { + prevlen = strlen(dst); + strncat(dst, source, hit1 - source); + dst[prevlen + (hit1 - source)] = '\0'; + } + /* Figure the name of the env var we just found */ + strncpy(name, hit1 + ENVVAR_P_SIZE, + hit2 - (hit1 + ENVVAR_P_SIZE)); + name[hit2 - (hit1 + ENVVAR_P_SIZE)] = '\0'; + /* See if we can get something with that name */ + value = getenv(name); + if (value) { + /* Push the var value */ + strcat(dst, value); + } else { + /* Leave the var name, so it is clear that it failed */ + strcat(dst, ENVVAR_PREFFIX); + strcat(dst, name); + strcat(dst, ENVVAR_SUFFIX); + } + /* Continue after closing mark, like a new string */ + source = hit2 + ENVVAR_S_SIZE; + } else { + /* Non terminated var so "copy as is" and finish */ + strcat(dst, source); + done = 1; + } + } else { + /* "Copy" whatever is left */ + strcat(dst, source); + done = 1; + } + } +} + + +/** + Return a full path if the filename exists when combined + with any item from pathlist. Or NULL otherwise. + */ +#ifdef WIN32 + #define SEPARATOR ';' +#else + #define SEPARATOR ':' +#endif +char* find_in_pathlist(char* filename, char* pathlist) { + char first[FILE_MAX + 10]; + char* rest = NULL; + + /* Separate first path from rest, use typical separator for current OS */ + rest = strchr(pathlist, SEPARATOR); + if (rest) { + strncpy(first, pathlist, rest - pathlist); + first[rest - pathlist] = '\0'; + /* Skip the separator so it becomes a valid new pathlist */ + rest++; + } else { + strcpy(first, pathlist); + } + + /* Check if combination exists */ + BLI_add_slash(first); + strcat(first, filename); + if(BLI_exist(first)) { + return strdup(first); + } + + /* First path failed, try with rest of paths if possible */ + if(rest) { + return find_in_pathlist(filename, rest); + } else { + return NULL; + } +} + + +/** + Setup fpath and tpath based in the needs of the bfile. + */ +void fill_paths(BFILE *bfile, const char *path) { + char* source_path = NULL; + int bflags = bfile->uflags; + + if(bflags & BFILE_NORMAL || bflags & BFILE_RAW) { +// bfile->fpath is path with // replaced + } + if(bflags & BFILE_TEMP) { +// bfile->fpath is tempdir+path + } + if(bflags & BFILE_CONFIG) { +// bfile->fpath is userdir+version+path +// source_path is first hit in (if using fallback to older versions) +// userdir+curversion+path (... userdir+limitversion+path) sysdir+path +// (limitversion is based in path, using some kind of regex or "tables") + } + + if(bfile->classf & BCF_WRITE && !(bflags & BFILE_RAW)) { + /* Generate temp path */ + // bfile->tpath is fpath+randstring + if(!(bfile->classf & BCF_DISCARD)) { + /* Copy data to tpath */ + if(source_path) { + // copy it from older version or sys version + } + } + } else { + bfile->tpath = bfile->fpath; + } +} + + +/** + Create a temp directory in safe and multiuser way. + */ +void setup_temp() { + char template[MAXPATHLEN]; + char* tempdir; + + if(getenv("TMPDIR")) { + sprintf(template, "%s/blender-XXXXXX", getenv("TMPDIR")); + } else { + sprintf(template, "/tmp/blender-XXXXXX"); +// MacOSX NSTemporaryDirectory and WIN32 ??? + } + tempdir = mkdtemp(template); + BLI_setenv("BLENDER_TEMP", tempdir); +} + |