60#if defined __APPLE__ || defined _POSIX_C_SOURCE >= 1 || defined _XOPEN_SOURCE || defined _BSD_SOURCE \
61 || defined _SVID_SOURCE || defined _POSIX_SOURCE || defined __DragonFly__ || defined __FreeBSD__ \
62 || defined __NetBSD__ || defined __OpenBSD__
64 #include <sys/types.h>
75#include <glib/gi18n.h>
84#include <librsvg/rsvg.h>
87#include <librsvg/rsvg-cairo.h>
92 return str ? strlen(str) : 0;
99 va_start(args, format);
100 const size_t clen = str ? strlen(str) : 0;
101 const int alen = g_vsnprintf(NULL, 0, format, args);
102 const int nsize = alen + clen + 1;
105 ns = g_realloc(str, nsize);
110 va_start(args, format);
111 g_vsnprintf(ns + clen, alen + 1, format, args);
114 ns[nsize - 1] =
'\0';
122 if(haystack && needle)
124 const gchar *
p = haystack;
125 if((
p = g_strstr_len(
p, strlen(
p), needle)) != NULL)
130 }
while((
p = g_strstr_len((
p + 1), strlen(
p + 1), needle)) != NULL);
139 gchar *nstring = NULL;
143 nstring = g_malloc_n(strlen(
string) + (occurrences * strlen(substitute)) + 1,
sizeof(gchar));
144 const gchar *pend =
string + strlen(
string);
145 const gchar *s = string, *
p = string;
147 if((s = g_strstr_len(s, strlen(s), pattern)) != NULL)
151 memcpy(np,
p, s -
p);
153 memcpy(np, substitute, strlen(substitute));
154 np += strlen(substitute);
155 p = s + strlen(pattern);
156 }
while((s = g_strstr_len((s + 1), strlen(s + 1), pattern)) != NULL);
158 memcpy(np,
p, pend -
p);
162 nstring = g_strdup(
string);
170 const unsigned int count = g_list_length(
items);
171 gchar *result = NULL;
174 gchar **strings = g_malloc0_n(count + 1,
sizeof(gchar *));
180 strings[
i++] =
items->data;
185 result = g_strjoinv(separator, strings);
198 GList *last_item = NULL;
200 items = g_list_sort(
items, (GCompareFunc)g_strcmp0);
204 gchar *
value = (gchar *)iter->data;
205 if(!g_strcmp0(last,
value))
216 iter = g_list_next(iter);
234 const size_t len = strlen(path);
245 if(len > 1 && path[1] !=
'/')
247 while(path[off] !=
'\0' && path[off] !=
'/')
252 user = g_strndup(path + 1, off - 1);
260 return g_strdup(path);
263 rpath = g_build_filename(home_path, path + off, NULL);
268 rpath = g_strdup(path);
291 register const gchar *s = src;
292 while(s - src <
n && *s)
294 s = g_utf8_next_char(s);
300 s = g_utf8_prev_char(s);
301 strncpy(dest, src, s - src);
302 dest[s - src] =
'\0';
306 s = g_utf8_next_char(s);
312 strncpy(dest, src, s - src);
313 dest[s - src] =
'\0';
320 if(g_access(filename, R_OK))
return FALSE;
322 struct _stati64 stats;
329 wchar_t *wfilename = g_utf8_to_utf16(filename, -1, NULL, NULL, NULL);
330 const int result = _wstati64(wfilename, &stats);
332 if(result)
return FALSE;
335 if(stat(filename, &stats))
return FALSE;
338 const gboolean regular = (S_ISREG(stats.st_mode)) != 0;
339 const gboolean size_ok = stats.st_size > 0;
341 return regular && size_ok;
348 struct _stati64 stats;
350 wchar_t *wpath = g_utf8_to_utf16(path, -1, NULL, NULL, NULL);
351 const int result = _wstati64(wpath, &stats);
360 if(stat(path, &stats))
return FALSE;
362 if(S_ISDIR(stats.st_mode) == 0)
return FALSE;
363 if(g_access(path, W_OK | X_OK) != 0)
return FALSE;
372 return g_file_test(dir, G_FILE_TEST_IS_DIR);
378 GDir *dir = g_dir_open(dirname, 0, NULL);
381 while(g_dir_read_name(dir) != NULL)
396 if(g_utf8_validate(
string, -1, NULL))
397 tag = g_strdup(
string);
399 tag = g_convert(
string, -1,
"UTF-8",
"LATIN1", NULL, NULL, NULL);
403 tag = g_strdup(
string);
407 if((*c < 0x20) || (*c >= 0x7f)) *c =
'?';
417 const int a = Y % 19;
418 const int b = Y / 100;
419 const int c = Y % 100;
422 const int f = (b + 8) / 25;
423 const int g = (b -
f + 1) / 3;
424 const int h = (19*a + b -
d -
g + 15) % 30;
427 const int L = (32 + 2*e + 2*
i - h -
k) % 7;
428 const int m = (a + 11*h + 22*
L) / 451;
429 *month = (h +
L - 7*
m + 114) / 31;
430 *
day = ((h +
L - 7*
m + 114) % 31) + 1;
439 localtime_r(&now, <);
442 if((lt.tm_mon == 9 && lt.tm_mday == 31) || (lt.tm_mon == 10 && lt.tm_mday == 1))
450 struct tm easter_sunday = lt;
451 easter(lt.tm_year+1900, &easter_sunday.tm_mon, &easter_sunday.tm_mday);
452 easter_sunday.tm_mon--;
453 easter_sunday.tm_hour = easter_sunday.tm_min = easter_sunday.tm_sec = 0;
454 easter_sunday.tm_isdst = -1;
455 time_t easter_sunday_sec = mktime(&easter_sunday);
465 GError *
error = NULL;
466 cairo_surface_t *surface = NULL;
470 char *dtlogo = g_build_filename(datadir,
"pixmaps", logo, NULL);
471 RsvgHandle *svg = rsvg_handle_new_from_file(dtlogo, &
error);
483 const int stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, final_width);
485 guint8 *image_buffer = (guint8 *)calloc(stride * final_height,
sizeof(guint8));
488 final_height, stride);
490 surface = cairo_image_surface_create_for_data(image_buffer, CAIRO_FORMAT_ARGB32, final_width,
491 final_height, stride);
492 if(cairo_surface_status(surface) != CAIRO_STATUS_SUCCESS)
494 fprintf(stderr,
"warning: can't load darktable logo from SVG file `%s'\n", dtlogo);
495 cairo_surface_destroy(surface);
501 cairo_t *cr = cairo_create(surface);
505 cairo_surface_flush(surface);
511 fprintf(stderr,
"warning: can't load darktable logo from SVG file `%s'\n%s\n", dtlogo,
error->message);
526 logo = g_strdup_printf(
"idbutton-%d.svg", (
int)season);
528 logo = g_strdup(
"idbutton.svg");
542#define OSD_COORDINATES_CHR_N "N"
543#define OSD_COORDINATES_CHR_S "S"
544#define OSD_COORDINATES_CHR_E "E"
545#define OSD_COORDINATES_CHR_W "W"
554 float integral, fractional;
556 if(isnan(latitude))
return NULL;
560 latitude = fabsf(latitude);
564 fractional = modff(latitude, &integral);
566 return g_strdup_printf(
"%s %02d\302\260 %06.3f'", c, (
int)integral, fractional*60.0);
572 float integral, fractional;
574 if(isnan(longitude))
return NULL;
578 longitude = fabsf(longitude);
582 fractional = modff(longitude, &integral);
584 return g_strdup_printf(
"%s %03d\302\260 %06.3f'", c, (
int)integral, fractional*60.0);
591 if(isnan(elevation))
return NULL;
595 elevation = fabsf(elevation);
599 return g_strdup_printf(
"%.2f %s %s", elevation, _(
"m"), _(c));
609 gchar dir = toupper(input[strlen(input) - 1]);
610 gchar **list = g_strsplit(input,
",", 0);
614 res = g_ascii_strtoll(list[0], NULL, 10) + (g_ascii_strtod(list[1], NULL) / 60.0);
615 else if(list[3] == NULL)
616 res = g_ascii_strtoll(list[0], NULL, 10) + (g_ascii_strtoll(list[1], NULL, 10) / 60.0)
617 + (g_ascii_strtoll(list[2], NULL, 10) / 3600.0);
618 if(dir ==
'S' || dir ==
'W') res *= -1.0;
625 const double r1_2,
const double r2_1,
const double r2_2,
char sign,
631 double num, den,
min, sec;
634 if(den == 0)
return FALSE;
639 if(den == 0)
return FALSE;
641 if(
min != -1.0) res +=
min / 60.0;
654 if(sec != -1.0) res += sec / 3600.0;
656 if(
sign ==
'S' ||
sign ==
'W') res *= -1.0;
667 const double num = r_1;
668 const double den = r_2;
669 if(den == 0)
return FALSE;
672 if(
sign !=
'0') res *= -1.0;
684 if(g_utf8_validate(_input, -1, NULL))
685 input = g_strdup(_input);
688 input = g_locale_to_utf8(_input, -1, NULL, NULL, NULL);
692 const gchar *input = _input;
695 gchar *filename = g_filename_from_uri(input, NULL, NULL);
699 if(g_str_has_prefix(input,
"file://"))
702 input += strlen(
"file://");
703 filename = g_uri_unescape_string(input, NULL);
706 filename = g_strdup(input);
713 if(g_path_is_absolute(filename) ==
FALSE)
715 char *current_dir = g_get_current_dir();
716 char *tmp_filename = g_build_filename(current_dir, filename, NULL);
738 GFile *gfile = g_file_new_for_path(filename);
742 filename = g_file_get_path(gfile);
743 g_object_unref(gfile);
747 const char first = g_ascii_toupper(filename[0]);
748 if(first >=
'A' && first <=
'Z' && filename[1] ==
':')
753 else if(first ==
'\\' && filename[1] ==
'\\')
767const gboolean dt_util_path_is_UNC(
const gchar *filename)
769 return filename[0] == G_DIR_SEPARATOR && filename[1] == G_DIR_SEPARATOR;
776 gchar *dirname = g_path_get_dirname(filename);
781 int last = strlen(dirname) - 1;
782 if(G_IS_DIR_SEPARATOR(dirname[last]))
783 dirname[last] =
'\0';
793 GFile *file = g_file_new_for_path(path);
794 GError *
error = NULL;
795 GFileInfo *info = g_file_query_info(file, G_FILE_ATTRIBUTE_STANDARD_NAME
"," G_FILE_ATTRIBUTE_TIME_MODIFIED,
796 G_FILE_QUERY_INFO_NONE, NULL, &
error);
800 g_object_unref(file);
804 const guint64 datetime = g_file_info_get_attribute_uint64(info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
805 g_object_unref(file);
806 g_object_unref(info);
807 return g_date_time_new_from_unix_local(datetime);
816 if(text[0] == needle) count ++;
824 const struct lconv *currentLocalConv = localeconv();
825 const gchar loc_decimal_point = currentLocalConv->decimal_point[0];
826 const gchar *en_decimal_point =
".";
827 g_strdelimit(data, en_decimal_point, loc_decimal_point);
835 gchar *entry = g_strdup(text);
837 int len = strlen(prev);
840 gchar *next = g_strstr_len(prev, -1, separator);
843 const gchar c = next[0];
845 item = g_strdup(prev);
847 prev = next + strlen(separator);
849 list = g_list_prepend(list, item);
850 if(!len) list = g_list_prepend(list, g_strdup(
""));
854 item = g_strdup(prev);
856 list = g_list_prepend(list, item);
859 list = g_list_reverse(list);
868 if(exposuretime >= 1.0f)
870 if(nearbyintf(exposuretime) == exposuretime)
871 result = g_strdup_printf(
"%.0f\"", exposuretime);
873 result = g_strdup_printf(
"%.1f\"", exposuretime);
876 else if(exposuretime < 0.29f)
877 result = g_strdup_printf(
"1/%.0f", 1.0 / exposuretime);
880 else if(nearbyintf(1.0f / exposuretime) == 1.0f / exposuretime)
881 result = g_strdup_printf(
"1/%.0f", 1.0 / exposuretime);
884 else if(10 * nearbyintf(10.0f / exposuretime) == nearbyintf(100.0f / exposuretime))
885 result = g_strdup_printf(
"1/%.1f", 1.0 / exposuretime);
888 result = g_strdup_printf(
"%.1f\"", exposuretime);
895 if (filesize) *filesize = 0;
896 FILE *fd = g_fopen(filename,
"rb");
899 fseek(fd, 0, SEEK_END);
900 const size_t end = ftell(fd);
903 char *content = (
char *)malloc(
sizeof(
char) * end);
906 const size_t count = fread(content,
sizeof(
char), end, fd);
910 if (filesize) *filesize = end;
919 char *content = NULL;
920 FILE *fin = g_fopen(sourcefile,
"rb");
921 FILE *fout = g_fopen(dst,
"wb");
925 fseek(fin, 0, SEEK_END);
926 const size_t end = ftell(fin);
928 content = (
char *)g_malloc_n(end,
sizeof(
char));
930 if(fread(content,
sizeof(
char), end, fin) != end)
goto END;
931 if(fwrite(content,
sizeof(
char), end, fout) != end)
goto END;
945 gchar *sourcefile = g_build_filename(share, src, NULL);
954 #if LIBRSVG_CHECK_VERSION(2,52,0)
957 if(rsvg_handle_get_intrinsic_size_in_pixels(svg, &
width, &
height))
964#define VIEWPORT_SIZE 32767
965 const RsvgRectangle viewport = {
968 .width = VIEWPORT_SIZE,
969 .height = VIEWPORT_SIZE,
972 RsvgRectangle rectangle;
973 rsvg_handle_get_geometry_for_layer(svg, NULL, &viewport, NULL, &rectangle, NULL);
974 dimension.width = lround(rectangle.width);
975 dimension.height = lround(rectangle.height);
978 rsvg_handle_get_dimensions(svg, &
dimension);
986 #if LIBRSVG_CHECK_VERSION(2,52,0)
987 RsvgRectangle viewport = {
993 rsvg_handle_render_document(svg, cr, &viewport, NULL);
995 rsvg_handle_render_cairo(svg, cr);
1003 if(!filename1 || !filename2)
return FALSE;
1004 const char *dot1 = strrchr(filename1,
'.');
1006 const char *dot2 = strrchr(filename2,
'.');
1008 const int length1 = dot1 - filename1;
1009 const int length2 = dot2 - filename2;
1010 if(length1 != length2)
1012 for(
int i = length1 - 1;
i > 0;
i--)
1013 if(filename1[
i] != filename2[
i])
1022 if(!filename1 || !filename2)
return NULL;
1023 const char *dot1 = strrchr(filename1,
'.');
1025 const char *dot2 = strrchr(filename2,
'.');
1027 const int name_lgth = dot1 - filename1;
1028 const int ext_lgth = strlen(dot2);
1029 char *output = g_malloc(name_lgth + ext_lgth + 1);
1032 memcpy(output, filename1, name_lgth);
1033 memcpy(&output[name_lgth], &filename2[strlen(filename2) - ext_lgth], ext_lgth + 1);
1041 gchar **split = g_strsplit(
string, search, -1);
1042 gchar *res = g_strjoinv(replace, split);
1061 gchar **split = g_strsplit(path, G_DIR_SEPARATOR_S, -1);
1062 for(
int i = 0;
i < g_strv_length(split);
i++)
1063 if(g_strdup(split[
i]) != NULL ) g_strstrip(split[
i]);
1065 char* result = g_strjoinv(G_DIR_SEPARATOR_S, split);
static void error(char *msg)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
const dt_aligned_pixel_t f
static const float const float const float min
static const dt_aligned_pixel_simd_t sign
static const dt_aligned_pixel_simd_t value
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dt_loc_get_datadir(char *datadir, size_t bufsize)
gchar * dt_loc_get_home_dir(const gchar *user)
const dt_collection_sort_t items[]
static gchar * g_realpath(const char *path)
static cairo_surface_t * dt_cairo_image_surface_create_for_data(unsigned char *data, cairo_format_t format, int width, int height, int stride)
float *const restrict const size_t k
static const char *const day[7]
struct dt_gui_gtk_t * gui
gboolean dt_util_gps_elevation_to_number(const double r_1, const double r_2, char sign, double *result)
guint dt_util_string_count_char(const char *text, const char needle)
gchar * dt_util_str_replace(const gchar *string, const gchar *pattern, const gchar *substitute)
gchar * dt_util_longitude_str(float longitude)
gchar * dt_str_replace(const char *string, const char *search, const char *replace)
gboolean dt_has_same_path_basename(const char *filename1, const char *filename2)
void dt_util_str_to_loc_numbers_format(char *data)
#define OSD_COORDINATES_CHR_N
gchar * dt_cleanup_separators(gchar *string)
gchar * dt_util_elevation_str(float elevation)
gboolean dt_util_dir_exist(const char *dir)
dt_logo_season_t dt_util_get_logo_season(void)
RsvgDimensionData dt_get_svg_dimension(RsvgHandle *svg)
char * dt_read_file(const char *const filename, size_t *filesize)
static const char * OSD_ELEVATION_BSL
#define OSD_COORDINATES_CHR_S
cairo_surface_t * dt_util_get_logo_text(const float size)
static void easter(int Y, int *month, int *day)
GDateTime * dt_util_get_file_datetime(const char *const path)
GList * dt_util_str_to_glist(const gchar *separator, const gchar *text)
gboolean dt_util_test_image_file(const char *filename)
#define OSD_COORDINATES_CHR_W
void dt_copy_file(const char *const sourcefile, const char *dst)
void dt_copy_resource_file(const char *src, const char *dst)
guint dt_util_str_occurence(const gchar *haystack, const gchar *needle)
double dt_util_gps_string_to_number(const gchar *input)
gchar * dt_util_path_get_dirname(const gchar *filename)
gboolean dt_util_is_dir_empty(const char *dirname)
#define OSD_COORDINATES_CHR_E
gchar * dt_util_normalize_path(const gchar *_input)
size_t dt_utf8_strlcpy(char *dest, const char *src, size_t n)
size_t safe_strlen(const char *str)
check if the string is empty or NULL before calling strlen()
char * dt_util_format_exposure(const float exposuretime)
gboolean dt_util_test_writable_dir(const char *path)
gboolean dt_util_gps_rationale_to_number(const double r0_1, const double r0_2, const double r1_1, const double r1_2, const double r2_1, const double r2_2, char sign, double *result)
gchar * dt_util_fix_path(const gchar *path)
gchar * dt_util_foo_to_utf8(const char *string)
gchar * dt_util_latitude_str(float latitude)
gchar * dt_util_remove_whitespace(const gchar *path)
void dt_render_svg(RsvgHandle *svg, cairo_t *cr, double width, double height, double offset_x, double offset_y)
static const char * OSD_ELEVATION_ASL
gchar * dt_util_glist_to_str(const gchar *separator, GList *items)
char * dt_copy_filename_extension(const char *filename1, const char *filename2)
static cairo_surface_t * _util_get_svg_img(gchar *logo, const float size)
gchar * dt_util_dstrcat(gchar *str, const gchar *format,...)
GList * dt_util_glist_uniq(GList *items)
cairo_surface_t * dt_util_get_logo(const float size)
@ DT_LOGO_SEASON_HALLOWEEN