From 464847c5b25588448e550017a6d91447c076b944 Mon Sep 17 00:00:00 2001 From: Tomasz Kramkowski Date: Wed, 23 Nov 2016 21:23:09 +0000 Subject: init commit --- params.c | 330 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 330 insertions(+) create mode 100644 params.c (limited to 'params.c') 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 + * + * 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#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; +} -- cgit v1.2.3-54-g00ecf