From dab39d3b5ca4e364d3e87a8de5d5fa1208043c03 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Wed, 17 Mar 2021 16:58:44 +0100 Subject: [PATCH 1/6] Implement xrdb reading without popen Avoid using the shell, awk and cut command --- src/main.c | 35 ++---------- src/meson.build | 1 + src/xrdb_parse.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++ src/xrdb_parse.h | 6 ++ 4 files changed, 152 insertions(+), 29 deletions(-) create mode 100644 src/xrdb_parse.c create mode 100644 src/xrdb_parse.h diff --git a/src/main.c b/src/main.c index daf3dc3f..dc3abda1 100644 --- a/src/main.c +++ b/src/main.c @@ -7,7 +7,7 @@ #include #elif __linux__ #include - #include + #include "xrdb_parse.h" #elif __APPLE__ #include #endif @@ -15,40 +15,17 @@ SDL_Window *window; - static double get_scale(void) { +#if _WIN32 float dpi; SDL_GetDisplayDPI(0, NULL, &dpi, NULL); -#if _WIN32 return dpi / 96.0; #elif __linux__ - FILE *stream; - char *xrdb = "xrdb -query | grep dpi | cut -f 2"; - - // In case something goes wrong in popen (e.g., fork or exec calls) or any - // other calls listed below we return the dpi equal to 1. - if ((stream = popen(xrdb, "r")) == NULL) - return 1.0; - - char *line = NULL; - size_t buffer = 0; - ssize_t length = getline(&line, &buffer, stream); - - if (length == -1) { - free(line); - pclose(stream); - return 1.0; + int xft_dpi = xrdb_find_dpi(); + if (xft_dpi > 0) { + return xft_dpi / 96.0; } - - if (pclose(stream)) { - free(line); - return 1.0; - } - - dpi = strtol(line, NULL, 10) / 96.0; - free(line); - - return dpi; + return 1.0; #else return 1.0; #endif diff --git a/src/meson.build b/src/meson.build index 66107d7a..e6e50cc8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,6 +5,7 @@ lite_sources = [ 'api/system.c', 'renderer.c', 'rencache.c', + 'xrdb_parse.c', 'main.c', ] diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c new file mode 100644 index 00000000..197bb60d --- /dev/null +++ b/src/xrdb_parse.c @@ -0,0 +1,139 @@ +#include +#include +#include +#include +#include +#include "xrdb_parse.h" + +extern char **environ; + +static int join_path(char buf[], int buf_size, const char *path, const char *name) { + const char *path_delim = strchr(path, ':'); + if (!path_delim) { + path_delim = path + strlen(path); + } + const int path_len = path_delim - path, name_len = strlen(name); + if (buf_size < path_len + 1 + name_len + 1) return -1; + memcpy(buf, path, path_len); + buf[path_len] = '/'; + memcpy(buf + path_len + 1, name, name_len + 1); + return 0; +} + + +static int xrdb_popen (int *pid_ptr) { + int fd[2]; + + pipe(fd); + int read_fd = fd[STDIN_FILENO]; + int write_fd = fd[STDOUT_FILENO]; + + char *path = getenv("PATH"); + + int pid = fork(); + if (pid == 0) { + close(read_fd); + dup2(write_fd, STDOUT_FILENO); + close(write_fd); + char xrdb_filename[256]; + while (path) { + char *xrgb_argv[3] = {"xrdb", "-query", NULL}; + if (join_path(xrdb_filename, 256, path, "xrdb") == 0) { + execve(xrdb_filename, xrgb_argv, environ); + } + path = strchr(path, ':'); + if (path) { + path++; + } + } + } else { + *pid_ptr = pid; + close(write_fd); + return read_fd; + } + return -1; +} + + +static int xrdb_try_dpi_match(const char *line, int len) { + if (len >= 8 && strncmp(line, "Xft.dpi:", 8) == 0 && len - 8 + 1 <= 64) { + char buf[64]; + memcpy(buf, line + 8, len - 8); + buf[len - 8] = 0; + return strtol(buf, NULL, 10); + } + return -1; +} + +#define XRDB_READ_BUF_SIZE 256 +static void xrdb_complete_reading(int read_fd) { + char buf[XRDB_READ_BUF_SIZE]; + while (1) { + int nr = read(read_fd, buf, XRDB_READ_BUF_SIZE); + if (nr <= 0) return; + } +} + +static int xrdb_parse_for_dpi(int read_fd) { + char buf[XRDB_READ_BUF_SIZE]; + char read_buf_offset = 0; + while (1) { + int nr = read(read_fd, buf + read_buf_offset, XRDB_READ_BUF_SIZE - read_buf_offset); + if (nr > 0) { + const char * const buf_limit = buf + nr + read_buf_offset; + char *line_start = buf; + while (line_start < buf_limit) { + char *nlptr = line_start; + while (nlptr < buf_limit && *nlptr != '\n') { + nlptr++; + } + if (nlptr < buf_limit) { + int dpi_read = xrdb_try_dpi_match(line_start, nlptr - line_start); + if (dpi_read > 0) { + xrdb_complete_reading(read_fd); + return dpi_read; + } + line_start = nlptr + 1; + } else { + /* No newline found: copy the remaining part at the beginning of buf + and read again from file descriptor. */ + const int rem = nr + read_buf_offset - (line_start - buf); + if (rem >= XRDB_READ_BUF_SIZE) { + /* Line is too long for the buffer: skip. */ + read_buf_offset = 0; + } else { + int c = 0; + while (c < rem) { + buf[c] = line_start[c]; + c++; + } + read_buf_offset = rem; + } + break; + } + } + } else { + if (nr == 0 && read_buf_offset > 0) { + int dpi_read = xrdb_try_dpi_match(buf, read_buf_offset); + if (dpi_read > 0) { + return dpi_read; + } + } + break; + } + } + return -1; +} + +int xrdb_find_dpi() { + int xrdb_pid; + int read_fd = xrdb_popen(&xrdb_pid); + if (read_fd >= 0) { + int dpi_read = xrdb_parse_for_dpi(read_fd); + int child_status; + waitpid(xrdb_pid, &child_status, 0); + close(read_fd); + return dpi_read; + } + return -1; +} diff --git a/src/xrdb_parse.h b/src/xrdb_parse.h new file mode 100644 index 00000000..e7ef8396 --- /dev/null +++ b/src/xrdb_parse.h @@ -0,0 +1,6 @@ +#ifndef XRDB_PARSE_H +#define XRDB_PARSE_H + +extern int xrdb_find_dpi(); + +#endif From 30f9f20e235269181da5b29aee917ea1987420ba Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Wed, 17 Mar 2021 18:10:47 +0100 Subject: [PATCH 2/6] Ensure xrdb code is compiled only on unix --- src/main.c | 2 +- src/xrdb_parse.c | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main.c b/src/main.c index dc3abda1..0024a717 100644 --- a/src/main.c +++ b/src/main.c @@ -20,7 +20,7 @@ static double get_scale(void) { float dpi; SDL_GetDisplayDPI(0, NULL, &dpi, NULL); return dpi / 96.0; -#elif __linux__ +#elif __unix__ int xft_dpi = xrdb_find_dpi(); if (xft_dpi > 0) { return xft_dpi / 96.0; diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c index 197bb60d..2c90de9d 100644 --- a/src/xrdb_parse.c +++ b/src/xrdb_parse.c @@ -1,3 +1,5 @@ +#ifdef __unix__ + #include #include #include @@ -25,16 +27,15 @@ static int xrdb_popen (int *pid_ptr) { int fd[2]; pipe(fd); - int read_fd = fd[STDIN_FILENO]; - int write_fd = fd[STDOUT_FILENO]; - - char *path = getenv("PATH"); + int read_fd = fd[0]; + int write_fd = fd[1]; int pid = fork(); if (pid == 0) { close(read_fd); dup2(write_fd, STDOUT_FILENO); close(write_fd); + char *path = getenv("PATH"); char xrdb_filename[256]; while (path) { char *xrgb_argv[3] = {"xrdb", "-query", NULL}; @@ -93,6 +94,7 @@ static int xrdb_parse_for_dpi(int read_fd) { xrdb_complete_reading(read_fd); return dpi_read; } + /* doesn't match: position after newline to search again */ line_start = nlptr + 1; } else { /* No newline found: copy the remaining part at the beginning of buf @@ -137,3 +139,5 @@ int xrdb_find_dpi() { } return -1; } + +#endif From ac0728d073b147ef22146508f00f92cea07f13a5 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Wed, 17 Mar 2021 18:29:50 +0100 Subject: [PATCH 3/6] Check for error in pipe call --- src/xrdb_parse.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c index 2c90de9d..bc90b025 100644 --- a/src/xrdb_parse.c +++ b/src/xrdb_parse.c @@ -26,7 +26,7 @@ static int join_path(char buf[], int buf_size, const char *path, const char *nam static int xrdb_popen (int *pid_ptr) { int fd[2]; - pipe(fd); + if (pipe(fd) != 0) return -1; int read_fd = fd[0]; int write_fd = fd[1]; @@ -104,10 +104,8 @@ static int xrdb_parse_for_dpi(int read_fd) { /* Line is too long for the buffer: skip. */ read_buf_offset = 0; } else { - int c = 0; - while (c < rem) { + for (int c = 0; c < rem; c++) { buf[c] = line_start[c]; - c++; } read_buf_offset = rem; } From 51e7c9493f92470826b1669622f023a847b1d2b0 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Thu, 18 Mar 2021 09:32:52 +0100 Subject: [PATCH 4/6] Minor change for xrdb output parsing Use memmove to copy remaining bytes at beginning of buffer --- src/xrdb_parse.c | 21 +++++++++------------ 1 file changed, 9 insertions(+), 12 deletions(-) diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c index bc90b025..dd8170d8 100644 --- a/src/xrdb_parse.c +++ b/src/xrdb_parse.c @@ -77,11 +77,11 @@ static void xrdb_complete_reading(int read_fd) { static int xrdb_parse_for_dpi(int read_fd) { char buf[XRDB_READ_BUF_SIZE]; - char read_buf_offset = 0; + char buf_remaining = 0; while (1) { - int nr = read(read_fd, buf + read_buf_offset, XRDB_READ_BUF_SIZE - read_buf_offset); + int nr = read(read_fd, buf + buf_remaining, XRDB_READ_BUF_SIZE - buf_remaining); if (nr > 0) { - const char * const buf_limit = buf + nr + read_buf_offset; + const char * const buf_limit = buf + nr + buf_remaining; char *line_start = buf; while (line_start < buf_limit) { char *nlptr = line_start; @@ -99,22 +99,19 @@ static int xrdb_parse_for_dpi(int read_fd) { } else { /* No newline found: copy the remaining part at the beginning of buf and read again from file descriptor. */ - const int rem = nr + read_buf_offset - (line_start - buf); - if (rem >= XRDB_READ_BUF_SIZE) { + buf_remaining = buf_limit - line_start; + if (buf_remaining >= XRDB_READ_BUF_SIZE) { /* Line is too long for the buffer: skip. */ - read_buf_offset = 0; + buf_remaining = 0; } else { - for (int c = 0; c < rem; c++) { - buf[c] = line_start[c]; - } - read_buf_offset = rem; + memmove(buf, line_start, rem); } break; } } } else { - if (nr == 0 && read_buf_offset > 0) { - int dpi_read = xrdb_try_dpi_match(buf, read_buf_offset); + if (nr == 0 && buf_remaining > 0) { + int dpi_read = xrdb_try_dpi_match(buf, buf_remaining); if (dpi_read > 0) { return dpi_read; } From 43e08b0f8ec43e7d573076120108972fc60cc6e7 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Thu, 18 Mar 2021 10:00:03 +0100 Subject: [PATCH 5/6] Fix problem with previous commit and remove strtol call --- src/xrdb_parse.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c index dd8170d8..24961b72 100644 --- a/src/xrdb_parse.c +++ b/src/xrdb_parse.c @@ -57,11 +57,13 @@ static int xrdb_popen (int *pid_ptr) { static int xrdb_try_dpi_match(const char *line, int len) { - if (len >= 8 && strncmp(line, "Xft.dpi:", 8) == 0 && len - 8 + 1 <= 64) { - char buf[64]; - memcpy(buf, line + 8, len - 8); - buf[len - 8] = 0; - return strtol(buf, NULL, 10); + if (len >= 8 && strncmp(line, "Xft.dpi:", 8) == 0) { + for (line += 8; *line && (*line == '\t' || *line == ' '); line++) { } + int dpi = 0; + for ( ; *line >= '0' && *line <= '9'; line++) { + dpi = dpi * 10 + ((int) (*line) - (int) '0'); + } + return dpi; } return -1; } @@ -104,7 +106,7 @@ static int xrdb_parse_for_dpi(int read_fd) { /* Line is too long for the buffer: skip. */ buf_remaining = 0; } else { - memmove(buf, line_start, rem); + memmove(buf, line_start, buf_remaining); } break; } From a742c56ee7182c13178f49d85b3b6a03f964b816 Mon Sep 17 00:00:00 2001 From: Francesco Abbate Date: Thu, 18 Mar 2021 10:06:01 +0100 Subject: [PATCH 6/6] Minor xrdb buffer optimization --- src/xrdb_parse.c | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/xrdb_parse.c b/src/xrdb_parse.c index 24961b72..47018106 100644 --- a/src/xrdb_parse.c +++ b/src/xrdb_parse.c @@ -68,15 +68,14 @@ static int xrdb_try_dpi_match(const char *line, int len) { return -1; } -#define XRDB_READ_BUF_SIZE 256 -static void xrdb_complete_reading(int read_fd) { - char buf[XRDB_READ_BUF_SIZE]; +static void xrdb_complete_reading(int read_fd, char *buf, size_t buf_size) { while (1) { - int nr = read(read_fd, buf, XRDB_READ_BUF_SIZE); + int nr = read(read_fd, buf, buf_size); if (nr <= 0) return; } } +#define XRDB_READ_BUF_SIZE 256 static int xrdb_parse_for_dpi(int read_fd) { char buf[XRDB_READ_BUF_SIZE]; char buf_remaining = 0; @@ -93,7 +92,7 @@ static int xrdb_parse_for_dpi(int read_fd) { if (nlptr < buf_limit) { int dpi_read = xrdb_try_dpi_match(line_start, nlptr - line_start); if (dpi_read > 0) { - xrdb_complete_reading(read_fd); + xrdb_complete_reading(read_fd, buf, XRDB_READ_BUF_SIZE); return dpi_read; } /* doesn't match: position after newline to search again */