diff options
Diffstat (limited to 'www/content/posts')
-rw-r--r-- | www/content/posts/_index.md (renamed from www/content/posts/_index.html) | 0 | ||||
-rw-r--r-- | www/content/posts/c-func-ext.md | 94 |
2 files changed, 85 insertions, 9 deletions
diff --git a/www/content/posts/_index.html b/www/content/posts/_index.md index 76fa783..76fa783 100644 --- a/www/content/posts/_index.html +++ b/www/content/posts/_index.md diff --git a/www/content/posts/c-func-ext.md b/www/content/posts/c-func-ext.md index f5ab8fb..7106fad 100644 --- a/www/content/posts/c-func-ext.md +++ b/www/content/posts/c-func-ext.md @@ -8,16 +8,92 @@ tags: - posix --- -Recently, I've been working on porting libraries to GNU/Hurd. The maintainers of GNU/Hurd -have a strong belief that [`*_MAX` macros on POSIX system interfaces](https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/nframe.html) -are very evil things. This is indeed true as a lot of (old) libraries relying on those macros -to determine the buffer size. In modern programming world, it is definitely a bad -idea to use fixed values for buffer sizes without considering possible overflow, unless -you are certain that size is sufficient. - -When you get rid of some old things, you will always meet compatibility problems. In these -case, old source codes using these macros just do not compile now. So here are some +Recently, I’ve been working on porting some libraries to GNU/Hurd. Many (old) +libraries use [`*_MAX` constants on POSIX system +interfaces](https://pubs.opengroup.org/onlinepubs/9699919799.2008edition/nframe.html) +to calculate buffer sizes. However, the GNU/Hurd maintainers urge against the +blind use of them and refuse to define them in system headers. When old APIs are +gone, compatibility problems come. To make my life easier, I'll put some +reusable code snippets here to help *fix `*_MAX` bugs*. <!--more--> +```c +#include <stdlib.h> +#include <stdarg.h> +#include <unistd.h> +#include <stdio.h> +#include <errno.h> + +static inline char *xreadlink(const char *restrict path) { + char *buffer; + size_t allocated = 128; + ssize_t len; + + while (1) { + buffer = (char*) malloc(allocated); + if (!buffer) { return NULL; } + len = readlink(path, buffer, allocated); + if (len < (ssize_t) allocated) { return buffer; } + free(buffer); + if (len >= (ssize_t) allocated) { allocated *= 2; continue; } + return NULL; + } + } + + +static inline char *xgethostname(void) { + long max_host_name; + char *buffer; + + max_host_name = sysconf(_SC_HOST_NAME_MAX); + buffer = malloc(max_host_name + 1); + + if (gethostname(buffer, max_host_name + 1)) { + free(buffer); + return NULL; + } + + buffer[max_host_name] = '\0'; + return buffer; +} + +static inline char *xgetcwd(void) { + char *buffer; + size_t allocated = 128; + + while (1) { + buffer = (char*) malloc(allocated); + if (!buffer) { return NULL; } + getcwd(buffer, allocated); + if (buffer) return buffer; + free(buffer); + if (errno == ERANGE) { allocated *= 2; continue; } + return NULL; + } +} + +static inline __attribute__((__format__(__printf__, 2, 3))) int +xsprintf(char **buf_ptr, const char *restrict format, ...) { + char *buffer; + int ret; + + va_list args; + va_start(args, format); + + ret = snprintf(NULL, 0, format, args); + if (ret < 0) { goto out; } + + buffer = malloc(ret + 1); + if (!buffer) { ret = -1; goto out; } + + ret = snprintf(NULL, 0, format, args); + if (ret < 0) { free(buffer); goto out; } + + *buf_ptr = buffer; +out: + va_end(args); + return ret; +} +``` |