#include #include #include #include #include #include "util.h" #include "any_log.h" char *color_to_string(color_t *color) { unsigned int r = color->r * 255, g = color->g * 255, b = color->b * 255, a = color->a * 255; char buffer[32]; int n = snprintf(buffer, 32, "#%02x%02x%02x%02x", r, g, b, a); return strslice(buffer, 0, n); } void color_print(FILE *stream, color_t *color) { unsigned int r = color->r * 255, g = color->g * 255, b = color->b * 255, a = color->a * 255; fprintf(stream, "#%02x%02x%02x%02x", r, g, b, a); } char *gradient_to_string(gradient_t *gradient) { char buffer[256]; const size_t max = sizeof(buffer); int start = 0; for (size_t i = 0; i < gradient->length; i++) { unsigned int r = gradient->colors[i].r * 255, g = gradient->colors[i].g * 255, b = gradient->colors[i].b * 255, a = gradient->colors[i].a * 255; start += snprintf(buffer + start, max - start, "#%02x%02x%02x%02x", r, g, b, a); if (i != gradient->length - 1) start += snprintf(buffer + start, max - start, ", "); } return strslice(buffer, 0, start); } void gradient_print(FILE *stream, gradient_t *gradient) { for (size_t i = 0; i < gradient->length; i++) { unsigned int r = gradient->colors[i].r * 255, g = gradient->colors[i].g * 255, b = gradient->colors[i].b * 255, a = gradient->colors[i].a * 255; fprintf(stream, "#%02x%02x%02x%02x", r, g, b, a); if (i != gradient->length - 1) fputs(", ", stream); } } void gradient_free(gradient_t *gradient) { free(gradient->colors); if (gradient->pattern != NULL) cairo_pattern_destroy(gradient->pattern); } const struct timespec timespec_from_ms(long ms) { struct timespec ts = { .tv_sec = ms / 1000, .tv_nsec = (ms % 1000) * 1000000ul, }; return ts; } const long timespec_to_ms(struct timespec ts) { return (ts.tv_sec * 1000) + (ts.tv_nsec / 1000000ul); } struct timespec timespec_diff(struct timespec a, struct timespec b) { bool over = (a.tv_nsec - b.tv_nsec) < 0; struct timespec ts = { .tv_sec = a.tv_sec - b.tv_sec - over, .tv_nsec = a.tv_nsec - b.tv_nsec + over * 1000000000ul, }; return ts; } struct timespec timespec_add(struct timespec a, struct timespec b) { bool over = (a.tv_nsec + b.tv_nsec) > 1000000000ul; struct timespec ts = { .tv_sec = a.tv_sec + b.tv_sec + over, .tv_nsec = a.tv_nsec + b.tv_nsec - over * 1000000000ul, }; return ts; } struct timespec timespec_div(struct timespec ts, int n) { ts.tv_nsec /= n; ts.tv_nsec += ((ts.tv_sec % n) * 1000000000ul) / n; ts.tv_sec /= n; return ts; } bool timespec_greater(struct timespec a, struct timespec b) { return a.tv_sec > b.tv_sec || (a.tv_sec == b.tv_sec && a.tv_nsec > b.tv_nsec); } bool timespec_zero(struct timespec ts) { return ts.tv_sec == 0 && ts.tv_nsec == 0; } void timespec_print(FILE *stream, struct timespec *ts) { fprintf(stream, "%ld.%.9ld", ts->tv_sec, ts->tv_nsec); } bool check_rect(int px, int py, int x, int y, int w, int h) { return px >= x && px <= x + w && py >= y && py <= y + h; } bool check_circle(int px, int py, int x, int y, int r) { int dx = x - px; int dy = y - py; return (dx * dx + dy * dy) <= r * r; } bool check_capsule(int px, int py, int x, int y, int w, int h) { assert(w >= h); int radius = h / 2; // Trivial case if (w == h) return check_circle(px, py, x + radius, y + radius, radius); // General case return check_circle(px, py, x + radius, y + radius, radius) || check_circle(px, py, x + w - radius, y + radius, radius) || check_rect(px, py, x + radius, y, w - 2 * radius, h); } char *strslice(const char *string, size_t start, size_t end) { if (string == NULL) return NULL; char *result = malloc(end - start + 1); memcpy(result, string + start, end - start); result[end - start] = '\0'; return result; } char *strcopy(const char *string) { if (string == NULL) return NULL; return strslice(string, 0, strlen(string)); } bool strfind(const char *string, const char *cases[]) { for (int i = 0; cases[i] != NULL; i++) { if (strstr(string, cases[i]) != NULL) return true; } return false; } size_t strprefix(const char *string, const char *prefix) { size_t i = 0; for ( ; prefix[i] != '\0'; i++) { if (string[i] != prefix[i]) return 0; } return i; } void strfreelist(char **list) { if (list == NULL) return; for (char **head = list; *head != NULL; head++) free(*head); free(list); } double steps(double value, int n) { return floor(value * n) * (1.0 / n); } bool iszero(const void *ptr, size_t size) { for (size_t i = 0; i < size; i++) { if (((const char *)ptr)[i] != 0) return false; } return true; } void render_triangle(cairo_t *cr, int x, int y, int w, int h) { cairo_new_sub_path(cr); cairo_line_to(cr, x, y + h); cairo_line_to(cr, x + w, y + h); cairo_line_to(cr, x + w / 2, y); cairo_close_path(cr); } void render_capsule_fast(cairo_t *cr, int x, int y, int w, int r1, int r2) { const double degree = M_PI / 180.0; assert(w >= r1 * 2); cairo_new_sub_path(cr); cairo_arc(cr, x + r1, y + r1, r2, 90 * degree, 270 * degree); cairo_arc(cr, x + w - r1, y + r1, r2, 270 * degree, 450 * degree); cairo_close_path(cr); } void render_capsule(cairo_t *cr, int x, int y, int w, int r1, int r2) { // Fast path if (w >= r1 * 2) { render_capsule_fast(cr, x, y, w, r1, r2); return; } if (w == 0) return; const double degree = M_PI / 180.0; int x_off = -(r1 - w); double angle1 = acos(1.0 - (w / 2.0) / (double)r1); double angle2 = acos(1.0 - (w / 2.0) / (double)r1); double left1 = 180 * degree - angle2, left2 = 180 * degree + angle1, right1 = 360 * degree - angle2, right2 = angle2; cairo_new_sub_path(cr); cairo_arc(cr, x + r1, y + r1, r2, left1, left2); cairo_arc(cr, x + x_off, y + r1, r2, right1, right2); cairo_close_path(cr); } int snprintf_units(char *buffer, size_t max, uint64_t bytes, unit_t unit) { int base = unit & UNIT_SI ? 1000 : 1024; double value = bytes; const char *label = ""; switch (unit & ~UNIT_SI) { case UNIT_B: break; case UNIT_TB: value /= base; // fallthrough case UNIT_GB: value /= base; // fallthrough case UNIT_MB: value /= base; // fallthrough case UNIT_KB: value /= base; break; default: { int i = 0; while (round(value) >= base && i < 4) { value /= base; i++; } const char *units[2][5] = { { " B", " kB", " MB", " GB", " TB" }, { " B", " KiB", " MiB", " GiB", " TiB" }, }; label = units[!(unit & UNIT_SI)][i]; break; } } int prec = 1; if (floor(value) >= 100.0) { value = ceil(value); prec = 0; } int ret = snprintf(buffer, max, "%.*lf%s", prec, value, label); assert(ret > 0); return ret; }