diff options
author | Erik K <erikk@previousplan.org> | 2022-05-13 17:24:26 +0000 |
---|---|---|
committer | Erik K <erikk@previousplan.org> | 2022-05-13 17:24:26 +0000 |
commit | b2fada1dd19211d71e04557653d08e697134a6ce (patch) | |
tree | 063b6d1280193046321db1e53506be5b72d2220f /sm.c |
initial commit
Diffstat (limited to 'sm.c')
-rw-r--r-- | sm.c | 442 |
1 files changed, 442 insertions, 0 deletions
@@ -0,0 +1,442 @@ +#include <sys/wait.h> + +#include <ctype.h> +#include <errno.h> +#include <stdio.h> +#include <string.h> +#include <strings.h> +#include <time.h> +#include <unistd.h> + +#include "util.h" + +#define MAIN +#include "config.h" +#include "plugins.h" + +#define MIN(A, B) (A < B ? A : B) + +typedef struct { + char argv[10][CLEN]; + int argc; +} Cmd; + +int cat(const char *, FILE *); + +static int dbdel(const char *); +static Document *dbfind(const char *); +static void dbread(const char *); +static void dbwrite(const char *); +static void doautoexport(const char *); +static void cmdsplit(Cmd *, char *); +static void cfgread(const char *); +static void expandlink(Document *d); +static void expandpath(char *, size_t); +static int pladddoc(const char *, Document *); + +static int add(const char *); +static int edit(const char *); +static void list(const char *); + +static Document **docdb; +static int ndocdb; +static int autoedit; +static int autoexport; + +int +cat(const char *in, FILE *outf) +{ + char buf[BUFSIZ]; + size_t ret; + FILE *inf; + + if ((inf = fopen(in, "r")) == NULL) { + fprintf(stderr, "%s: %s\n", in, strerror(errno)); + return 0; + } + while ((ret = fread(buf, 1, sizeof(buf), inf))) { + if (!fwrite(buf, ret, 1, outf)) { + fprintf(stderr, "fwrite: %s\n", strerror(errno)); + exit(1); + } + } + if (ferror(inf)) { + fprintf(stderr, "fread: %s\n", strerror(errno)); + exit(1); + } + return 1; +} + + +static int +dbdel(const char *filename) +{ + char path[512]; + Document *d; + int i, j; + int di; + + if ((d = dbfind(filename)) == NULL) { + fprintf(stderr, "%s: no such file\n", filename); + return 0; + } + + for (i = 0; i < NPLUGINS; i++) { + for (j = 0; j < plugins[i]->nusedby; j++) { + if (plugins[i]->usedby[j] != d) + continue; + if (j + 1 < plugins[i]->nusedby) { + memmove(&plugins[i]->usedby[j], &plugins[i]->usedby[j + + 1], (plugins[i]->nusedby - j - 1) * + sizeof(*plugins[i]->usedby)); + } + plugins[i]->usedby = xrealloc(plugins[i]->usedby, + --plugins[i]->nusedby * + sizeof(*plugins[i]->usedby)); + } + } + + for (di = 0; di < ndocdb; di++) { + if (docdb[di] == d) + break; + } + if (di == ndocdb) + return 0; + if (di + 1 < ndocdb) { + memmove(&docdb[di], &docdb[di + 1], (ndocdb - di - 1) * + sizeof(*docdb)); + } + docdb = xrealloc(docdb, --ndocdb * sizeof(*docdb)); + + snprintf(path, sizeof(path), "%s/%s", kcontentdir, filename); + unlink(path); + free(d); + return 1; +} + +static Document * +dbfind(const char *filename) +{ + int i; + + for (i = 0; i < ndocdb; i++) { + if (!strcmp(docdb[i]->filename, filename)) { + return docdb[i]; + } + } + + return NULL; +} + +static void +dbread(const char *path) +{ + FILE *db; + char buf[1024], *field, *p; + Document *d; + int i; + + if ((db = fopen(path, "r")) == NULL) + return; + while (xfgets(buf, sizeof(buf), db)) { + if (buf[0] == '\0') + continue; + d = xmalloc(sizeof(*d)); + for (i = 0, p = buf; (field = strsep(&p, "\t")); i++) { + switch (i) { + case 0: my_strlcpy(d->filename, field, sizeof(d->filename)); break; + case 1: my_strlcpy(d->title, field, sizeof(d->title)); break; + case 2: d->creat = strtoll(field, NULL, 10); break; + case 3: d->mod = strtoll(field, NULL, 10); break; + default: pladddoc(field, d); + } + } + if (i > 3) { + expandlink(d); + docdb = xrealloc(docdb, ++ndocdb * sizeof(*docdb)); + docdb[ndocdb-1] = d; + } else { + free(d); + } + } + fclose(db); +} + +static void +dbwrite(const char *path) +{ + FILE *db; + int i, j, k; + + db = xfopen(path, "w"); + for (i = 0; i < ndocdb; i++) { + fprintf(db, "%s\t%s\t%ld\t%ld", docdb[i]->filename, + docdb[i]->title, docdb[i]->creat, + docdb[i]->mod); + for (j = 0; j < NPLUGINS; j++) { + for (k = 0; k < plugins[j]->nusedby; k++) { + if (plugins[j]->usedby[k] == docdb[i]) { + fprintf(db, "\t%s", plugins[j]->name); + break; + } + } + } + fputs("\n", db); + } + fclose(db); +} + +static void +doautoexport(const char *filename) +{ + Document *d; + int i, j; + + if ((d = dbfind(filename)) == NULL) + return; + for (i = 0; i < NPLUGINS; i++) { + for (j = 0; j < plugins[i]->nusedby; j++) { + if (plugins[i]->usedby[j] == d) { + plugins[i]->export(plugins[i]->usedby, + plugins[i]->nusedby); + } + } + } +} + +static void +cmdsplit(Cmd *cmd, char *line) +{ + char *p, *arg; + + p = line; + cmd->argc = 0; + while (cmd->argc < LEN(cmd->argv) && (arg = strsep(&p, " "))) { + if (!arg[0]) + continue; + my_strlcpy(cmd->argv[cmd->argc++], arg, sizeof(cmd->argv[cmd->argc])); + } +} + +static void +cfgread(const char *path) +{ + char buf[CLEN], *end, *value, *store; + int ispath; + FILE *cfg; + + cfg = xfopen(path, "r"); + while (xfgets(buf, sizeof(buf), cfg)) { + if (buf[0] == '#' || !buf[0]) + continue; + if ((value = strchr(buf, ' ')) == NULL || value == buf) + continue; + *value++ = '\0'; + for (end = value + strlen(value) - 1; end >= value + && isspace(*end); *end-- = '\0') { + continue; + } + if ((store = storepointer(buf, &ispath))) { + my_strlcpy(store, value, CLEN); + if (ispath) + expandpath(store, CLEN); + } + } + fclose(cfg); +} + +static void +expandlink(Document *d) +{ + int i, j; + + for (i = j = 0; j + 1 < sizeof(d->link) && klinkpreset[i]; i++) { + if (klinkpreset[i] == '%') { + my_strlcpy(&d->link[j], d->filename, sizeof(d->link) - j); + j += MIN(sizeof(d->link) - j - 1, strlen(d->filename)); + } else { + d->link[j++] = klinkpreset[i]; + } + } + d->link[j] = '\0'; +} + +static void +expandpath(char *str, size_t max) +{ + const char *home = getenv("HOME"); + char newpath[CLEN]; + + if (home == NULL) + return; + if (str[0] == '~') { + snprintf(newpath, sizeof(newpath), "%s%s", home, str + 1); + my_strlcpy(str, newpath, max); + } +} + +/* pladddoc -- e.g -- pluginadddoc */ +static int +pladddoc(const char *plname, Document *d) +{ + int i, j; + + for (i = 0; i < NPLUGINS; i++) { + if (strcmp(plugins[i]->name, plname) != 0) + continue; + for (j = 0; j < plugins[i]->nusedby; j++) { + if (plugins[i]->usedby[j] == d) + goto next; + } + plugins[i]->usedby = xrealloc(plugins[i]->usedby, + ++plugins[i]->nusedby * + sizeof(*plugins[i]->usedby)); + plugins[i]->usedby[plugins[i]->nusedby-1] = d; +next: + } +} + + +static int +add(const char *filename) +{ + Document *d; + char title[128]; + + if ((d = dbfind(filename))) { + fprintf(stderr, "%s: file exists\n", filename); + return 0; + } + + xfputs("Title: ", stdout); + fflush(stdout); + if (!xfgets(title, sizeof(title), stdin)) + return 0; + + d = xmalloc(sizeof(*d)); + my_strlcpy(d->filename, filename, sizeof(d->filename)); + my_strlcpy(d->title, title, sizeof(d->title)); + d->creat = d->mod = time(NULL); + + expandlink(d); + docdb = xrealloc(docdb, ++ndocdb * sizeof(*docdb)); + docdb[ndocdb-1] = d; + + return 1; +} + +static int +edit(const char *filename) +{ + Document *d; + char path[512]; + pid_t pid; + + if ((d = dbfind(filename)) == NULL) { + fprintf(stderr, "%s: no such file\n", filename); + return 0; + } + snprintf(path, sizeof(path), "%s/%s", kcontentdir, filename); + switch ((pid = fork())) { + case -1: + fprintf(stderr, "fork: %s\n", strerror(errno)); + exit(1); + case 0: + execl("/bin/sh", "sh", "-c", "$EDITOR \"$1\"", "sm-edit", path, NULL); + exit(1); + } + waitpid(pid, NULL, 0); + d->mod = time(NULL); + return 1; +} + +static void +list(const char *filename) +{ + char path[512]; + FILE *f; + int i; + + if (filename) { + snprintf(path, sizeof(path), "%s/%s", kcontentdir, filename); + cat(path, stdout); + } else for (i = 0; i < ndocdb; i++) { + printf("%-15s: %s\n", docdb[i]->filename, docdb[i]->title); + } +} + + + +int +main(int argc, char *argv[]) +{ + char *cfgpath = "sm.conf"; + char linebuf[CLEN]; + Document *d; + Cmd cmd; + int i; + + if (argc >= 2) + cfgpath = argv[1]; + + cfgread(cfgpath); + DUMPCFG(); + + if (!strcasecmp(kautoedit, "yes") || !strcasecmp(kautoedit, "true")) + autoedit = 1; + if (!strcasecmp(kautoexport, "yes") || !strcasecmp(kautoexport, "true")) + autoexport = 1; + + dbread(kdbloc); + for (;;) { + xfputs("[sm-" VERSION "] ", stdout); + fflush(stdout); + if (!xfgets(linebuf, sizeof(linebuf), stdin)) + break; + cmdsplit(&cmd, linebuf); + if (cmd.argc == 0) + continue; + for (i = 0; i < NPLUGINS; i++) { + if (!strcmp(plugins[i]->name, cmd.argv[0])) { + plugins[i]->export(plugins[i]->usedby, plugins[i]->nusedby); + break; + } + } + if (i != NPLUGINS) + continue; + if (!strcmp(cmd.argv[0], "quit") || !strcmp(cmd.argv[0], "exit")) + break; + if (!strcmp(cmd.argv[0], "list")) { + list(cmd.argc >= 2 ? cmd.argv[1] : NULL); + } else if (!strcmp(cmd.argv[0], "save")) { + dbwrite(kdbloc); + } else if (cmd.argc < 2) { + fprintf(stderr, "invalid command/needs more parameters\n"); + } else if (!strcmp(cmd.argv[0], "add")) { + if (add(cmd.argv[1])) + dbwrite(kdbloc); + if (autoedit) + goto editcmd; + } else if (!strcmp(cmd.argv[0], "edit")) { +editcmd: + if (edit(cmd.argv[1])) { + doautoexport(cmd.argv[1]); + dbwrite(kdbloc); + } + } else if (!strcmp(cmd.argv[0], "rm")) { + if (dbdel(cmd.argv[1])) + dbwrite(kdbloc); + } else if (cmd.argc < 3) { + fprintf(stderr, "invalid command/needs more parameters\n"); + } else if (!strcmp(cmd.argv[0], "set")) { + if ((d = dbfind(cmd.argv[1])) == NULL) { + fprintf(stderr, "%s: no such file\n", cmd.argv[1]); + continue; + } + if (pladddoc(cmd.argv[2], d)) + dbwrite(kdbloc); + } + } + fputc('\n', stdout); + return 0; +} |