31 char *current = haystack;
32 while ((current = strchr(current, needle)))
33 *current++ = replacement;
43 int size, buf_len, repl_len;
45 buf_len = strlen(buf);
46 repl_len = strlen(repl);
47 size = (buf_len - len) + repl_len + 1;
49 if (repl_len <= len) {
53 memcpy(tmp, buf, pos);
56 memcpy(tmp + pos, repl, repl_len);
57 memmove(tmp + pos + repl_len, buf + pos + len, buf_len - (pos + len) + 1);
74 int needle_len, repl_len;
76 needle_len = strlen(needle);
77 if (needle_len == 0) {
81 start = strstr(haystack, needle);
82 repl_len = strlen(replacement);
85 needle_pos = start - haystack;
87 start = strstr(haystack + needle_pos + repl_len, needle);
103 new = g_strconcat(a, b, NULL);
105 new = g_strconcat(a, sep, b, NULL);
115 size_t len = strlen(value);
118 if (value[0] ==
'"' && value[len-1] ==
'"')
119 s = g_strndup(value + 1, len-2);
130 int iread=-1, iwrite=0, copen=0;
132 while (str[++iread] != 0) {
133 if (str[iread] == a) {
135 }
else if (str[iread] == b && copen > 0) {
137 }
else if (copen == 0) {
139 str[iwrite++] = str[iread];
147 for (
int i = 0; i < cskip; i++) {
148 str[iwrite++] = str[iread++];
158 arr = g_strsplit(
string, delimiter, 0);
159 for (
int i = 0; arr[i]; i++) {
183 switch (wordexp(
string, &we, WRDE_NOCMD | WRDE_UNDEF)) {
187 LOG_W(
"Expansion of \"%s\" failed. It contains invalid characters.",
string);
190 LOG_W(
"Expansion of \"%s\" failed. It contains an undefined variable.",
string);
193 LOG_W(
"Expansion of \"%s\" failed. The requested command substitution is currently not supported.",
string);
196 LOG_W(
"Expansion of \"%s\" failed. We ran out of memory.",
string);
199 LOG_W(
"Expansion of \"%s\" failed. It contains invalid syntax.",
string);
204 char *res = g_strjoinv(
" ", we.we_wordv);
213 long long val = g_ascii_strtoll(str, &endptr, 10);
216 LOG_W(
"'%s': %s.", str, strerror(errno));
218 }
else if (str == endptr) {
219 LOG_W(
"'%s': No digits found.", str);
221 }
else if (*endptr !=
'\0') {
222 LOG_W(
"'%s': String contains non-digits.", str);
235 if (l < INT_MIN || l > INT_MAX) {
237 LOG_W(
"'%s': %s.", str, strerror(errno));
248 double val = g_ascii_strtod(str, &endptr);
250 LOG_W(
"'%s': %s.", str, strerror(errno));
252 }
else if (str == endptr) {
253 LOG_W(
"'%s': No digits found.", str);
255 }
else if (*endptr !=
'\0') {
256 LOG_W(
"'%s': String contains non-digits.", str);
269 gint64 val = strtol(
string, &endptr, 10);
272 LOG_W(
"Time: '%s': %s.",
string, strerror(errno));
274 }
else if (
string == endptr) {
276 LOG_W(
"Time: '%s': No digits found.",
string);
278 }
else if (val < -1) {
281 LOG_W(
"Time: '%s': Time should be positive (-1 is allowed too sometimes)",
285 else if (errno == 0 && !*endptr) {
289 while (isspace(*endptr))
293 LOG_W(
"Time: '%s' signal value -1 should not have a suffix",
string);
300 else if (
STRN_EQ(endptr,
"s", 1))
302 else if (
STRN_EQ(endptr,
"m", 1))
303 return S2US(val) * 60;
304 else if (
STRN_EQ(endptr,
"h", 1))
305 return S2US(val) * 60 * 60;
306 else if (
STRN_EQ(endptr,
"d", 1))
307 return S2US(val) * 60 * 60 * 24;
317 struct timespec tv_now;
326 clock_gettime(CLOCK_BOOTTIME, &tv_now);
328 clock_gettime(CLOCK_MONOTONIC, &tv_now);
330 return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000;
335 struct timespec tv_now;
337 clock_gettime(CLOCK_REALTIME, &tv_now);
338 return S2US(tv_now.tv_sec) + tv_now.tv_nsec / 1000;
344 if (stat(path, &statbuf) != 0)
347 return S2US(statbuf.st_mtim.tv_sec) + statbuf.st_mtim.tv_nsec / 1000;
352 static const char *home_directory = NULL;
356 home_directory = getenv(
"HOME");
360 home_directory = getpwuid(getuid())->pw_dir;
362 return home_directory;
372 setenv(key, value, 1);
378static const char* special_sections[] = {
388static const char* deprecated_sections[] = {
393static const char* deprecated_sections_message[] = {
394 "The settings from the frame section have been moved to the global section.",
395 "Settings in the shortcuts sections have been moved to the global section.\nAlternatively you can bind shortcuts in your window manager to dunstctl commands. For that, see the manual for dunstctl.",
399 for (
size_t i = 0; i < G_N_ELEMENTS(special_sections); i++) {
400 if (
STR_EQ(special_sections[i], s)) {
408 for (
size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) {
409 if (
STR_EQ(deprecated_sections[i], s)) {
416const char *get_section_deprecation_message(
const char *s) {
417 for (
size_t i = 0; i < G_N_ELEMENTS(deprecated_sections); i++) {
418 if (
STR_EQ(deprecated_sections[i], s)) {
419 return deprecated_sections_message[i];
429 size_t len = strlen(s);
430 if (s[0] ==
'(' && s[len-1] ==
')')
431 return g_strndup(s + 1, len-2);
442 if (0 == stat(path, &statbuf)) {
444 if (!(statbuf.st_mode & (S_IFIFO | S_IFREG))) {
450 }
else if (0 == access(path, R_OK)) {
464 LOG_I(MSG_FOPEN_SUCCESS(path, f));
466 LOG_W(MSG_FOPEN_FAILURE(path));
473 const char *xdg_data_dirs = g_getenv(env_name);
475 xdg_data_dirs = alternative;
478 for (
int i = 0; xdg_data_dirs_arr[i] != NULL; i++) {
479 char *loc = g_build_filename(xdg_data_dirs_arr[i], subdir, NULL);
480 g_ptr_array_add(arr, loc);
482 g_strfreev(xdg_data_dirs_arr);
487 while (isspace(*str)) str++;
488 while (isdigit(*str)) str++;
489 while (isspace(*str)) str++;
497 return string[0] ==
'/' ||
string[0] ==
'~'
498 || (
string[0] ==
'.' &&
string[1] ==
'.' &&
string[2] ==
'/')
499 || (
string[0] ==
'.' &&
string[1] ==
'/');
Logging subsystem and helpers.
List of all the valid settings and values.
gint64 modification_time(const char *path)
Get the modification time of the file at path.
gint64 time_monotonic_now(void)
Get the current monotonic time.
bool safe_setenv(const char *key, const char *value)
Try to set an environment variable safely.
char * string_replace_at(char *buf, int pos, int len, const char *repl)
Replace a substring inside a string with another string.
bool string_is_int(const char *str)
Check if string contains digits.
bool is_like_path(const char *string)
Check if the strings looks like a path.
FILE * fopen_verbose(const char *const path)
Open files verbosely.
bool safe_string_to_long_long(long long *in, const char *str)
Same as safe_string_to_int, but then for a long.
const char * user_get_home(void)
Retrieve the HOME directory of the user running dunst.
int string_array_length(char **s)
Returns the length of a string array, -1 if the input is NULL.
bool is_readable_file(const char *const path)
Check if file is readable.
gint64 time_now(void)
Get the current real time.
char * string_strip_brackets(const char *s)
Strips a string of it's brackets if the first and last character are a bracket.
bool safe_string_to_double(double *in, const char *str)
Same as safe_string_to_int, but then for a double.
bool safe_string_to_int(int *in, const char *str)
Convert string to int in a safe way.
void string_strip_delimited(char *str, char a, char b)
Strip content between two delimiter characters.
char * string_to_path(char *string)
Replace tilde and path-specific values with it's equivalents.
char * string_strip_quotes(const char *value)
Strip quotes from a string, ignoring inner quotes.
bool is_deprecated_section(const char *s)
This function tells if a section is deprecated.
char * string_replace_all(const char *needle, const char *replacement, char *haystack)
Replace all occurences of a substring.
bool is_special_section(const char *s)
Some sections are handled differently in dunst.
char * string_append(char *a, const char *b, const char *sep)
Append b to string a, then concatenate both with sep (if they are non-empty).
void add_paths_from_env(GPtrArray *arr, char *env_name, char *subdir, char *alternative)
Adds the contents of env_name with subdir to the array, interpreting the environment variable as a co...
char ** string_to_array(const char *string, const char *delimiter)
Parse a string into a dynamic array of tokens, using the delimiter string.
char * string_replace_char(char needle, char replacement, char *haystack)
Replaces all occurrences of the char needle with the char replacement in haystack.
gint64 string_to_time(const char *string)
Convert time units (ms, s, m) to the internal gint64 microseconds format.
String, time and other various helpers.
#define STR_EMPTY(s)
Test if a string is NULL or empty.
#define S2US(s)
Convert seconds into microseconds.
#define STRN_EQ(a, b, n)
Test if string a and b are same up to n chars.
#define STR_EQ(a, b)
Test if string a and b contain the same chars.
#define ASSERT_OR_RET(expr, val)
Assert that expr evaluates to true, if not return val.