#include #include #include #include #include #include #include #include #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 int unset(const char *, 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)); break; } } 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]; char plugstats[NPLUGINS+3]; FILE *f; int i, j, k; plugstats[0] = '['; plugstats[NPLUGINS+1] = ']'; if (filename) { snprintf(path, sizeof(path), "%s/%s", kcontentdir, filename); cat(path, stdout); } else for (i = 0; i < ndocdb; i++) { for (j = 0; j < NPLUGINS; j++) { plugstats[j + 1] = ' '; for (k = 0; k < plugins[j]->nusedby; k++) { if (plugins[j]->usedby[k] == docdb[i]) { plugstats[j + 1] = plugins[j]->name[0] & ~0x20; break; } } } printf("%s %-15s: %s\n", plugstats, docdb[i]->filename, docdb[i]->title); } } static int unset(const char *filename, const char *plname) { Document *d; int i, j; if ((d = dbfind(filename)) == NULL) { fprintf(stderr, "%s: no such file\n", filename); return 0; } 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) 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)); return 1; } } return 0; } 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); } else if (!strcmp(cmd.argv[0], "unset")) { if (unset(cmd.argv[1], cmd.argv[2])) dbwrite(kdbloc); } } fputc('\n', stdout); return 0; }