summaryrefslogtreecommitdiff
path: root/utils/nsxiv/util.c
diff options
context:
space:
mode:
authorstkhan <personal@slickd.xyz>2022-06-20 19:54:29 +0000
committerstkhan <personal@slickd.xyz>2022-06-20 19:54:29 +0000
commit4c40a4dc245f7715f4891ed02d71475628e7a959 (patch)
treefa52419490b5a0d89d746f6e3a0b0c1e675b7726 /utils/nsxiv/util.c
parent513b0e238b98f72a01d740a0bd99a3739918645c (diff)
new directory structure
Diffstat (limited to 'utils/nsxiv/util.c')
-rw-r--r--utils/nsxiv/util.c289
1 files changed, 289 insertions, 0 deletions
diff --git a/utils/nsxiv/util.c b/utils/nsxiv/util.c
new file mode 100644
index 0000000..d580839
--- /dev/null
+++ b/utils/nsxiv/util.c
@@ -0,0 +1,289 @@
+/* Copyright 2011-2020 Bert Muennich
+ * Copyright 2021-2022 nsxiv contributors
+ *
+ * This file is a part of nsxiv.
+ *
+ * nsxiv is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation; either version 2 of the License,
+ * or (at your option) any later version.
+ *
+ * nsxiv is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with nsxiv. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "nsxiv.h"
+
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include <errno.h>
+
+const char *progname;
+
+void* emalloc(size_t size)
+{
+ void *ptr;
+
+ ptr = malloc(size);
+ if (ptr == NULL)
+ error(EXIT_FAILURE, errno, NULL);
+ return ptr;
+}
+
+void* ecalloc(size_t nmemb, size_t size)
+{
+ void *ptr;
+
+ ptr = calloc(nmemb, size);
+ if (ptr == NULL)
+ error(EXIT_FAILURE, errno, NULL);
+ return ptr;
+}
+
+void* erealloc(void *ptr, size_t size)
+{
+ ptr = realloc(ptr, size);
+ if (ptr == NULL)
+ error(EXIT_FAILURE, errno, NULL);
+ return ptr;
+}
+
+char* estrdup(const char *s)
+{
+ char *d;
+ size_t n = strlen(s) + 1;
+
+ d = malloc(n);
+ if (d == NULL)
+ error(EXIT_FAILURE, errno, NULL);
+ memcpy(d, s, n);
+ return d;
+}
+
+void error(int eval, int err, const char* fmt, ...)
+{
+ va_list ap;
+
+ if (eval == 0 && options->quiet)
+ return;
+
+ fflush(stdout);
+ fprintf(stderr, "%s: ", progname);
+ va_start(ap, fmt);
+ if (fmt != NULL)
+ vfprintf(stderr, fmt, ap);
+ va_end(ap);
+ if (err != 0)
+ fprintf(stderr, "%s%s", fmt != NULL ? ": " : "", strerror(err));
+ fputc('\n', stderr);
+
+ if (eval != 0)
+ exit(eval);
+}
+
+int r_opendir(r_dir_t *rdir, const char *dirname, bool recursive)
+{
+ if (*dirname == '\0')
+ return -1;
+
+ if ((rdir->dir = opendir(dirname)) == NULL) {
+ rdir->name = NULL;
+ rdir->stack = NULL;
+ return -1;
+ }
+
+ rdir->stcap = 512;
+ rdir->stack = emalloc(rdir->stcap * sizeof(char*));
+ rdir->stlen = 0;
+
+ rdir->name = (char*) dirname;
+ rdir->d = 0;
+ rdir->recursive = recursive;
+
+ return 0;
+}
+
+int r_closedir(r_dir_t *rdir)
+{
+ int ret = 0;
+
+ if (rdir->stack != NULL) {
+ while (rdir->stlen > 0)
+ free(rdir->stack[--rdir->stlen]);
+ free(rdir->stack);
+ rdir->stack = NULL;
+ }
+
+ if (rdir->dir != NULL) {
+ if ((ret = closedir(rdir->dir)) == 0)
+ rdir->dir = NULL;
+ }
+
+ if (rdir->d != 0) {
+ free(rdir->name);
+ rdir->name = NULL;
+ }
+
+ return ret;
+}
+
+char* r_readdir(r_dir_t *rdir, bool skip_dotfiles)
+{
+ size_t len;
+ char *filename;
+ struct dirent *dentry;
+ struct stat fstats;
+
+ while (true) {
+ if (rdir->dir != NULL && (dentry = readdir(rdir->dir)) != NULL) {
+ if (dentry->d_name[0] == '.') {
+ if (skip_dotfiles)
+ continue;
+ if (dentry->d_name[1] == '\0')
+ continue;
+ if (dentry->d_name[1] == '.' && dentry->d_name[2] == '\0')
+ continue;
+ }
+
+ len = strlen(rdir->name) + strlen(dentry->d_name) + 2;
+ filename = emalloc(len);
+ snprintf(filename, len, "%s%s%s", rdir->name,
+ rdir->name[strlen(rdir->name)-1] == '/' ? "" : "/",
+ dentry->d_name);
+
+ if (stat(filename, &fstats) < 0)
+ continue;
+ if (S_ISDIR(fstats.st_mode)) {
+ /* put subdirectory on the stack */
+ if (rdir->stlen == rdir->stcap) {
+ rdir->stcap *= 2;
+ rdir->stack = erealloc(rdir->stack,
+ rdir->stcap * sizeof(char*));
+ }
+ rdir->stack[rdir->stlen++] = filename;
+ continue;
+ }
+ return filename;
+ }
+
+ if (rdir->recursive && rdir->stlen > 0) {
+ /* open next subdirectory */
+ closedir(rdir->dir);
+ if (rdir->d != 0)
+ free(rdir->name);
+ rdir->name = rdir->stack[--rdir->stlen];
+ rdir->d = 1;
+ if ((rdir->dir = opendir(rdir->name)) == NULL)
+ error(0, errno, "%s", rdir->name);
+ continue;
+ }
+ /* no more entries */
+ break;
+ }
+ return NULL;
+}
+
+int r_mkdir(char *path)
+{
+ char c, *s = path;
+ struct stat st;
+
+ while (*s != '\0') {
+ if (*s == '/') {
+ s++;
+ continue;
+ }
+ for (; *s != '\0' && *s != '/'; s++);
+ c = *s;
+ *s = '\0';
+ if (mkdir(path, 0755) == -1)
+ if (errno != EEXIST || stat(path, &st) == -1 || !S_ISDIR(st.st_mode))
+ return -1;
+ *s = c;
+ }
+ return 0;
+}
+
+void construct_argv(char **argv, unsigned int len, ...)
+{
+ unsigned int i;
+ va_list args;
+
+ va_start(args, len);
+ for (i = 0; i < len; ++i)
+ argv[i] = va_arg(args, char *);
+ va_end(args);
+ if (argv[len-1] != NULL)
+ error(EXIT_FAILURE, 0, "argv not NULL terminated");
+}
+
+spawn_t spawn(const char *cmd, char *const argv[], unsigned int flags)
+{
+ pid_t pid;
+ spawn_t status = { -1, -1, -1 };
+ int pfd_read[2] = { -1, -1 };
+ int pfd_write[2] = { -1, -1 };
+ const bool r = flags & X_READ;
+ const bool w = flags & X_WRITE;
+
+ if (cmd == NULL || argv == NULL || flags == 0)
+ return status;
+
+ if (r && pipe(pfd_read) < 0) {
+ error(0, errno, "pipe: %s", cmd);
+ return status;
+ }
+
+ if (w && pipe(pfd_write) < 0) {
+ if (r) {
+ close(pfd_read[0]);
+ close(pfd_read[1]);
+ }
+ error(0, errno, "pipe: %s", cmd);
+ return status;
+ }
+
+ if ((pid = fork()) == 0) {
+ bool err = (r && dup2(pfd_read[1], 1) < 0) || (w && dup2(pfd_write[0], 0) < 0);
+ if (r) {
+ close(pfd_read[0]);
+ close(pfd_read[1]);
+ }
+ if (w) {
+ close(pfd_write[0]);
+ close(pfd_write[1]);
+ }
+
+ if (err)
+ error(EXIT_FAILURE, errno, "dup2: %s", cmd);
+ execv(cmd, argv);
+ error(EXIT_FAILURE, errno, "exec: %s", cmd);
+ }
+
+ if (r)
+ close(pfd_read[1]);
+ if (w)
+ close(pfd_write[0]);
+
+ if (pid < 0) {
+ if (r)
+ close(pfd_read[0]);
+ if (w)
+ close(pfd_write[1]);
+ error(0, errno, "fork: %s", cmd);
+ return status;
+ }
+
+ status.pid = pid;
+ status.readfd = pfd_read[0];
+ status.writefd = pfd_write[1];
+ return status;
+}