initial commit
This commit is contained in:
commit
e9618d91db
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
.idea/
|
||||
build/
|
||||
|
||||
185
src/main.c
Normal file
185
src/main.c
Normal 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;
|
||||
}
|
||||
|
||||
Loading…
Reference in New Issue
Block a user