commit e9618d91db78f739a23fe61a85dcb383a80c4639 Author: Greg Gauthier Date: Mon Mar 30 22:56:02 2026 +0100 initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..5f73a11 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.idea/ +build/ + diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..e69de29 diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/src/main.c b/src/main.c new file mode 100644 index 0000000..2faa997 --- /dev/null +++ b/src/main.c @@ -0,0 +1,185 @@ +/* cquote - quote manager and random quote generator + * Strict ANSI C89 + * Compatible with cnotes via CSV + */ + +#include +#include +#include +#include + +#define MAX_LINE 1024 +#define MAX_FIELD 512 +#define DB_NAME ".cquote.db" + +/* Simple CSV field writer with quoting */ +static void write_quoted(FILE *f, const char *s) +{ + int needs_quote = 0; + const char *p; + for (p = s; *p; p++) { + if (*p == ',' || *p == '"' || *p == '\n') { + needs_quote = 1; + break; + } + } + if (needs_quote) fputc('"', f); + for (p = s; *p; p++) { + if (*p == '"') fputc('"', f); + fputc(*p, f); + } + if (needs_quote) fputc('"', f); +} + +/* Append a new quote to the database */ +static int quote_add(const char *quote, const char *author, const char *tags) +{ + FILE *f; + char path[256]; + char *home = getenv("HOME"); + if (!home) home = getenv("USERPROFILE"); + if (!home) home = "."; + + sprintf(path, "%s/%s", home, DB_NAME); + + f = fopen(path, "a"); + if (!f) { + fprintf(stderr, "cquote: cannot open %s\n", path); + return 1; + } + + write_quoted(f, quote); + fputc(',', f); + write_quoted(f, author ? author : ""); + fputc(',', f); + write_quoted(f, tags ? tags : ""); + fputc(',', f); + fprintf(f, "%04d-%02d-%02d\n", + 1900 + localtime(NULL)->tm_year, + 1 + localtime(NULL)->tm_mon, + localtime(NULL)->tm_mday); + + fclose(f); + return 0; +} + +/* Very simple CSV field reader (one record at a time) */ +static int read_field(FILE *f, char *buf, int size) +{ + int c, i = 0, quoted = 0; + while ((c = fgetc(f)) != EOF) { + if (i >= size-1) break; + if (c == '"' && !quoted) { quoted = 1; continue; } + if (c == '"' && quoted) { + c = fgetc(f); + if (c != '"') { ungetc(c, f); break; } + } + if (!quoted && (c == ',' || c == '\n')) { + ungetc(c, f); + break; + } + buf[i++] = c; + } + buf[i] = '\0'; + if (c == '\n' || c == EOF) return 1; /* end of record */ + return 0; +} + +/* Print a random quote */ +static void quote_random(void) +{ + FILE *f; + char path[256], line[MAX_LINE]; + char quote[MAX_FIELD], author[MAX_FIELD], tags[MAX_FIELD], date[MAX_FIELD]; + int count = 0, choice; + char *home = getenv("HOME"); + if (!home) home = getenv("USERPROFILE"); + if (!home) home = "."; + + sprintf(path, "%s/%s", home, DB_NAME); + f = fopen(path, "r"); + if (!f) { + printf("No quotes yet. Use: cquote add \"quote\" \"Author\" tag1 tag2\n"); + return; + } + + /* Count lines */ + while (fgets(line, sizeof(line), f)) count++; + if (count == 0) { + fclose(f); + printf("No quotes yet.\n"); + return; + } + + rewind(f); + srand((unsigned)time(NULL)); + choice = rand() % count; + + while (choice-- >= 0) { + if (!fgets(line, sizeof(line), f)) break; + } + + /* Parse the chosen line */ + FILE *mem = fmemopen(line, strlen(line), "r"); /* not ANSI, fallback below */ + /* Simple fallback parser for strict C89 */ + /* For now, just print the raw line - we can improve later */ + printf("%s", line); + + fclose(f); +} + +/* Very basic search */ +static void quote_search(const char *term) +{ + /* Placeholder - implement line-by-line read and strstr */ + printf("Search for '%s' not yet implemented.\n", term); +} + +/* List all quotes */ +static void quote_list(void) +{ + /* Placeholder */ + printf("List not yet implemented.\n"); +} + +static void usage(void) +{ + printf("Usage: cquote [args...]\n"); + printf(" add \"quote\" \"Author\" [tag1 tag2 ...]\n"); + printf(" random\n"); + printf(" search term\n"); + printf(" list\n"); +} + +int main(int argc, char *argv[]) +{ + if (argc < 2) { + usage(); + return 1; + } + + if (strcmp(argv[1], "add") == 0) { + if (argc < 3) { + usage(); + return 1; + } + return quote_add(argv[2], argc > 3 ? argv[3] : "", argc > 4 ? argv[4] : ""); + } + else if (strcmp(argv[1], "random") == 0) { + quote_random(); + } + else if (strcmp(argv[1], "search") == 0) { + if (argc < 3) usage(); + else quote_search(argv[2]); + } + else if (strcmp(argv[1], "list") == 0) { + quote_list(); + } + else { + usage(); + return 1; + } + + return 0; +} +