/* app/reader_conf.c — 阅读器 App 私有配置实现(见 app/reader_conf.h)。 */ #include "reader_conf.h" #include "meow_ui.h" /* meow_config_dir() */ #include #include #include #include #include /* 从 MEOW_DATA_DIR(/MeowData//data)剥掉尾 "/data",得到 /MeowData/。 */ static void strip_data_suffix(const char *d, char *out, int outsz) { if (!d || !d[0]) { strncpy(out, "/tmp", (size_t)outsz - 1); out[outsz - 1] = 0; return; } size_t n = strlen(d); const char *suffix = "/data"; size_t sl = strlen(suffix); size_t keep; if (n >= sl && strcmp(d + n - sl, suffix) == 0) keep = n - sl; else keep = n; if (keep >= (size_t)outsz) keep = (size_t)outsz - 1; memcpy(out, d, keep); out[keep] = 0; } static void conf_path(char *out, int outsz) { const char *data = meow_config_dir(); char base[360]; strip_data_suffix(data ? data : "", base, sizeof base); if (snprintf(out, (size_t)outsz, "%s/reader.conf", base) >= outsz) out[0] = 0; /* mkdir -p base */ char tmp[400]; strncpy(tmp, base, sizeof tmp - 1); tmp[sizeof tmp - 1] = 0; for (char *p = tmp + 1; *p; p++) { if (*p == '/') { *p = 0; mkdir(tmp, 0755); *p = '/'; } } mkdir(tmp, 0755); } static void conf_defaults(rdconf *c) { c->fs = 20; c->ls = 130; strcpy(c->bg, "black"); /* B 定案:默认纯黑 */ strcpy(c->theme, "auto"); strcpy(c->shelf, "list"); /* A 定案:默认 list */ c->header = 1; c->footer = 1; c->font[0] = 0; } static void clamp_str(char *v, size_t sz) { v[sz - 1] = 0; } rdconf *rdconf_get(void) { static rdconf g; static int loaded = 0; if (loaded) return &g; conf_defaults(&g); char path[440]; conf_path(path, sizeof path); FILE *f = path[0] ? fopen(path, "r") : NULL; if (f) { char line[512]; while (fgets(line, sizeof line, f)) { line[strcspn(line, "\r\n")] = 0; char *eq = strchr(line, '='); if (!eq) continue; *eq = 0; const char *k = line, *v = eq + 1; if (!strcmp(k, "ui.shelf_layout")) { strncpy(g.shelf, v, sizeof g.shelf - 1); g.shelf[sizeof g.shelf - 1] = 0; } else if (!strcmp(k, "rd.fs")) { int t = atoi(v); if (t >= 14 && t <= 40) g.fs = t; } else if (!strcmp(k, "rd.ls")) { int t = atoi(v); if (t >= 100 && t <= 200) g.ls = t; } else if (!strcmp(k, "rd.bg")) { strncpy(g.bg, v, sizeof g.bg - 1); g.bg[sizeof g.bg - 1] = 0; } else if (!strcmp(k, "rd.theme")) { strncpy(g.theme, v, sizeof g.theme - 1); g.theme[sizeof g.theme - 1] = 0; } else if (!strcmp(k, "rd.header")) { g.header = atoi(v) ? 1 : 0; } else if (!strcmp(k, "rd.footer")) { g.footer = atoi(v) ? 1 : 0; } else if (!strcmp(k, "rd.font")) { strncpy(g.font, v, sizeof g.font - 1); g.font[sizeof g.font - 1] = 0; } } fclose(f); } /* 校验合法取值(越界回默认/回退),避免脏档破坏 UI */ if (strcmp(g.shelf, "grid") && strcmp(g.shelf, "list")) strcpy(g.shelf, "list"); if (strcmp(g.bg, "black") && strcmp(g.bg, "white") && strcmp(g.bg, "sepia") && strcmp(g.bg, "auto")) strcpy(g.bg, "black"); if (strcmp(g.theme, "light") && strcmp(g.theme, "dark") && strcmp(g.theme, "auto")) strcpy(g.theme, "auto"); clamp_str(g.shelf, sizeof g.shelf); clamp_str(g.bg, sizeof g.bg); clamp_str(g.theme, sizeof g.theme); clamp_str(g.font, sizeof g.font); loaded = 1; return &g; } int rdconf_persist(void) { rdconf *c = rdconf_get(); char path[440]; conf_path(path, sizeof path); if (!path[0]) return -1; FILE *f = fopen(path, "wb"); if (!f) return -5; fprintf(f, "ui.shelf_layout=%s\n", c->shelf); fprintf(f, "rd.fs=%d\n", c->fs); fprintf(f, "rd.ls=%d\n", c->ls); fprintf(f, "rd.bg=%s\n", c->bg); fprintf(f, "rd.theme=%s\n", c->theme); fprintf(f, "rd.header=%d\n", c->header); fprintf(f, "rd.footer=%d\n", c->footer); fprintf(f, "rd.font=%s\n", c->font); fclose(f); return 0; }