From: John Tsiombikas Date: Sun, 31 Jul 2016 20:13:36 +0000 (+0300) Subject: moving along X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=vrfileman;a=commitdiff_plain;h=dfbd5842ef2f270e7d83507c4ba7bed005eea780 moving along --- diff --git a/src/fs.cc b/src/fs.cc index c85040a..b65db45 100644 --- a/src/fs.cc +++ b/src/fs.cc @@ -1,7 +1,12 @@ #include #include #include +#include +#include +#include #include +#include +#include #include "fs.h" #include "icon.h" #include "gmath/gmath.h" @@ -10,6 +15,10 @@ static IconRenderer *iconrend; +static std::map node_cache; +static FSNode *cur_node; +static int start_child; + bool init_fs() { iconrend = new ShapesIcons; @@ -17,83 +26,158 @@ bool init_fs() return false; } + cur_node = get_fsnode(0); + cur_node->expand(); return true; } void cleanup_fs() { + std::map::iterator it = node_cache.begin(); + while(it != node_cache.end()) { + FSNode *node = it++->second; + delete node; + } + node_cache.clear(); delete iconrend; } -void draw_fs() +static Vec3 icon_pos(int row, int col, int ncols, float row_spacing, float radius) { - FSNode test; - test.type = FSNODE_DIR; + float angle = 2.0 * M_PI * (float)col / (float)ncols; + float x = sin(angle) * radius; + float z = -cos(angle) * radius; + float y = (float)row * row_spacing; + return Vec3(x, y, z); +} - Mat4 xform; - xform.rotate(time_sec, 0, 0); - xform.rotate(0, 0, time_sec * 0.5); - xform.translate(0, 2, -5); +void draw_fs() +{ + static const int ncols = 8; + static const float row_spacing = 2.0; + static const float radius = 5; - glPushMatrix(); - glMultMatrixf(xform[0]); + Mat4 base_xform; + base_xform.rotate(time_sec, 0, 0); + base_xform.rotate(0, 0, time_sec * 0.5); + base_xform.translate(0, 2, 0); glUseProgram(0); glDisable(GL_TEXTURE_2D); - iconrend->draw(&test); - glPopMatrix(); + int first = start_child % ncols; + int nchildren = (int)cur_node->children.size(); + int col = 0, row = 0; + + for(int i=0; idraw(cur_node->children[idx]); + glPopMatrix(); + + if(++col >= ncols) { + col = 0; + ++row; + } + } } -// ---- FSNode implementation ---- -FSNode::FSNode() +FSNode *get_fsnode(const char *path) { - type = FSNODE_UNKNOWN; - abs_path = name = suffix = 0; + char *abspath = make_abs_path(path); + + FSNode *node = node_cache[abspath]; + if(!node) { + node = new FSNode; + node->path = path; + + struct stat st; + if(stat(node->path, &st) == -1) { + fprintf(stderr, "failed to stat: %s\n", node->path.get_path()); + delete node; + return 0; + } + node->size = st.st_size; + + switch(st.st_mode & S_IFMT) { + case S_IFREG: + node->type = FSTYPE_FILE; + break; + + case S_IFDIR: + node->type = FSTYPE_DIR; + break; + + case S_IFBLK: + case S_IFCHR: + node->type = FSTYPE_DEV; + break; + + default: + node->type = FSTYPE_UNKNOWN; + } + node_cache[abspath] = node; + } + + return node; } -FSNode::~FSNode() +FSNode *get_fsnode(const char *dir, const char *name) { - if(abs_path) { - delete [] abs_path; + if(!dir) { + return get_fsnode(name); + } + if(!name || *name == '/') { + return 0; } + + int len = strlen(dir) + 1 + strlen(name); + char *buf = new char[len + 1]; + sprintf(buf, "%s/%s", dir, name); + FSNode *res = get_fsnode(buf); + delete [] buf; + return res; } -void FSNode::set_path(const char *s) +// ---- FSNode implementation ---- +FSNode::FSNode() { - int len = strlen(s); - if(!len) return; + type = FSTYPE_UNKNOWN; + size = 0; + parent = 0; +} - delete [] abs_path; +bool FSNode::expand() +{ + if(type != FSTYPE_DIR) { + return false; + } - const char *slash = s + len - 1; - while(slash > s && *slash != '/') { - --slash; + DIR *dir = opendir(path); + if(!dir) { + fprintf(stderr, "failed to open dir: %s: %s\n", path.get_path(), strerror(errno)); + return false; } - if(name == s) { // no slashes found - char buf[1024]; - if(!getcwd(buf, sizeof buf)) { - abort(); - } - int dirlen = strlen(buf); - abs_path = new char[len + dirlen + 2]; - sprintf(abs_path, "%s/%s", buf, s); + struct dirent *dent; + while((dent = readdir(dir))) { + if(strcmp(dent->d_name, ".") == 0 || strcmp(dent->d_name, "..") == 0) { + continue; + } - name = abs_path + dirlen + 1; - suffix = abs_path + len + dirlen - 1; - } else { - abs_path = new char[len + 1]; - memcpy(abs_path, s, len + 1); + FSNode *node = get_fsnode(path, dent->d_name); + if(!node) continue; - name = abs_path + (slash - s); - suffix = abs_path + len - 1; + children.push_back(node); } + printf("expanded %d children\n", (int)children.size()); - while(suffix > name && *suffix != '.') { - --suffix; - } - if(suffix == name) { - suffix = 0; - } + parent = get_fsnode(path.get_parent()); + return true; } diff --git a/src/fs.h b/src/fs.h index c6f95a7..6c7b406 100644 --- a/src/fs.h +++ b/src/fs.h @@ -1,23 +1,29 @@ #ifndef FS_H_ #define FS_H_ +#include +#include +#include "fspath.h" + enum FSNodeType { - FSNODE_UNKNOWN, - FSNODE_FILE, - FSNODE_DIR, - FSNODE_DEV + FSTYPE_UNKNOWN, + FSTYPE_FILE, + FSTYPE_DIR, + FSTYPE_DEV }; class FSNode { public: FSNodeType type; - char *abs_path; - char *name, *suffix; + FSPath path; + size_t size; + + FSNode *parent; + std::vector children; FSNode(); - ~FSNode(); - void set_path(const char *s); + bool expand(); }; bool init_fs(); @@ -25,4 +31,7 @@ void cleanup_fs(); void draw_fs(); +FSNode *get_fsnode(const char *path); +FSNode *get_fsnode(const char *dir, const char *name); + #endif // FS_H_ diff --git a/src/fspath.cc b/src/fspath.cc new file mode 100644 index 0000000..e6677bd --- /dev/null +++ b/src/fspath.cc @@ -0,0 +1,296 @@ +#include +#include +#include +#include +#include +#include "fspath.h" + + +char *make_abs_path(const char *s) +{ + char wd[1024]; + int slen = s ? strlen(s) : 0; + int len = slen; + char *res; + + if(!s || *s != '/') { + getcwd(wd, sizeof wd); + int wdlen = strlen(wd); + len = wdlen + 1 + slen; + + res = new char[len + 1]; + if(s) { + sprintf(res, "%s/%s", wd, s); + } else { + memcpy(res, wd, len + 1); + } + } else { + res = new char[len + 1]; + memcpy(res, s, len + 1); + } + + return res; +} + +FSPath::FSPath() +{ + abs_path = name = suffix = parent = 0; +} + +FSPath::FSPath(const char *s) +{ + abs_path = name = suffix = parent = 0; + set_path(s); +} + +FSPath::~FSPath() +{ + delete [] abs_path; + delete [] parent; +} + +FSPath::FSPath(const FSPath &p) +{ + abs_path = name = suffix = parent = 0; + + if(abs_path) { + int len = strlen(p.abs_path); + abs_path = new char[len + 1]; + memcpy(abs_path, p.abs_path, len + 1); + + if(p.name) { + name = abs_path + (p.name - p.abs_path); + } + if(p.suffix) { + suffix = abs_path + (p.suffix - p.abs_path); + } + } + if(p.parent) { + int len = strlen(p.parent); + parent = new char[len + 1]; + memcpy(parent, p.parent, len + 1); + } +} + +FSPath &FSPath::operator =(const FSPath &p) +{ + if(&p != this) { + delete [] abs_path; + delete [] parent; + abs_path = name = suffix = parent = 0; + + if(p.abs_path) { + int len = strlen(p.abs_path); + abs_path = new char[len + 1]; + memcpy(abs_path, p.abs_path, len + 1); + + if(p.name) { + name = abs_path + (p.name - p.abs_path); + } + if(p.suffix) { + suffix = abs_path + (p.suffix - p.abs_path); + } + } + if(p.parent) { + int len = strlen(p.parent); + parent = new char[len + 1]; + memcpy(parent, p.parent, len + 1); + } + } + return *this; +} + +FSPath::FSPath(FSPath &&p) +{ + abs_path = p.abs_path; + name = p.name; + suffix = p.suffix; + parent = p.parent; + + p.abs_path = p.name = p.suffix = p.parent = 0; +} + +FSPath &FSPath::operator =(FSPath &&p) +{ + if(&p != this) { + delete [] abs_path; + delete [] parent; + + abs_path = p.abs_path; + name = p.name; + suffix = p.suffix; + parent = p.parent; + + p.abs_path = p.name = p.suffix = p.parent = 0; + } + return *this; +} + +void FSPath::sanitize() +{ + // first pass, convert and backslashes to slashes + char *s = abs_path; + while(*s) { + if(*s == '\\') { + *s = '/'; + } + ++s; + } + + // second pass, remove any "./" and "foo/.." parts + s = abs_path; + int len = strlen(s); + while((s = strstr(s, "./"))) { + len -= 2; + memmove(s, s + 2, len + 1); + } + assert(len == (int)strlen(abs_path)); + + s = abs_path; + while((s = strstr(s, "/.."))) { + char *start = s; + while(start > abs_path && *--start != '/'); + + memmove(start, s + 3, len - 2); + len -= (s + 3) - start; + s = start; + } + assert(len == (int)strlen(abs_path)); + + // remove double slashes + while((s = strstr(abs_path, "//"))) { + memmove(s, s + 1, len-- - (s - abs_path)); + } + assert(len == (int)strlen(abs_path)); + + // remove trailing slash + if(abs_path[len - 1] == '/') { + abs_path[--len] = 0; + } + assert(len == (int)strlen(abs_path)); + + // setup name and prefix pointers as necessary + name = suffix = 0; + s = abs_path; + while(*s) { + if(*s == '/') name = s + 1; + if(*s == '.') suffix = s; + ++s; + } + + if(!name) { + name = abs_path; // shouldn't happen, all paths start with a slash + fprintf(stderr, "FSPath::sanitize: absolute path \"%s\" isn't absolute!\n", abs_path); + } + + if(suffix == abs_path || suffix <= name) { + suffix = 0; + } + + // create parent name string + if(abs_path[0] == '/' && abs_path[1] == 0) { + parent = 0; // root dir has no parent + } else { + int plen = name - 1 - abs_path; + assert(plen > 0); + + parent = new char[plen + 1]; + memcpy(parent, abs_path, plen); + parent[plen] = 0; + } +} + +bool FSPath::set_path(const char *s) +{ + char *tmp = make_abs_path(s); + if(!tmp) { + return false; + } + + delete [] abs_path; + delete [] parent; + abs_path = tmp; + parent = 0; + + sanitize(); + return true; +} + +const char *FSPath::get_path() const +{ + return abs_path; +} + +const char *FSPath::get_name() const +{ + return name; +} + +const char *FSPath::get_suffix() const +{ + return suffix; +} + +const char *FSPath::get_parent() const +{ + return parent; +} + +bool FSPath::append_path(const char *s) +{ + if(!s || !*s) return false; + + if(!abs_path) { + return set_path(s); + } + + if(*s == '/') { + return false; // can't append an absolute path + } + + int len = strlen(abs_path) + 1 + strlen(s); + try { + char *tmp = new char[len + 1]; + + delete [] abs_path; + abs_path = tmp; + delete [] parent; + parent = 0; + } + catch(...) { + return false; + } + + sanitize(); + return true; +} + +bool FSPath::exists() const +{ + struct stat st; + return abs_path && stat(abs_path, &st) != -1; +} + +bool FSPath::is_file() const +{ + struct stat st; + return abs_path && stat(abs_path, &st) != -1 && S_ISREG(st.st_mode); +} + +bool FSPath::is_dir() const +{ + struct stat st; + return abs_path && stat(abs_path, &st) != -1 && S_ISDIR(st.st_mode); +} + +bool FSPath::is_dev() const +{ + struct stat st; + unsigned int devmask = S_IFBLK | S_IFCHR; + return abs_path && stat(abs_path, &st) != -1 && (st.st_mode & devmask); +} + +FSPath::operator const char* () const +{ + return abs_path; +} diff --git a/src/fspath.h b/src/fspath.h new file mode 100644 index 0000000..0bc0b70 --- /dev/null +++ b/src/fspath.h @@ -0,0 +1,47 @@ +#ifndef FSPATH_H_ +#define FSPATH_H_ + +char *make_abs_path(const char *s); + +class FSPath { +private: + char *abs_path; + char *name, *suffix; + char *parent; + + void sanitize(); + +public: + FSPath(); + FSPath(const char *s); + ~FSPath(); + + FSPath(const FSPath &p); + FSPath &operator =(const FSPath &p); + + FSPath(FSPath &&p); + FSPath &operator =(FSPath &&p); + + bool set_path(const char *s); + const char *get_path() const; + + const char *get_name() const; + const char *get_suffix() const; + const char *get_parent() const; + + bool append_path(const char *s); + + // does this path actually exist in the filesystem? + bool exists() const; + // true if this path exists and is a regular file + bool is_file() const; + // true if this path exists and is a directory + bool is_dir() const; + // true of this path exists and is a device file + bool is_dev() const; + + operator const char* () const; +}; + + +#endif // FSPATH_H_ diff --git a/src/icon.cc b/src/icon.cc index 1e92995..ee7ccba 100644 --- a/src/icon.cc +++ b/src/icon.cc @@ -52,7 +52,7 @@ bool ShapesIcons::init() Mat4 xform; gen_geosphere(priv->shape[SHAPE_SPHERE], 0.5, 0); - gen_box(priv->shape[SHAPE_BOX], 1, 1, 1); + gen_box(priv->shape[SHAPE_BOX], 0.7, 0.7, 0.7); gen_torus(priv->shape[SHAPE_TORUS], 0.4, 0.1, 12, 6); gen_cone(priv->shape[SHAPE_CONE], 0.5, 1.0, 8, 2, 1); @@ -72,11 +72,11 @@ void ShapesIcons::shutdown() static int fstype_shape(FSNodeType type) { switch(type) { - case FSNODE_FILE: + case FSTYPE_FILE: return SHAPE_SPHERE; - case FSNODE_DIR: + case FSTYPE_DIR: return SHAPE_BOX; - case FSNODE_DEV: + case FSTYPE_DEV: return SHAPE_TORUS; default: break;