utils

tiny programs I use on my system
Download | Log | Files | Refs | README | LICENSE

commit 4ae2d93217cddfe7630d3f2f989cffc7028c8e98
parent e5d21c3fdff551b74a46fba6f2d3f5359e4324df
Author: amrfti <andrew@kloet.net>
Date:   Mon, 19 Jan 2026 12:39:58 -0500

POSIX c99

Diffstat:
MMakefile | 2+-
Msb-time.c | 2+-
Msb-weather.c | 3++-
Mvidir.c | 108++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
4 files changed, 72 insertions(+), 43 deletions(-)

diff --git a/Makefile b/Makefile @@ -1,5 +1,5 @@ CC = cc -CFLAGS = -Wall -Wextra -O3 +CFLAGS = -Wall -Wextra -pedantic -std=c99 -O3 CURL_LIBS = -lcurl SOURCES = vidir.c sb-cpu.c sb-date.c sb-memory.c sb-time.c sb-weather.c sb-battery.c diff --git a/sb-time.c b/sb-time.c @@ -5,7 +5,7 @@ int main() { time_t t = time(NULL); char time_str[10]; - strftime(time_str, sizeof(time_str), "%I:%M%P", localtime(&t)); + strftime(time_str, sizeof(time_str), "%I:%M%p", localtime(&t)); printf("%s\n", time_str); return 0; } diff --git a/sb-weather.c b/sb-weather.c @@ -18,7 +18,8 @@ int main(int argc, char *argv[]) { } char url[MAX_SIZE], weather_data[MAX_SIZE] = {0}, cache_path[MAX_SIZE]; - const char *cache_dir = getenv("XDG_CACHE_HOME") ?: "/tmp"; + const char *cache_dir = + getenv("XDG_CACHE_HOME") ? getenv("XDG_CACHE_HOME") : "/tmp"; snprintf(url, sizeof(url), "https://wttr.in/%s%s", argv[1], WEATHER_FORMAT); snprintf(cache_path, sizeof(cache_path), "%s/weatherreport", cache_dir); diff --git a/vidir.c b/vidir.c @@ -1,5 +1,9 @@ -// vidir.c - rewrite of Joey Hess's vidir in C -// usage: ./vidir [--verbose] [dir|file|-] +/* + * vidir.c - rewrite of Joey Hess's vidir in C + * usage: ./vidir [--verbose] [dir|file|-] + */ + +#define _XOPEN_SOURCE 700 #include <ctype.h> #include <dirent.h> @@ -29,13 +33,22 @@ void die(const char *msg) { exit(1); } +char *my_strdup(const char *s) { + size_t len = strlen(s) + 1; + char *new = malloc(len); + if (new) { + memcpy(new, s, len); + } + return new; +} + void add_item(const char *path) { if (n_items >= MAX_FILES) { fprintf(stderr, "too many files\n"); exit(1); } items[n_items].id = n_items + 1; - items[n_items].path = strdup(path); + items[n_items].path = my_strdup(path); n_items++; } @@ -103,7 +116,7 @@ int main(int argc, char *argv[]) { if (n_items == 0) read_dir("."); - // write numbered list + /* Write numbered list */ fd = mkstemp(tmpname); if (fd < 0) die("mkstemp"); @@ -115,7 +128,7 @@ int main(int argc, char *argv[]) { fprintf(tmp, "%0*d\t%s\n", digits, items[i].id, items[i].path); fclose(tmp); - // pick editor + /* Pick editor */ editor = getenv("VISUAL"); if (!editor) editor = getenv("EDITOR"); @@ -130,7 +143,9 @@ int main(int argc, char *argv[]) { exit(1); } - // re-read edited list + int seen[MAX_FILES] = {0}; + + /* Re-read edited list */ tmp = fopen(tmpname, "r"); if (!tmp) die("fopen tmp"); @@ -140,66 +155,79 @@ int main(int argc, char *argv[]) { line[strcspn(line, "\r\n")] = 0; if (strlen(line) == 0) continue; + int num; if (sscanf(line, "%d%[^\n]", &num, newname) < 1) continue; + + if (num <= 0 || num > n_items) + continue; + + /* Mark this file as still existing in the list */ + seen[num - 1] = 1; + char *p = newname; while (isspace((unsigned char)*p)) p++; - if (num <= 0 || num > n_items) - continue; + char *old = items[num - 1].path; - if (*p == '\0') { - // deleted line -> remove file - if (rm_path(old) != 0) { - fprintf(stderr, "failed to remove %s: %s\n", old, strerror(errno)); - error_flag = 1; - } else if (verbose) { - printf("removed '%s'\n", old); - } - } else if (strcmp(p, old) != 0) { - // rename + + /* Logic for renaming */ + if (strcmp(p, old) != 0) { char dirbuf[PATH_MAX]; - strlcpy(dirbuf, p, sizeof(dirbuf)); + strncpy(dirbuf, p, sizeof(dirbuf) - 1); + dirbuf[sizeof(dirbuf) - 1] = '\0'; char *d = dirname(dirbuf); mkdir(d, 0777); + + /* Handle collisions */ if (access(p, F_OK) == 0) { - char tmpname[PATH_MAX + 16]; // allow space for suffixes + char collision_tmp[PATH_MAX + 16]; int suffix = 0; - snprintf(tmpname, sizeof(tmpname), "%s~", p); - while (access(tmpname, F_OK) == 0) { + snprintf(collision_tmp, sizeof(collision_tmp), "%s~", p); + while (access(collision_tmp, F_OK) == 0) { suffix++; - snprintf(tmpname, sizeof(tmpname), "%s~%d", p, suffix); + snprintf(collision_tmp, sizeof(collision_tmp), "%s~%d", p, suffix); } - if (rename(p, tmpname) != 0) { - fprintf(stderr, "failed to rename '%s' -> '%s': %s\n", p, tmpname, - strerror(errno)); - error_flag = 1; - } else if (verbose) { - printf("renamed '%s' -> '%s'\n", p, tmpname); - } - // update internal mapping so future renames see the new tmp location - for (int j = 0; j < n_items; j++) { - if (strcmp(items[j].path, p) == 0) { - free(items[j].path); - items[j].path = strdup(tmpname); + if (rename(p, collision_tmp) == 0) { + if (verbose) + printf("collision: renamed '%s' -> '%s'\n", p, collision_tmp); + for (int j = 0; j < n_items; j++) { + if (strcmp(items[j].path, p) == 0) { + free(items[j].path); + items[j].path = my_strdup(collision_tmp); + } } } } - // now perform the intended rename if (rename(old, p) != 0) { fprintf(stderr, "failed to rename %s -> %s: %s\n", old, p, strerror(errno)); error_flag = 1; - } else if (verbose) { - printf("renamed '%s' -> '%s'\n", old, p); + } else { + if (verbose) + printf("renamed '%s' -> '%s'\n", old, p); + free(items[num - 1].path); + items[num - 1].path = my_strdup(p); } - free(items[num - 1].path); - items[num - 1].path = strdup(p); } } fclose(tmp); + + /* Delete files that were not in the edited file */ + for (int i = 0; i < n_items; i++) { + if (!seen[i]) { + if (rm_path(items[i].path) != 0) { + fprintf(stderr, "failed to remove %s: %s\n", items[i].path, + strerror(errno)); + error_flag = 1; + } else if (verbose) { + printf("removed '%s'\n", items[i].path); + } + } + } + unlink(tmpname); return error_flag; }