Simplify -U parsing so that more filenames with colons pass

This commit is contained in:
Stefan Rueger
2023-05-17 23:36:06 +01:00
parent f119c0c29d
commit fdedba8485

View File

@@ -50,103 +50,68 @@ FILEFMT upd_format(char c) {
}
}
UPDATE * parse_op(char * s)
{
char buf[1024];
char * p, * cp, c;
UPDATE * upd;
int i;
size_t fnlen;
/*
* Parsing of [<memory>:<op>:<file>[:<fmt>] | <file>[:<fmt>]]
*
* As memory names don't contain colons and the r/w/v operation <op> is
* a single character, check whether the first two colons sandwich one
* character. If not, treat the argument as a filename (defaulting to
* flash write). This allows colons in filenames other than those for
* enclosing <op> and separating <fmt>, eg, C:/some/file.hex
*/
UPDATE *parse_op(char *s) {
// Assume -U <file>[:<fmt>] first
UPDATE *upd = (UPDATE *) cfg_malloc(__func__, sizeof *upd);
upd->memtype = NULL; // Defaults to flash or application
upd->op = DEVICE_WRITE;
char *fn = s;
upd = (UPDATE *) cfg_malloc("parse_op()", sizeof(UPDATE));
i = 0;
p = s;
while (i < (int) sizeof(buf)-1 && *p && *p != ':')
buf[i++] = *p++;
buf[i] = 0;
if (*p != ':') {
upd->memtype = NULL; /* default memtype, "flash", or "application" */
upd->op = DEVICE_WRITE;
upd->filename = cfg_strdup("parse_op()", buf);
upd->format = FMT_AUTO;
return upd;
}
upd->memtype = cfg_strdup("parse_op()", buf);
p++;
if (*p == 'r') {
upd->op = DEVICE_READ;
}
else if (*p == 'w') {
upd->op = DEVICE_WRITE;
}
else if (*p == 'v') {
upd->op = DEVICE_VERIFY;
}
else {
pmsg_error("invalid I/O mode '%c' in update specification\n", *p);
msg_error(" allowed values are:\n"
" r = read device\n"
" w = write device\n"
" v = verify device\n");
free(upd->memtype);
free(upd);
return NULL;
}
p++;
if (*p != ':') {
pmsg_error("invalid update specification\n");
free(upd->memtype);
free(upd);
return NULL;
}
p++;
/*
* Now, parse the filename component. Instead of looking for the
* leftmost possible colon delimiter, we look for the rightmost one.
* If we found one, we do have a trailing :format specifier, and
* process it. Otherwise, the remainder of the string is our file
* name component. That way, the file name itself is allowed to
* contain a colon itself (e. g. C:/some/file.hex), except the
* optional format specifier becomes mandatory then.
*/
cp = p;
p = strrchr(cp, ':');
if (p == NULL) {
// missing format, default to "AUTO" for write and verify,
// and to binary for read operations:
upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO;
fnlen = strlen(cp);
upd->filename = (char *) cfg_malloc("parse_op()", fnlen + 1);
} else {
fnlen = p - cp;
upd->filename = (char *) cfg_malloc("parse_op()", fnlen +1);
c = *++p;
if (c && p[1])
/* More than one char - force failure below. */
c = '?';
upd->format = upd_format(c);
if(upd->format == FMT_ERROR) {
pmsg_error("invalid file format '%s' in update specifier\n", p);
// Check for <memory>:c: start in which case override defaults
char *fc = strchr(s, ':');
if(fc && fc[1] && fc[2] == ':') {
if(!strchr("rwv", fc[1])) {
pmsg_error("invalid I/O mode :%c: in -U %s\n", fc[1], s);
imsg_error("I/O mode can be r, w or v for read, write or verify device\n");
free(upd->memtype);
free(upd);
return NULL;
}
upd->memtype = memcpy(cfg_malloc(__func__, fc-s+1), s, fc-s);
upd->op =
fc[1]=='r'? DEVICE_READ:
fc[1]=='w'? DEVICE_WRITE: DEVICE_VERIFY;
fn = fc+2;
}
memcpy(upd->filename, cp, fnlen);
upd->filename[fnlen] = 0;
// Default to AUTO for write and verify, and to raw binary for read
upd->format = upd->op == DEVICE_READ? FMT_RBIN: FMT_AUTO;
// Filename: last char is format if the penultimate char is a colon
size_t len = strlen(fn);
if(len > 2 && fn[len-2] == ':') { // Assume format specified
upd->format = upd_format(fn[len-1]);
if(upd->format == FMT_ERROR) {
pmsg_error("invalid file format :%c in -U %s; known formats are\n", fn[len-1], s);
for(int f, c, i=0; i<62; i++) {
c = i<10? '0'+i: (i&1? 'A': 'a') + (i-10)/2;
f = upd_format(c);
if(f != FMT_ERROR)
imsg_error(" :%c %s\n", c, fileio_fmtstr(f));
}
free(upd->memtype);
free(upd);
return NULL;
}
len -= 2;
}
upd->filename = memcpy(cfg_malloc(__func__, len +1), fn, len);
return upd;
}
UPDATE * dup_update(UPDATE * upd)
{
UPDATE * u;