util.c (4303B)
1#include <stddef.h> 2#define _XOPEN_SOURCE 600 3#define _GNU_SOURCE 4 5#include "tui.h" 6#include "util.h" 7#include "log.h" 8 9#include "grapheme.h" 10 11#include <wchar.h> 12#include <time.h> 13#include <execinfo.h> 14#include <errno.h> 15#include <stdarg.h> 16#include <stdlib.h> 17#include <string.h> 18 19static const char *allowed = "abcdefghijklmnopqrstuvwxyz" 20 "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789.:,;-_(){}[]"; 21 22void 23panic(const char *file, int line, const char *msg, ...) 24{ 25 va_list ap; 26 27 if (tui_enabled()) 28 tui_restore(); 29 30 va_start(ap, msg); 31 fprintf(stderr, "tmus: panic at %s:%i (", file, line); 32 vfprintf(stderr, msg, ap); 33 fprintf(stderr, ")\n"); 34 va_end(ap); 35 36 abort(); 37} 38 39void 40assert(int cond, const char *file, int line, const char *condstr) 41{ 42 if (cond) return; 43 44 if (tui_enabled()) 45 tui_restore(); 46 47 fprintf(stderr, "tmus: assertion failed %s:%i (%s)\n", 48 file, line, condstr); 49 50 abort(); 51} 52 53void 54warn(bool add_error, int type, const char *fmtstr, ...) 55{ 56 va_list ap; 57 58 va_start(ap, fmtstr); 59 if (tui_enabled()) { 60 if (type != USER) 61 log_info("tmus: "); 62 log_infov(fmtstr, ap); 63 if (add_error) 64 log_info(": %s", strerror(errno)); 65 log_info("\n"); 66 } else { 67 if (type != USER) 68 fprintf(stderr, "tmus: "); 69 vfprintf(stderr, fmtstr, ap); 70 if (add_error) 71 fprintf(stderr, ": %s", strerror(errno)); 72 fprintf(stderr, "\n"); 73 } 74 va_end(ap); 75} 76 77void 78error(bool add_error, int type, const char *fmtstr, ...) 79{ 80 va_list ap; 81 82 if (tui_enabled()) 83 tui_restore(); 84 85 va_start(ap, fmtstr); 86 if (type != USER) 87 fprintf(stderr, "tmus: "); 88 vfprintf(stderr, fmtstr, ap); 89 if (add_error) 90 fprintf(stderr, ": %s", strerror(errno)); 91 fprintf(stderr, "\n"); 92 va_end(ap); 93 94 if (type == INTERNAL) 95 abort(); 96 else 97 exit(1); 98} 99 100char * 101astrdup(const char *str) 102{ 103 char *alloc; 104 105 alloc = strdup(str); 106 if (!alloc) ERROR(SYSTEM, "strdup"); 107 108 return alloc; 109} 110 111char * 112aprintf(const char *fmtstr, ...) 113{ 114 va_list ap, cpy; 115 ssize_t size; 116 char *str; 117 118 va_copy(cpy, ap); 119 120 va_start(ap, fmtstr); 121 size = vsnprintf(NULL, 0, fmtstr, ap); 122 if (size < 0) ERROR(SYSTEM, "snprintf"); 123 va_end(ap); 124 125 str = malloc(size + 1); 126 if (!str) ERROR(SYSTEM, "malloc"); 127 128 va_start(cpy, fmtstr); 129 vsnprintf(str, size + 1, fmtstr, cpy); 130 va_end(cpy); 131 132 return str; 133} 134 135char * 136appendstrf(char *alloc, const char *fmtstr, ...) 137{ 138 va_list ap, cpy; 139 size_t size, prevlen; 140 141 va_copy(cpy, ap); 142 143 va_start(ap, fmtstr); 144 size = vsnprintf(NULL, 0, fmtstr, ap); 145 va_end(ap); 146 147 prevlen = alloc ? strlen(alloc) : 0; 148 alloc = realloc(alloc, prevlen + size + 1); 149 if (!alloc) ERROR(SYSTEM, "realloc"); 150 151 va_start(cpy, fmtstr); 152 vsnprintf(alloc + prevlen, size + 1, fmtstr, cpy); 153 va_end(cpy); 154 155 return alloc; 156} 157 158char * 159sanitized(const char *instr) 160{ 161 const char *p; 162 char *clean; 163 int i; 164 165 clean = astrdup(instr); 166 for (i = 0, p = instr; *p; p++) { 167 if (strchr(allowed, *p)) 168 clean[i++] = *p; 169 } 170 ASSERT(i != 0); 171 clean[i] = '\0'; 172 173 return clean; 174} 175 176const char * 177timestr(unsigned int secs) 178{ 179 static char buf[16]; 180 unsigned int mins, hours; 181 182 hours = secs / 3600; 183 mins = secs / 60 % 60; 184 secs = secs % 60; 185 186 if (hours) { 187 snprintf(buf, sizeof(buf), "%02u:%02u:%02u", hours, mins, secs); 188 } else { 189 snprintf(buf, sizeof(buf), "%02u:%02u", mins, secs); 190 } 191 192 return buf; 193} 194 195uint64_t 196current_ms(void) 197{ 198 struct timespec tp; 199 uint64_t ms; 200 201 clock_gettime(CLOCK_REALTIME, &tp); 202 ms = tp.tv_sec * 1000UL + tp.tv_nsec / 1000000UL; 203 204 return ms; 205} 206 207size_t 208text_width(const char *utf8, size_t len) 209{ 210 size_t left; 211 size_t n, width; 212 uint32_t out; 213 214 width = 0; 215 left = len; 216 while (left) { 217 n = MAX(1, grapheme_next_character_break_utf8(utf8, left)); 218 grapheme_decode_utf8(utf8, n, &out); 219 if (out == GRAPHEME_INVALID_CODEPOINT) 220 width += 1; 221 else 222 width += wcwidth(out); 223 utf8 += n; 224 left -= n; 225 } 226 227 return width; 228} 229 230size_t 231utf8_next_break_left(const char *utf8, size_t prev) 232{ 233 size_t pos, n; 234 size_t len, left; 235 236 len = strlen(utf8); 237 238 left = len; 239 pos = 0; 240 while (left) { 241 n = MAX(1, grapheme_next_character_break_utf8(utf8, left)); 242 if (pos + n >= prev) { 243 return pos; 244 } 245 utf8 += n; 246 left -= n; 247 pos += n; 248 } 249 250 return len; 251} 252 253size_t 254utf8_next_break_right(const char *utf8, size_t pos) 255{ 256 size_t len; 257 258 len = strlen(utf8); 259 if (len > pos) { 260 pos += MAX(1, grapheme_next_character_break_utf8(utf8 + pos, len - pos)); 261 } 262 263 return pos; 264}