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