aboutsummaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
authorB. Watson <urchlay@slackware.uk>2024-01-03 00:35:20 -0500
committerB. Watson <urchlay@slackware.uk>2024-01-03 00:35:20 -0500
commitba9e5e94e3c0622a0dc5a91dcb0fe671cb35c07c (patch)
treef1049a0583a3d4dd24521fa5e6fd355c1493c813 /config.c
downloadhcalc-ba9e5e94e3c0622a0dc5a91dcb0fe671cb35c07c.tar.gz
initial commit
Diffstat (limited to 'config.c')
-rw-r--r--config.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/config.c b/config.c
new file mode 100644
index 0000000..752dec5
--- /dev/null
+++ b/config.c
@@ -0,0 +1,157 @@
+/* Config file stuff for hcalc.
+ Copyright 2023, B. Watson.
+ Distributed under the terms of the GNU GPL.
+*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include "hcalc.h"
+
+#define SIGNATURE "\x88\x83\xa1\xac\xa3\x82\x97\x00"
+#define SIGLEN (sizeof(SIGNATURE) - 1)
+#define TRAILER 0x626c6168L
+
+#define FILENAME ".hcalc.cfg"
+
+#define MAX_HOME 8192
+
+/* signature may end up in file(1) magic.
+ doublesize and trailer are there to avoid using configs created
+ on a different architecture.
+ Also, the file size is checked against the size of the struct.
+ In theory this could be affected by compiler options, but on my
+ system, Xlib code compiled with -fpack-struct fails to run anyway.
+ I suspect this is true everywhere...
+ */
+struct hcalc_config {
+ char signature[SIGLEN];
+ char doublesize;
+ char winsize;
+ char base;
+ char quiet;
+ double value, saved, stored;
+ long trailer;
+};
+
+char *home_dir = NULL;
+char config_path[MAX_HOME]; /* ludicrous size */
+
+size_t filesize(FILE *f) {
+ struct stat st;
+
+ if(fstat(fileno(f), &st) < 0) {
+ perror("fstat");
+ return 0;
+ }
+
+ return st.st_size;
+}
+
+void set_home_dir(void) {
+ home_dir = getenv("HOME"); /* could be fancier (getpwent()) */
+ if(!home_dir) return;
+ if(strlen(home_dir) > (MAX_HOME - 100))
+ home_dir = NULL;
+}
+
+void set_config_path(void) {
+ sprintf(config_path, "%s/%s", home_dir, FILENAME);
+/* fprintf(stderr, "Using config file: %s\n", config_path); */
+}
+
+void load_config(void) {
+ FILE *f;
+ struct hcalc_config conf;
+ int result;
+
+/* printf("load_config() called\n"); */
+ set_home_dir();
+ if(!home_dir) {
+ fprintf(stderr, "HOME not set or too long, not loading/saving config file.\n");
+ return;
+ }
+ set_config_path();
+
+ f = fopen(config_path, "rb");
+ if(!f) {
+ if(errno != ENOENT) perror(config_path);
+ return;
+ }
+
+ if(filesize(f) != sizeof(conf)) {
+ fprintf(stderr, "%s: wrong size (should be %ld bytes), ignoring.\n", config_path, sizeof(conf));
+ fclose(f);
+ return;
+ }
+
+ fread(&conf, 1, sizeof(conf), f);
+ result = ferror(f);
+ fclose(f);
+
+ if(result) {
+ perror(config_path);
+ return;
+ }
+
+ if(memcmp(conf.signature, SIGNATURE, SIGLEN) != 0) {
+ fprintf(stderr, "%s: Bad config file signature, ignoring\n", config_path);
+ return;
+ }
+
+ if(conf.doublesize != sizeof(double) || conf.trailer != TRAILER) {
+ fprintf(stderr, "%s: Bad config file architecture, ignoring\n", config_path);
+ return;
+ }
+
+/* fprintf(stderr, "%s: config file OK\n", config_path); */
+ value = conf.value;
+ saved = conf.saved;
+ stored = conf.stored;
+ winsize = conf.winsize;
+ base = conf.base;
+ quiet = conf.quiet;
+}
+
+void save_config(void) {
+ FILE *f;
+ struct hcalc_config conf;
+ int result;
+
+/* printf("save_config() called\n"); */
+ set_home_dir();
+ if(!home_dir) return;
+ set_config_path();
+
+ unlink(config_path); /* avoid symlink weirdness */
+
+ f = fopen(config_path, "wb");
+ if(!f) {
+ perror(config_path);
+ return;
+ }
+
+ memcpy(conf.signature, SIGNATURE, SIGLEN);
+ conf.doublesize = sizeof(double);
+ conf.value = value;
+ conf.saved = saved;
+ conf.stored = stored;
+ conf.winsize = winsize;
+ conf.base = base;
+ conf.quiet = quiet;
+ conf.trailer = TRAILER;
+
+ fwrite(&conf, 1, sizeof(conf), f);
+ result = ferror(f);
+
+ if(result) {
+ perror(config_path);
+ } else {
+/* fprintf(stderr, "Wrote config OK\n"); */
+ }
+
+ fclose(f);
+}