ltk

GUI toolkit for X11 (WIP)
git clone git://lumidify.org/ltk.git (fast, but not encrypted)
git clone https://lumidify.org/ltk.git (encrypted, but very slow)
git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
Log | Files | Refs | README | LICENSE

util.c (5609B)


      1 /*
      2  * Copyright (c) 2021-2024 lumidify <nobody@lumidify.org>
      3  *
      4  * Permission to use, copy, modify, and/or distribute this software for any
      5  * purpose with or without fee is hereby granted, provided that the above
      6  * copyright notice and this permission notice appear in all copies.
      7  *
      8  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
      9  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     10  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     11  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     12  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     13  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     14  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     15  */
     16 
     17 #include <pwd.h>
     18 #include <time.h>
     19 #include <ctype.h>
     20 #include <errno.h>
     21 #include <stdio.h>
     22 #include <stdlib.h>
     23 #include <string.h>
     24 #include <stdarg.h>
     25 #include <unistd.h>
     26 #include <sys/stat.h>
     27 
     28 #include "ltk.h"
     29 #include "util.h"
     30 #include "array.h"
     31 #include "memory.h"
     32 #include "txtbuf.h"
     33 
     34 /* FIXME: Should these functions really fail on memory error? */
     35 
     36 char *
     37 ltk_read_file(const char *filename, size_t *len_ret, char **errstr_ret) {
     38 	long len;
     39 	char *file_contents;
     40 	FILE *file;
     41 
     42 	/* FIXME: https://wiki.sei.cmu.edu/confluence/display/c/FIO19-C.+Do+not+use+fseek()+and+ftell()+to+compute+the+size+of+a+regular+file */
     43 	file = fopen(filename, "r");
     44 	if (!file) goto error;
     45 	if (fseek(file, 0, SEEK_END)) goto errorclose;
     46 	len = ftell(file);
     47 	if (len < 0) goto errorclose;
     48 	if (fseek(file, 0, SEEK_SET)) goto errorclose;
     49 	file_contents = ltk_malloc((size_t)len + 1);
     50 	clearerr(file);
     51 	fread(file_contents, 1, (size_t)len, file);
     52 	if (ferror(file)) goto errorclose;
     53 	file_contents[len] = '\0';
     54 	if (fclose(file)) goto error;
     55 	*len_ret = (size_t)len;
     56 	return file_contents;
     57 error:
     58 	if (errstr_ret)
     59 		*errstr_ret = strerror(errno);
     60 	return NULL;
     61 errorclose:
     62 	if (errstr_ret)
     63 		*errstr_ret = strerror(errno);
     64 	fclose(file);
     65 	return NULL;
     66 }
     67 
     68 /* FIXME: not sure if errno actually is set usefully after all these functions */
     69 int
     70 ltk_write_file(const char *path, const char *data, size_t len, char **errstr_ret) {
     71 	FILE *file = fopen(path, "w");
     72 	if (!file) goto error;
     73 	clearerr(file);
     74 	if (fwrite(data, 1, len, file) < len) goto errorclose;
     75 	if (fclose(file)) goto error;
     76 	return 0;
     77 error:
     78 	if (errstr_ret)
     79 		*errstr_ret = strerror(errno);
     80 	return 1;
     81 errorclose:
     82 	if (errstr_ret)
     83 		*errstr_ret = strerror(errno);
     84 	fclose(file);
     85 	return 1;
     86 }
     87 
     88 /* If `needed` is larger than `*alloc_size`, resize `*str` to
     89    `max(needed, *alloc_size * 2)`. Aborts program on error. */
     90 void
     91 ltk_grow_string(char **str, int *alloc_size, int needed) {
     92         if (needed <= *alloc_size) return;
     93         int new_size = needed > (*alloc_size * 2) ? needed : (*alloc_size * 2);
     94         char *new = ltk_realloc(*str, new_size);
     95         *str = new;
     96         *alloc_size = new_size;
     97 }
     98 
     99 /* Get the directory to store ltk files in and optionally create it if it
    100    doesn't exist yet and `create` is set.
    101    This first checks the environment variable `env` and, if that doesn't
    102    exist, the home directory with "/" and `default` appended.
    103    Returns NULL on error. */
    104 char *
    105 ltk_setup_directory(const char *envname, const char *defaultname, int create) {
    106 	char *dir, *dir_orig;
    107 	struct passwd *pw;
    108 	uid_t uid;
    109 
    110 	dir_orig = getenv(envname);
    111 	if (dir_orig) {
    112 		dir = ltk_strdup(dir_orig);
    113 	} else {
    114 		uid = getuid();
    115 		pw = getpwuid(uid);
    116 		if (!pw)
    117 			return NULL;
    118 		size_t len = strlen(pw->pw_dir);
    119 		size_t dlen = strlen(defaultname);
    120 		dir = ltk_malloc(len + dlen + 2);
    121 		strcpy(dir, pw->pw_dir);
    122 		dir[len] = '/';
    123 		strcpy(dir + len + 1, defaultname);
    124 	}
    125 
    126 	if (create && mkdir(dir, 0700) < 0) {
    127 		if (errno != EEXIST)
    128 			return NULL;
    129 	}
    130 
    131 	return dir;
    132 }
    133 
    134 /* Concatenate the two given strings and return the result.
    135    This allocates new memory for the result string, unlike
    136    the actual strcat. Aborts program on error */
    137 char *
    138 ltk_strcat_useful(const char *str1, const char *str2) {
    139 	int len1, len2;
    140 	char *ret;
    141 
    142 	len1 = strlen(str1);
    143 	len2 = strlen(str2);
    144 	ret = ltk_malloc(len1 + len2 + 1);
    145 	strcpy(ret, str1);
    146 	strcpy(ret + len1, str2);
    147 
    148 	return ret;
    149 }
    150 
    151 static void
    152 ltk_log_msg(const char *mode, const char *format, va_list args) {
    153 	char logtime[25]; /* FIXME: This should always be big enough, right? */
    154 	time_t clock;
    155 	struct tm *timeptr;
    156 
    157 	time(&clock);
    158 	timeptr = localtime(&clock);
    159 	strftime(logtime, 25, "%Y-%m-%d %H:%M:%S", timeptr);
    160 
    161 	fprintf(stderr, "%s ltk %s: ", logtime, mode);
    162 	vfprintf(stderr, format, args);
    163 }
    164 
    165 LTK_GEN_LOG_FUNCS(ltk, ltk_log_msg, ltk_deinit)
    166 
    167 int
    168 str_array_equal(const char *terminated, const char *array, size_t len) {
    169 	if (!strncmp(terminated, array, len)) {
    170 		/* this is kind of inefficient, but there's no way to know
    171 		   otherwise if strncmp just stopped comparing after a '\0' */
    172 		return strlen(terminated) == len;
    173 	}
    174 	return 0;
    175 }
    176 
    177 size_t
    178 prev_utf8(char *text, size_t index) {
    179 	if (index == 0)
    180 		return 0;
    181 	size_t i = index - 1;
    182 	/* find valid utf8 char - this probably needs to be improved */
    183 	while (i > 0 && ((text[i] & 0xC0) == 0x80))
    184 		i--;
    185 	return i;
    186 }
    187 
    188 size_t
    189 next_utf8(char *text, size_t len, size_t index) {
    190 	if (index >= len)
    191 		return len;
    192 	size_t i = index + 1;
    193 	while (i < len && ((text[i] & 0xC0) == 0x80))
    194 		i++;
    195 	return i;
    196 }
    197 
    198 void
    199 ltk_assert_impl(const char *file, int line, const char *func, const char *failedexpr)
    200 {
    201 	(void)fprintf(stderr,
    202 	    "assertion \"%s\" failed: file \"%s\", line %d, function \"%s\"\n",
    203 	    failedexpr, file, line, func);
    204 	abort();
    205 	/* NOTREACHED */
    206 }