# HG changeset patch # User bsmith@81767d24-ef19-dc11-ae90-00e081727c95 # Date 1668507532 0 # Node ID 59106bf7f9f45c80e18ce79556023c76a630bec2 # Parent de1a0cd266910d82ef1975b3ba028975cfba7f9c GTK2/3/4: Refactor dw_init(), splitting off path detection into _dw_init_path(). Using argv[0] to detect the executable path is very inaccurate, so we will add platform specific code for Linux and FreeBSD to query the executable path. If platform specific code fails, fall back to argv[0] like before. diff -r de1a0cd26691 -r 59106bf7f9f4 gtk/dw.c --- a/gtk/dw.c Tue Nov 15 04:24:25 2022 +0000 +++ b/gtk/dw.c Tue Nov 15 10:18:52 2022 +0000 @@ -46,6 +46,11 @@ #include #endif +#ifdef __FreeBSD__ +#include +#include +#endif + #if __STDC_VERSION__ < 199901L # if __GNUC__ >= 2 # define __func__ __FUNCTION__ @@ -2092,6 +2097,58 @@ } #endif +void _dw_init_path(char *arg) +{ + char path[PATH_MAX+1] = {0}; + +#ifdef __linux__ + if(readlink("/proc/self/exe", path, PATH_MAX) == -1) +#elif defined(__FreeBSD__) + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t length = PATH_MAX; + + if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1) +#endif + strncpy(path, arg ? arg : "", PATH_MAX); + + if(path[0]) + { + char *pos = strrchr(path, '/'); + char *binname = path; + + /* If we have a / then... + * the binary name should be at the end. + */ + if(pos) + { + binname = pos + 1; + *pos = 0; + } + + if(*binname) + { + char *binpos = strstr(path, "/bin"); + + if(binpos) + strncpy(_dw_share_path, path, (size_t)(binpos - path)); + else + strcpy(_dw_share_path, "/usr/local"); + strcat(_dw_share_path, "/share/"); + strcat(_dw_share_path, binname); +#if GLIB_CHECK_VERSION(2,28,0) + if(!_dw_app_id[0]) + { + /* If we have a binary name, use that for the Application ID instead. */ + snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname); + } +#endif + } + } + /* If that failed... just get the current directory */ + if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX)) + _dw_share_path[0] = '/'; +} + /* * Initializes the Dynamic Windows engine. * Parameters: @@ -2109,45 +2166,7 @@ /* Setup the private data directory */ - if(argc > 0 && argv[0]) - { - char *pathcopy = strdup(argv[0]); - char *pos = strrchr(pathcopy, '/'); - char *binname = pathcopy; - - /* If we have a / then... - * the binary name should be at the end. - */ - if(pos) - { - binname = pos + 1; - *pos = 0; - } - - if(*binname) - { - char *binpos = strstr(pathcopy, "/bin"); - - if(binpos) - strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy)); - else - strcpy(_dw_share_path, "/usr/local"); - strcat(_dw_share_path, "/share/"); - strcat(_dw_share_path, binname); -#if GLIB_CHECK_VERSION(2,28,0) - if(!_dw_app_id[0]) - { - /* If we have a binary name, use that for the Application ID instead. */ - snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname); - } -#endif - } - if(pathcopy) - free(pathcopy); - } - /* If that failed... just get the current directory */ - if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX)) - _dw_share_path[0] = '/'; + _dw_init_path(argc > 0 ? argv[0] : NULL); gtk_set_locale(); #if !GLIB_CHECK_VERSION(2,32,0) diff -r de1a0cd26691 -r 59106bf7f9f4 gtk3/dw.c --- a/gtk3/dw.c Tue Nov 15 04:24:25 2022 +0000 +++ b/gtk3/dw.c Tue Nov 15 10:18:52 2022 +0000 @@ -44,6 +44,11 @@ #include +#ifdef __FreeBSD__ +#include +#include +#endif + #if !GTK_CHECK_VERSION(3,1,0) #error GTK 3.0 is no longer supported, please use 3.2 or later. #endif @@ -2032,20 +2037,24 @@ } #endif -/* - * Initializes the Dynamic Windows engine. - * Parameters: - * newthread: True if this is the only thread. - * False if there is already a message loop running. - */ -int dw_init(int newthread, int argc, char *argv[]) -{ - /* Setup the private data directory */ - if(argc > 0 && argv[0]) - { - char *pathcopy = strdup(argv[0]); - char *pos = strrchr(pathcopy, '/'); - char *binname = pathcopy; +void _dw_init_path(char *arg) +{ + char path[PATH_MAX+1] = {0}; + +#ifdef __linux__ + if(readlink("/proc/self/exe", path, PATH_MAX) == -1) +#elif defined(__FreeBSD__) + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t length = PATH_MAX; + + if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1) +#endif + strncpy(path, arg ? arg : "", PATH_MAX); + + if(path[0]) + { + char *pos = strrchr(path, '/'); + char *binname = path; /* If we have a / then... * the binary name should be at the end. @@ -2058,10 +2067,10 @@ if(*binname) { - char *binpos = strstr(pathcopy, "/bin"); + char *binpos = strstr(path, "/bin"); if(binpos) - strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy)); + strncpy(_dw_share_path, path, (size_t)(binpos - path)); else strcpy(_dw_share_path, "/usr/local"); strcat(_dw_share_path, "/share/"); @@ -2074,12 +2083,22 @@ } #endif } - if(pathcopy) - free(pathcopy); } /* If that failed... just get the current directory */ if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX)) _dw_share_path[0] = '/'; +} + +/* + * Initializes the Dynamic Windows engine. + * Parameters: + * newthread: True if this is the only thread. + * False if there is already a message loop running. + */ +int dw_init(int newthread, int argc, char *argv[]) +{ + /* Setup the private data directory */ + _dw_init_path(argc > 0 ? argv[0] : NULL); #if !GLIB_CHECK_VERSION(2,31,0) g_thread_init(NULL); diff -r de1a0cd26691 -r 59106bf7f9f4 gtk4/dw.c --- a/gtk4/dw.c Tue Nov 15 04:24:25 2022 +0000 +++ b/gtk4/dw.c Tue Nov 15 10:18:52 2022 +0000 @@ -39,6 +39,11 @@ #include +#ifdef __FreeBSD__ +#include +#include +#endif + #if __STDC_VERSION__ < 199901L # if __GNUC__ >= 2 # define __func__ __FUNCTION__ @@ -1503,20 +1508,24 @@ */ } -/* - * Initializes the Dynamic Windows engine. - * Parameters: - * newthread: True if this is the only thread. - * False if there is already a message loop running. - */ -int API dw_init(int newthread, int argc, char *argv[]) -{ - /* Setup the private data directory */ - if(argc > 0 && argv[0]) - { - char *pathcopy = strdup(argv[0]); - char *pos = strrchr(pathcopy, '/'); - char *binname = pathcopy; +void _dw_init_path(char *arg) +{ + char path[PATH_MAX+1] = {0}; + +#ifdef __linux__ + if(readlink("/proc/self/exe", path, PATH_MAX) == -1) +#elif defined(__FreeBSD__) + int name[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 }; + size_t length = PATH_MAX; + + if(sysctl(name, 4, exe, &length, NULL, 0) == -1 || length <= 1) +#endif + strncpy(path, arg ? arg : "", PATH_MAX); + + if(path[0]) + { + char *pos = strrchr(path, '/'); + char *binname = path; /* If we have a / then... * the binary name should be at the end. @@ -1529,10 +1538,10 @@ if(*binname) { - char *binpos = strstr(pathcopy, "/bin"); + char *binpos = strstr(path, "/bin"); if(binpos) - strncpy(_dw_share_path, pathcopy, (size_t)(binpos - pathcopy)); + strncpy(_dw_share_path, path, (size_t)(binpos - path)); else strcpy(_dw_share_path, "/usr/local"); strcat(_dw_share_path, "/share/"); @@ -1543,12 +1552,22 @@ snprintf(_dw_app_id, _DW_APP_ID_SIZE, "%s.%s", DW_APP_DOMAIN_DEFAULT, binname); } } - if(pathcopy) - free(pathcopy); - } + } /* If that failed... just get the current directory */ if(!_dw_share_path[0] && !getcwd(_dw_share_path, PATH_MAX)) _dw_share_path[0] = '/'; +} + +/* + * Initializes the Dynamic Windows engine. + * Parameters: + * newthread: True if this is the only thread. + * False if there is already a message loop running. + */ +int API dw_init(int newthread, int argc, char *argv[]) +{ + /* Setup the private data directory */ + _dw_init_path(argc > 0 ? argv[0] : NULL); gtk_init();