aboutsummaryrefslogtreecommitdiffstats
path: root/util.c
diff options
context:
space:
mode:
Diffstat (limited to 'util.c')
-rw-r--r--util.c222
1 files changed, 221 insertions, 1 deletions
diff --git a/util.c b/util.c
index 5c5737b..e16de94 100644
--- a/util.c
+++ b/util.c
@@ -18,11 +18,16 @@
#include <stdlib.h>
#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
#include "options.h"
#include "util.h"
-#define FNAME_LEN 512
+#define DNAME_CNT 512
+#define FNAME_LEN 1024
void cleanup();
@@ -78,6 +83,221 @@ void size_readable(float *size, const char **unit) {
*unit = units[MIN(i, LEN(units) - 1)];
}
+char* absolute_path(const char *filename) {
+ size_t len;
+ char *path = NULL;
+ const char *basename;
+ char *dirname = NULL;
+ char *cwd = NULL;
+ char *twd = NULL;
+ char *dir;
+ char *s;
+
+ if (!filename || *filename == '\0' || *filename == '/')
+ return NULL;
+
+ len = FNAME_LEN;
+ cwd = (char*) s_malloc(len);
+ while (!(s = getcwd(cwd, len)) && errno == ERANGE) {
+ len *= 2;
+ cwd = (char*) s_realloc(cwd, len);
+ }
+ if (!s)
+ goto error;
+
+ s = strrchr(filename, '/');
+ if (s) {
+ len = s - filename;
+ dirname = (char*) s_malloc(len + 1);
+ strncpy(dirname, filename, len);
+ dirname[len] = '\0';
+ basename = s + 1;
+
+ if (chdir(cwd))
+ /* we're not able to come back afterwards */
+ goto error;
+ if (chdir(dirname))
+ goto error;
+
+ len = FNAME_LEN;
+ twd = (char*) s_malloc(len);
+ while (!(s = getcwd(twd, len)) && errno == ERANGE) {
+ len *= 2;
+ twd = (char*) s_realloc(twd, len);
+ }
+ if (chdir(cwd))
+ die("could not revert to prior working directory");
+ if (!s)
+ goto error;
+ dir = twd;
+ } else {
+ /* only a single filename given */
+ basename = filename;
+ dir = cwd;
+ }
+
+ len = strlen(dir) + strlen(basename) + 2;
+ path = (char*) s_malloc(len);
+ snprintf(path, len, "%s/%s", dir, basename);
+
+goto end;
+
+error:
+ if (path) {
+ free(path);
+ path = NULL;
+ }
+
+end:
+ if (dirname)
+ free(dirname);
+ if (cwd)
+ free(cwd);
+ if (twd)
+ free(twd);
+
+ return path;
+}
+
+int r_opendir(r_dir_t *rdir, const char *dirname) {
+ if (!rdir || !dirname || !*dirname)
+ return -1;
+
+ if (!(rdir->dir = opendir(dirname))) {
+ rdir->name = NULL;
+ rdir->stack = NULL;
+ return -1;
+ }
+
+ rdir->stcap = DNAME_CNT;
+ rdir->stack = (char**) s_malloc(rdir->stcap * sizeof(char*));
+ rdir->stlen = 0;
+
+ rdir->name = (char*) dirname;
+ rdir->d = 0;
+
+ return 0;
+}
+
+int r_closedir(r_dir_t *rdir) {
+ int ret = 0;
+
+ if (!rdir)
+ return -1;
+
+ if (rdir->stack) {
+ while (rdir->stlen > 0)
+ free(rdir->stack[--rdir->stlen]);
+ free(rdir->stack);
+ rdir->stack = NULL;
+ }
+
+ if (rdir->dir) {
+ if (!(ret = closedir(rdir->dir)))
+ rdir->dir = NULL;
+ }
+
+ if (rdir->d && rdir->name) {
+ free(rdir->name);
+ rdir->name = NULL;
+ }
+
+ return ret;
+}
+
+char* r_readdir(r_dir_t *rdir) {
+ size_t len;
+ char *filename;
+ struct dirent *dentry;
+ struct stat fstats;
+
+ if (!rdir || !rdir->dir || !rdir->name)
+ return NULL;
+
+ while (1) {
+ if (rdir->dir && (dentry = readdir(rdir->dir))) {
+ if (!strcmp(dentry->d_name, ".") || !strcmp(dentry->d_name, ".."))
+ continue;
+
+ len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
+ filename = (char*) s_malloc(len);
+ snprintf(filename, len, "%s%s%s", rdir->name,
+ rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
+ dentry->d_name);
+
+ if (!stat(filename, &fstats) && S_ISDIR(fstats.st_mode)) {
+ /* put subdirectory on the stack */
+ if (rdir->stlen == rdir->stcap) {
+ rdir->stcap *= 2;
+ rdir->stack = (char**) s_realloc(rdir->stack,
+ rdir->stcap * sizeof(char*));
+ }
+ rdir->stack[rdir->stlen++] = filename;
+ continue;
+ }
+ return filename;
+ }
+
+ if (rdir->stlen > 0) {
+ /* open next subdirectory */
+ closedir(rdir->dir);
+ if (rdir->d)
+ free(rdir->name);
+ rdir->name = rdir->stack[--rdir->stlen];
+ rdir->d = 1;
+ if (!(rdir->dir = opendir(rdir->name)))
+ warn("could not open directory: %s", rdir->name);
+ continue;
+ }
+
+ /* no more entries */
+ break;
+ }
+
+ return NULL;
+}
+
+int r_mkdir(const char *path) {
+ char *dir, *d;
+ struct stat stats;
+ int err = 0;
+
+ if (!path || !*path)
+ return -1;
+
+ if (!stat(path, &stats)) {
+ if (S_ISDIR(stats.st_mode)) {
+ return 0;
+ } else {
+ warn("not a directory: %s", path);
+ return -1;
+ }
+ }
+
+ d = dir = (char*) s_malloc(strlen(path) + 1);
+ strcpy(dir, path);
+
+ while (d != NULL && !err) {
+ d = strchr(d + 1, '/');
+ if (d != NULL)
+ *d = '\0';
+ if (access(dir, F_OK) && errno == ENOENT) {
+ if (mkdir(dir, 0755)) {
+ warn("could not create directory: %s", dir);
+ err = -1;
+ }
+ } else if (stat(dir, &stats) || !S_ISDIR(stats.st_mode)) {
+ warn("not a directory: %s", dir);
+ err = -1;
+ }
+ if (d != NULL)
+ *d = '/';
+ }
+ free(dir);
+
+ return err;
+}
+
char* readline(FILE *stream) {
size_t len;
char *buf, *s, *end;