aboutsummaryrefslogtreecommitdiffstats
path: root/params.c
diff options
context:
space:
mode:
authorTomasz Kramkowski <tk@the-tk.com>2016-11-23 21:23:09 +0000
committerTomasz Kramkowski <tk@the-tk.com>2016-11-23 21:23:30 +0000
commit464847c5b25588448e550017a6d91447c076b944 (patch)
treecb48ce0793232ab0046ac1ad18ad50862ed77f5c /params.c
downloadhktool-464847c5b25588448e550017a6d91447c076b944.tar.gz
hktool-464847c5b25588448e550017a6d91447c076b944.tar.xz
hktool-464847c5b25588448e550017a6d91447c076b944.zip
init commit
Diffstat (limited to 'params.c')
-rw-r--r--params.c330
1 files changed, 330 insertions, 0 deletions
diff --git a/params.c b/params.c
new file mode 100644
index 0000000..6e0286c
--- /dev/null
+++ b/params.c
@@ -0,0 +1,330 @@
+/* params.c -- Device parameter file handling.
+ *
+ * Copyright (C) 2016 Tomasz Kramkowski <tk@the-tk.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glob.h>
+
+#include "halfkay.h"
+#include "log.h"
+#include "params.h"
+#include "util.h"
+
+/* TODO: make this dynamic */
+#define SZMAX_PFILE 1024
+
+struct params {
+ char *chip;
+ char *board;
+ struct flashparams fp;
+};
+
+static int paramc = 0;
+static struct params *paramv = NULL;
+
+/* addparams: add a param definition to the param list */
+static void addparams(struct params *p)
+{
+ static int avail = 1;
+
+ for (int i = 0; i < paramc; i++) {
+ if (xstrcasecmp(paramv[i].chip, p->chip) != 0)
+ continue;
+ return;
+ }
+
+ if (paramc >= avail - 1) {
+ avail = szmul(avail, 2);
+ paramv = xrealloc(paramv, szmul(avail, sizeof *paramv));
+ }
+
+ paramv[paramc].chip = xstrdup(p->chip);
+ paramv[paramc].board = p->board != NULL ? xstrdup(p->board) : NULL;
+ paramv[paramc].fp = p->fp;
+ paramc++;
+}
+
+static void freeparams(struct params *p)
+{
+ free(p->chip);
+ free(p->board);
+ free(p);
+}
+
+/* atosz: convert string to size_t */
+static int atosz(size_t *size, char *str)
+{
+ unsigned long long val;
+ char *endptr;
+
+ assert(size);
+ assert(str);
+
+ /* for some silly reason strtoull actually allows negatives */
+ if (str[0] == '-')
+ return -1;
+
+ errno = 0;
+ val = strtoull(str, &endptr, 0);
+ if (errno || *endptr)
+ return -1;
+
+ if (val > SIZE_MAX)
+ return -1;
+
+ *size = val;
+
+ return 0;
+}
+
+/* TODO: remove the need for freeparams by not allocating this */
+/* readparams: read a file's param definition */
+static struct params *readparams(const char *file)
+{
+ const char *chip, *board;
+ struct flashparams fp;
+ struct params *par;
+ size_t contsz;
+ char cont[SZMAX_PFILE], *tok;
+ FILE *f;
+
+ assert(file);
+
+ chip = file;
+ for (size_t i = 0; i < strlen(file); i++)
+ if (file[i] == '/')
+ chip = &file[i + 1];
+
+ assert(chip[0]);
+
+ f = fopen(file, "r");
+ if (f == NULL) {
+ warning(errno, EMSG_OPEN, file);
+ NULL;
+ }
+
+ contsz = fread(cont, 1, SZMAX_PFILE, f);
+ if (contsz >= sizeof cont) {
+ warning(0, "Parameter file '%s' is longer than %zu",
+ file, sizeof cont - 1);
+ contsz = sizeof cont - 1;
+ }
+ for (size_t i = 0; i < contsz; i++) {
+ if (cont[i] == '\0') {
+ warning(0, "Parameter file '%s' contains null byte", file);
+ cont[i] = ' ';
+ } else if (isspace(cont[i]) || !isprint(cont[i])) {
+ cont[i] = ' ';
+ }
+ }
+ cont[contsz] = '\0';
+
+ tok = strtok(cont, " ");
+ if (tok == NULL)
+ goto fail;
+ if (atosz(&fp.memsz, tok) != 0)
+ goto fail;
+
+ tok = strtok(NULL, " ");
+ if (tok == NULL)
+ goto fail;
+ if (atosz(&fp.blksz, tok) != 0)
+ goto fail;
+
+ tok = strtok(NULL, " ");
+ if (tok == NULL)
+ goto fail;
+ if (atosz(&fp.cmdsz, tok) != 0)
+ goto fail;
+
+ tok = strtok(NULL, " ");
+ if (tok == NULL)
+ goto fail;
+ if (atosz(&fp.addrshft, tok) != 0)
+ goto fail;
+
+ board = strtok(NULL, "");
+
+ par = xmalloc(sizeof *par);
+ par->chip = xstrdup(chip);
+ par->board = board != NULL ? xstrdup(board) : NULL;
+ par->fp = fp;
+
+fail:
+ if (par == NULL)
+ warning(0, "Parameter file '%s' is malformed", file);
+ fclose(f);
+
+ return par;
+}
+
+/* getdirs: returns a NULL terminated list of data paths */
+static char **getdirs(void)
+{
+ static const char *globsuffix = "/hktool/*";
+ char **dirs, *xddirs, *tok;
+ size_t len = 0, avail = 1;
+
+ xddirs = getenv("XDG_DATA_DIRS");
+ if (!xddirs || !*xddirs)
+ xddirs = "/usr/local/share:/usr/share";
+ xddirs = xstrdup(xddirs);
+
+ for (char *s = xddirs; tok = strtok(s, ":"), tok != NULL; s = NULL) {
+ size_t slen;
+
+ if (tok[0] == '\\')
+ continue;
+
+ if (len >= avail - 1) {
+ avail = szmul(avail, 2);
+ dirs = xrealloc(dirs, szmul(avail, sizeof *dirs));
+ }
+
+ slen = szadd(strlen(tok), strlen(globsuffix));
+ dirs[len] = xstrmalloc(slen);
+ snprintf(dirs[len], slen + 1, "%s%s", tok, globsuffix);
+ len++;
+ }
+
+ free(xddirs);
+
+ dirs[len++] = NULL;
+ dirs = xrealloc(dirs, szmul(len, sizeof *dirs));
+
+ return dirs;
+}
+
+/* freedirs: frees list returned by getdirs */
+static void freedirs(char **dirs)
+{
+ assert(dirs);
+
+ for (size_t i = 0; dirs[i]; i++)
+ free(dirs[i]);
+ free(dirs);
+}
+
+/* loadparams: locate and load all param files */
+static void loadparams(void)
+{
+ char **dirs;
+ glob_t globbuf;
+
+ if (paramv != NULL)
+ return;
+
+ dirs = getdirs();
+
+ for (int i = 0; dirs[i]; i++) {
+ int ret;
+
+ ret = glob(dirs[i], i != 0 ? GLOB_APPEND : 0, NULL, &globbuf);
+ if (ret == GLOB_NOSPACE)
+ error(0, EMSG_GNOMEM);
+ if (ret == GLOB_NOMATCH)
+ continue;
+ if (ret == GLOB_ABORTED) {
+ warning(0, "A call to glob resulted in a read error");
+ continue;
+ }
+ }
+
+ freedirs(dirs);
+
+ for (size_t i = 0; i < globbuf.gl_pathc; i++) {
+ struct params *par;
+ par = readparams(globbuf.gl_pathv[i]);
+ if (par == NULL)
+ continue;
+ addparams(par);
+ freeparams(par);
+ }
+
+ globfree(&globbuf);
+}
+
+static int b16len(size_t n)
+{
+ return snprintf(NULL, 0, "%zx", n);
+}
+
+/* listparams: display a list of found parameter files */
+void listparams(void)
+{
+ int lengths[5] = { 0 };
+
+ loadparams();
+
+ for (int i = 0; i < paramc; i++) {
+ int clengths[5];
+
+ clengths[0] = strlen(paramv[i].chip);
+ clengths[1] = b16len(paramv[i].fp.memsz);
+ clengths[2] = b16len(paramv[i].fp.blksz);
+ clengths[3] = b16len(paramv[i].fp.cmdsz);
+ clengths[4] = b16len(paramv[i].fp.addrshft);
+
+ for (int j = 0; j < 5; j++)
+ if (clengths[j] > lengths[j])
+ lengths[j] = clengths[j];
+ }
+
+ for (int i = 0; i < paramc; i++)
+ printf("%-*s - (0x%.*zx 0x%.*zx 0x%.*zx 0x%.*zx) %s\n",
+ lengths[0], paramv[i].chip,
+ lengths[1], paramv[i].fp.memsz, lengths[2], paramv[i].fp.blksz,
+ lengths[3], paramv[i].fp.cmdsz, lengths[4], paramv[i].fp.addrshft,
+ paramv[i].board != NULL ? paramv[i].board : "");
+}
+
+/* getparams: return the flash params for the specified MCU */
+int getparams(struct flashparams *fp, const char *mcufile)
+{
+ assert(fp);
+ assert(mcufile);
+
+ loadparams();
+
+ if (strchr(mcufile, '/') != NULL) {
+ struct params *par;
+ par = readparams(mcufile);
+ if (par == NULL)
+ return -1;
+ *fp = par->fp;
+ freeparams(par);
+ return 0;
+ }
+
+ for (int i = 0; i < paramc; i++) {
+ if (xstrcasecmp(paramv[i].chip, mcufile) == 0) {
+ *fp = paramv[i].fp;
+ return 0;
+ }
+ }
+
+ warning(0, "'%s' is not a valid MCU name", mcufile);
+
+ return -1;
+}