#include <inttypes.h>
#include <stdlib.h>
#include <stdio.h>
+#include <string.h>
#include <ctype.h>
#include <unistd.h>
fprintf(stderr, "zpm-note [-I] [-s <status> ...] [-S <status>] [package]\n");
}
+void show_note(struct zpm_note *n) {
+ printf("Note %" PRId64 " %s\n", n->id, n->ts);
+ if (n->pkgid) {
+ printf("Package: %s\n", n->pkgid);
+ }
+ if (n->path) {
+ printf("Path: %s\n", n->pkgid);
+ }
+ if (n->file) {
+ printf("Hash: %s\n", n->file);
+ }
+
+ printf("%s\n", n->note);
+}
+
+void jstring(char *field, char *value, int indent, int final) {
+ while (indent--) {
+ putchar('\t');
+ }
+ printf("\"%s\": ", field);
+ if (value) {
+ while (*value) {
+ if (strchr("\"\\\b\f\n\r\t", *value)) {
+ putchar('\\');
+ }
+ putchar(*value++);
+ }
+ } else {
+ printf("null");
+ }
+ if (!final) {
+ printf(",");
+ }
+ putchar('\n');
+}
+
+void show_json(struct zpm_note *n) {
+ size_t len = 0;
+
+ if (n->pkgid) {
+ len = strcspn(n->note, "\n\r");
+ }
+
+ printf("{\n\t\"id\": %" PRId64 ",\n", n->id);
+ jstring("package", n->pkgid, 1, 0);
+ jstring("hash", n->file, 1, 0);
+ jstring("path", n->path, 1, 0);
+
+ if (len) {
+ printf("\t\"subject\": \"%.*s\",\n", (int)len, n->note);
+ } else {
+ printf("\t\"subject\": null,\n");
+ }
+ jstring("note", n->note, 1, 1);
+ printf("}\n");
+}
+
void print_note(struct zpm_note *n) {
- printf("%" PRId64 " %s %s\n", n->id, n->pkgid ? n->pkgid : "-", n->note);
+ size_t len;
+ size_t space = 66;
+ uint64_t id = n->id;
+
+ if (n->pkgid) {
+ space -= strlen(n->pkgid);
+ } else {
+ space -= 1;
+ }
+
+ do {
+ space--;
+ } while (id /= 10);
+
+ len = strcspn(n->note, "\n\r");
+ if (len > space) {
+ len = space;
+ }
+
+ printf("%" PRId64 " %.10s %s %.*s\n", n->id, n->ts,
+ n->pkgid ? n->pkgid : "-", (int)len, n->note);
}
int main(int ac, char **av){
struct zpm pkg;
char *dbfile;
int fail, echo = 0;
+ int64_t start = 0, end = INT64_MAX;
+ char *range = 0;
int select = 1;
n.pkgid = 0;
n.hash = 0;
n.path = 0;
+ n.ts = 0;
dbfile = getenv("ZPMDB");
if (!dbfile) {
* -n note id
* -D delete
* -H hash
- * -a all
* -m note message, otherwise EDITOR/vi to edit a text file
* -e echo note after creating
* zpm note -p pkgid -P path -H hash -m 'foo'
* zpm note -D <n>
* zpm note -A <n>
*/
- int list = 0, delete = 0, ack = 0;
- while ((opt = getopt(ac, av, "f:p:P:H:m:n:lDAa")) != -1) {
+ int list = 0, delete = 0, ack = 0, show = 0, json = 0;
+ char *notefrom = 0;
+ while ((opt = getopt(ac, av, "f:p:P:H:m:n:lDAauesjF:")) != -1) {
switch (opt) {
case 'f': dbfile = optarg; break;
case 'p': n.pkgid = optarg; break;
case 'P': n.path = optarg; break;
case 'H': n.hash = optarg; break;
case 'm': n.note = optarg; break;
- case 'n': n.id = strtoll(optarg, NULL, 10); break;
+ case 'F': notefrom = optarg; break;
+ case 'n': range = optarg; break;
case 'l': list = 1; break;
+ case 'j': json = 1; break;
+ case 's': show = 1; break;
case 'e': echo = 1; break;
case 'D': delete = 1; break;
case 'A': ack = 1; break;
- case 'a': select = 3; break;
+ case 'a': select |= 2; break;
+ case 'u': select |= 6; break;
default:
usage();
break;
}
}
+/* 0x1 = next note,
+ * 0x2 = include acked
+ * 0x4 = suppress unack, implies 0x2
+ */
+
+ if (range) {
+ if (*range == '-') {
+ start = 0;
+ end = strtoll(range+1, NULL, 10);
+ } else if (isdigit(*range)) {
+ char *next;
+ start = strtoll(range, &next, 10);
+ if (next && *next == '-') {
+ end = -1;
+ next++;
+ if (isdigit(*next)) {
+ end = strtoll(next, NULL, 10);
+ }
+ } else {
+ end = start;
+ }
+ }
+ }
if (!dbfile) {
fprintf(stderr, "must specify db\n");
/* given a package name, get the packages */
/* no package name, get all */
+ char *filenote = 0;
+ if (notefrom) {
+ size_t in = 0;
+ ssize_t cread = 0;
+ FILE *input;
+
+ if (strcmp(notefrom, "-")) {
+ input = fopen(notefrom, "r");
+ } else {
+ input = stdin;
+ }
+ if (!input) {
+ perror("can't read input file");
+ exit(EXIT_FAILURE);
+ }
+ cread = getdelim(&filenote, &in, 0, input);
+ if (cread == -1) {
+ perror("error reading file");
+ exit(EXIT_FAILURE);
+ }
+ n.note = filenote;
+ }
if (zpm_open(&pkg, dbfile)) {
- if (list) {
+ if (list || show || delete || ack) {
+ n.id = start ? start - 1 : start;
while (zpm_note(&pkg, &n, select)) {
- print_note(&n);
+ if (n.id > end) {
+ break;
+ }
+ if (delete) {
+ zpm_note_del(&pkg, n.id);
+ } else if (ack) {
+ zpm_note_ack(&pkg, n.id);
+ } else if (show) {
+ if (json) {
+ show_json(&n);
+ } else {
+ show_note(&n);
+ }
+ } else {
+ print_note(&n);
+ }
zpm_note_free(&n);
}
+ zpm_note_free(&n);
} else if (n.note) {
n.id = zpm_note_add(&pkg, n.pkgid, n.path, n.hash, "%s", n.note);
+ zpm_note(&pkg, &n, 2);
if (n.id) {
if (echo) {
print_note(&n);
fprintf(stderr, "unable to create note\n");
pkg.error = 1;
}
- } else if (delete) {
- zpm_note_del(&pkg, n.id);
- } else if (ack) {
- zpm_note_ack(&pkg, n.id);
}
} else {
fprintf(stderr, "unable to open %s\n", dbfile);
}
fail = pkg.error;
zpm_close(&pkg);
+ free(filenote);
return fail ? EXIT_FAILURE : EXIT_SUCCESS;
}