tmus

TUI Music Player
git clone https://git.sinitax.com/sinitax/tmus
Log | Files | Refs | Submodules | LICENSE | sfeed.txt

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}