util.c - ltk - GUI toolkit for X11 (WIP)
HTML git clone git://lumidify.org/ltk.git (fast, but not encrypted)
HTML git clone https://lumidify.org/git/ltk.git (encrypted, but very slow)
HTML git clone git://4kcetb7mo7hj6grozzybxtotsub5bempzo4lirzc3437amof2c2impyd.onion/ltk.git (over tor)
DIR Log
DIR Files
DIR Refs
DIR README
DIR 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 }