initial commit

This commit is contained in:
Greg Gauthier 2026-03-30 22:56:02 +01:00
commit e9618d91db
4 changed files with 188 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
.idea/
build/

0
Makefile Normal file
View File

0
README.md Normal file
View File

185
src/main.c Normal file
View File

@ -0,0 +1,185 @@
/* cquote - quote manager and random quote generator
* Strict ANSI C89
* Compatible with cnotes via CSV
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#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 <command> [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;
}