diff --git a/src/libavrdude.h b/src/libavrdude.h index fc4f1696..a3dc2154 100644 --- a/src/libavrdude.h +++ b/src/libavrdude.h @@ -1783,6 +1783,7 @@ extern "C" { int pgmid_is(const char *str); char *mmt_realpath(const char *); char *str_sysconfig(void); + char *str_usrconfig(void); int led_set(const PROGRAMMER *pgm, int led); int led_clr(const PROGRAMMER *pgm, int led); diff --git a/src/strutil.c b/src/strutil.c index a635931b..0a1afc02 100644 --- a/src/strutil.c +++ b/src/strutil.c @@ -28,6 +28,7 @@ #include #include #include +#include #include "avrdude.h" #include "libavrdude.h" @@ -1784,3 +1785,45 @@ char *str_sysconfig(void) { return mmt_realpath(CONFIG_DIR "/" SYSTEM_CONF_FILE); #endif } + +#if !defined(WIN32) +// Safely concatenate dir/file into dst that has size n +static char *concatpath(char *dst, char *dir, char *file, size_t n) { + // Dir or file empty? + if(!dir || !*dir || !file || !*file) + return NULL; + + size_t len = strlen(dir); + + // Insufficient space? + if(len + (dir[len - 1] != '/') + strlen(file) > n - 1) + return NULL; + + if(dst != dir) + strcpy(dst, dir); + + if(dst[len - 1] != '/') + strcat(dst, "/"); + + strcat(dst, file); + + return dst; +} +#endif + +// Return mmt_malloc'd location of personal configuration file +char *str_usrconfig(void) { + char config[PATH_MAX] = { 0 }; + struct stat sb; + +#if defined(WIN32) + win_set_path(config, sizeof config, USER_CONF_FILE); +#else + if(!concatpath(config, getenv("XDG_CONFIG_HOME"), XDG_USER_CONF_FILE, sizeof config)) + concatpath(config, getenv("HOME"), ".config/" XDG_USER_CONF_FILE, sizeof config); + if(stat(config, &sb) < 0 || (sb.st_mode & S_IFREG) == 0) + concatpath(config, getenv("HOME"), USER_CONF_FILE, sizeof config); +#endif + + return mmt_realpath(config); +}