1 #define _POSIX_C_SOURCE 200112L
2 #include <signal.h>
3 #include <stdarg.h>
4 #include <stdio.h>
5 #include <stdlib.h>
6 #include <time.h>
7 #include <unistd.h>
8 #include "log.h"
9 
10 static terminate_callback_t log_terminate = exit;
11 
_sway_abort(const char * format,...)12 void _sway_abort(const char *format, ...) {
13 	va_list args;
14 	va_start(args, format);
15 	_sway_vlog(SWAY_ERROR, format, args);
16 	va_end(args);
17 	log_terminate(EXIT_FAILURE);
18 }
19 
_sway_assert(bool condition,const char * format,...)20 bool _sway_assert(bool condition, const char *format, ...) {
21 	if (condition) {
22 		return true;
23 	}
24 
25 	va_list args;
26 	va_start(args, format);
27 	_sway_vlog(SWAY_ERROR, format, args);
28 	va_end(args);
29 
30 #ifndef NDEBUG
31 	raise(SIGABRT);
32 #endif
33 
34 	return false;
35 }
36 
37 static bool colored = true;
38 static sway_log_importance_t log_importance = SWAY_ERROR;
39 static struct timespec start_time = {-1, -1};
40 
41 static const char *verbosity_colors[] = {
42 	[SWAY_SILENT] = "",
43 	[SWAY_ERROR ] = "\x1B[1;31m",
44 	[SWAY_INFO  ] = "\x1B[1;34m",
45 	[SWAY_DEBUG ] = "\x1B[1;90m",
46 };
47 
timespec_sub(struct timespec * r,const struct timespec * a,const struct timespec * b)48 static void timespec_sub(struct timespec *r, const struct timespec *a,
49 		const struct timespec *b) {
50 	const long NSEC_PER_SEC = 1000000000;
51 	r->tv_sec = a->tv_sec - b->tv_sec;
52 	r->tv_nsec = a->tv_nsec - b->tv_nsec;
53 	if (r->tv_nsec < 0) {
54 		r->tv_sec--;
55 		r->tv_nsec += NSEC_PER_SEC;
56 	}
57 }
58 
init_start_time(void)59 static void init_start_time(void) {
60 	if (start_time.tv_sec >= 0) {
61 		return;
62 	}
63 	clock_gettime(CLOCK_MONOTONIC, &start_time);
64 }
65 
sway_log_stderr(sway_log_importance_t verbosity,const char * fmt,va_list args)66 static void sway_log_stderr(sway_log_importance_t verbosity, const char *fmt,
67 		va_list args) {
68 	init_start_time();
69 
70 	if (verbosity > log_importance) {
71 		return;
72 	}
73 
74 	struct timespec ts = {0};
75 	clock_gettime(CLOCK_MONOTONIC, &ts);
76 	timespec_sub(&ts, &ts, &start_time);
77 
78 	fprintf(stderr, "%02d:%02d:%02d.%03ld ", (int)(ts.tv_sec / 60 / 60),
79 		(int)(ts.tv_sec / 60 % 60), (int)(ts.tv_sec % 60),
80 		ts.tv_nsec / 1000000);
81 
82 	unsigned c = (verbosity < SWAY_LOG_IMPORTANCE_LAST) ? verbosity :
83 		SWAY_LOG_IMPORTANCE_LAST - 1;
84 
85 	if (colored && isatty(STDERR_FILENO)) {
86 		fprintf(stderr, "%s", verbosity_colors[c]);
87 	}
88 
89 	vfprintf(stderr, fmt, args);
90 
91 	if (colored && isatty(STDERR_FILENO)) {
92 		fprintf(stderr, "\x1B[0m");
93 	}
94 	fprintf(stderr, "\n");
95 }
96 
sway_log_init(sway_log_importance_t verbosity,terminate_callback_t callback)97 void sway_log_init(sway_log_importance_t verbosity, terminate_callback_t callback) {
98 	init_start_time();
99 
100 	if (verbosity < SWAY_LOG_IMPORTANCE_LAST) {
101 		log_importance = verbosity;
102 	}
103 	if (callback) {
104 		log_terminate = callback;
105 	}
106 }
107 
_sway_vlog(sway_log_importance_t verbosity,const char * fmt,va_list args)108 void _sway_vlog(sway_log_importance_t verbosity, const char *fmt, va_list args) {
109 	sway_log_stderr(verbosity, fmt, args);
110 }
111 
_sway_log(sway_log_importance_t verbosity,const char * fmt,...)112 void _sway_log(sway_log_importance_t verbosity, const char *fmt, ...) {
113 	va_list args;
114 	va_start(args, fmt);
115 	sway_log_stderr(verbosity, fmt, args);
116 	va_end(args);
117 }
118