X-Git-Url: http://cloudbase.mooo.com/gitweb/z180-stamp.git/blobdiff_plain/b30c4e8f1aef96f6fdc93da9f125545f5f74d06e..52ef24e4020adcb773adcb0d82b1c2c385610461:/avr/env.c diff --git a/avr/env.c b/avr/env.c index 952c88a..3bb04c2 100644 --- a/avr/env.c +++ b/avr/env.c @@ -4,25 +4,18 @@ * SPDX-License-Identifier: GPL-2.0 */ -#include "common.h" -#include -#include -#include +#include "env.h" #include #include "config.h" #include "debug.h" -#include "xmalloc.h" #include "crc.h" -#include "command.h" -#include "env.h" +#include "getopt-min.h" +#define DEBUG_ENV 0 /* set to 1 to debug */ -#define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) -1) -#define ACTIVE_FLAG 1 -#define OBSOLETE_FLAG 0 - -#define ENVLIST_DELETE (1<<0) +#define debug_env(fmt, args...) \ + debug_cond(DEBUG_ENV, fmt, ##args) /* @@ -34,37 +27,36 @@ const FLASH char default_env[] = { ENV_BAUDRATE "=" "115200" DELIM ENV_BOOTDELAY "=" "3" DELIM - ENV_BOOTCMD "=" "pin ${pins}; loadcpm3; go ${startaddress}" DELIM + ENV_BOOTCMD "=" "pin ${pins};loadcpm3;go ${startaddress}" DELIM ENV_CPM3_SYSFILE "=" CONFIG_CPM3_SYSFILE DELIM ENV_PINALIAS "=" "0:PG5,1:PG4,2:PB4,3:PB5,4:PB6,5:PB7," "6:PG3,7:PG2,8:PG1,9:PG0,10:PE7" DELIM - ENV_STARTADDRESS "=" "0" DELIM + //ENV_STARTADDRESS "=" "0" DELIM "pins" "=" "2,8 low 9 high 3 2" DELIM DELIM }; +#define ENV_SIZE (CONFIG_ENV_SIZE - sizeof(uint16_t) - sizeof(uint8_t)) + +#define ENVLIST_DELETE (1<<0) + + /* EEPROM storage */ typedef struct environment_s { uint16_t crc; /* CRC16 over data bytes */ uint8_t flags; /* active/obsolete flags */ +#define ACTIVE_FLAG 1 +#define OBSOLETE_FLAG 0 char data[ENV_SIZE]; /* Environment data */ } env_t; -/* */ -typedef struct env_item_s { - char * envvar; -} env_item_t; - - static uint8_t env_valid; -static env_item_t env_list[CONFIG_ENVVAR_MAX]; -static int entrycount; - +static char env_list[ENV_SIZE]; static -char env_get_char(uint16_t index) +char env_get_char(uint_fast16_t index) { unsigned int off = CONFIG_ENV_OFFSET; char ret; @@ -84,92 +76,160 @@ char env_get_char(uint16_t index) return ret; } - -static const FLASH char *comp_key; +static void envlist_clear(void) +{ + memset(env_list, 0, sizeof env_list); +} static -int comp_env_items(const void *m1, const void *m2) +int env_item_delete(char *ep) { - env_item_t *ep1 = (env_item_t *) m1; - env_item_t *ep2 = (env_item_t *) m2; + char *next = ep + strlen(ep) + 1; + char *end = next; + while (*end++ != 0) + while (*end++ != 0); - if (ep1 == NULL) - return - strcmp_P(ep2->envvar, comp_key); - else - return strcmp(ep1->envvar, ep2->envvar); + memmove(ep, next, end - next); + + return 0; } +static int envcmp(const char *s1, const char *s2) +{ + const unsigned char *u1 = (const unsigned char *)s1; + const unsigned char *u2 = (const unsigned char *)s2; + unsigned char c1, c2; + + do { + c1 = *u1++; c2 = *u2++; + if (c1 == '=') c1 = '\0'; + if (c2 == '=') c2 = '\0'; + } while (c1 != 0 && c1 - c2 == 0); -env_item_t *envlist_search(const MEMX char *name) + return c1 - c2; +} + +static char *envlist_search(const MEMX char *name) { -#ifdef __MEMX - if (__builtin_avr_flash_segment(name) != -1) { - comp_key = name; - return bsearch(0, env_list, entrycount, - sizeof(env_item_t), comp_env_items); - } else { + char key[CONFIG_SYS_ENV_NAMELEN + 1]; + const MEMX char *np = name; + int keylen = 0; + char c; + + while (keylen <= CONFIG_SYS_ENV_NAMELEN && (c = *np++) != '\0') + key[keylen++] = c; + key[keylen] = '\0'; + + for (char *lp = env_list; *lp != 0; ++lp) { - env_item_t e; - e.envvar = (char *) name; + if (envcmp(lp, key) == 0) + return lp; - return bsearch(&e, env_list, entrycount, - sizeof(env_item_t), comp_env_items); + while (*lp != 0) + ++lp; } -#else - env_item_t e; - e.envvar = (char *) name; - return bsearch(&e, env_list, entrycount, - sizeof(env_item_t), comp_env_items); -#endif /* __MEMX */ + return NULL; } +static char *env_item_insert_name(char *pos, const char *name, int len) +{ + char *dstp = pos + len + 1; + char *end = pos; + while (*end++ != 0) + while (*end++ != 0); + + if (end + len >= env_list + ENV_SIZE) + return NULL; -static -env_item_t *envlist_enter(env_item_t *e) + memmove(dstp, pos, end - pos); + strcpy(pos, name); + memset(pos + strlen(name), '=', dstp - pos - strlen(name)); + *(dstp - 1) = '\0'; + + return pos; +} + + +static char *envlist_alloc(const char *name, int len) { - const size_t size = sizeof(env_item_t); - env_item_t *ep; + char *lp; + int rc; - ep = bsearch(e, env_list, entrycount, - size, comp_env_items); - if (ep == NULL) { - if (entrycount < CONFIG_ENVVAR_MAX) { + for (lp = env_list; *lp != 0; ++lp) { - env_list[entrycount++] = *e; - qsort(env_list, entrycount, size, comp_env_items); - ep = bsearch(e, env_list, entrycount, - size, comp_env_items); - } - } else { - free(ep->envvar); - ep->envvar = e->envvar; + rc = envcmp(lp, name); + if (rc >= 0) + break; + + /* rc < 0 : check next place */ + while (*lp != 0) + ++lp; } - return ep; + /* rc == 0 : entry found, replace */ + if (rc == 0) + env_item_delete(lp); + + /* rc > 0 : entry not in list, insert */ + /* *lp == 0 : entry not in list, insert */ + + lp = env_item_insert_name(lp, name, len); + + return lp; } +#if 0 +static char *env_item_insert(char *pos, const char *envstr) +{ + char *dstp = pos + strlen(envstr) + 1; + char *end = pos; + while (*end++ != 0) + while (*end++ != 0); -static -int env_item_delete(env_item_t *ep) + if (end > env_list + ENV_SIZE) + return NULL; + + memmove(dstp, pos, end - pos); + strcpy(pos, envstr); + + return pos; +} + +static char *envlist_enter(const char *ep) { - if (entrycount == 0) - return -1; + char *lp; + int rc; - free(ep->envvar); + for (lp = env_list; *lp != 0; ++lp) { - entrycount--; - size_t size = sizeof(env_item_t); - memmove(ep, ep + 1, (env_list - ep)*size + entrycount*size); + rc = envcmp(lp, ep); + if (rc >= 0) + break; - return 0; + /* rc < 0 : check next place */ + while (*lp != 0) + ++lp; + } + + /* rc == 0 : entry found, replace */ + if (rc == 0) + env_item_delete(lp); + + /* rc > 0 : entry not in list, insert */ + /* *lp == 0 : entry not in list, insert */ + + lp = env_item_insert(lp, ep); + + return lp; } +#endif static int envlist_delete(const MEMX char *name) { - env_item_t *ep = envlist_search(name); + char *ep = envlist_search(name); if (ep != NULL) return env_item_delete(ep); @@ -177,48 +237,43 @@ int envlist_delete(const MEMX char *name) return 1; } - - static int envlist_import(uint8_t flags) { - uint16_t index; - - int len; - env_item_t e; - char *np, c; - uint_fast8_t ef; - if ((flags & ENVLIST_DELETE) != 0) - while (entrycount != 0) - env_item_delete(&env_list[entrycount-1]); - - for (index = 0; env_get_char(index) != '\0'; ) { - for (len = 0; env_get_char(index + len) != '\0'; ++len) { + envlist_clear(); + + for (uint_fast16_t index = 0; env_get_char(index) != '\0'; ) { + char name[CONFIG_SYS_ENV_NAMELEN+1]; + uint_fast8_t nlen = 0; + size_t len; + char ch; + for (len = 0; (ch = env_get_char(index + len)) != '\0'; ++len) { if ((index + len) >= ENV_SIZE) return -1; + if (nlen == 0) { + if (ch == '=') { + nlen = len; + name[nlen] = '\0'; + } else { + if (len > CONFIG_SYS_ENV_NAMELEN) + return -1; + name[len] = ch; + } + } } - np = (char *) xmalloc(len+1); - if (np == NULL) { - printf_P(PSTR("## Can't malloc %d bytes\n"), len+1); + char *ep = envlist_alloc(name, len); + if (ep == NULL) { + printf_P(PSTR("## Error inserting \"%s\" variable.\n"), name); return 1; } - e.envvar = np; - ef = 0; - while ((c = env_get_char(index++)) != '\0') { - if (!ef && (c == '=')) { - *np = '\0'; - ef = 1; - } else - *np = c; - np++; - } - *np = '\0'; - envlist_enter(&e); - } - + index += nlen; + char *p = ep + nlen; + while ((*p++ = env_get_char(index++)) != '\0') + ; + } return 0; } @@ -320,36 +375,28 @@ int env_init(void) char *getenv_str(const MEMX char *name) { - env_item_t *ep; - char *ret = NULL; - - ep = envlist_search(name); + char *ep = envlist_search(name); if (ep != NULL) - ret = ep->envvar + strlen(ep->envvar) +1; - return ret; + return strchr(ep, '=') + 1; + else + return NULL; } static -int env_item_save(env_item_t *ep, uint16_t offset, int space_left) +int env_item_save(char *ep, uint16_t offset, int space_left) { - int nlen, vlen; - char *var = ep->envvar; + int len; - nlen = strlen(var); - if (nlen == 0) - return 0; - vlen = strlen(var + nlen + 1); - if (vlen == 0) + len = strlen(ep); + if (len == 0) return 0; - if (nlen + vlen + 2 > space_left) + len += 1; + if (len > space_left) return 0; - eeprom_update_block(var, (uint8_t *) offset, nlen); - offset += nlen; - eeprom_update_byte((uint8_t *) offset++, '='); - eeprom_update_block(var + nlen +1, (uint8_t *) offset, vlen+1); + eeprom_update_block(ep, (uint8_t *) offset, len); - return nlen + vlen + 2; + return len; } @@ -372,14 +419,18 @@ int saveenv(void) pos = off + offsetof(env_t, data); left = ENV_SIZE - 1; - for (int i = 0 ; i < entrycount; i++) { - len = env_item_save(&env_list[i], pos, left); + + char *ep = env_list; + while (*ep) { + len = env_item_save(ep, pos, left); if (len == 0) { return 1; } pos += len; left -= len; + while (*ep++); } + /* terminate list */ eeprom_update_byte((uint8_t *) pos, 0); crc = env_crc(off + offsetof(env_t, data)); @@ -398,13 +449,19 @@ int saveenv(void) static -int env_item_print(env_item_t *ep) +int env_item_print(char *ep, bool mode) { - int len; - char *ev = ep->envvar; - - len = printf_P(PSTR("%s="), ev); - len += printf_P(PSTR("%s\n"), ev + len); + int len = strlen(ep) + 1; + + if (mode) { + my_puts_P(PSTR("setenv ")); + char ch; + while ((ch = *ep++) != '=') + putchar(ch); + printf_P(PSTR(" '%s'\n"), ep); + } else { + puts(ep); + } return len; } @@ -416,20 +473,23 @@ int env_item_print(env_item_t *ep) * Returns -1 in case of error, or length of printed string */ static -int env_print(const MEMX char *name) +int env_print(const char *name, bool mode) { int len = -1; + char *ep; - if (name) { /* print a single name */ + if (name != NULL) { /* print a single name */ - env_item_t *ep = envlist_search(name); + ep = envlist_search(name); if (ep != NULL) - len = env_item_print(ep); + len = env_item_print(ep, mode); } else { /* print whole list */ len = 0; - for (int i = 0 ; i < entrycount; i++) { - len += env_item_print(&env_list[i]); + ep = env_list; + while (*ep) { + len += env_item_print(ep, mode); + while (*ep++); } } return len; @@ -451,67 +511,47 @@ int env_print(const MEMX char *name) * @return 0 if ok, 1 on error */ static -command_ret_t _do_env_set(int flag, int argc, char * const argv[]) +command_ret_t _do_env_set(uint_fast8_t flag UNUSED, int argc, char * const argv[]) { - int i, len; - char *name, *value, *valp, *p; - env_item_t e, *ep; - - (void) flag; - - name = argv[1]; - value = argv[2]; + char *name = argv[1]; if (strchr(name, '=')) { printf_P(PSTR("## Error: illegal character '='" "in variable name \"%s\"\n"), name); return CMD_RET_FAILURE; } - len = strlen(name); + size_t len = strlen(name); if (len > CONFIG_SYS_ENV_NAMELEN) { printf_P(PSTR("## Error: Variable name \"%s\" too long. " "(max %d characters)\n"), name, CONFIG_SYS_ENV_NAMELEN); return CMD_RET_FAILURE; } -/* - env_id++; -*/ + /* Delete only ? */ - if (argc < 3 || argv[2] == NULL) { + if (argc < 3) { int rc = envlist_delete(name); return rc ? CMD_RET_FAILURE : CMD_RET_SUCCESS; } - /* - * Insert / replace new value - */ - for (i = 2, len += 1; i < argc; ++i) + /* Insert / replace new value */ + + for (int_fast8_t i = 2; i < argc; ++i) len += strlen(argv[i]) + 1; - value = xmalloc(len); - if (value == NULL) { - printf_P(PSTR("## Can't malloc %d bytes\n"), len); + char *pos = envlist_alloc(name, len); + if (pos == NULL) { + printf_P(PSTR("## Error inserting \"%s\" variable.\n"), name); return CMD_RET_FAILURE; } - strcpy(value, name); - valp = value + strlen(name) + 1; - for (i = 2, p = valp; i < argc; ++i) { - char *v = argv[i]; - while ((*p++ = *v++) != '\0') - ; - *(p - 1) = ' '; - } - if (p != valp) - *--p = '\0'; - - e.envvar = value; - ep = envlist_enter(&e); - if (!ep) { - printf_P(PSTR("## Error inserting \"%s\" variable.\n"), - name); - return CMD_RET_FAILURE; + char *vp = pos + strlen(name) + 1; + for (int_fast8_t i = 2; i < argc; ++i) { + char *ap = argv[i]; + while ((*vp++ = *ap++) != '\0'); + //if (i < argc-1) + *(vp-1) = ' '; } + *(vp-1) = '\0'; return CMD_RET_SUCCESS; } @@ -529,7 +569,7 @@ int setenv(const MEMX char *varname, const char *varvalue) int rc; #ifdef __MEMX - char *tmpname = NULL; + char *tmpname; if (__builtin_avr_flash_segment(varname) != -1) { tmpname = malloc(strlen_P(varname)+1); if (tmpname == NULL) { @@ -539,9 +579,12 @@ int setenv(const MEMX char *varname, const char *varvalue) strcpy_P(tmpname, varname); } else tmpname = (char *) varname; -#endif const char * const argv[3] = { NULL, tmpname, varvalue }; +#else + const char * const argv[3] = { NULL, varname, varvalue }; +#endif + int argc = 3; if (varvalue == NULL || varvalue[0] == '\0') @@ -550,7 +593,8 @@ int setenv(const MEMX char *varname, const char *varvalue) rc = (int) _do_env_set(0, argc, (char * const *)argv); #ifdef __MEMX - free(tmpname); + if (__builtin_avr_flash_segment(varname) != -1) + free(tmpname); #endif return rc; } @@ -613,10 +657,9 @@ unsigned long getenv_ulong(const MEMX char *name, int base, unsigned long defaul unsigned long value; char *vp, *endp; - env_item_t *ep = envlist_search(name); + vp = getenv_str(name); - if (ep != NULL ) { - vp = ep->envvar + strlen(ep->envvar) +1; + if (vp != NULL ) { value = strtoul(vp, &endp, base); if (endp != vp) return value; @@ -644,39 +687,50 @@ bool getenv_yesno(const MEMX char *name) */ } -command_ret_t do_env_print(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +command_ret_t do_env_print(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, + int argc, char * const argv[]) { + bool mode = 0; command_ret_t rc = CMD_RET_SUCCESS; - (void) cmdtp; (void) flag; + int opt; + while ((opt = getopt(argc, argv, PSTR("s"))) != -1) { + switch (opt) { + case 's': + mode = 1; + break; + default: /* '?' */ + return CMD_RET_USAGE; + } + } - if (argc == 1) { + if (optind == argc) { /* print all env vars */ - int size = env_print(NULL); + int size = env_print(NULL, mode); if (size < 0) return CMD_RET_FAILURE; - printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"), - size, ENV_SIZE); + if (mode == 0) + printf_P(PSTR("\nEnvironment size: %d/%d bytes\n"), + size, ENV_SIZE - 1); return CMD_RET_SUCCESS; } /* print selected env vars */ - for (int i = 1; i < argc; ++i) { - int rc = env_print(argv[i]); + while (optind < argc) { + int rc = env_print(argv[optind], mode); if (rc < 0) { - printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[i]); + printf_P(PSTR("## Error: \"%s\" not defined\n"), argv[optind]); rc = CMD_RET_FAILURE; } + optind++; } return rc; } -command_ret_t do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +command_ret_t do_env_set(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag, int argc, char * const argv[]) { - (void) cmdtp; - if (argc < 2) return CMD_RET_USAGE; @@ -684,11 +738,9 @@ command_ret_t do_env_set(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv } -command_ret_t do_env_default(cmd_tbl_t *cmdtp, int flag, - int argc, char * const argv[]) +command_ret_t do_env_default(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, + int argc UNUSED, char * const argv[] UNUSED) { - (void) cmdtp; (void) flag; (void) argc; (void) argv; - uint8_t tmp = env_valid; env_valid = 0; @@ -702,10 +754,8 @@ command_ret_t do_env_default(cmd_tbl_t *cmdtp, int flag, } -command_ret_t do_env_save(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) +command_ret_t do_env_save(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) { - (void) cmdtp; (void) flag; (void) argc; (void) argv; - printf_P(PSTR("Saving Environment ...\n")); return saveenv() ? CMD_RET_FAILURE : CMD_RET_SUCCESS; } @@ -742,3 +792,91 @@ int env_complete(char *var, int maxv, char *cmdv[], int bufsz, char *buf) return found; } #endif + +cmd_tbl_t cmd_tbl_env[] = { +CMD_TBL_ITEM_COMPLETE( + printenv, CONFIG_SYS_MAXARGS, 1|CTBL_SUBCMDAUTO, do_env_print, + "print environment variables", + "[-s] [name ...]\n" + " Print value of environment variable(s) 'name'\n" + " If no names are given, print values of all environment variables\n" + " -s Print in setenv form", + var_complete +), +CMD_TBL_ITEM_COMPLETE( + setenv, CONFIG_SYS_MAXARGS, CTBL_SUBCMDAUTO, do_env_set, + "set environment variables", + "name value ...\n" + " - set environment variable 'name' to 'value ...'\n" + "setenv name\n" + " - delete environment variable 'name'", + var_complete +), +CMD_TBL_ITEM( + saveenv, 1, CTBL_SUBCMDAUTO, do_env_save, + "save environment variables to persistent storage", + "" +), +CMD_TBL_ITEM( + defaultenv, 1, CTBL_SUBCMDAUTO, do_env_default, + "set all environment variables to their default values", + "" +), + +CMD_TBL_ITEM_COMPLETE( + print, CONFIG_SYS_MAXARGS, 1, do_env_print, + "print environment variables", + "[-s] [name ...]\n" + " Print value of environment variable(s) 'name'\n" + " If no names are given, print values of all environment variables\n" + " -s Print in setenv form", + var_complete +), +CMD_TBL_ITEM_COMPLETE( + set, CONFIG_SYS_MAXARGS, 0, do_env_set, + "set environment variables", + "name value ...\n" + " - set environment variable 'name' to 'value ...'\n" + "setenv name\n" + " - delete environment variable 'name'", + var_complete +), +CMD_TBL_ITEM( + save, 1, 0, do_env_save, + "save environment variables to persistent storage", + "" +), +CMD_TBL_ITEM( + default, 1, 0, do_env_default, + "set all environment variables to their default values", + "" +), + +CMD_TBL_ITEM( + help, CONFIG_SYS_MAXARGS, CTBL_RPT, do_help, + "Print sub command description/usage", + "\n" + " - print brief description of all sub commands\n" + "env help command ...\n" + " - print detailed usage of sub cmd 'command'" +), + +/* This does not use the CMD_TBL_ITEM macro as ? can't be used in symbol names */ + {FSTR("?"), CONFIG_SYS_MAXARGS, 1, do_help, + NULL, +#ifdef CONFIG_SYS_LONGHELP + FSTR(""), +#endif /* CONFIG_SYS_LONGHELP */ + NULL, +#ifdef CONFIG_AUTO_COMPLETE + NULL, +#endif +}, +/* Mark end of table */ +CMD_TBL_END(cmd_tbl_env) +}; + +command_ret_t do_env(cmd_tbl_t *cmdtp UNUSED, uint_fast8_t flag UNUSED, int argc UNUSED, char * const argv[] UNUSED) +{ + return CMD_RET_USAGE; +}