diff options
Diffstat (limited to 'src')
72 files changed, 26793 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..add035f --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,4 @@ + +SUBDIRS = lib bin tests + +MAINTAINERCLEANFILES = Makefile.in diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..e07c928 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,618 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +SUBDIRS = lib bin tests +MAINTAINERCLEANFILES = Makefile.in +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile +installdirs: installdirs-recursive +installdirs-am: +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs installdirs-am maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-generic \ + mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \ + uninstall uninstall-am + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/bin/Makefile.am b/src/bin/Makefile.am new file mode 100644 index 0000000..3040a20 --- /dev/null +++ b/src/bin/Makefile.am @@ -0,0 +1,29 @@ + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +@EFREET_CFLAGS@ + +internal_bindir=$(libdir)/efreet +internal_bin_PROGRAMS = \ +efreet_desktop_cache_create \ +efreet_icon_cache_create + +efreet_desktop_cache_create_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_desktop_cache_create_SOURCES = \ +efreet_desktop_cache_create.c + +efreet_icon_cache_create_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_icon_cache_create_SOURCES = \ +efreet_icon_cache_create.c diff --git a/src/bin/Makefile.in b/src/bin/Makefile.in new file mode 100644 index 0000000..bd9ba1f --- /dev/null +++ b/src/bin/Makefile.in @@ -0,0 +1,622 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +internal_bin_PROGRAMS = efreet_desktop_cache_create$(EXEEXT) \ + efreet_icon_cache_create$(EXEEXT) +subdir = src/bin +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(internal_bindir)" +PROGRAMS = $(internal_bin_PROGRAMS) +am_efreet_desktop_cache_create_OBJECTS = \ + efreet_desktop_cache_create.$(OBJEXT) +efreet_desktop_cache_create_OBJECTS = \ + $(am_efreet_desktop_cache_create_OBJECTS) +efreet_desktop_cache_create_DEPENDENCIES = \ + $(top_builddir)/src/lib/libefreet.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_efreet_icon_cache_create_OBJECTS = \ + efreet_icon_cache_create.$(OBJEXT) +efreet_icon_cache_create_OBJECTS = \ + $(am_efreet_icon_cache_create_OBJECTS) +efreet_icon_cache_create_DEPENDENCIES = \ + $(top_builddir)/src/lib/libefreet.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(efreet_desktop_cache_create_SOURCES) \ + $(efreet_icon_cache_create_SOURCES) +DIST_SOURCES = $(efreet_desktop_cache_create_SOURCES) \ + $(efreet_icon_cache_create_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +MAINTAINERCLEANFILES = Makefile.in +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +@EFREET_CFLAGS@ + +internal_bindir = $(libdir)/efreet +efreet_desktop_cache_create_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_desktop_cache_create_SOURCES = \ +efreet_desktop_cache_create.c + +efreet_icon_cache_create_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_icon_cache_create_SOURCES = \ +efreet_icon_cache_create.c + +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/bin/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/bin/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-internal_binPROGRAMS: $(internal_bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(internal_bindir)" || $(MKDIR_P) "$(DESTDIR)$(internal_bindir)" + @list='$(internal_bin_PROGRAMS)'; test -n "$(internal_bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(internal_bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(internal_bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-internal_binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(internal_bin_PROGRAMS)'; test -n "$(internal_bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(internal_bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(internal_bindir)" && rm -f $$files + +clean-internal_binPROGRAMS: + @list='$(internal_bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +efreet_desktop_cache_create$(EXEEXT): $(efreet_desktop_cache_create_OBJECTS) $(efreet_desktop_cache_create_DEPENDENCIES) + @rm -f efreet_desktop_cache_create$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_desktop_cache_create_OBJECTS) $(efreet_desktop_cache_create_LDADD) $(LIBS) +efreet_icon_cache_create$(EXEEXT): $(efreet_icon_cache_create_OBJECTS) $(efreet_icon_cache_create_DEPENDENCIES) + @rm -f efreet_icon_cache_create$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_icon_cache_create_OBJECTS) $(efreet_icon_cache_create_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_desktop_cache_create.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_icon_cache_create.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(internal_bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-internal_binPROGRAMS clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-internal_binPROGRAMS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-internal_binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-internal_binPROGRAMS clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am \ + install-internal_binPROGRAMS install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-internal_binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/bin/efreet_desktop_cache_create.c b/src/bin/efreet_desktop_cache_create.c new file mode 100644 index 0000000..c397022 --- /dev/null +++ b/src/bin/efreet_desktop_cache_create.c @@ -0,0 +1,541 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include <Eina.h> +#include <Eet.h> +#include <Ecore.h> +#include <Ecore_File.h> + +#define EFREET_MODULE_LOG_DOM _efreet_desktop_cache_log_dom +static int _efreet_desktop_cache_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_cache_private.h" + +static Eet_Data_Descriptor *edd = NULL; +static Eet_File *ef = NULL; +static Eet_File *util_ef = NULL; + +static Eina_Hash *desktops = NULL; + +static Eina_Hash *file_ids = NULL; +static Efreet_Cache_Hash *old_file_ids = NULL; +static Eina_Hash *paths = NULL; + +static Eina_Hash *mime_types = NULL; +static Eina_Hash *categories = NULL; +static Eina_Hash *startup_wm_class = NULL; +static Eina_Hash *name = NULL; +static Eina_Hash *generic_name = NULL; +static Eina_Hash *comment = NULL; +static Eina_Hash *exec = NULL; + +static int +strcmplen(const void *data1, const void *data2) +{ + return strncmp(data1, data2, eina_stringshare_strlen(data1)); +} + +static int +cache_add(const char *path, const char *file_id, int priority __UNUSED__, int *changed) +{ + Efreet_Desktop *desk; + char *ext; + + INF("FOUND: %s", path); + if (file_id) INF(" (id): %s", file_id); + ext = strrchr(path, '.'); + if (!ext || (strcmp(ext, ".desktop") && strcmp(ext, ".directory"))) return 1; + desk = efreet_desktop_new(path); + if (desk) INF(" OK"); + else INF(" FAIL"); + if (!desk) return 1; + if (!desk->eet) + { + /* This file isn't in cache */ + *changed = 1; + INF(" NEW"); + } + else if (ecore_file_mod_time(desk->orig_path) != desk->load_time) + { + efreet_desktop_free(desk); + *changed = 1; + desk = efreet_desktop_uncached_new(path); + if (desk) INF(" CHANGED"); + else INF(" NO UNCACHED"); + } + if (!desk) return 1; + if (file_id && old_file_ids && !eina_hash_find(old_file_ids->hash, file_id)) + { + *changed = 1; + INF(" NOT IN UTILS"); + } + if (!eina_hash_find(paths, desk->orig_path)) + { + if (!eet_data_write(ef, edd, desk->orig_path, desk, 0)) + return 0; + eina_hash_add(paths, desk->orig_path, (void *)1); + } + /* TODO: We should check priority, and not just hope we search in right order */ + /* TODO: We need to find out if prioritized file id has changed because of + * changed search order. */ + if (!desk->hidden && desk->type == EFREET_DESKTOP_TYPE_APPLICATION && + file_id && !eina_hash_find(file_ids, file_id)) + { + Eina_List *l; + char *data; + Efreet_Cache_Array_String *array; + +#define ADD_LIST(list, hash) \ + EINA_LIST_FOREACH((list), l, data) \ + { \ + array = eina_hash_find((hash), data); \ + if (!array) \ + array = NEW(Efreet_Cache_Array_String, 1); \ + array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \ + array->array[array->array_count++] = desk->orig_path; \ + eina_hash_set((hash), data, array); \ + } +#define ADD_ELEM(elem, hash) \ + if ((elem)) \ + { \ + data = (elem); \ + array = eina_hash_find((hash), data); \ + if (!array) \ + array = NEW(Efreet_Cache_Array_String, 1); \ + array->array = realloc(array->array, sizeof (char *) * (array->array_count + 1)); \ + array->array[array->array_count++] = desk->orig_path; \ + eina_hash_set((hash), data, array); \ + } + ADD_LIST(desk->mime_types, mime_types); + ADD_LIST(desk->categories, categories); + ADD_ELEM(desk->startup_wm_class, startup_wm_class); + ADD_ELEM(desk->name, name); + ADD_ELEM(desk->generic_name, generic_name); + ADD_ELEM(desk->comment, comment); + ADD_ELEM(desk->exec, exec); + eina_hash_add(file_ids, file_id, desk->orig_path); + eina_hash_add(desktops, desk->orig_path, desk); + } + else + efreet_desktop_free(desk); + return 1; +} + + +static int +cache_scan(const char *path, const char *base_id, int priority, int recurse, int *changed) +{ + char *file_id = NULL; + char id[PATH_MAX]; + char buf[PATH_MAX]; + Eina_Iterator *it; + Eina_File_Direct_Info *info; + + if (!ecore_file_is_dir(path)) return 1; + + it = eina_file_direct_ls(path); + if (!it) return 1; + + id[0] = '\0'; + EINA_ITERATOR_FOREACH(it, info) + { + const char *fname; + + fname = info->path + info->name_start; + if (base_id) + { + if (*base_id) + snprintf(id, sizeof(id), "%s-%s", base_id, fname); + else + strcpy(id, fname); + file_id = id; + } + + snprintf(buf, sizeof(buf), "%s/%s", path, fname); + if (ecore_file_is_dir(buf)) + { + if (recurse) + cache_scan(buf, file_id, priority, recurse, changed); + } + else + { + if (!cache_add(buf, file_id, priority, changed)) + { + eina_iterator_free(it); + return 0; + } + } + } + eina_iterator_free(it); + return 1; +} + +static int +cache_lock_file(void) +{ + char file[PATH_MAX]; + struct flock fl; + int lockfd; + + snprintf(file, sizeof(file), "%s/efreet/desktop_data.lock", efreet_cache_home_get()); + lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (lockfd < 0) return -1; + efreet_fsetowner(lockfd); + + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if (fcntl(lockfd, F_SETLK, &fl) < 0) + { + INF("LOCKED! You may want to delete %s if this persists", file); + close(lockfd); + return -1; + } + + return lockfd; +} + +int +main(int argc, char **argv) +{ + /* TODO: + * - Add file monitor on files, so that we catch changes on files + * during whilst this program runs. + * - Maybe linger for a while to reduce number of cache re-creates. + */ + Efreet_Cache_Hash hash; + Efreet_Cache_Version version; + Eina_List *dirs = NULL; + Eina_List *systemdirs = NULL; + Efreet_Cache_Array_String *user_dirs = NULL; + Eina_List *extra_dirs = NULL; + Eina_List *store_dirs = NULL; + int priority = 0; + char *dir = NULL; + char *path; + int lockfd = -1, tmpfd; + int changed = 0; + int i; + char file[PATH_MAX] = { '\0' }; + char util_file[PATH_MAX] = { '\0' }; + + if (!eina_init()) goto eina_error; + _efreet_desktop_cache_log_dom = + eina_log_domain_register("efreet_desktop_cache", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_desktop_cache_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop_cache."); + return -1; + } + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-v")) + eina_log_domain_level_set("efreet_desktop_cache", EINA_LOG_LEVEL_DBG); + else if ((!strcmp(argv[i], "-h")) || + (!strcmp(argv[i], "-help")) || + (!strcmp(argv[i], "--h")) || + (!strcmp(argv[i], "--help"))) + { + printf("Options:\n"); + printf(" -v Verbose mode\n"); + printf(" -d dir1 dir2 Extra dirs\n"); + exit(0); + } + else if (!strcmp(argv[i], "-d")) + { + while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) + extra_dirs = eina_list_append(extra_dirs, argv[++i]); + } + } + extra_dirs = eina_list_sort(extra_dirs, -1, EINA_COMPARE_CB(strcmp)); + + /* init external subsystems */ + if (!eet_init()) goto eet_error; + if (!ecore_init()) goto ecore_error; + + efreet_cache_update = 0; + /* finish efreet init */ + if (!efreet_init()) goto efreet_error; + + /* create homedir */ + snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get()); + if (!ecore_file_exists(file)) + { + if (!ecore_file_mkpath(file)) goto efreet_error; + efreet_setowner(file); + } + + /* lock process, so that we only run one copy of this program */ + lockfd = cache_lock_file(); + if (lockfd == -1) goto efreet_error; + + edd = efreet_desktop_edd(); + if (!edd) goto edd_error; + + /* read user dirs from old cache */ + ef = eet_open(efreet_desktop_cache_file(), EET_FILE_MODE_READ); + if (ef) + { + user_dirs = eet_data_read(ef, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS); + eet_close(ef); + } + + ef = eet_open(efreet_desktop_util_cache_file(), EET_FILE_MODE_READ); + if (ef) + { + old_file_ids = eet_data_read(ef, efreet_hash_string_edd(), "file_id"); + eet_close(ef); + } + + /* create cache */ + snprintf(file, sizeof(file), "%s.XXXXXX", efreet_desktop_cache_file()); + tmpfd = mkstemp(file); + if (tmpfd < 0) goto error; + close(tmpfd); + ef = eet_open(file, EET_FILE_MODE_READ_WRITE); + if (!ef) goto error; + + snprintf(util_file, sizeof(util_file), "%s.XXXXXX", efreet_desktop_util_cache_file()); + tmpfd = mkstemp(util_file); + if (tmpfd < 0) goto error; + close(tmpfd); + util_ef = eet_open(util_file, EET_FILE_MODE_READ_WRITE); + if (!util_ef) goto error; + + /* write cache version */ + version.major = EFREET_DESKTOP_UTILS_CACHE_MAJOR; + version.minor = EFREET_DESKTOP_UTILS_CACHE_MINOR; + eet_data_write(util_ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1); + version.major = EFREET_DESKTOP_CACHE_MAJOR; + version.minor = EFREET_DESKTOP_CACHE_MINOR; + eet_data_write(ef, efreet_version_edd(), EFREET_CACHE_VERSION, &version, 1); + + desktops = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_desktop_free)); + + file_ids = eina_hash_string_superfast_new(NULL); + paths = eina_hash_string_superfast_new(NULL); + + mime_types = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + categories = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + startup_wm_class = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + generic_name = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + comment = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + exec = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + + dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(), + "applications"); + if (!dirs) goto error; + + EINA_LIST_FREE(dirs, path) + { + char file_id[PATH_MAX] = { '\0' }; + + if (!cache_scan(path, file_id, priority++, 1, &changed)) goto error; + systemdirs = eina_list_append(systemdirs, path); + } + + if (user_dirs) + { + unsigned int j; + + for (j = 0; j < user_dirs->array_count; j++) + { + if (eina_list_search_unsorted_list(systemdirs, strcmplen, user_dirs->array[j])) + continue; + if (!ecore_file_is_dir(user_dirs->array[j])) continue; + if (!cache_scan(user_dirs->array[j], NULL, priority, 0, &changed)) goto error; + + store_dirs = eina_list_append(store_dirs, user_dirs->array[j]); + } + store_dirs = eina_list_sort(store_dirs, -1, EINA_COMPARE_CB(strcmp)); + } + + if (extra_dirs) + { + Eina_List *l; + + EINA_LIST_FOREACH(extra_dirs, l, path) + { + if (eina_list_search_unsorted_list(systemdirs, strcmplen, path)) + continue; + if (eina_list_search_unsorted_list(store_dirs, EINA_COMPARE_CB(strcmp), path)) + continue; + if (!ecore_file_is_dir(path)) continue; + + /* If we scan a passed dir, we must have changed */ + changed = 1; + if (!cache_scan(path, NULL, priority, 0, &changed)) goto error; + + store_dirs = eina_list_append(store_dirs, path); + } + store_dirs = eina_list_sort(store_dirs, -1, EINA_COMPARE_CB(strcmp)); + } + + if (user_dirs) + efreet_cache_array_string_free(user_dirs); + + /* store user dirs */ + if (store_dirs) + { + Eina_List *l; + + user_dirs = NEW(Efreet_Cache_Array_String, 1); + user_dirs->array = NEW(char *, eina_list_count(store_dirs)); + user_dirs->array_count = 0; + EINA_LIST_FOREACH(store_dirs, l, path) + user_dirs->array[user_dirs->array_count++] = path; + + eet_data_write(ef, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS, user_dirs, 1); + IF_FREE(user_dirs->array); + free(user_dirs); + } + + /* store util */ +#define STORE_HASH_ARRAY(_hash) \ + if (eina_hash_population((_hash)) > 0) \ + { \ + Eina_Iterator *it; \ + Efreet_Cache_Array_String array; \ + const char *str; \ + \ + hash.hash = (_hash); \ + eet_data_write(util_ef, efreet_hash_array_string_edd(), #_hash "_hash", &hash, 1); \ + array.array_count = 0; \ + array.array = malloc(eina_hash_population(hash.hash) * sizeof(char *)); \ + it = eina_hash_iterator_key_new(hash.hash); \ + EINA_ITERATOR_FOREACH(it, str) \ + array.array[array.array_count++] = str; \ + eina_iterator_free(it); \ + eet_data_write(util_ef, efreet_array_string_edd(), #_hash "_list", &array, 1); \ + free(array.array); \ + } + STORE_HASH_ARRAY(mime_types); + STORE_HASH_ARRAY(categories); + STORE_HASH_ARRAY(startup_wm_class); + STORE_HASH_ARRAY(name); + STORE_HASH_ARRAY(generic_name); + STORE_HASH_ARRAY(comment); + STORE_HASH_ARRAY(exec); + if (eina_hash_population(file_ids) > 0) + { + hash.hash = file_ids; + eet_data_write(util_ef, efreet_hash_string_edd(), "file_id", &hash, 1); + } + + eina_hash_free(mime_types); + eina_hash_free(categories); + eina_hash_free(startup_wm_class); + eina_hash_free(name); + eina_hash_free(generic_name); + eina_hash_free(comment); + eina_hash_free(exec); + + if (old_file_ids) + { + eina_hash_free(old_file_ids->hash); + free(old_file_ids); + } + + eina_hash_free(file_ids); + eina_hash_free(paths); + + eina_hash_free(desktops); + + /* check if old and new caches contain the same number of entries */ + if (!changed) + { + Eet_File *old; + + old = eet_open(efreet_desktop_cache_file(), EET_FILE_MODE_READ); + if (!old || eet_num_entries(old) != eet_num_entries(ef)) changed = 1; + if (old) eet_close(old); + old = eet_open(efreet_desktop_util_cache_file(), EET_FILE_MODE_READ); + if (!old || eet_num_entries(old) != eet_num_entries(util_ef)) changed = 1; + if (old) eet_close(old); + } + + /* cleanup */ + eet_close(util_ef); + eet_close(ef); + + /* unlink old cache files */ + if (changed) + { + if (unlink(efreet_desktop_cache_file()) < 0) + { + if (errno != ENOENT) goto error; + } + if (unlink(efreet_desktop_util_cache_file()) < 0) + { + if (errno != ENOENT) goto error; + } + /* rename tmp files to real files */ + if (rename(util_file, efreet_desktop_util_cache_file()) < 0) goto error; + efreet_setowner(efreet_desktop_util_cache_file()); + if (rename(file, efreet_desktop_cache_file()) < 0) goto error; + efreet_setowner(efreet_desktop_cache_file()); + } + else + { + unlink(util_file); + unlink(file); + } + + /* touch update file */ + snprintf(file, sizeof(file), "%s/efreet/desktop_data.update", efreet_cache_home_get()); + tmpfd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (tmpfd >= 0) + { + char c = 'n'; + + efreet_fsetowner(tmpfd); + if (changed) c = 'c'; + if (write(tmpfd, &c, 1) != 1) perror("write"); + close(tmpfd); + } + + EINA_LIST_FREE(systemdirs, dir) + eina_stringshare_del(dir); + eina_list_free(extra_dirs); + eina_list_free(store_dirs); + efreet_shutdown(); + ecore_shutdown(); + eet_shutdown(); + eina_log_domain_unregister(_efreet_desktop_cache_log_dom); + eina_shutdown(); + close(lockfd); + return 0; +error: + IF_FREE(dir); +edd_error: + if (user_dirs) efreet_cache_array_string_free(user_dirs); + if (old_file_ids) + { + eina_hash_free(old_file_ids->hash); + free(old_file_ids); + } + efreet_shutdown(); +efreet_error: + ecore_shutdown(); +ecore_error: + eet_shutdown(); +eet_error: + EINA_LIST_FREE(systemdirs, dir) + eina_stringshare_del(dir); + eina_list_free(extra_dirs); + eina_list_free(store_dirs); + eina_log_domain_unregister(_efreet_desktop_cache_log_dom); + eina_shutdown(); +eina_error: + if (lockfd >= 0) close(lockfd); + return 1; +} diff --git a/src/bin/efreet_icon_cache_create.c b/src/bin/efreet_icon_cache_create.c new file mode 100644 index 0000000..e8d100c --- /dev/null +++ b/src/bin/efreet_icon_cache_create.c @@ -0,0 +1,1131 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include <Eina.h> +#include <Eet.h> +#include <Ecore.h> +#include <Ecore_File.h> + +#define EFREET_MODULE_LOG_DOM _efreet_icon_cache_log_dom +static int _efreet_icon_cache_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_cache_private.h" + +/* TODO: + * - Need to handle programs using different exts + */ + +static Eina_Array *exts = NULL; +static Eina_Array *extra_dirs = NULL; +static Eina_Array *strs = NULL; +static Eina_Hash *icon_themes = NULL; + +static Eina_Bool +cache_directory_modified(Eina_Hash *dirs, const char *dir) +{ + Efreet_Cache_Directory *dcache; + struct stat st; + + if (!dirs) return EINA_TRUE; + + if (stat(dir, &st) < 0) return EINA_FALSE; + dcache = eina_hash_find(dirs, dir); + if (!dcache) + { + dcache = malloc(sizeof (Efreet_Cache_Directory)); + if (!dcache) return EINA_TRUE; + + dcache->modified_time = (long long) st.st_mtime; + eina_hash_add(dirs, dir, dcache); + } + else if (dcache->modified_time == (long long) st.st_mtime) return EINA_FALSE; + dcache->modified_time = st.st_mtime; + + return EINA_TRUE; +} + +static Eina_Bool +cache_extension_lookup(const char *ext) +{ + unsigned int i; + + for (i = 0; i < exts->count; ++i) + if (!strcmp(exts->data[i], ext)) + return EINA_TRUE; + return EINA_FALSE; +} + +static Eina_Bool +cache_fallback_scan_dir(Eina_Hash *icons, Eina_Hash *dirs, const char *dir) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *entry; + + if (!cache_directory_modified(dirs, dir)) return EINA_TRUE; + + it = eina_file_stat_ls(dir); + if (!it) return EINA_TRUE; + + EINA_ITERATOR_FOREACH(it, entry) + { + Efreet_Cache_Fallback_Icon *icon; + char *name; + char *ext; + unsigned int i; + + if (entry->type == EINA_FILE_DIR) + continue; + + ext = strrchr(entry->path + entry->name_start, '.'); + if (!ext || !cache_extension_lookup(ext)) + continue; + + /* icon with known extension */ + name = entry->path + entry->name_start; + *ext = '\0'; + + icon = eina_hash_find(icons, name); + if (!icon) + { + icon = NEW(Efreet_Cache_Fallback_Icon, 1); + icon->theme = NULL; + eina_hash_add(icons, name, icon); + } + + *ext = '.'; + + for (i = 0; i < icon->icons_count; ++i) + if (!strcmp(icon->icons[i], entry->path)) + break; + + if (i != icon->icons_count) + continue; + + icon->icons = realloc(icon->icons, sizeof (char *) * (icon->icons_count + 1)); + icon->icons[icon->icons_count] = eina_stringshare_add(entry->path); + eina_array_push(strs, icon->icons[icon->icons_count++]); + } + + eina_iterator_free(it); + + return EINA_TRUE; +} + +static Eina_Bool +cache_fallback_scan(Eina_Hash *icons, Eina_Hash *dirs) +{ + unsigned int i; + Eina_List *xdg_dirs, *l; + const char *dir; + char path[PATH_MAX]; + + for (i = 0; i < extra_dirs->count; i++) + cache_fallback_scan_dir(icons, dirs, extra_dirs->data[i]); + + cache_fallback_scan_dir(icons, dirs, efreet_icon_deprecated_user_dir_get()); + cache_fallback_scan_dir(icons, dirs, efreet_icon_user_dir_get()); + + xdg_dirs = efreet_data_dirs_get(); + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(path, sizeof(path), "%s/icons", dir); + cache_fallback_scan_dir(icons, dirs, path); + } + +#ifndef STRICT_SPEC + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(path, sizeof(path), "%s/pixmaps", dir); + cache_fallback_scan_dir(icons, dirs, path); + } +#endif + + cache_fallback_scan_dir(icons, dirs, "/usr/share/pixmaps"); + + return EINA_TRUE; +} + +static Eina_Bool +check_fallback_changed(Efreet_Cache_Icon_Theme *theme) +{ + unsigned int i; + Eina_List *xdg_dirs, *l; + const char *dir; + char path[PATH_MAX]; + + /* Check if the dirs we have cached are changed */ + if (theme->dirs) + { + Eina_Iterator *it; + Eina_Bool changed = EINA_FALSE; + + it = eina_hash_iterator_key_new(theme->dirs); + EINA_ITERATOR_FOREACH(it, dir) + { + changed = !ecore_file_exists(dir); + if (changed) break; + changed = cache_directory_modified(theme->dirs, dir); + if (changed) break; + } + eina_iterator_free(it); + if (changed) return EINA_TRUE; + } + + /* Check if spec dirs have changed */ + for (i = 0; i < extra_dirs->count; i++) + if (cache_directory_modified(theme->dirs, extra_dirs->data[i])) return EINA_TRUE; + + if (cache_directory_modified(theme->dirs, efreet_icon_deprecated_user_dir_get())) return EINA_TRUE; + if (cache_directory_modified(theme->dirs, efreet_icon_user_dir_get())) return EINA_TRUE; + + xdg_dirs = efreet_data_dirs_get(); + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(path, sizeof(path), "%s/icons", dir); + if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE; + } + +#ifndef STRICT_SPEC + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(path, sizeof(path), "%s/pixmaps", dir); + if (cache_directory_modified(theme->dirs, path)) return EINA_TRUE; + } +#endif + + if (cache_directory_modified(theme->dirs, "/usr/share/pixmaps")) return EINA_TRUE; + return EINA_FALSE; +} + +static Eina_Bool +cache_scan_path_dir(Efreet_Icon_Theme *theme, + const char *path, + Efreet_Icon_Theme_Directory *dir, + Eina_Hash *icons) +{ + Eina_Iterator *it; + char buf[PATH_MAX]; + Eina_File_Direct_Info *entry; + + snprintf(buf, sizeof(buf), "%s/%s", path, dir->name); + + it = eina_file_stat_ls(buf); + if (!it) return EINA_TRUE; + + EINA_ITERATOR_FOREACH(it, entry) + { + Efreet_Cache_Icon *icon; + char *name; + char *ext; + unsigned int i; + + if (entry->type == EINA_FILE_DIR) + continue; + + ext = strrchr(entry->path + entry->name_start, '.'); + if (!ext || !cache_extension_lookup(ext)) + continue; + + /* icon with known extension */ + name = entry->path + entry->name_start; + *ext = '\0'; + + icon = eina_hash_find(icons, name); + if (!icon) + { + icon = NEW(Efreet_Cache_Icon, 1); + icon->theme = eina_stringshare_add(theme->name.internal); + eina_array_push(strs, icon->theme); + eina_hash_add(icons, name, icon); + } + else if (icon->theme && strcmp(icon->theme, theme->name.internal)) + { + /* We got this icon from a parent theme */ + continue; + } + + /* find if we have the same icon in another type */ + for (i = 0; i < icon->icons_count; ++i) + { + if ((icon->icons[i]->type == dir->type) && + (icon->icons[i]->normal == dir->size.normal) && + (icon->icons[i]->max == dir->size.max) && + (icon->icons[i]->min == dir->size.min)) + break; + } + + *ext = '.'; + + if (i != icon->icons_count) + { + unsigned int j; + + /* check if the path already exist */ + for (j = 0; j < icon->icons[i]->paths_count; ++j) + if (!strcmp(icon->icons[i]->paths[j], entry->path)) + break; + + if (j != icon->icons[i]->paths_count) + continue; + } + /* no icon match so add a new one */ + else + { + icon->icons = realloc(icon->icons, + sizeof (Efreet_Cache_Icon_Element*) * (++icon->icons_count)); + icon->icons[i] = NEW(Efreet_Cache_Icon_Element, 1); + icon->icons[i]->type = dir->type; + icon->icons[i]->normal = dir->size.normal; + icon->icons[i]->min = dir->size.min; + icon->icons[i]->max = dir->size.max; + icon->icons[i]->paths = NULL; + icon->icons[i]->paths_count = 0; + } + + /* and finally store the path */ + icon->icons[i]->paths = realloc(icon->icons[i]->paths, + sizeof (char*) * (icon->icons[i]->paths_count + 1)); + icon->icons[i]->paths[icon->icons[i]->paths_count] = eina_stringshare_add(entry->path); + eina_array_push(strs, icon->icons[i]->paths[icon->icons[i]->paths_count++]); + } + + eina_iterator_free(it); + + return EINA_TRUE; +} + +static Eina_Bool +cache_scan_path(Efreet_Icon_Theme *theme, Eina_Hash *icons, const char *path) +{ + Eina_List *l; + Efreet_Icon_Theme_Directory *dir; + + EINA_LIST_FOREACH(theme->directories, l, dir) + if (!cache_scan_path_dir(theme, path, dir, icons)) return EINA_FALSE; + + return EINA_TRUE; +} + +static Eina_Bool +cache_scan(Efreet_Icon_Theme *theme, Eina_Hash *themes, Eina_Hash *icons) +{ + Eina_List *l; + const char *path; + const char *name; + + if (!theme) return EINA_TRUE; + if (eina_hash_find(themes, theme->name.internal)) return EINA_TRUE; + eina_hash_direct_add(themes, theme->name.internal, theme); + + /* scan theme */ + EINA_LIST_FOREACH(theme->paths, l, path) + if (!cache_scan_path(theme, icons, path)) return EINA_FALSE; + + /* scan inherits */ + if (theme->inherits) + { + EINA_LIST_FOREACH(theme->inherits, l, name) + { + Efreet_Icon_Theme *inherit; + + inherit = eina_hash_find(icon_themes, name); + if (!inherit) + INF("Theme `%s` not found for `%s`.", + name, theme->name.internal); + if (!cache_scan(inherit, themes, icons)) return EINA_FALSE; + } + } + else if (strcmp(theme->name.internal, "hicolor")) + { + theme = eina_hash_find(icon_themes, "hicolor"); + if (!cache_scan(theme, themes, icons)) return EINA_FALSE; + } + + return EINA_TRUE; +} + +static Eina_Bool +check_changed(Efreet_Cache_Icon_Theme *theme) +{ + Eina_List *l; + const char *name; + + if (!theme) return EINA_FALSE; + + if (theme->changed) return EINA_TRUE; + if (theme->theme.inherits) + { + EINA_LIST_FOREACH(theme->theme.inherits, l, name) + { + Efreet_Cache_Icon_Theme *inherit; + + inherit = eina_hash_find(icon_themes, name); + if (!inherit) + INF("Theme `%s` not found for `%s`.", + name, theme->theme.name.internal); + if (check_changed(inherit)) return EINA_TRUE; + } + } + else if (strcmp(theme->theme.name.internal, "hicolor")) + { + theme = eina_hash_find(icon_themes, "hicolor"); + if (check_changed(theme)) return EINA_TRUE; + } + return EINA_FALSE; +} + +static Efreet_Icon_Theme_Directory * +icon_theme_directory_new(Efreet_Ini *ini, const char *name) +{ + Efreet_Icon_Theme_Directory *dir; + int val; + const char *tmp; + + if (!ini) return NULL; + + dir = NEW(Efreet_Icon_Theme_Directory, 1); + if (!dir) return NULL; + dir->name = eina_stringshare_add(name); + eina_array_push(strs, dir->name); + + efreet_ini_section_set(ini, name); + + tmp = efreet_ini_string_get(ini, "Context"); + if (tmp) + { + if (!strcasecmp(tmp, "Actions")) + dir->context = EFREET_ICON_THEME_CONTEXT_ACTIONS; + + else if (!strcasecmp(tmp, "Devices")) + dir->context = EFREET_ICON_THEME_CONTEXT_DEVICES; + + else if (!strcasecmp(tmp, "FileSystems")) + dir->context = EFREET_ICON_THEME_CONTEXT_FILESYSTEMS; + + else if (!strcasecmp(tmp, "MimeTypes")) + dir->context = EFREET_ICON_THEME_CONTEXT_MIMETYPES; + } + + /* Threshold is fallback */ + dir->type = EFREET_ICON_SIZE_TYPE_THRESHOLD; + + tmp = efreet_ini_string_get(ini, "Type"); + if (tmp) + { + if (!strcasecmp(tmp, "Fixed")) + dir->type = EFREET_ICON_SIZE_TYPE_FIXED; + + else if (!strcasecmp(tmp, "Scalable")) + dir->type = EFREET_ICON_SIZE_TYPE_SCALABLE; + } + + dir->size.normal = efreet_ini_int_get(ini, "Size"); + + if (dir->type == EFREET_ICON_SIZE_TYPE_THRESHOLD) + { + val = efreet_ini_int_get(ini, "Threshold"); + if (val < 0) val = 2; + dir->size.max = dir->size.normal + val; + dir->size.min = dir->size.normal - val; + } + else if (dir->type == EFREET_ICON_SIZE_TYPE_SCALABLE) + { + val = efreet_ini_int_get(ini, "MinSize"); + if (val < 0) dir->size.min = dir->size.normal; + else dir->size.min = val; + + val = efreet_ini_int_get(ini, "MaxSize"); + if (val < 0) dir->size.max = dir->size.normal; + else dir->size.max = val; + } + + return dir; +} + +static Eina_Bool +icon_theme_index_read(Efreet_Cache_Icon_Theme *theme, const char *path) +{ + Efreet_Ini *ini; + Efreet_Icon_Theme_Directory *dir; + const char *tmp; + struct stat st; + char rp[PATH_MAX]; + + if (!theme || !path) return EINA_FALSE; + + if (!realpath(path, rp)) return EINA_FALSE; + + if (stat(rp, &st) < 0) return EINA_FALSE; + if (theme->path && !strcmp(theme->path, rp) && theme->last_cache_check >= (long long) st.st_mtime) + { + /* no change */ + theme->valid = 1; + return EINA_TRUE; + } + if (!theme->path || strcmp(theme->path, rp)) + { + theme->path = eina_stringshare_add(rp); + eina_array_push(strs, theme->path); + } + if ((long long) st.st_mtime > theme->last_cache_check) + theme->last_cache_check = (long long) st.st_mtime; + theme->changed = 1; + + ini = efreet_ini_new(path); + if (!ini) return EINA_FALSE; + if (!ini->data) + { + efreet_ini_free(ini); + return EINA_FALSE; + } + + efreet_ini_section_set(ini, "Icon Theme"); + tmp = efreet_ini_localestring_get(ini, "Name"); + if (tmp) + { + theme->theme.name.name = eina_stringshare_add(tmp); + eina_array_push(strs, theme->theme.name.name); + } + + tmp = efreet_ini_localestring_get(ini, "Comment"); + if (tmp) + { + theme->theme.comment = eina_stringshare_add(tmp); + eina_array_push(strs, theme->theme.comment); + } + + tmp = efreet_ini_string_get(ini, "Example"); + if (tmp) + { + theme->theme.example_icon = eina_stringshare_add(tmp); + eina_array_push(strs, theme->theme.example_icon); + } + + theme->hidden = efreet_ini_boolean_get(ini, "Hidden"); + + theme->valid = 1; + + /* Check the inheritance. If there is none we inherit from the hicolor theme */ + tmp = efreet_ini_string_get(ini, "Inherits"); + if (tmp) + { + char *t, *s, *p; + const char *i; + size_t len; + + len = strlen(tmp) + 1; + t = alloca(len); + memcpy(t, tmp, len); + s = t; + p = strchr(s, ','); + + while (p) + { + *p = '\0'; + + i = eina_stringshare_add(s); + theme->theme.inherits = eina_list_append(theme->theme.inherits, i); + eina_array_push(strs, i); + s = ++p; + p = strchr(s, ','); + } + i = eina_stringshare_add(s); + theme->theme.inherits = eina_list_append(theme->theme.inherits, i); + eina_array_push(strs, i); + } + + /* make sure this one is done last as setting the directory will change + * the ini section ... */ + tmp = efreet_ini_string_get(ini, "Directories"); + if (tmp) + { + char *t, *s, *p; + size_t len; + + len = strlen(tmp) + 1; + t = alloca(len); + memcpy(t, tmp, len); + s = t; + p = s; + + while (p) + { + p = strchr(s, ','); + + if (p) *p = '\0'; + + dir = icon_theme_directory_new(ini, s); + if (!dir) goto error; + theme->theme.directories = eina_list_append(theme->theme.directories, dir); + + if (p) s = ++p; + } + } + +error: + efreet_ini_free(ini); + + return EINA_TRUE; +} + +static Eina_Bool +cache_theme_scan(const char *dir) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *entry; + + it = eina_file_stat_ls(dir); + if (!it) return EINA_TRUE; + + EINA_ITERATOR_FOREACH(it, entry) + { + Efreet_Cache_Icon_Theme *theme; + const char *name; + const char *path; + char buf[PATH_MAX]; + struct stat st; + + if (stat(entry->path, &st) < 0) continue; + + if ((entry->type != EINA_FILE_DIR) && + (entry->type != EINA_FILE_LNK)) + continue; + + name = entry->path + entry->name_start; + theme = eina_hash_find(icon_themes, name); + + if (!theme) + { + theme = NEW(Efreet_Cache_Icon_Theme, 1); + theme->theme.name.internal = eina_stringshare_add(name); + eina_array_push(strs, theme->theme.name.internal); + eina_hash_direct_add(icon_themes, + (void *)theme->theme.name.internal, theme); + theme->changed = 1; + } + if ((long long) st.st_mtime > theme->last_cache_check) + { + theme->last_cache_check = (long long) st.st_mtime; + theme->changed = 1; + } + + /* TODO: We need to handle change in order of included paths */ + if (!eina_list_search_unsorted(theme->theme.paths, EINA_COMPARE_CB(strcmp), entry->path)) + { + path = eina_stringshare_add(entry->path); + theme->theme.paths = eina_list_append(theme->theme.paths, path); + eina_array_push(strs, path); + theme->changed = 1; + } + + /* we're already valid so no reason to check for an index.theme file */ + if (theme->valid) continue; + + /* if the index.theme file exists we parse it into the theme */ + memcpy(buf, entry->path, entry->path_length); + memcpy(buf + entry->path_length, "/index.theme", sizeof("/index.theme")); + if (ecore_file_exists(buf)) + { + if (!icon_theme_index_read(theme, buf)) + theme->valid = 0; + } + } + eina_iterator_free(it); + return EINA_TRUE; +} + +static int +cache_lock_file(void) +{ + char file[PATH_MAX]; + struct flock fl; + int lockfd; + + snprintf(file, sizeof(file), "%s/efreet/icon_data.lock", efreet_cache_home_get()); + lockfd = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (lockfd < 0) return -1; + efreet_fsetowner(lockfd); + + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if (fcntl(lockfd, F_SETLK, &fl) < 0) + { + WRN("LOCKED! You may want to delete %s if this persists", file); + close(lockfd); + return -1; + } + + return lockfd; +} + +static void +icon_theme_free(Efreet_Cache_Icon_Theme *theme) +{ + void *data; + + eina_list_free(theme->theme.paths); + eina_list_free(theme->theme.inherits); + EINA_LIST_FREE(theme->theme.directories, data) + free(data); + if (theme->dirs) efreet_hash_free(theme->dirs, free); + free(theme); +} + +/** + * @internal + * @return EINA_TRUE if data adds new + */ +static Eina_Bool +add_data(Eet_File *ef, Eina_Array *data, const char *key) +{ + Efreet_Cache_Array_String *add; + unsigned int i, j; + Eina_Bool added = EINA_FALSE; + + add = eet_data_read(ef, efreet_array_string_edd(), key); + if (!add) return EINA_TRUE; + /* loop once to check added */ + for (i = 0; i < data->count; i++) + { + int found = 0; + for (j = 0; j < add->array_count; ++j) + { + if (!strcmp(add->array[j], data->data[i])) + { + found = 1; + break; + } + } + if (!found) + { + added = EINA_TRUE; + break; + } + } + /* loop again to add all data */ + for (i = 0; i < add->array_count; i++) + { + int found = 0; + for (j = 0; j < data->count; ++j) + { + if (!strcmp(add->array[i], data->data[j])) + { + found = 1; + break; + } + } + if (!found) + eina_array_push(data, add->array[i]); + } + IF_FREE(add->array); + free(add); + + return added; +} + + +static void +save_data(Eet_File *ef, Eina_Array *data, const char *key) +{ + Efreet_Cache_Array_String *save; + unsigned int i; + + if (!data || !data->count) return; + + save = NEW(Efreet_Cache_Array_String, 1); + save->array = NEW(char *, data->count); + save->array_count = 0; + for (i = 0; i < data->count; ++i) + save->array[save->array_count++] = data->data[i]; + eet_data_write(ef, efreet_array_string_edd(), key, save, 1); + IF_FREE(save->array); + free(save); +} + +int +main(int argc, char **argv) +{ + /* TODO: + * - Add file monitor on files, so that we catch changes on files + * during whilst this program runs. + * - Maybe linger for a while to reduce number of cache re-creates. + */ + Eina_Iterator *it; + Efreet_Cache_Version *icon_version; + Efreet_Cache_Version *theme_version; + Efreet_Cache_Icon_Theme *theme; + Eet_Data_Descriptor *theme_edd; + Eet_Data_Descriptor *icon_edd; + Eet_Data_Descriptor *fallback_edd; + Eet_File *icon_ef; + Eet_File *theme_ef; + Eina_List *xdg_dirs = NULL; + Eina_List *l = NULL; + char file[PATH_MAX]; + const char *path; + char *dir = NULL; + Eina_Bool changed = EINA_FALSE; + Eina_Bool flush = EINA_FALSE; + int lockfd = -1; + int tmpfd = -1; + char **keys; + int num, i; + + /* init external subsystems */ + if (!eina_init()) return -1; + _efreet_icon_cache_log_dom = + eina_log_domain_register("efreet_icon_cache", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_icon_cache_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_icon_cache."); + return -1; + } + + eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_ERR); + + exts = eina_array_new(10); + extra_dirs = eina_array_new(10); + + for (i = 1; i < argc; i++) + { + if (!strcmp(argv[i], "-v")) + eina_log_domain_level_set("efreet_icon_cache", EINA_LOG_LEVEL_DBG); + else if ((!strcmp(argv[i], "-h")) || + (!strcmp(argv[i], "-help")) || + (!strcmp(argv[i], "--h")) || + (!strcmp(argv[i], "--help"))) + { + printf("Options:\n"); + printf(" -v Verbose mode\n"); + printf(" -e .ext1 .ext2 Extensions\n"); + printf(" -d dir1 dir2 Extra dirs\n"); + exit(0); + } + else if (!strcmp(argv[i], "-e")) + { + while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) + eina_array_push(exts, argv[++i]); + } + else if (!strcmp(argv[i], "-d")) + { + while ((i < (argc - 1)) && (argv[(i + 1)][0] != '-')) + eina_array_push(extra_dirs, argv[++i]); + } + } + + if (!eet_init()) return -1; + if (!ecore_init()) return -1; + + efreet_cache_update = 0; + /* finish efreet init */ + if (!efreet_init()) goto on_error; + + strs = eina_array_new(32); + + /* create homedir */ + snprintf(file, sizeof(file), "%s/efreet", efreet_cache_home_get()); + if (!ecore_file_exists(file)) + { + if (!ecore_file_mkpath(file)) return -1; + efreet_setowner(file); + } + + /* lock process, so that we only run one copy of this program */ + lockfd = cache_lock_file(); + if (lockfd == -1) goto on_error; + + /* Need to init edd's, so they are like we want, not like userspace wants */ + icon_edd = efreet_icon_edd(); + fallback_edd = efreet_icon_fallback_edd(); + theme_edd = efreet_icon_theme_edd(EINA_TRUE); + + icon_themes = eina_hash_string_superfast_new(EINA_FREE_CB(icon_theme_free)); + + INF("opening theme cache"); + /* open theme file */ + theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE); + if (!theme_ef) goto on_error_efreet; + theme_version = eet_data_read(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION); + if (theme_version && + ((theme_version->major != EFREET_ICON_CACHE_MAJOR) || + (theme_version->minor != EFREET_ICON_CACHE_MINOR))) + { + // delete old cache + eet_close(theme_ef); + if (unlink(efreet_icon_theme_cache_file()) < 0) + { + if (errno != ENOENT) goto on_error_efreet; + } + theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ_WRITE); + if (!theme_ef) goto on_error_efreet; + } + if (!theme_version) + theme_version = NEW(Efreet_Cache_Version, 1); + + theme_version->major = EFREET_ICON_CACHE_MAJOR; + theme_version->minor = EFREET_ICON_CACHE_MINOR; + + if (add_data(theme_ef, exts, EFREET_CACHE_ICON_EXTENSIONS)) + flush = EINA_TRUE; + if (add_data(theme_ef, extra_dirs, EFREET_CACHE_ICON_EXTRA_DIRS)) + flush = EINA_TRUE; + if (flush) + changed = EINA_TRUE; + + if (exts->count == 0) + { + ERR("Need to pass extensions to icon cache create process"); + goto on_error_efreet; + } + + keys = eet_list(theme_ef, "*", &num); + if (keys) + { + for (i = 0; i < num; i++) + { + if (!strncmp(keys[i], "__efreet", 8)) continue; + theme = eet_data_read(theme_ef, theme_edd, keys[i]); + if (theme) + { + theme->valid = 0; + eina_hash_direct_add(icon_themes, theme->theme.name.internal, theme); + } + } + free(keys); + } + + INF("scan for themes"); + /* scan themes */ + cache_theme_scan(efreet_icon_deprecated_user_dir_get()); + cache_theme_scan(efreet_icon_user_dir_get()); + + xdg_dirs = efreet_data_dirs_get(); + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(file, sizeof(file), "%s/icons", dir); + cache_theme_scan(file); + } + +#ifndef STRICT_SPEC + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(file, sizeof(file), "%s/pixmaps", dir); + cache_theme_scan(file); + } +#endif + + cache_theme_scan("/usr/share/pixmaps"); + + /* scan icons */ + it = eina_hash_iterator_data_new(icon_themes); + EINA_ITERATOR_FOREACH(it, theme) + { + if (!theme->valid) continue; +#ifndef STRICT_SPEC + if (!theme->theme.name.name) continue; +#endif + INF("scan theme %s", theme->theme.name.name); + + theme->changed = check_changed(theme); + if (flush) + theme->changed = EINA_TRUE; + + INF("open icon file"); + /* open icon file */ + icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE); + if (!icon_ef) goto on_error_efreet; + icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION); + if (theme->changed || (icon_version && + ((icon_version->major != EFREET_ICON_CACHE_MAJOR) || + (icon_version->minor != EFREET_ICON_CACHE_MINOR)))) + { + // delete old cache + eet_close(icon_ef); + if (unlink(efreet_icon_cache_file(theme->theme.name.internal)) < 0) + { + if (errno != ENOENT) goto on_error_efreet; + } + icon_ef = eet_open(efreet_icon_cache_file(theme->theme.name.internal), EET_FILE_MODE_READ_WRITE); + if (!icon_ef) goto on_error_efreet; + theme->changed = EINA_TRUE; + } + + if (theme->changed) + changed = EINA_TRUE; + + if (theme->changed) + { + Eina_Hash *themes; + Eina_Hash *icons; + + if (!icon_version) + icon_version = NEW(Efreet_Cache_Version, 1); + + icon_version->major = EFREET_ICON_CACHE_MAJOR; + icon_version->minor = EFREET_ICON_CACHE_MINOR; + + themes = eina_hash_string_superfast_new(NULL); + icons = eina_hash_string_superfast_new(NULL); + + INF("scan icons\n"); + if (cache_scan(&(theme->theme), themes, icons)) + { + Eina_Iterator *icons_it; + Eina_Hash_Tuple *tuple; + + INF("generated: '%s' %i (%i)", + theme->theme.name.internal, + changed, + eina_hash_population(icons)); + + icons_it = eina_hash_iterator_tuple_new(icons); + EINA_ITERATOR_FOREACH(icons_it, tuple) + eet_data_write(icon_ef, icon_edd, tuple->key, tuple->data, 1); + eina_iterator_free(icons_it); + + INF("theme change: %s %lld", theme->theme.name.internal, theme->last_cache_check); + eet_data_write(theme_ef, theme_edd, theme->theme.name.internal, theme, 1); + } + eina_hash_free(themes); + eina_hash_free(icons); + } + + eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1); + eet_close(icon_ef); + efreet_setowner(efreet_icon_cache_file(theme->theme.name.internal)); + free(icon_version); + } + eina_iterator_free(it); + + INF("scan fallback icons"); + theme = eet_data_read(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK); + if (!theme) + { + theme = NEW(Efreet_Cache_Icon_Theme, 1); + theme->changed = EINA_TRUE; + } + if (flush) + theme->changed = EINA_TRUE; + + INF("open fallback file"); + /* open icon file */ + icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE); + if (!icon_ef) goto on_error_efreet; + icon_version = eet_data_read(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION); + if (theme->changed || (icon_version && + ((icon_version->major != EFREET_ICON_CACHE_MAJOR) || + (icon_version->minor != EFREET_ICON_CACHE_MINOR)))) + { + // delete old cache + eet_close(icon_ef); + if (unlink(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)) < 0) + { + if (errno != ENOENT) goto on_error_efreet; + } + icon_ef = eet_open(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EET_FILE_MODE_READ_WRITE); + if (!icon_ef) goto on_error_efreet; + theme->changed = EINA_TRUE; + } + if (!theme->changed) + theme->changed = check_fallback_changed(theme); + if (theme->changed && theme->dirs) + { + efreet_hash_free(theme->dirs, free); + theme->dirs = NULL; + } + if (!theme->dirs) + theme->dirs = eina_hash_string_superfast_new(NULL); + + if (theme->changed) + changed = EINA_TRUE; + + if (theme->changed) + { + Eina_Hash *icons; + + if (!icon_version) + icon_version = NEW(Efreet_Cache_Version, 1); + + icon_version->major = EFREET_ICON_CACHE_MAJOR; + icon_version->minor = EFREET_ICON_CACHE_MINOR; + + icons = eina_hash_string_superfast_new(NULL); + + INF("scan fallback icons"); + /* Save fallback in the right part */ + if (cache_fallback_scan(icons, theme->dirs)) + { + Eina_Iterator *icons_it; + Eina_Hash_Tuple *tuple; + + INF("generated: fallback %i (%i)", theme->changed, eina_hash_population(icons)); + + icons_it = eina_hash_iterator_tuple_new(icons); + EINA_ITERATOR_FOREACH(icons_it, tuple) + eet_data_write(icon_ef, fallback_edd, tuple->key, tuple->data, 1); + eina_iterator_free(icons_it); + } + eina_hash_free(icons); + + eet_data_write(theme_ef, theme_edd, EFREET_CACHE_ICON_FALLBACK, theme, 1); + } + + icon_theme_free(theme); + + eet_data_write(icon_ef, efreet_version_edd(), EFREET_CACHE_VERSION, icon_version, 1); + eet_close(icon_ef); + efreet_setowner(efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK)); + free(icon_version); + + eina_hash_free(icon_themes); + + /* save data */ + eet_data_write(theme_ef, efreet_version_edd(), EFREET_CACHE_VERSION, theme_version, 1); + save_data(theme_ef, exts, EFREET_CACHE_ICON_EXTENSIONS); + save_data(theme_ef, extra_dirs, EFREET_CACHE_ICON_EXTRA_DIRS); + + eet_close(theme_ef); + efreet_setowner(efreet_icon_theme_cache_file()); + free(theme_version); + + /* touch update file */ + snprintf(file, sizeof(file), "%s/efreet/icon_data.update", efreet_cache_home_get()); + tmpfd = open(file, O_CREAT | O_WRONLY, S_IRUSR | S_IWUSR); + if (tmpfd >= 0) + { + char c = 'n'; + + efreet_fsetowner(tmpfd); + if (changed) c = 'c'; + if (write(tmpfd, &c, 1) != 1) perror("write"); + close(tmpfd); + } + + INF("done"); +on_error_efreet: + efreet_shutdown(); + +on_error: + if (lockfd >= 0) close(lockfd); + + while ((path = eina_array_pop(strs))) + eina_stringshare_del(path); + eina_array_free(strs); + eina_array_free(exts); + eina_array_free(extra_dirs); + + ecore_shutdown(); + eet_shutdown(); + eina_log_domain_unregister(_efreet_icon_cache_log_dom); + eina_shutdown(); + + return 0; +} diff --git a/src/lib/Efreet.h b/src/lib/Efreet.h new file mode 100644 index 0000000..c5b8104 --- /dev/null +++ b/src/lib/Efreet.h @@ -0,0 +1,107 @@ +#ifndef EFREET_H +#define EFREET_H + +/** + * @file Efreet.h + * @brief The file that must be included by any project wishing to use + * Efreet. Efreet.h provides all of the necessary headers and includes to + * work with Efreet. + */ + +/** + * @mainpage The Efreet Library + * + * @section intro Introduction + * + * Efreet is a library designed to help apps work several of the + * Freedesktop.org standards regarding Icons, Desktop files and Menus. To + * that end it implements the following specifications: + * + * @li XDG Base Directory Specification + * @li Icon Theme Specification + * @li Desktop Entry Specification + * @li Desktop Menu Specification + * @li FDO URI Specification + * @li Shared Mime Info Specification + * @li Trash Specification + */ + +#include <Eina.h> + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EFREET_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EFREET_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +#define EFREET_VERSION_MAJOR 1 +#define EFREET_VERSION_MINOR 7 + + typedef struct _Efreet_Version + { + int major; + int minor; + int micro; + int revision; + } Efreet_Version; + + EAPI extern Efreet_Version *efreet_version; + +#include "efreet_base.h" +#include "efreet_ini.h" +#include "efreet_icon.h" +#include "efreet_desktop.h" +#include "efreet_menu.h" +#include "efreet_utils.h" +#include "efreet_uri.h" + +/** + * @return Value > @c 0 if the initialization was successful, @c 0 otherwise. + * @brief Initializes the Efreet system + */ +EAPI int efreet_init(void); + +/** + * @return The number of times the init function has been called minus the + * corresponding init call. + * @brief Shuts down Efreet if a balanced number of init/shutdown calls have + * been made + */ +EAPI int efreet_shutdown(void); + +/** + * @brief Resets language dependent variables and resets language dependent + * caches This must be called whenever the locale is changed. + * @since 1.7 + */ +EAPI void efreet_lang_reset(void); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Efreet_Mime.h b/src/lib/Efreet_Mime.h new file mode 100644 index 0000000..d6873fc --- /dev/null +++ b/src/lib/Efreet_Mime.h @@ -0,0 +1,125 @@ +#ifndef EFREET_MIME_H +#define EFREET_MIME_H + +/** + * @file Efreet_Mime.h + * @brief The file that must be included by any project wishing to use + * @addtogroup Efreet_Mime Efreet_Mime: The XDG Shared Mime Info standard + * Efreet Mime is a library designed to help apps work with the + * Freedesktop.org Shared Mime Info standard. + * Efreet_Mime.h provides all of the necessary headers and + * includes to work with Efreet_Mime. + * @{ + */ + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EFREET_MIME_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EFREET_MIME_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + + +/** + * @return @c 1 on success or @c 0 on failure. + * @brief Initializes the efreet mime settings + */ +EAPI int efreet_mime_init(void); + +/** + * @return No value. + * @brief Cleans up the efreet mime settings system + */ +EAPI int efreet_mime_shutdown(void); + +/** + * @param file The file to find the mime type + * @return Mime type as a string. + * @brief Retrieve the mime type of a file + */ +EAPI const char *efreet_mime_type_get(const char *file); + +/** + * @param file The file to check the mime type + * @return Mime type as a string. + * @brief Retrieve the mime type of a file using magic + */ +EAPI const char *efreet_mime_magic_type_get(const char *file); + +/** + * @param file The file to check the mime type + * @return Mime type as a string. + * @brief Retrieve the mime type of a file using globs + */ +EAPI const char *efreet_mime_globs_type_get(const char *file); + +/** + * @param file The file to check the mime type + * @return Mime type as a string. + * @brief Retrieve the special mime type of a file + */ +EAPI const char *efreet_mime_special_type_get(const char *file); + +/** + * @param file The file to check the mime type + * @return Mime type as a string. + * @brief Retrieve the fallback mime type of a file. + */ +EAPI const char *efreet_mime_fallback_type_get(const char *file); + + +/** + * @param mime The name of the mime type + * @param theme The name of the theme to search icons in + * @param size The wanted size of the icon + * @return Mime type icon path as a string. + * @brief Retrieve the mime type icon for a file. + */ +EAPI const char *efreet_mime_type_icon_get(const char *mime, const char *theme, + unsigned int size); + +/** + * @brief Clear mime icons mapping cache + */ +EAPI void efreet_mime_type_cache_clear(void); + +/** + * @brief Flush mime icons mapping cache + * + * Flush timeout is defined at compile time by + * EFREET_MIME_ICONS_FLUSH_TIMEOUT + */ +EAPI void efreet_mime_type_cache_flush(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Efreet_Trash.h b/src/lib/Efreet_Trash.h new file mode 100644 index 0000000..3f86aa2 --- /dev/null +++ b/src/lib/Efreet_Trash.h @@ -0,0 +1,102 @@ +#ifndef EFREET_TRASH_H +#define EFREET_TRASH_H + +#ifdef EAPI +# undef EAPI +#endif + +#ifdef _WIN32 +# ifdef EFL_EFREET_TRASH_BUILD +# ifdef DLL_EXPORT +# define EAPI __declspec(dllexport) +# else +# define EAPI +# endif /* ! DLL_EXPORT */ +# else +# define EAPI __declspec(dllimport) +# endif /* ! EFL_EFREET_TRASH_BUILD */ +#else +# ifdef __GNUC__ +# if __GNUC__ >= 4 +# define EAPI __attribute__ ((visibility("default"))) +# else +# define EAPI +# endif +# else +# define EAPI +# endif +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/** + * @file Efreet_Trash.h + * @brief Contains the methods used to support the FDO trash specification. + * @addtogroup Efreet_Trash Efreet_Trash: The XDG Trash Specification + * Efreet_Trash.h provides all of the necessary headers and includes to + * work with Efreet_Trash. + * @{ + */ + +/** + * @return @c 1 on success or @c 0 on failure. + * @brief Initializes the efreet trash system + */ +EAPI int efreet_trash_init(void); + +/** + * @return No value. + * @brief Cleans up the efreet trash system + */ +EAPI int efreet_trash_shutdown(void); + +/** + * @return The XDG Trash local directory or @c NULL on errors. + * Return value must be freed with eina_stringshare_del. + * @brief Retrieves the XDG Trash local directory + */ +EAPI const char *efreet_trash_dir_get(const char *for_file); + +/** + * @param uri The local uri to move in the trash + * @param force_delete If you set this to @c 1 than files on different filesystems + * will be deleted permanently + * @return @c 1 on success, @c 0 on failure or @c -1 in case the uri is not on + * the same filesystem and force_delete is not set. + * @brief This function try to move the given uri to the trash. Files on + * different filesystem can't be moved to trash. If force_delete + * is @c 0 than non-local files will be ignored and @c -1 is returned, if you set + * force_delete to @c 1 non-local files will be deleted without asking. + */ +EAPI int efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete); + +/** + * @return A list of strings with filename (remember to free the list + * when you don't need anymore). + * @brief List all the files and directory currently inside the trash. + */ +EAPI Eina_List *efreet_trash_ls(void); + +/** + * @return @c 1 if the trash is empty or @c 0 if some file are in. + * @brief Check if the trash is currently empty + */ +EAPI int efreet_trash_is_empty(void); + +/** + * @return @c 1 on success or @c 0 on failure. + * @brief Delete all the files inside the trash. + */ +EAPI int efreet_trash_empty_trash(void); + +/** + * @} + */ + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am new file mode 100644 index 0000000..824c8de --- /dev/null +++ b/src/lib/Makefile.am @@ -0,0 +1,69 @@ + +MAINTAINERCLEANFILES = Makefile.in + +lib_LTLIBRARIES = libefreet.la libefreet_mime.la libefreet_trash.la + +INCLUDES = \ +-DLOCALE_DIR=\"@LOCALE_DIR@\" + +EFREETHEADERS = \ +Efreet.h \ +efreet_base.h \ +efreet_desktop.h \ +efreet_icon.h \ +efreet_ini.h \ +efreet_menu.h \ +efreet_utils.h \ +efreet_uri.h + +EFREETSOURCES = \ +efreet.c \ +efreet_base.c \ +efreet_icon.c \ +efreet_xml.c \ +efreet_ini.c \ +efreet_desktop.c \ +efreet_desktop_command.c \ +efreet_menu.c \ +efreet_utils.c \ +efreet_uri.c \ +efreet_cache.c + +includes_HEADERS = $(EFREETHEADERS) Efreet_Mime.h Efreet_Trash.h +includesdir = $(includedir)/efreet-@VMAJ@ + +# Not sure if this was for 'make dist', so left it in but commented - dh +# dist_installed_headers_DATA = $(EFREETHEADERS) Efreet_Mime.h Efreet_Trash.h + +libefreet_la_SOURCES = $(EFREETSOURCES) +libefreet_la_CPPFLAGS = \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_BUILD@ \ +@EFREET_CFLAGS@ +libefreet_la_LIBADD = @EFREET_LIBS@ @WIN32_LIBS@ +libefreet_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + + +libefreet_mime_la_SOURCES = efreet_mime.c +libefreet_mime_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_MIME_BUILD@ \ +@EFREET_CFLAGS@ +libefreet_mime_la_LIBADD = @EFREET_LIBS@ libefreet.la @WIN32_LIBS@ +libefreet_mime_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + + +libefreet_trash_la_SOURCES = efreet_trash.c +libefreet_trash_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_TRASH_BUILD@ \ +@EFREET_CFLAGS@ +libefreet_trash_la_LIBADD = @EFREET_LIBS@ libefreet.la +libefreet_trash_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ + +EXTRA_DIST = efreet_private.h efreet_xml.h efreet_cache_private.h diff --git a/src/lib/Makefile.in b/src/lib/Makefile.in new file mode 100644 index 0000000..b3ef936 --- /dev/null +++ b/src/lib/Makefile.in @@ -0,0 +1,821 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/lib +DIST_COMMON = $(includes_HEADERS) $(srcdir)/Makefile.am \ + $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includesdir)" +LTLIBRARIES = $(lib_LTLIBRARIES) +libefreet_la_DEPENDENCIES = +am__objects_1 = libefreet_la-efreet.lo libefreet_la-efreet_base.lo \ + libefreet_la-efreet_icon.lo libefreet_la-efreet_xml.lo \ + libefreet_la-efreet_ini.lo libefreet_la-efreet_desktop.lo \ + libefreet_la-efreet_desktop_command.lo \ + libefreet_la-efreet_menu.lo libefreet_la-efreet_utils.lo \ + libefreet_la-efreet_uri.lo libefreet_la-efreet_cache.lo +am_libefreet_la_OBJECTS = $(am__objects_1) +libefreet_la_OBJECTS = $(am_libefreet_la_OBJECTS) +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +libefreet_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(libefreet_la_LDFLAGS) $(LDFLAGS) -o $@ +libefreet_mime_la_DEPENDENCIES = libefreet.la +am_libefreet_mime_la_OBJECTS = libefreet_mime_la-efreet_mime.lo +libefreet_mime_la_OBJECTS = $(am_libefreet_mime_la_OBJECTS) +libefreet_mime_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libefreet_mime_la_LDFLAGS) $(LDFLAGS) \ + -o $@ +libefreet_trash_la_DEPENDENCIES = libefreet.la +am_libefreet_trash_la_OBJECTS = libefreet_trash_la-efreet_trash.lo +libefreet_trash_la_OBJECTS = $(am_libefreet_trash_la_OBJECTS) +libefreet_trash_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(AM_CFLAGS) $(CFLAGS) $(libefreet_trash_la_LDFLAGS) \ + $(LDFLAGS) -o $@ +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(libefreet_la_SOURCES) $(libefreet_mime_la_SOURCES) \ + $(libefreet_trash_la_SOURCES) +DIST_SOURCES = $(libefreet_la_SOURCES) $(libefreet_mime_la_SOURCES) \ + $(libefreet_trash_la_SOURCES) +HEADERS = $(includes_HEADERS) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +MAINTAINERCLEANFILES = Makefile.in +lib_LTLIBRARIES = libefreet.la libefreet_mime.la libefreet_trash.la +INCLUDES = \ +-DLOCALE_DIR=\"@LOCALE_DIR@\" + +EFREETHEADERS = \ +Efreet.h \ +efreet_base.h \ +efreet_desktop.h \ +efreet_icon.h \ +efreet_ini.h \ +efreet_menu.h \ +efreet_utils.h \ +efreet_uri.h + +EFREETSOURCES = \ +efreet.c \ +efreet_base.c \ +efreet_icon.c \ +efreet_xml.c \ +efreet_ini.c \ +efreet_desktop.c \ +efreet_desktop_command.c \ +efreet_menu.c \ +efreet_utils.c \ +efreet_uri.c \ +efreet_cache.c + +includes_HEADERS = $(EFREETHEADERS) Efreet_Mime.h Efreet_Trash.h +includesdir = $(includedir)/efreet-@VMAJ@ + +# Not sure if this was for 'make dist', so left it in but commented - dh +# dist_installed_headers_DATA = $(EFREETHEADERS) Efreet_Mime.h Efreet_Trash.h +libefreet_la_SOURCES = $(EFREETSOURCES) +libefreet_la_CPPFLAGS = \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_BUILD@ \ +@EFREET_CFLAGS@ + +libefreet_la_LIBADD = @EFREET_LIBS@ @WIN32_LIBS@ +libefreet_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ +libefreet_mime_la_SOURCES = efreet_mime.c +libefreet_mime_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_MIME_BUILD@ \ +@EFREET_CFLAGS@ + +libefreet_mime_la_LIBADD = @EFREET_LIBS@ libefreet.la @WIN32_LIBS@ +libefreet_mime_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ +libefreet_trash_la_SOURCES = efreet_trash.c +libefreet_trash_la_CPPFLAGS = \ +-I$(top_builddir)/src/lib \ +-I$(top_srcdir)/src/lib \ +@EFL_EFREET_TRASH_BUILD@ \ +@EFREET_CFLAGS@ + +libefreet_trash_la_LIBADD = @EFREET_LIBS@ libefreet.la +libefreet_trash_la_LDFLAGS = -no-undefined @lt_enable_auto_import@ -version-info @version_info@ @release_info@ +EXTRA_DIST = efreet_private.h efreet_xml.h efreet_cache_private.h +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/lib/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/lib/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-libLTLIBRARIES: $(lib_LTLIBRARIES) + @$(NORMAL_INSTALL) + test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)" + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ + } + +uninstall-libLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ + done + +clean-libLTLIBRARIES: + -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) + @list='$(lib_LTLIBRARIES)'; for p in $$list; do \ + dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \ + test "$$dir" != "$$p" || dir=.; \ + echo "rm -f \"$${dir}/so_locations\""; \ + rm -f "$${dir}/so_locations"; \ + done +libefreet.la: $(libefreet_la_OBJECTS) $(libefreet_la_DEPENDENCIES) + $(AM_V_CCLD)$(libefreet_la_LINK) -rpath $(libdir) $(libefreet_la_OBJECTS) $(libefreet_la_LIBADD) $(LIBS) +libefreet_mime.la: $(libefreet_mime_la_OBJECTS) $(libefreet_mime_la_DEPENDENCIES) + $(AM_V_CCLD)$(libefreet_mime_la_LINK) -rpath $(libdir) $(libefreet_mime_la_OBJECTS) $(libefreet_mime_la_LIBADD) $(LIBS) +libefreet_trash.la: $(libefreet_trash_la_OBJECTS) $(libefreet_trash_la_DEPENDENCIES) + $(AM_V_CCLD)$(libefreet_trash_la_LINK) -rpath $(libdir) $(libefreet_trash_la_OBJECTS) $(libefreet_trash_la_LIBADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_base.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_cache.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_desktop.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_desktop_command.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_icon.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_ini.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_menu.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_uri.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_utils.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_la-efreet_xml.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_mime_la-efreet_mime.Plo@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libefreet_trash_la-efreet_trash.Plo@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +libefreet_la-efreet.lo: efreet.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet.Tpo -c -o libefreet_la-efreet.lo `test -f 'efreet.c' || echo '$(srcdir)/'`efreet.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet.Tpo $(DEPDIR)/libefreet_la-efreet.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet.c' object='libefreet_la-efreet.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet.lo `test -f 'efreet.c' || echo '$(srcdir)/'`efreet.c + +libefreet_la-efreet_base.lo: efreet_base.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_base.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_base.Tpo -c -o libefreet_la-efreet_base.lo `test -f 'efreet_base.c' || echo '$(srcdir)/'`efreet_base.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_base.Tpo $(DEPDIR)/libefreet_la-efreet_base.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_base.c' object='libefreet_la-efreet_base.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_base.lo `test -f 'efreet_base.c' || echo '$(srcdir)/'`efreet_base.c + +libefreet_la-efreet_icon.lo: efreet_icon.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_icon.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_icon.Tpo -c -o libefreet_la-efreet_icon.lo `test -f 'efreet_icon.c' || echo '$(srcdir)/'`efreet_icon.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_icon.Tpo $(DEPDIR)/libefreet_la-efreet_icon.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_icon.c' object='libefreet_la-efreet_icon.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_icon.lo `test -f 'efreet_icon.c' || echo '$(srcdir)/'`efreet_icon.c + +libefreet_la-efreet_xml.lo: efreet_xml.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_xml.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_xml.Tpo -c -o libefreet_la-efreet_xml.lo `test -f 'efreet_xml.c' || echo '$(srcdir)/'`efreet_xml.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_xml.Tpo $(DEPDIR)/libefreet_la-efreet_xml.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_xml.c' object='libefreet_la-efreet_xml.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_xml.lo `test -f 'efreet_xml.c' || echo '$(srcdir)/'`efreet_xml.c + +libefreet_la-efreet_ini.lo: efreet_ini.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_ini.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_ini.Tpo -c -o libefreet_la-efreet_ini.lo `test -f 'efreet_ini.c' || echo '$(srcdir)/'`efreet_ini.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_ini.Tpo $(DEPDIR)/libefreet_la-efreet_ini.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_ini.c' object='libefreet_la-efreet_ini.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_ini.lo `test -f 'efreet_ini.c' || echo '$(srcdir)/'`efreet_ini.c + +libefreet_la-efreet_desktop.lo: efreet_desktop.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_desktop.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_desktop.Tpo -c -o libefreet_la-efreet_desktop.lo `test -f 'efreet_desktop.c' || echo '$(srcdir)/'`efreet_desktop.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_desktop.Tpo $(DEPDIR)/libefreet_la-efreet_desktop.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_desktop.c' object='libefreet_la-efreet_desktop.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_desktop.lo `test -f 'efreet_desktop.c' || echo '$(srcdir)/'`efreet_desktop.c + +libefreet_la-efreet_desktop_command.lo: efreet_desktop_command.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_desktop_command.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_desktop_command.Tpo -c -o libefreet_la-efreet_desktop_command.lo `test -f 'efreet_desktop_command.c' || echo '$(srcdir)/'`efreet_desktop_command.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_desktop_command.Tpo $(DEPDIR)/libefreet_la-efreet_desktop_command.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_desktop_command.c' object='libefreet_la-efreet_desktop_command.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_desktop_command.lo `test -f 'efreet_desktop_command.c' || echo '$(srcdir)/'`efreet_desktop_command.c + +libefreet_la-efreet_menu.lo: efreet_menu.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_menu.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_menu.Tpo -c -o libefreet_la-efreet_menu.lo `test -f 'efreet_menu.c' || echo '$(srcdir)/'`efreet_menu.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_menu.Tpo $(DEPDIR)/libefreet_la-efreet_menu.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_menu.c' object='libefreet_la-efreet_menu.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_menu.lo `test -f 'efreet_menu.c' || echo '$(srcdir)/'`efreet_menu.c + +libefreet_la-efreet_utils.lo: efreet_utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_utils.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_utils.Tpo -c -o libefreet_la-efreet_utils.lo `test -f 'efreet_utils.c' || echo '$(srcdir)/'`efreet_utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_utils.Tpo $(DEPDIR)/libefreet_la-efreet_utils.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_utils.c' object='libefreet_la-efreet_utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_utils.lo `test -f 'efreet_utils.c' || echo '$(srcdir)/'`efreet_utils.c + +libefreet_la-efreet_uri.lo: efreet_uri.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_uri.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_uri.Tpo -c -o libefreet_la-efreet_uri.lo `test -f 'efreet_uri.c' || echo '$(srcdir)/'`efreet_uri.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_uri.Tpo $(DEPDIR)/libefreet_la-efreet_uri.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_uri.c' object='libefreet_la-efreet_uri.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_uri.lo `test -f 'efreet_uri.c' || echo '$(srcdir)/'`efreet_uri.c + +libefreet_la-efreet_cache.lo: efreet_cache.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_la-efreet_cache.lo -MD -MP -MF $(DEPDIR)/libefreet_la-efreet_cache.Tpo -c -o libefreet_la-efreet_cache.lo `test -f 'efreet_cache.c' || echo '$(srcdir)/'`efreet_cache.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_la-efreet_cache.Tpo $(DEPDIR)/libefreet_la-efreet_cache.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_cache.c' object='libefreet_la-efreet_cache.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_la-efreet_cache.lo `test -f 'efreet_cache.c' || echo '$(srcdir)/'`efreet_cache.c + +libefreet_mime_la-efreet_mime.lo: efreet_mime.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_mime_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_mime_la-efreet_mime.lo -MD -MP -MF $(DEPDIR)/libefreet_mime_la-efreet_mime.Tpo -c -o libefreet_mime_la-efreet_mime.lo `test -f 'efreet_mime.c' || echo '$(srcdir)/'`efreet_mime.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_mime_la-efreet_mime.Tpo $(DEPDIR)/libefreet_mime_la-efreet_mime.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_mime.c' object='libefreet_mime_la-efreet_mime.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_mime_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_mime_la-efreet_mime.lo `test -f 'efreet_mime.c' || echo '$(srcdir)/'`efreet_mime.c + +libefreet_trash_la-efreet_trash.lo: efreet_trash.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_trash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT libefreet_trash_la-efreet_trash.lo -MD -MP -MF $(DEPDIR)/libefreet_trash_la-efreet_trash.Tpo -c -o libefreet_trash_la-efreet_trash.lo `test -f 'efreet_trash.c' || echo '$(srcdir)/'`efreet_trash.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libefreet_trash_la-efreet_trash.Tpo $(DEPDIR)/libefreet_trash_la-efreet_trash.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='efreet_trash.c' object='libefreet_trash_la-efreet_trash.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libefreet_trash_la_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o libefreet_trash_la-efreet_trash.lo `test -f 'efreet_trash.c' || echo '$(srcdir)/'`efreet_trash.c + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-includesHEADERS: $(includes_HEADERS) + @$(NORMAL_INSTALL) + test -z "$(includesdir)" || $(MKDIR_P) "$(DESTDIR)$(includesdir)" + @list='$(includes_HEADERS)'; test -n "$(includesdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(includesdir)'"; \ + $(INSTALL_HEADER) $$files "$(DESTDIR)$(includesdir)" || exit $$?; \ + done + +uninstall-includesHEADERS: + @$(NORMAL_UNINSTALL) + @list='$(includes_HEADERS)'; test -n "$(includesdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(includesdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(includesdir)" && rm -f $$files + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(LTLIBRARIES) $(HEADERS) +installdirs: + for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(includesdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libLTLIBRARIES clean-libtool \ + mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-includesHEADERS + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-libLTLIBRARIES + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-includesHEADERS uninstall-libLTLIBRARIES + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-generic \ + clean-libLTLIBRARIES clean-libtool ctags distclean \ + distclean-compile distclean-generic distclean-libtool \ + distclean-tags distdir dvi dvi-am html html-am info info-am \ + install install-am install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-includesHEADERS install-info \ + install-info-am install-libLTLIBRARIES install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags uninstall uninstall-am uninstall-includesHEADERS \ + uninstall-libLTLIBRARIES + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/lib/efreet.c b/src/lib/efreet.c new file mode 100644 index 0000000..c48223f --- /dev/null +++ b/src/lib/efreet.c @@ -0,0 +1,366 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <Eet.h> +#include <Ecore.h> +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM /* no logging in this file */ + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_xml.h" + +/* + * Needs EAPI because of helper binaries + */ +EAPI int efreet_cache_update = 1; + +static int _efreet_init_count = 0; +static int efreet_parsed_locale = 0; +static const char *efreet_lang = NULL; +static const char *efreet_lang_country = NULL; +static const char *efreet_lang_modifier = NULL; +static void efreet_parse_locale(void); +static int efreet_parse_locale_setting(const char *env); + +#ifndef _WIN32 +static uid_t ruid; +static uid_t rgid; +#endif + +EAPI int +efreet_init(void) +{ +#ifndef _WIN32 + char *tmp; +#endif + + if (++_efreet_init_count != 1) + return _efreet_init_count; + +#ifndef _WIN32 + /* Find users real uid and gid */ + tmp = getenv("SUDO_UID"); + if (tmp) + ruid = strtoul(tmp, NULL, 10); + else + ruid = getuid(); + + tmp = getenv("SUDO_GID"); + if (tmp) + rgid = strtoul(tmp, NULL, 10); + else + rgid = getgid(); +#endif + + if (!eina_init()) + return --_efreet_init_count; + if (!eet_init()) + goto shutdown_eina; + if (!ecore_init()) + goto shutdown_eet; + if (!ecore_file_init()) + goto shutdown_ecore; + + if (!efreet_base_init()) + goto shutdown_ecore_file; + + if (!efreet_cache_init()) + goto shutdown_efreet_base; + + if (!efreet_xml_init()) + goto shutdown_efreet_cache; + + if (!efreet_icon_init()) + goto shutdown_efreet_xml; + + if (!efreet_ini_init()) + goto shutdown_efreet_icon; + + if (!efreet_desktop_init()) + goto shutdown_efreet_ini; + + if (!efreet_menu_init()) + goto shutdown_efreet_desktop; + + if (!efreet_util_init()) + goto shutdown_efreet_menu; + +#ifdef ENABLE_NLS + bindtextdomain(PACKAGE, LOCALE_DIR); + bind_textdomain_codeset(PACKAGE, "UTF-8"); +#endif + + return _efreet_init_count; + +shutdown_efreet_menu: + efreet_menu_shutdown(); +shutdown_efreet_desktop: + efreet_desktop_shutdown(); +shutdown_efreet_ini: + efreet_ini_shutdown(); +shutdown_efreet_icon: + efreet_icon_shutdown(); +shutdown_efreet_xml: + efreet_xml_shutdown(); +shutdown_efreet_cache: + efreet_cache_shutdown(); +shutdown_efreet_base: + efreet_base_shutdown(); +shutdown_ecore_file: + ecore_file_shutdown(); +shutdown_ecore: + ecore_shutdown(); +shutdown_eet: + eet_shutdown(); +shutdown_eina: + eina_shutdown(); + + return --_efreet_init_count; +} + +EAPI int +efreet_shutdown(void) +{ + if (_efreet_init_count <= 0) + { + EINA_LOG_ERR("Init count not greater than 0 in shutdown."); + return 0; + } + if (--_efreet_init_count != 0) + return _efreet_init_count; + + efreet_util_shutdown(); + efreet_menu_shutdown(); + efreet_desktop_shutdown(); + efreet_ini_shutdown(); + efreet_icon_shutdown(); + efreet_xml_shutdown(); + efreet_cache_shutdown(); + efreet_base_shutdown(); + + IF_RELEASE(efreet_lang); + IF_RELEASE(efreet_lang_country); + IF_RELEASE(efreet_lang_modifier); + efreet_parsed_locale = 0; /* reset this in case they init efreet again */ + + ecore_file_shutdown(); + ecore_shutdown(); + eet_shutdown(); + eina_shutdown(); + + return _efreet_init_count; +} + +EAPI void +efreet_lang_reset(void) +{ + IF_RELEASE(efreet_lang); + IF_RELEASE(efreet_lang_country); + IF_RELEASE(efreet_lang_modifier); + efreet_parsed_locale = 0; /* reset this in case they init efreet again */ + + efreet_dirs_reset(); + efreet_cache_desktop_close(); + efreet_cache_desktop_update(); +} + + /** + * @internal + * @return Returns the current users language setting or NULL if none set + * @brief Retrieves the current language setting + */ +const char * +efreet_lang_get(void) +{ + if (efreet_parsed_locale) return efreet_lang; + + efreet_parse_locale(); + return efreet_lang; +} + +/** + * @internal + * @return Returns the current language country setting or NULL if none set + * @brief Retrieves the current country setting for the current language or + */ +const char * +efreet_lang_country_get(void) +{ + if (efreet_parsed_locale) return efreet_lang_country; + + efreet_parse_locale(); + return efreet_lang_country; +} + +/** + * @internal + * @return Returns the current language modifier setting or NULL if none + * set. + * @brief Retrieves the modifier setting for the language. + */ +const char * +efreet_lang_modifier_get(void) +{ + if (efreet_parsed_locale) return efreet_lang_modifier; + + efreet_parse_locale(); + return efreet_lang_modifier; +} + +/** + * @internal + * @return Returns no value + * @brief Parses out the language, country and modifer setting from the + * LC_MESSAGES environment variable + */ +static void +efreet_parse_locale(void) +{ + efreet_parsed_locale = 1; + + if (efreet_parse_locale_setting("LANG")) + return; + + if (efreet_parse_locale_setting("LC_ALL")) + return; + + efreet_parse_locale_setting("LC_MESSAGES"); +} + +/** + * @internal + * @param env The environment variable to grab + * @return Returns 1 if we parsed something of @a env, 0 otherwise + * @brief Tries to parse the lang settings out of the given environment + * variable + */ +static int +efreet_parse_locale_setting(const char *env) +{ + int found = 0; + char *setting; + char *p; + size_t len; + + p = getenv(env); + if (!p) return 0; + len = strlen(p) + 1; + setting = alloca(len); + memcpy(setting, p, len); + + /* pull the modifier off the end */ + p = strrchr(setting, '@'); + if (p) + { + *p = '\0'; + efreet_lang_modifier = eina_stringshare_add(p + 1); + found = 1; + } + + /* if there is an encoding we ignore it */ + p = strrchr(setting, '.'); + if (p) *p = '\0'; + + /* get the country if available */ + p = strrchr(setting, '_'); + if (p) + { + *p = '\0'; + efreet_lang_country = eina_stringshare_add(p + 1); + found = 1; + } + + if (*setting != '\0') + { + efreet_lang = eina_stringshare_add(setting); + found = 1; + } + + return found; +} + +/** + * @internal + * @param buffer The destination buffer + * @param size The destination buffer size + * @param strs The strings to concatenate together + * @return Returns the size of the string in @a buffer + * @brief Concatenates the strings in @a strs into the given @a buffer not + * exceeding the given @a size. + */ +size_t +efreet_array_cat(char *buffer, size_t size, const char *strs[]) +{ + int i; + size_t n; + for (i = 0, n = 0; n < size && strs[i]; i++) + { + n += eina_strlcpy(buffer + n, strs[i], size - n); + } + return n; +} + +#ifndef _WIN32 +EAPI void +efreet_fsetowner(int fd) +{ + struct stat st; + + if (fd < 0) return; + if (fstat(fd, &st) < 0) return; + if (st.st_uid == ruid) return; + + if (fchown(fd, ruid, rgid) != 0) return; +} +#else +EAPI void +efreet_fsetowner(int fd __UNUSED__) +{ +} +#endif + +#ifndef _WIN32 +EAPI void +efreet_setowner(const char *path) +{ + EINA_SAFETY_ON_NULL_RETURN(path); + + int fd; + + fd = open(path, O_RDONLY); + if (fd < 0) return; + efreet_fsetowner(fd); + close(fd); +} +#else +EAPI void +efreet_setowner(const char *path __UNUSED__) +{ +} +#endif diff --git a/src/lib/efreet_base.c b/src/lib/efreet_base.c new file mode 100644 index 0000000..afb5920 --- /dev/null +++ b/src/lib/efreet_base.c @@ -0,0 +1,387 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <unistd.h> + +#ifdef _WIN32 +# include <winsock2.h> +#endif + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_base_log_dom +static int _efreet_base_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" + +static Efreet_Version _version = { VMAJ, VMIN, VMIC, VREV }; +EAPI Efreet_Version *efreet_version = &_version; + +#ifdef _WIN32 +# define EFREET_PATH_SEP ';' +#else +# define EFREET_PATH_SEP ':' +#endif + +static const char *efreet_home_dir = NULL; +static const char *xdg_data_home = NULL; +static const char *xdg_config_home = NULL; +static const char *xdg_cache_home = NULL; +static Eina_List *xdg_data_dirs = NULL; +static Eina_List *xdg_config_dirs = NULL; +static const char *xdg_desktop_dir = NULL; +static const char *hostname = NULL; + +static const char *efreet_dir_get(const char *key, const char *fallback); +static Eina_List *efreet_dirs_get(const char *key, + const char *fallback); +static const char *efreet_user_dir_get(const char *key, const char *fallback); + +/** + * @internal + * @return Returns @c 1 on success or @c 0 on failure + * @brief Initializes the efreet base settings + */ +int +efreet_base_init(void) +{ + _efreet_base_log_dom = eina_log_domain_register + ("efreet_base", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_base_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_base.\n"); + return 0; + } + return 1; +} + +/** + * @internal + * @return Returns no value + * @brief Cleans up the efreet base settings system + */ +void +efreet_base_shutdown(void) +{ + IF_RELEASE(efreet_home_dir); + IF_RELEASE(xdg_desktop_dir); + IF_RELEASE(xdg_data_home); + IF_RELEASE(xdg_config_home); + IF_RELEASE(xdg_cache_home); + + IF_FREE_LIST(xdg_data_dirs, eina_stringshare_del); + IF_FREE_LIST(xdg_config_dirs, eina_stringshare_del); + + IF_RELEASE(hostname); + + eina_log_domain_unregister(_efreet_base_log_dom); + _efreet_base_log_dom = -1; +} + +/** + * @internal + * @return Returns the users home directory + * @brief Gets the users home directory and returns it. + */ +const char * +efreet_home_dir_get(void) +{ + if (efreet_home_dir) return efreet_home_dir; + + efreet_home_dir = getenv("HOME"); +#ifdef _WIN32 + if (!efreet_home_dir || efreet_home_dir[0] == '\0') + efreet_home_dir = getenv("USERPROFILE"); +#endif + if (!efreet_home_dir || efreet_home_dir[0] == '\0') + efreet_home_dir = "/tmp"; + + efreet_home_dir = eina_stringshare_add(efreet_home_dir); + + return efreet_home_dir; +} + +EAPI const char * +efreet_desktop_dir_get(void) +{ + if (xdg_desktop_dir) return xdg_desktop_dir; + xdg_desktop_dir = efreet_user_dir_get("XDG_DESKTOP_DIR", _("Desktop")); + return xdg_desktop_dir; +} + +EAPI const char * +efreet_data_home_get(void) +{ + if (xdg_data_home) return xdg_data_home; + xdg_data_home = efreet_dir_get("XDG_DATA_HOME", "/.local/share"); + return xdg_data_home; +} + +EAPI Eina_List * +efreet_data_dirs_get(void) +{ +#ifdef _WIN32 + char buf[4096]; +#endif + + if (xdg_data_dirs) return xdg_data_dirs; + +#ifdef _WIN32 + snprintf(buf, 4096, "%s\\Efl;" PACKAGE_DATA_DIR ";/usr/share;/usr/local/share", getenv("APPDATA")); + xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS", buf); +#else + xdg_data_dirs = efreet_dirs_get("XDG_DATA_DIRS", + PACKAGE_DATA_DIR ":/usr/share:/usr/local/share"); +#endif + return xdg_data_dirs; +} + +EAPI const char * +efreet_config_home_get(void) +{ + if (xdg_config_home) return xdg_config_home; + xdg_config_home = efreet_dir_get("XDG_CONFIG_HOME", "/.config"); + return xdg_config_home; +} + +EAPI Eina_List * +efreet_config_dirs_get(void) +{ + if (xdg_config_dirs) return xdg_config_dirs; + xdg_config_dirs = efreet_dirs_get("XDG_CONFIG_DIRS", "/etc/xdg"); + return xdg_config_dirs; +} + +EAPI const char * +efreet_cache_home_get(void) +{ + if (xdg_cache_home) return xdg_cache_home; + xdg_cache_home = efreet_dir_get("XDG_CACHE_HOME", "/.cache"); + return xdg_cache_home; +} + +EAPI const char * +efreet_hostname_get(void) +{ + char buf[256]; + + if (hostname) return hostname; + if (gethostname(buf, sizeof(buf)) < 0) + hostname = eina_stringshare_add(""); + else + hostname = eina_stringshare_add(buf); + return hostname; +} + +void +efreet_dirs_reset(void) +{ + eina_stringshare_replace(&xdg_desktop_dir, NULL); +} + +/** + * @internal + * @param key The environment key to lookup + * @param fallback The fallback value to use + * @return Returns the directory related to the given key or the fallback + * @brief This tries to determine the correct directory name given the + * environment key @a key and fallbacks @a fallback. + */ +static const char * +efreet_dir_get(const char *key, const char *fallback) +{ + char *dir; + const char *t; + + dir = getenv(key); + if (!dir || dir[0] == '\0') + { + int len; + const char *user; + + user = efreet_home_dir_get(); + len = strlen(user) + strlen(fallback) + 1; + dir = alloca(len); + snprintf(dir, len, "%s%s", user, fallback); + + t = eina_stringshare_add(dir); + } + else t = eina_stringshare_add(dir); + + return t; +} + +/** + * @internal + * @param key The environment key to lookup + * @param fallback The fallback value to use + * @return Returns a list of directories specified by the given key @a key + * or from the list of fallbacks in @a fallback. + * @brief Creates a list of directories as given in the environment key @a + * key or from the fallbacks in @a fallback + */ +static Eina_List * +efreet_dirs_get(const char *key, const char *fallback) +{ + Eina_List *dirs = NULL; + const char *path; + char *tmp, *s, *p; + char ts[PATH_MAX]; + size_t len; + + path = getenv(key); + if (!path || (path[0] == '\0')) path = fallback; + + if (!path) return dirs; + + len = strlen(path) + 1; + tmp = alloca(len); + memcpy(tmp, path, len); + s = tmp; + p = strchr(s, EFREET_PATH_SEP); + while (p) + { + *p = '\0'; + if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s)) + { + // resolve path properly/fully to remove path//path2 to + // path/path2, path/./path2 to path/path2 etc. + if (realpath(s, ts)) + dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts)); + } + + s = ++p; + p = strchr(s, EFREET_PATH_SEP); + } + if (!eina_list_search_unsorted(dirs, EINA_COMPARE_CB(strcmp), s)) + { + // resolve path properly/fully to remove path//path2 to + // path/path2, path/./path2 to path/path2 etc. + if (realpath(s, ts)) + dirs = eina_list_append(dirs, (void *)eina_stringshare_add(ts)); + } + + return dirs; +} + +static const char * +efreet_env_expand(const char *in) +{ + Eina_Strbuf *sb; + const char *ret, *p, *e1 = NULL, *e2 = NULL, *val; + char *env; + + if (!in) return NULL; + sb = eina_strbuf_new(); + if (!sb) return NULL; + + /* maximum length of any env var is the input string */ + env = alloca(strlen(in) + 1); + for (p = in; *p; p++) + { + if (!e1) + { + if (*p == '$') e1 = p + 1; + else eina_strbuf_append_char(sb, *p); + } + else if (!(((*p >= 'a') && (*p <= 'z')) || + ((*p >= 'A') && (*p <= 'Z')) || + ((*p >= '0') && (*p <= '9')) || + (*p == '_'))) + { + size_t len; + + e2 = p; + len = (size_t)(e2 - e1); + if (len > 0) + { + memcpy(env, e1, len); + env[len] = 0; + val = getenv(env); + if (val) eina_strbuf_append(sb, val); + } + e1 = NULL; + eina_strbuf_append_char(sb, *p); + } + } + ret = eina_stringshare_add(eina_strbuf_string_get(sb)); + eina_strbuf_free(sb); + return ret; +} + +/** + * @internal + * @param key The user-dirs key to lookup + * @param fallback The fallback value to use + * @return Returns the directory related to the given key or the fallback + * @brief This tries to determine the correct directory name given the + * user-dirs key @a key and fallbacks @a fallback. + */ +static const char * +efreet_user_dir_get(const char *key, const char *fallback) +{ + Eina_File *file = NULL; + Eina_File_Line *line; + Eina_Iterator *it = NULL; + const char *config_home; + char path[PATH_MAX]; + char *ret = NULL; + + config_home = efreet_config_home_get(); + snprintf(path, sizeof(path), "%s/user-dirs.dirs", config_home); + + file = eina_file_open(path, EINA_FALSE); + if (!file) goto fallback; + it = eina_file_map_lines(file); + if (!it) goto fallback; + EINA_ITERATOR_FOREACH(it, line) + { + const char *eq, *end; + + if (line->length < 3) continue; + if (line->start[0] == '#') continue; + if (strncmp(line->start, "XDG", 3)) continue; + eq = memchr(line->start, '=', line->length); + if (!eq) continue; + if (strncmp(key, line->start, eq - line->start)) continue; + if (++eq >= line->end) continue; + if (*eq != '"') continue; + if (++eq >= line->end) continue; + end = memchr(eq, '"', line->end - eq); + if (!end) continue; + ret = alloca(end - eq + 1); + memcpy(ret, eq, end - eq); + ret[end - eq] = '\0'; + break; + } +fallback: + if (it) eina_iterator_free(it); + if (file) eina_file_close(file); + if (!ret) + { + const char *home; + home = efreet_home_dir_get(); + ret = alloca(strlen(home) + strlen(fallback) + 2); + sprintf(ret, "%s/%s", home, fallback); + } + return efreet_env_expand(ret); +} diff --git a/src/lib/efreet_base.h b/src/lib/efreet_base.h new file mode 100644 index 0000000..0eb3d52 --- /dev/null +++ b/src/lib/efreet_base.h @@ -0,0 +1,86 @@ +#ifndef EFREET_BASE_H +#define EFREET_BASE_H +/** + * @file efreet_base.h + * @brief Contains the methods used to support the FDO base directory + * specification. + * @addtogroup Efreet_Base Efreet_Base: The XDG Base Directory Specification + * functions + * + * @{ + */ + + +/** + * @return Returns the XDG Data Home directory + * @brief Retrieves the XDG Data Home directory + */ +EAPI const char *efreet_data_home_get(void); + +/** + * @return Returns the Eina_List of preference ordered extra data directories + * @brief Returns the Eina_List of preference ordered extra data directories + * + * @note The returned list is static inside Efreet. If you add/remove from the + * list then the next call to efreet_data_dirs_get() will return your + * modified values. DO NOT free this list. + */ +EAPI Eina_List *efreet_data_dirs_get(void); + + +/** + * @return Returns the XDG Config Home directory + * @brief Retrieves the XDG Config Home directory + */ +EAPI const char *efreet_config_home_get(void); + +/** + * @return Returns the XDG Desktop directory + * @brief Retrieves the XDG Desktop directory + * @since 1.3 + */ +EAPI const char *efreet_desktop_dir_get(void); + +/** + * @return Returns the Eina_List of preference ordered extra config directories + * @brief Returns the Eina_List of preference ordered extra config + * directories + * + * @note The returned list is static inside Efreet. If you add/remove from the + * list then the next call to efreet_config_dirs_get() will return your + * modified values. DO NOT free this list. + */ +EAPI Eina_List *efreet_config_dirs_get(void); + + +/** + * @return Returns the XDG Cache Home directory + * @brief Retrieves the XDG Cache Home directory + */ +EAPI const char *efreet_cache_home_get(void); + +/** + * @return Returns the current hostname + * @brief Returns the current hostname or empty string if not found + */ +EAPI const char *efreet_hostname_get(void); + +/** + * Efreet_Event_Cache_Update + */ +typedef struct _Efreet_Event_Cache_Update Efreet_Event_Cache_Update; + +/** + * Efreet_Event_Cache_Update + * @brief event struct sent with EFREET_EVENT_*_CACHE_UPDATE + */ +struct _Efreet_Event_Cache_Update +{ + int dummy; +}; + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_cache.c b/src/lib/efreet_cache.c new file mode 100644 index 0000000..b3b9855 --- /dev/null +++ b/src/lib/efreet_cache.c @@ -0,0 +1,1396 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* TODO: Consider flushing local icons cache after idling. + * Icon requests will probably come in batches, f.ex. during menu + * browsing. + */ + +#include <libgen.h> +#include <unistd.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include <Eet.h> +#include <Ecore.h> +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_cache_log_dom +static int _efreet_cache_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_cache_private.h" + +#define NON_EXISTING (void *)-1 + +typedef struct _Efreet_Old_Cache Efreet_Old_Cache; + +struct _Efreet_Old_Cache +{ + Eina_Hash *hash; + Eet_File *ef; +}; + +/** + * Data for cache files + */ +static Eet_Data_Descriptor *directory_edd = NULL; +static Eet_Data_Descriptor *icon_theme_edd = NULL; +static Eet_Data_Descriptor *icon_theme_directory_edd = NULL; + +static Eet_Data_Descriptor *icon_fallback_edd = NULL; +static Eet_Data_Descriptor *icon_element_pointer_edd = NULL; +static Eet_Data_Descriptor *icon_element_edd = NULL; +static Eet_Data_Descriptor *icon_edd = NULL; + +static Eet_File *icon_cache = NULL; +static Eet_File *fallback_cache = NULL; +static Eet_File *icon_theme_cache = NULL; + +static Eina_Hash *themes = NULL; +static Eina_Hash *icons = NULL; +static Eina_Hash *fallbacks = NULL; + +static const char *icon_theme_cache_file = NULL; + +static const char *theme_name = NULL; + +static Eet_Data_Descriptor *version_edd = NULL; +static Eet_Data_Descriptor *desktop_edd = NULL; +static Eet_Data_Descriptor *hash_array_string_edd = NULL; +static Eet_Data_Descriptor *array_string_edd = NULL; +static Eet_Data_Descriptor *hash_string_edd = NULL; + +static Eina_Hash *desktops = NULL; +static Eina_List *desktop_dirs_add = NULL; +static Eet_File *desktop_cache = NULL; +static const char *desktop_cache_file = NULL; + +static Ecore_File_Monitor *cache_monitor = NULL; + +static Ecore_Event_Handler *cache_exe_handler = NULL; +static Ecore_Timer *icon_cache_timer = NULL; +static Ecore_Exe *icon_cache_exe = NULL; +static int icon_cache_exe_lock = -1; +static Ecore_Timer *desktop_cache_timer = NULL; +static Ecore_Exe *desktop_cache_exe = NULL; +static int desktop_cache_exe_lock = -1; + +static Eina_List *old_desktop_caches = NULL; + +static const char *util_cache_file = NULL; +static Eet_File *util_cache = NULL; +static Efreet_Cache_Hash *util_cache_hash = NULL; +static const char *util_cache_hash_key = NULL; +static Efreet_Cache_Array_String *util_cache_names = NULL; +static const char *util_cache_names_key = NULL; + +static void efreet_cache_edd_shutdown(void); +static void efreet_cache_icon_free(Efreet_Cache_Icon *icon); +static void efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon); +static void efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme); + +static Eina_Bool efreet_cache_check(Eet_File **ef, const char *path, int major); +static void *efreet_cache_close(Eet_File *ef); + +static Eina_Bool cache_exe_cb(void *data, int type, void *event); +static Eina_Bool cache_check_change(const char *path); +static void cache_update_cb(void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, const char *path); + +static Eina_Bool desktop_cache_update_cache_cb(void *data); +static Eina_Bool icon_cache_update_cache_cb(void *data); +static void desktop_cache_update_free(void *data, void *ev); +static void icon_cache_update_free(void *data, void *ev); + +static void *hash_array_string_add(void *hash, const char *key, void *data); + +EAPI int EFREET_EVENT_ICON_CACHE_UPDATE = 0; +EAPI int EFREET_EVENT_DESKTOP_CACHE_UPDATE = 0; +EAPI int EFREET_EVENT_DESKTOP_CACHE_BUILD = 0; + +int +efreet_cache_init(void) +{ + char buf[PATH_MAX]; + + _efreet_cache_log_dom = eina_log_domain_register("efreet_cache", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_cache_log_dom < 0) + return 0; + + EFREET_EVENT_ICON_CACHE_UPDATE = ecore_event_type_new(); + EFREET_EVENT_DESKTOP_CACHE_UPDATE = ecore_event_type_new(); + EFREET_EVENT_DESKTOP_CACHE_BUILD = ecore_event_type_new(); + + themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free)); + icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free)); + fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free)); + desktops = eina_hash_string_superfast_new(NULL); + + if (efreet_cache_update) + { + snprintf(buf, sizeof(buf), "%s/efreet", efreet_cache_home_get()); + if (!ecore_file_exists(buf)) + { + if (!ecore_file_mkpath(buf)) + { + ERR("Failed to create directory '%s'", buf); + goto error; + } + efreet_setowner(buf); + } + + cache_exe_handler = ecore_event_handler_add(ECORE_EXE_EVENT_DEL, + cache_exe_cb, NULL); + if (!cache_exe_handler) + { + ERR("Failed to add exe del handler"); + goto error; + } + + cache_monitor = ecore_file_monitor_add(buf, + cache_update_cb, + NULL); + if (!cache_monitor) + { + ERR("Failed to set up ecore file monitor for '%s'", buf); + goto error; + } + + efreet_cache_icon_update(); + efreet_cache_desktop_update(); + } + + return 1; +error: + if (themes) eina_hash_free(themes); + themes = NULL; + if (icons) eina_hash_free(icons); + icons = NULL; + if (fallbacks) eina_hash_free(fallbacks); + fallbacks = NULL; + if (desktops) eina_hash_free(desktops); + desktops = NULL; + + if (cache_exe_handler) ecore_event_handler_del(cache_exe_handler); + cache_exe_handler = NULL; + if (cache_monitor) ecore_file_monitor_del(cache_monitor); + cache_monitor = NULL; + efreet_cache_edd_shutdown(); + return 0; +} + +void +efreet_cache_shutdown(void) +{ + Efreet_Old_Cache *d; + void *data; + + IF_RELEASE(theme_name); + + icon_cache = efreet_cache_close(icon_cache); + icon_theme_cache = efreet_cache_close(icon_theme_cache); + + IF_FREE_HASH(themes); + IF_FREE_HASH(icons); + IF_FREE_HASH(fallbacks); + + IF_FREE_HASH_CB(desktops, EINA_FREE_CB(efreet_cache_desktop_free)); + EINA_LIST_FREE(desktop_dirs_add, data) + eina_stringshare_del(data); + desktop_cache = efreet_cache_close(desktop_cache); + IF_RELEASE(desktop_cache_file); + + if (cache_exe_handler) ecore_event_handler_del(cache_exe_handler); + cache_exe_handler = NULL; + if (cache_monitor) ecore_file_monitor_del(cache_monitor); + cache_monitor = NULL; + + efreet_cache_edd_shutdown(); + if (desktop_cache_timer) + { + ecore_timer_del(desktop_cache_timer); + desktop_cache_timer = NULL; + } + IF_RELEASE(icon_theme_cache_file); + if (icon_cache_exe_lock > 0) + { + close(icon_cache_exe_lock); + icon_cache_exe_lock = -1; + } + + if (desktop_cache_exe_lock > 0) + { + close(desktop_cache_exe_lock); + desktop_cache_exe_lock = -1; + } + + if (old_desktop_caches) + ERR("This application has not properly closed all its desktop references!"); + EINA_LIST_FREE(old_desktop_caches, d) + { + eina_hash_free(d->hash); + eet_close(d->ef); + free(d); + } + + IF_RELEASE(util_cache_names_key); + efreet_cache_array_string_free(util_cache_names); + util_cache_names = NULL; + + IF_RELEASE(util_cache_hash_key); + if (util_cache_hash) + { + eina_hash_free(util_cache_hash->hash); + free(util_cache_hash); + util_cache_hash = NULL; + } + + util_cache = efreet_cache_close(util_cache); + IF_RELEASE(util_cache_file); + + eina_log_domain_unregister(_efreet_cache_log_dom); + _efreet_cache_log_dom = -1; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI const char * +efreet_icon_cache_file(const char *theme) +{ + static char cache_file[PATH_MAX] = { '\0' }; + const char *cache; + + EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL); + + cache = efreet_cache_home_get(); + + snprintf(cache_file, sizeof(cache_file), "%s/efreet/icons_%s_%s.eet", cache, theme, efreet_hostname_get()); + + return cache_file; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI const char * +efreet_icon_theme_cache_file(void) +{ + char tmp[PATH_MAX] = { '\0' }; + + if (icon_theme_cache_file) return icon_theme_cache_file; + + snprintf(tmp, sizeof(tmp), "%s/efreet/icon_themes_%s.eet", + efreet_cache_home_get(), efreet_hostname_get()); + icon_theme_cache_file = eina_stringshare_add(tmp); + + return icon_theme_cache_file; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI const char * +efreet_desktop_util_cache_file(void) +{ + char tmp[PATH_MAX] = { '\0' }; + const char *cache_dir, *lang, *country, *modifier; + + if (util_cache_file) return util_cache_file; + + cache_dir = efreet_cache_home_get(); + lang = efreet_lang_get(); + country = efreet_lang_country_get(); + modifier = efreet_lang_modifier_get(); + + if (lang && country && modifier) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s@%s.eet", cache_dir, efreet_hostname_get(), lang, country, modifier); + else if (lang && country) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s_%s.eet", cache_dir, efreet_hostname_get(), lang, country); + else if (lang) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s_%s.eet", cache_dir, efreet_hostname_get(), lang); + else + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_util_%s.eet", cache_dir, efreet_hostname_get()); + + util_cache_file = eina_stringshare_add(tmp); + return util_cache_file; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_version_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (version_edd) return version_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Version); + version_edd = eet_data_descriptor_file_new(&eddc); + if (!version_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version, + "minor", minor, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(version_edd, Efreet_Cache_Version, + "major", major, EET_T_UCHAR); + + return version_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_hash_array_string_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (hash_array_string_edd) return hash_array_string_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash); + eddc.func.hash_add = hash_array_string_add; + hash_array_string_edd = eet_data_descriptor_file_new(&eddc); + if (!hash_array_string_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_HASH(hash_array_string_edd, Efreet_Cache_Hash, + "hash", hash, efreet_array_string_edd()); + + return hash_array_string_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_hash_string_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (hash_string_edd) return hash_string_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Hash); + hash_string_edd = eet_data_descriptor_file_new(&eddc); + if (!hash_string_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_HASH_STRING(hash_string_edd, Efreet_Cache_Hash, + "hash", hash); + + return hash_string_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_array_string_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (array_string_edd) return array_string_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Array_String); + array_string_edd = eet_data_descriptor_file_new(&eddc); + if (!array_string_edd) return NULL; + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(array_string_edd, Efreet_Cache_Array_String, + "array", array); + + return array_string_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI const char * +efreet_desktop_cache_file(void) +{ + char tmp[PATH_MAX] = { '\0' }; + const char *cache, *lang, *country, *modifier; + + if (desktop_cache_file) return desktop_cache_file; + + cache = efreet_cache_home_get(); + lang = efreet_lang_get(); + country = efreet_lang_country_get(); + modifier = efreet_lang_modifier_get(); + + if (lang && country && modifier) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s@%s.eet", cache, efreet_hostname_get(), lang, country, modifier); + else if (lang && country) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s_%s.eet", cache, efreet_hostname_get(), lang, country); + else if (lang) + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s_%s.eet", cache, efreet_hostname_get(), lang); + else + snprintf(tmp, sizeof(tmp), "%s/efreet/desktop_%s.eet", cache, efreet_hostname_get()); + + desktop_cache_file = eina_stringshare_add(tmp); + return desktop_cache_file; +} + +#define EDD_SHUTDOWN(Edd) \ + if (Edd) eet_data_descriptor_free(Edd); \ +Edd = NULL; + +static void +efreet_cache_edd_shutdown(void) +{ + EDD_SHUTDOWN(version_edd); + EDD_SHUTDOWN(desktop_edd); + EDD_SHUTDOWN(hash_array_string_edd); + EDD_SHUTDOWN(array_string_edd); + EDD_SHUTDOWN(hash_string_edd); + EDD_SHUTDOWN(icon_theme_edd); + EDD_SHUTDOWN(icon_theme_directory_edd); + EDD_SHUTDOWN(directory_edd); + EDD_SHUTDOWN(icon_fallback_edd); + EDD_SHUTDOWN(icon_element_pointer_edd); + EDD_SHUTDOWN(icon_element_edd); + EDD_SHUTDOWN(icon_edd); +} + +#define EFREET_POINTER_TYPE(Edd_Dest, Edd_Source, Type) \ +{ \ + typedef struct _Efreet_##Type##_Pointer Efreet_##Type##_Pointer; \ + struct _Efreet_##Type##_Pointer \ + { \ + Efreet_##Type *pointer; \ + }; \ + \ + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_##Type##_Pointer); \ + Edd_Dest = eet_data_descriptor_file_new(&eddc); \ + EET_DATA_DESCRIPTOR_ADD_SUB(Edd_Dest, Efreet_##Type##_Pointer, \ + "pointer", pointer, Edd_Source); \ +} + +static Eet_Data_Descriptor * +efreet_icon_directory_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (directory_edd) return directory_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Directory); + directory_edd = eet_data_descriptor_file_new(&eddc); + if (!directory_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(directory_edd, Efreet_Cache_Directory, + "modified_time", modified_time, EET_T_LONG_LONG); + + return directory_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_icon_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (icon_edd) return icon_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Element); + icon_element_edd = eet_data_descriptor_file_new(&eddc); + if (!icon_element_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element, + "type", type, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element, + "normal", normal, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element, + "normal", normal, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element, + "min", min, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_element_edd, Efreet_Cache_Icon_Element, + "max", max, EET_T_USHORT); + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_element_edd, Efreet_Cache_Icon_Element, + "paths", paths); + + EFREET_POINTER_TYPE(icon_element_pointer_edd, icon_element_edd, Cache_Icon_Element); + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon); + icon_edd = eet_data_descriptor_file_new(&eddc); + if (!icon_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_edd, Efreet_Cache_Icon, + "theme", theme, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY(icon_edd, Efreet_Cache_Icon, + "icons", icons, icon_element_pointer_edd); + + return icon_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_icon_theme_edd(Eina_Bool cache) +{ + Eet_Data_Descriptor_Class eddc; + + if (icon_theme_edd) return icon_theme_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Icon_Theme_Directory); + icon_theme_directory_edd = eet_data_descriptor_file_new(&eddc); + if (!icon_theme_directory_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "name", name, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "context", context, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "type", type, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "size.normal", size.normal, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "size.min", size.min, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "size.max", size.max, EET_T_UINT); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_directory_edd, Efreet_Icon_Theme_Directory, + "size.threshold", size.threshold, EET_T_UINT); + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Icon_Theme); + icon_theme_edd = eet_data_descriptor_file_new(&eddc); + if (!icon_theme_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "name.internal", theme.name.internal, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "name.name", theme.name.name, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "comment", theme.comment, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "example_icon", theme.example_icon, EET_T_STRING); + + eet_data_descriptor_element_add(icon_theme_edd, "paths", EET_T_STRING, EET_G_LIST, + offsetof(Efreet_Cache_Icon_Theme, theme.paths), 0, NULL, NULL); + eet_data_descriptor_element_add(icon_theme_edd, "inherits", EET_T_STRING, EET_G_LIST, + offsetof(Efreet_Cache_Icon_Theme, theme.inherits), 0, NULL, NULL); + EET_DATA_DESCRIPTOR_ADD_LIST(icon_theme_edd, Efreet_Cache_Icon_Theme, + "directories", theme.directories, icon_theme_directory_edd); + + if (cache) + { + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "last_cache_check", last_cache_check, EET_T_LONG_LONG); + + EET_DATA_DESCRIPTOR_ADD_BASIC(icon_theme_edd, Efreet_Cache_Icon_Theme, + "path", path, EET_T_STRING); + + EET_DATA_DESCRIPTOR_ADD_HASH(icon_theme_edd, Efreet_Cache_Icon_Theme, + "dirs", dirs, efreet_icon_directory_edd()); + } + + return icon_theme_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_icon_fallback_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (icon_fallback_edd) return icon_fallback_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Fallback_Icon); + icon_fallback_edd = eet_data_descriptor_file_new(&eddc); + if (!icon_fallback_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_VAR_ARRAY_STRING(icon_fallback_edd, + Efreet_Cache_Fallback_Icon, "icons", icons); + + return icon_fallback_edd; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI Eet_Data_Descriptor * +efreet_desktop_edd(void) +{ + Eet_Data_Descriptor_Class eddc; + + if (desktop_edd) return desktop_edd; + + EET_EINA_FILE_DATA_DESCRIPTOR_CLASS_SET(&eddc, Efreet_Cache_Desktop); + desktop_edd = eet_data_descriptor_file_new(&eddc); + if (!desktop_edd) return NULL; + + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "type", desktop.type, EET_T_INT); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "version", desktop.version, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "orig_path", desktop.orig_path, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "load_time", desktop.load_time, EET_T_LONG_LONG); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "name", desktop.name, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "generic_name", desktop.generic_name, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "comment", desktop.comment, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "icon", desktop.icon, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "try_exec", desktop.try_exec, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "exec", desktop.exec, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "path", desktop.path, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_wm_class", desktop.startup_wm_class, EET_T_STRING); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "url", desktop.url, EET_T_STRING); + eet_data_descriptor_element_add(desktop_edd, "only_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.only_show_in), 0, NULL, NULL); + eet_data_descriptor_element_add(desktop_edd, "not_show_in", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.not_show_in), 0, NULL, NULL); + eet_data_descriptor_element_add(desktop_edd, "categories", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.categories), 0, NULL, NULL); + eet_data_descriptor_element_add(desktop_edd, "mime_types", EET_T_STRING, EET_G_LIST, offsetof(Efreet_Cache_Desktop, desktop.mime_types), 0, NULL, NULL); + eet_data_descriptor_element_add(desktop_edd, "x", EET_T_STRING, EET_G_HASH, offsetof(Efreet_Cache_Desktop, desktop.x), 0, NULL, NULL); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "no_display", desktop.no_display, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "hidden", desktop.hidden, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "terminal", desktop.terminal, EET_T_UCHAR); + EET_DATA_DESCRIPTOR_ADD_BASIC(desktop_edd, Efreet_Cache_Desktop, "startup_notify", desktop.startup_notify, EET_T_UCHAR); + + return desktop_edd; +} + +Efreet_Cache_Icon * +efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon) +{ + Efreet_Cache_Icon *cache = NULL; + + if (theme_name && strcmp(theme_name, theme->name.internal)) + { + /* FIXME: this is bad if people have pointer to this cache, things will go wrong */ + INF("theme_name change from `%s` to `%s`", theme_name, theme->name.internal); + IF_RELEASE(theme_name); + icon_cache = efreet_cache_close(icon_cache); + eina_hash_free(icons); + icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free)); + } + + if (!efreet_cache_check(&icon_cache, efreet_icon_cache_file(theme->name.internal), EFREET_ICON_CACHE_MAJOR)) return NULL; + if (!theme_name) + theme_name = eina_stringshare_add(theme->name.internal); + + cache = eina_hash_find(icons, icon); + if (cache == NON_EXISTING) return NULL; + if (cache) return cache; + + cache = eet_data_read(icon_cache, efreet_icon_edd(), icon); + if (cache) + eina_hash_add(icons, icon, cache); + else + eina_hash_add(icons, icon, NON_EXISTING); + return cache; +} + +Efreet_Cache_Fallback_Icon * +efreet_cache_icon_fallback_find(const char *icon) +{ + Efreet_Cache_Fallback_Icon *cache; + + if (!efreet_cache_check(&fallback_cache, efreet_icon_cache_file(EFREET_CACHE_ICON_FALLBACK), EFREET_ICON_CACHE_MAJOR)) return NULL; + + cache = eina_hash_find(fallbacks, icon); + if (cache == NON_EXISTING) return NULL; + if (cache) return cache; + + cache = eet_data_read(fallback_cache, efreet_icon_fallback_edd(), icon); + if (cache) + eina_hash_add(fallbacks, icon, cache); + else + eina_hash_add(fallbacks, icon, NON_EXISTING); + return cache; +} + +Efreet_Icon_Theme * +efreet_cache_icon_theme_find(const char *theme) +{ + Efreet_Cache_Icon_Theme *cache; + + if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL; + + cache = eina_hash_find(themes, theme); + if (cache == NON_EXISTING) return NULL; + if (cache) return &(cache->theme); + + cache = eet_data_read(icon_theme_cache, efreet_icon_theme_edd(EINA_FALSE), theme); + if (cache) + { + eina_hash_add(themes, theme, cache); + return &(cache->theme); + } + else + eina_hash_add(themes, theme, NON_EXISTING); + return NULL; +} + +static void +efreet_cache_icon_free(Efreet_Cache_Icon *icon) +{ + unsigned int i; + + if (!icon) return; + if (icon == NON_EXISTING) return; + + for (i = 0; i < icon->icons_count; ++i) + { + free(icon->icons[i]->paths); + free(icon->icons[i]); + } + + free(icon->icons); + free(icon); +} + +static void +efreet_cache_icon_fallback_free(Efreet_Cache_Fallback_Icon *icon) +{ + if (!icon) return; + if (icon == NON_EXISTING) return; + + free(icon->icons); + free(icon); +} + +static void +efreet_cache_icon_theme_free(Efreet_Icon_Theme *theme) +{ + void *data; + + if (!theme) return; + if (theme == NON_EXISTING) return; + + eina_list_free(theme->paths); + eina_list_free(theme->inherits); + EINA_LIST_FREE(theme->directories, data) + free(data); + + free(theme); +} + +Eina_List * +efreet_cache_icon_theme_list(void) +{ + Eina_List *ret = NULL; + char **keys; + int i, num; + + if (!efreet_cache_check(&icon_theme_cache, efreet_icon_theme_cache_file(), EFREET_ICON_CACHE_MAJOR)) return NULL; + keys = eet_list(icon_theme_cache, "*", &num); + for (i = 0; i < num; i++) + { + Efreet_Icon_Theme *theme; + if (!strncmp(keys[i], "__efreet", 8)) continue; + + theme = eina_hash_find(themes, keys[i]); + if (!theme) + theme = efreet_cache_icon_theme_find(keys[i]); + if (theme && theme != NON_EXISTING) + ret = eina_list_append(ret, theme); + } + free(keys); + return ret; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI void +efreet_cache_array_string_free(Efreet_Cache_Array_String *array) +{ + if (!array) return; + free(array->array); + free(array); +} + +Efreet_Desktop * +efreet_cache_desktop_find(const char *file) +{ + Efreet_Cache_Desktop *cache; + char rp[PATH_MAX]; + + if (!realpath(file, rp)) return NULL; + + if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) return NULL; + + cache = eina_hash_find(desktops, rp); + if (cache == NON_EXISTING) return NULL; + if (cache) + { + /* If less than one second since last stat, return desktop */ + if ((ecore_time_get() - cache->check_time) < 1) + { + INF("Return without stat %f %f", ecore_time_get(), cache->check_time); + return &cache->desktop; + } + if (cache->desktop.load_time == ecore_file_mod_time(cache->desktop.orig_path)) + { + INF("Return with stat %f %f", ecore_time_get(), cache->check_time); + cache->check_time = ecore_time_get(); + return &cache->desktop; + } + + /* We got stale data. The desktop will be free'd eventually as + * users will call efreet_desktop_free */ + eina_hash_set(desktops, rp, NON_EXISTING); + cache = NULL; + } + + cache = eet_data_read(desktop_cache, efreet_desktop_edd(), rp); + if (cache) + { + if (cache->desktop.load_time != ecore_file_mod_time(cache->desktop.orig_path)) + { + /* Don't return stale data */ + INF("We got stale data in the desktop cache"); + efreet_cache_desktop_free(&cache->desktop); + eina_hash_set(desktops, rp, NON_EXISTING); + } + else + { + cache->desktop.eet = 1; + cache->check_time = ecore_time_get(); + eina_hash_set(desktops, cache->desktop.orig_path, cache); + return &cache->desktop; + } + } + else + eina_hash_set(desktops, rp, NON_EXISTING); + return NULL; +} + +void +efreet_cache_desktop_free(Efreet_Desktop *desktop) +{ + Efreet_Old_Cache *d; + Efreet_Desktop *curr; + Eina_List *l; + + if (!desktop || + desktop == NON_EXISTING || + !desktop->eet) return; + + curr = eina_hash_find(desktops, desktop->orig_path); + if (curr == desktop) + { + INF("Found in current cache, purge\n"); + eina_hash_del_by_key(desktops, desktop->orig_path); + } + + EINA_LIST_FOREACH(old_desktop_caches, l, d) + { + curr = eina_hash_find(d->hash, desktop->orig_path); + if (curr == desktop) + { + INF("Found in old cache, purge\n"); + eina_hash_del_by_key(d->hash, desktop->orig_path); + if (eina_hash_population(d->hash) == 0) + { + INF("Cache empty, close file\n"); + eina_hash_free(d->hash); + eet_close(d->ef); + free(d); + old_desktop_caches = eina_list_remove_list(old_desktop_caches, l); + } + break; + } + } + + eina_list_free(desktop->only_show_in); + eina_list_free(desktop->not_show_in); + eina_list_free(desktop->categories); + eina_list_free(desktop->mime_types); + IF_FREE_HASH(desktop->x); + free(desktop); +} + +void +efreet_cache_desktop_add(Efreet_Desktop *desktop) +{ + char buf[PATH_MAX]; + char *dir; + Efreet_Cache_Array_String *arr; + + /* + * Read file from disk, save path in cache so it will be included in next + * cache update + */ + strncpy(buf, desktop->orig_path, PATH_MAX); + buf[PATH_MAX - 1] = '\0'; + dir = dirname(buf); + arr = efreet_cache_desktop_dirs(); + if (arr) + { + unsigned int i; + + for (i = 0; i < arr->array_count; i++) + { + /* Check if we already have this dir in cache */ + if (!strcmp(dir, arr->array[i])) + return; + } + efreet_cache_array_string_free(arr); + } + if (!eina_list_search_unsorted_list(desktop_dirs_add, EINA_COMPARE_CB(strcmp), dir)) + desktop_dirs_add = eina_list_append(desktop_dirs_add, eina_stringshare_add(dir)); + + efreet_cache_desktop_update(); +} + +Efreet_Cache_Array_String * +efreet_cache_desktop_dirs(void) +{ + if (!efreet_cache_check(&desktop_cache, efreet_desktop_cache_file(), EFREET_DESKTOP_CACHE_MAJOR)) return NULL; + + return eet_data_read(desktop_cache, efreet_array_string_edd(), EFREET_CACHE_DESKTOP_DIRS); +} + +void +efreet_cache_desktop_update(void) +{ + if (!efreet_cache_update) return; + + if (desktop_cache_timer) + ecore_timer_del(desktop_cache_timer); + desktop_cache_timer = ecore_timer_add(0.2, desktop_cache_update_cache_cb, NULL); +} + +void +efreet_cache_desktop_close(void) +{ + IF_RELEASE(util_cache_names_key); + IF_RELEASE(util_cache_hash_key); + + if ((desktop_cache) && (desktop_cache != NON_EXISTING)) + { + Efreet_Old_Cache *d = NEW(Efreet_Old_Cache, 1); + if (d) + { + d->hash = desktops; + d->ef = desktop_cache; + old_desktop_caches = eina_list_append(old_desktop_caches, d); + } + + desktops = eina_hash_string_superfast_new(NULL); + } + desktop_cache = NULL; + + efreet_cache_array_string_free(util_cache_names); + util_cache_names = NULL; + + if (util_cache_hash) + { + eina_hash_free(util_cache_hash->hash); + free(util_cache_hash); + util_cache_hash = NULL; + } + + util_cache = efreet_cache_close(util_cache); + + IF_RELEASE(desktop_cache_file); + IF_RELEASE(util_cache_file); +} + +void +efreet_cache_icon_update(void) +{ + if (!efreet_cache_update) return; + + if (icon_cache_timer) + ecore_timer_del(icon_cache_timer); + icon_cache_timer = ecore_timer_add(0.2, icon_cache_update_cache_cb, NULL); +} + +static Eina_Bool +efreet_cache_check(Eet_File **ef, const char *path, int major) +{ + Efreet_Cache_Version *version; + + if (*ef == NON_EXISTING) return EINA_FALSE; + if (*ef) return EINA_TRUE; + if (!*ef) + *ef = eet_open(path, EET_FILE_MODE_READ); + if (!*ef) + { + *ef = NON_EXISTING; + return EINA_FALSE; + } + + version = eet_data_read(*ef, efreet_version_edd(), EFREET_CACHE_VERSION); + if ((!version) || (version->major != major)) + { + IF_FREE(version); + eet_close(*ef); + *ef = NON_EXISTING; + return EINA_FALSE; + } + free(version); + return EINA_TRUE; +} + +static void * +efreet_cache_close(Eet_File *ef) +{ + if (ef && ef != NON_EXISTING) + eet_close(ef); + return NULL; +} + +Efreet_Cache_Hash * +efreet_cache_util_hash_string(const char *key) +{ + if (util_cache_hash_key && !strcmp(key, util_cache_hash_key)) + return util_cache_hash; + if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL; + + if (util_cache_hash) + { + /* free previous util_cache */ + IF_RELEASE(util_cache_hash_key); + eina_hash_free(util_cache_hash->hash); + free(util_cache_hash); + } + util_cache_hash_key = eina_stringshare_add(key); + util_cache_hash = eet_data_read(util_cache, efreet_hash_string_edd(), key); + return util_cache_hash; +} + +Efreet_Cache_Hash * +efreet_cache_util_hash_array_string(const char *key) +{ + if (util_cache_hash_key && !strcmp(key, util_cache_hash_key)) + return util_cache_hash; + if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL; + + IF_RELEASE(util_cache_hash_key); + if (util_cache_hash) + { + /* free previous cache */ + eina_hash_free(util_cache_hash->hash); + free(util_cache_hash); + } + util_cache_hash_key = eina_stringshare_add(key); + util_cache_hash = eet_data_read(util_cache, efreet_hash_array_string_edd(), key); + return util_cache_hash; +} + +Efreet_Cache_Array_String * +efreet_cache_util_names(const char *key) +{ + if (util_cache_names_key && !strcmp(key, util_cache_names_key)) + return util_cache_names; + if (!efreet_cache_check(&util_cache, efreet_desktop_util_cache_file(), EFREET_DESKTOP_UTILS_CACHE_MAJOR)) return NULL; + + if (util_cache_names) + { + /* free previous util_cache */ + IF_RELEASE(util_cache_names_key); + efreet_cache_array_string_free(util_cache_names); + } + util_cache_names_key = eina_stringshare_add(key); + util_cache_names = eet_data_read(util_cache, efreet_array_string_edd(), key); + return util_cache_names; +} + +static Eina_Bool +cache_exe_cb(void *data __UNUSED__, int type __UNUSED__, void *event) +{ + Ecore_Exe_Event_Del *ev; + + ev = event; + if (ev->exe == desktop_cache_exe) + { + if (desktop_cache_exe_lock > 0) + { + close(desktop_cache_exe_lock); + desktop_cache_exe_lock = -1; + } + desktop_cache_exe = NULL; + } + else if (ev->exe == icon_cache_exe) + { + if (icon_cache_exe_lock > 0) + { + close(icon_cache_exe_lock); + icon_cache_exe_lock = -1; + } + icon_cache_exe = NULL; + } + return ECORE_CALLBACK_RENEW; +} + +static Eina_Bool +cache_check_change(const char *path) +{ + const char *data; + Eina_Bool changed = EINA_TRUE; + Eina_File *f; + + f = eina_file_open(path, EINA_FALSE); + if (!f) return EINA_TRUE; + if (eina_file_size_get(f) < 1) return EINA_TRUE; + data = eina_file_map_all(f, EINA_FILE_SEQUENTIAL); + if (*data == 'n') changed = EINA_FALSE; + eina_file_close(f); + return changed; +} + +static void +cache_update_cb(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__, + Ecore_File_Event event, const char *path) +{ + const char *file; + Efreet_Event_Cache_Update *ev = NULL; + Efreet_Old_Cache *d = NULL; + Eina_List *l = NULL; + + if (event != ECORE_FILE_EVENT_CLOSED) + return; + + file = ecore_file_file_get(path); + if (!file) return; + if (!strcmp(file, "desktop_data.update")) + { + if (cache_check_change(path)) + { + ev = NEW(Efreet_Event_Cache_Update, 1); + if (!ev) goto error; + + efreet_cache_desktop_close(); + + ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE, ev, desktop_cache_update_free, d); + } + ecore_event_add(EFREET_EVENT_DESKTOP_CACHE_BUILD, NULL, NULL, NULL); + /* TODO: Check if desktop_dirs_add exists, and rebuild cache if */ + } + else if (!strcmp(file, "icon_data.update")) + { + if (cache_check_change(path)) + { + ev = NEW(Efreet_Event_Cache_Update, 1); + if (!ev) goto error; + + IF_RELEASE(theme_name); + + /* Save all old caches */ + d = NEW(Efreet_Old_Cache, 1); + if (!d) goto error; + d->hash = themes; + d->ef = icon_theme_cache; + l = eina_list_append(l, d); + + d = NEW(Efreet_Old_Cache, 1); + if (!d) goto error; + d->hash = icons; + d->ef = icon_cache; + l = eina_list_append(l, d); + + d = NEW(Efreet_Old_Cache, 1); + if (!d) goto error; + d->hash = fallbacks; + d->ef = fallback_cache; + l = eina_list_append(l, d); + + /* Create new empty caches */ + themes = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_theme_free)); + icons = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_free)); + fallbacks = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_icon_fallback_free)); + + icon_theme_cache = NULL; + icon_cache = NULL; + fallback_cache = NULL; + + /* Send event */ + ecore_event_add(EFREET_EVENT_ICON_CACHE_UPDATE, ev, icon_cache_update_free, l); + } + } + return; +error: + IF_FREE(ev); + IF_FREE(d); + EINA_LIST_FREE(l, d) + free(d); +} + +static Eina_Bool +desktop_cache_update_cache_cb(void *data __UNUSED__) +{ + char file[PATH_MAX]; + struct flock fl; + int prio; + + desktop_cache_timer = NULL; + + /* TODO: Retry update cache later */ + if (desktop_cache_exe_lock > 0) return ECORE_CALLBACK_CANCEL; + + snprintf(file, sizeof(file), "%s/efreet/desktop_exec.lock", efreet_cache_home_get()); + + desktop_cache_exe_lock = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (desktop_cache_exe_lock < 0) goto error; + efreet_fsetowner(desktop_cache_exe_lock); + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if (fcntl(desktop_cache_exe_lock, F_SETLK, &fl) < 0) goto error; + prio = ecore_exe_run_priority_get(); + ecore_exe_run_priority_set(19); + eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_desktop_cache_create", sizeof(file)); + if (desktop_dirs_add) + { + const char *str; + + eina_strlcat(file, " -d", sizeof(file)); + EINA_LIST_FREE(desktop_dirs_add, str) + { + eina_strlcat(file, " ", sizeof(file)); + eina_strlcat(file, str, sizeof(file)); + eina_stringshare_del(str); + } + } + INF("Run desktop cache creation: %s", file); + desktop_cache_exe = ecore_exe_run(file, NULL); + ecore_exe_run_priority_set(prio); + if (!desktop_cache_exe) goto error; + + return ECORE_CALLBACK_CANCEL; +error: + if (desktop_cache_exe_lock > 0) + { + close(desktop_cache_exe_lock); + desktop_cache_exe_lock = -1; + } + return ECORE_CALLBACK_CANCEL; +} + +static Eina_Bool +icon_cache_update_cache_cb(void *data __UNUSED__) +{ + char file[PATH_MAX]; + struct flock fl; + int prio; + Eina_List **l, *l2; + + icon_cache_timer = NULL; + + /* TODO: Retry update cache later */ + if (icon_cache_exe_lock > 0) return ECORE_CALLBACK_CANCEL; + + snprintf(file, sizeof(file), "%s/efreet/icon_exec.lock", efreet_cache_home_get()); + + icon_cache_exe_lock = open(file, O_CREAT | O_RDWR, S_IRUSR | S_IWUSR); + if (icon_cache_exe_lock < 0) goto error; + efreet_fsetowner(icon_cache_exe_lock); + memset(&fl, 0, sizeof(struct flock)); + fl.l_type = F_WRLCK; + fl.l_whence = SEEK_SET; + if (fcntl(icon_cache_exe_lock, F_SETLK, &fl) < 0) goto error; + prio = ecore_exe_run_priority_get(); + ecore_exe_run_priority_set(19); + eina_strlcpy(file, PACKAGE_LIB_DIR "/efreet/efreet_icon_cache_create", sizeof(file)); + l = efreet_icon_extra_list_get(); + if (l && eina_list_count(*l) > 0) + { + Eina_List *ll; + char *p; + + eina_strlcat(file, " -d", sizeof(file)); + EINA_LIST_FOREACH(*l, ll, p) + { + eina_strlcat(file, " ", sizeof(file)); + eina_strlcat(file, p, sizeof(file)); + } + } + l2 = efreet_icon_extensions_list_get(); + if (eina_list_count(l2) > 0) + { + Eina_List *ll; + char *p; + + eina_strlcat(file, " -e", sizeof(file)); + EINA_LIST_FOREACH(l2, ll, p) + { + eina_strlcat(file, " ", sizeof(file)); + eina_strlcat(file, p, sizeof(file)); + } + } + icon_cache_exe = ecore_exe_run(file, NULL); + ecore_exe_run_priority_set(prio); + if (!icon_cache_exe) goto error; + + return ECORE_CALLBACK_CANCEL; + +error: + if (icon_cache_exe_lock > 0) + { + close(icon_cache_exe_lock); + icon_cache_exe_lock = -1; + } + return ECORE_CALLBACK_CANCEL; +} + +static void +desktop_cache_update_free(void *data, void *ev) +{ + Efreet_Old_Cache *d; + int dangling = 0; + + d = data; + if (d && (eina_list_data_find(old_desktop_caches, d) == d)) + { + /* + * All users should now had the chance to update their pointers. + * Check whether we still have some dangling and print a warning. + * Programs might close their pointers later. + */ + if (d->hash) + { + Eina_Iterator *it; + Eina_Hash_Tuple *tuple; + + it = eina_hash_iterator_tuple_new(d->hash); + EINA_ITERATOR_FOREACH(it, tuple) + { + if (tuple->data == NON_EXISTING) continue; + WRN("%d:%s still in cache after update event!", + ((Efreet_Desktop *)tuple->data)->ref, (char *)tuple->key); + dangling++; + } + eina_iterator_free(it); + } + if (dangling != 0) + { + WRN("There are still %i desktop files with old\n" + "dangling references to desktop files. This application\n" + "has not handled the EFREET_EVENT_DESKTOP_CACHE_UPDATE\n" + "fully and released its references. Please fix the application\n" + "so it does this.", + dangling); + } + } + free(ev); +} + +static void +icon_cache_update_free(void *data, void *ev) +{ + Efreet_Old_Cache *d; + Eina_List *l; + + l = data; + EINA_LIST_FREE(l, d) + { + if (d->hash) + eina_hash_free(d->hash); + efreet_cache_close(d->ef); + free(d); + } + free(ev); +} + +static void * +hash_array_string_add(void *hash, const char *key, void *data) +{ + if (!hash) + hash = eina_hash_string_superfast_new(EINA_FREE_CB(efreet_cache_array_string_free)); + if (!hash) + return NULL; + eina_hash_add(hash, key, data); + return hash; +} diff --git a/src/lib/efreet_cache_private.h b/src/lib/efreet_cache_private.h new file mode 100644 index 0000000..e281e61 --- /dev/null +++ b/src/lib/efreet_cache_private.h @@ -0,0 +1,63 @@ +#ifndef EFREET_CACHE_PRIVATE_H +#define EFREET_CACHE_PRIVATE_H + +#define EFREET_DESKTOP_CACHE_MAJOR 1 +#define EFREET_DESKTOP_CACHE_MINOR 0 +#define EFREET_DESKTOP_UTILS_CACHE_MAJOR 1 +#define EFREET_DESKTOP_UTILS_CACHE_MINOR 0 + +#define EFREET_ICON_CACHE_MAJOR 1 +#define EFREET_ICON_CACHE_MINOR 0 + +#define EFREET_CACHE_VERSION "__efreet//version" +#define EFREET_CACHE_ICON_FALLBACK "__efreet_fallback" +#define EFREET_CACHE_ICON_EXTENSIONS "__efreet//icon_extensions" +#define EFREET_CACHE_ICON_EXTRA_DIRS "__efreet//icon_extra_dirs" +#define EFREET_CACHE_DESKTOP_DIRS "__efreet//desktop_dirs" + +EAPI const char *efreet_desktop_util_cache_file(void); +EAPI const char *efreet_desktop_cache_file(void); +EAPI const char *efreet_icon_cache_file(const char *theme); +EAPI const char *efreet_icon_theme_cache_file(void); + +EAPI Eet_Data_Descriptor *efreet_version_edd(void); +EAPI Eet_Data_Descriptor *efreet_desktop_edd(void); +EAPI Eet_Data_Descriptor *efreet_hash_array_string_edd(void); +EAPI Eet_Data_Descriptor *efreet_hash_string_edd(void); +EAPI Eet_Data_Descriptor *efreet_array_string_edd(void); +EAPI Eet_Data_Descriptor *efreet_icon_theme_edd(Eina_Bool cache); +EAPI Eet_Data_Descriptor *efreet_icon_edd(void); +EAPI Eet_Data_Descriptor *efreet_icon_fallback_edd(void); + +typedef struct _Efreet_Cache_Icon_Theme Efreet_Cache_Icon_Theme; +typedef struct _Efreet_Cache_Directory Efreet_Cache_Directory; +typedef struct _Efreet_Cache_Desktop Efreet_Cache_Desktop; + +struct _Efreet_Cache_Icon_Theme +{ + Efreet_Icon_Theme theme; + + long long last_cache_check; /**< Last time the cache was checked */ + + Eina_Hash *dirs; /**< All possible icon paths for this theme */ + + const char *path; /**< path to index.theme */ + + Eina_Bool hidden:1; /**< Should this theme be hidden from users */ + Eina_Bool valid:1; /**< Have we seen an index for this theme */ + Eina_Bool changed:1; /**< Changed since last seen */ +}; + +struct _Efreet_Cache_Directory +{ + long long modified_time; +}; + +struct _Efreet_Cache_Desktop +{ + Efreet_Desktop desktop; + + double check_time; /**< Last time we check for disk modification */ +}; + +#endif diff --git a/src/lib/efreet_desktop.c b/src/lib/efreet_desktop.c new file mode 100644 index 0000000..9293f94 --- /dev/null +++ b/src/lib/efreet_desktop.c @@ -0,0 +1,1085 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#ifdef HAVE_EVIL +# include <Evil.h> +#endif + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom +int _efreet_desktop_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" + +#define DESKTOP_VERSION "1.0" + +/** + * The current desktop environment (e.g. "Enlightenment" or "Gnome") + */ +static const char *desktop_environment = NULL; + +/** + * A list of the desktop types available + */ +static Eina_List *efreet_desktop_types = NULL; + +static Eina_Hash *change_monitors = NULL; + +EAPI int EFREET_DESKTOP_TYPE_APPLICATION = 0; +EAPI int EFREET_DESKTOP_TYPE_LINK = 0; +EAPI int EFREET_DESKTOP_TYPE_DIRECTORY = 0; + +/** + * @internal + * Information about custom types + */ +typedef struct Efreet_Desktop_Type_Info Efreet_Desktop_Type_Info; +struct Efreet_Desktop_Type_Info +{ + int id; + const char *type; + Efreet_Desktop_Type_Parse_Cb parse_func; + Efreet_Desktop_Type_Save_Cb save_func; + Efreet_Desktop_Type_Free_Cb free_func; +}; + +static int efreet_desktop_read(Efreet_Desktop *desktop); +static Efreet_Desktop_Type_Info *efreet_desktop_type_parse(const char *type_str); +static void efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info); +static void *efreet_desktop_application_fields_parse(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static void efreet_desktop_application_fields_save(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static void *efreet_desktop_link_fields_parse(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static void efreet_desktop_link_fields_save(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static int efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static void efreet_desktop_generic_fields_save(Efreet_Desktop *desktop, + Efreet_Ini *ini); +static Eina_Bool efreet_desktop_x_fields_parse(const Eina_Hash *hash, + const void *key, + void *data, + void *fdata); +static Eina_Bool efreet_desktop_x_fields_save(const Eina_Hash *hash, + const void *key, + void *value, + void *fdata); +static int efreet_desktop_environment_check(Efreet_Desktop *desktop); + +static void efreet_desktop_changes_listen(void); +static void efreet_desktop_changes_listen_recursive(const char *path); +static void efreet_desktop_changes_monitor_add(const char *path); +static void efreet_desktop_changes_cb(void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, const char *path); + +/** + * @internal + * @return Returns > 0 on success or 0 on failure + * @brief Initialize the Desktop parser subsystem + */ +int +efreet_desktop_init(void) +{ + _efreet_desktop_log_dom = eina_log_domain_register + ("efreet_desktop", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_desktop_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_desktop"); + return 0; + } + +#ifdef HAVE_EVIL + if (!evil_sockets_init()) + { + ERR("Could not initialize Winsock system"); + return 0; + } +#endif + + efreet_desktop_types = NULL; + + EFREET_DESKTOP_TYPE_APPLICATION = efreet_desktop_type_add("Application", + efreet_desktop_application_fields_parse, + efreet_desktop_application_fields_save, + NULL); + EFREET_DESKTOP_TYPE_LINK = efreet_desktop_type_add("Link", + efreet_desktop_link_fields_parse, + efreet_desktop_link_fields_save, NULL); + EFREET_DESKTOP_TYPE_DIRECTORY = efreet_desktop_type_add("Directory", NULL, + NULL, NULL); + + efreet_desktop_changes_listen(); + return 1; +} + +/** + * @internal + * @returns the number of initializations left for this system + * @brief Attempts to shut down the subsystem if nothing else is using it + */ +void +efreet_desktop_shutdown(void) +{ + Efreet_Desktop_Type_Info *info; + + IF_RELEASE(desktop_environment); + EINA_LIST_FREE(efreet_desktop_types, info) + efreet_desktop_type_info_free(info); + IF_FREE_HASH(change_monitors); +#ifdef HAVE_EVIL + evil_sockets_shutdown(); +#endif + eina_log_domain_unregister(_efreet_desktop_log_dom); + _efreet_desktop_log_dom = -1; +} + +EAPI Efreet_Desktop * +efreet_desktop_get(const char *file) +{ + Efreet_Desktop *desktop; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + desktop = efreet_desktop_new(file); + if (!desktop) return NULL; + + /* If we didn't find this file in the eet cache, add path to search path */ + if (!desktop->eet) + { + /* Check whether the desktop type is a system type, + * and therefor known by the cache builder */ + Efreet_Desktop_Type_Info *info; + + info = eina_list_nth(efreet_desktop_types, desktop->type); + if (info && ( + info->id == EFREET_DESKTOP_TYPE_APPLICATION || + info->id == EFREET_DESKTOP_TYPE_LINK || + info->id == EFREET_DESKTOP_TYPE_DIRECTORY + )) + efreet_cache_desktop_add(desktop); + } + + return desktop; +} + +EAPI int +efreet_desktop_ref(Efreet_Desktop *desktop) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + desktop->ref++; + return desktop->ref; +} + +EAPI Efreet_Desktop * +efreet_desktop_empty_new(const char *file) +{ + Efreet_Desktop *desktop; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + desktop = NEW(Efreet_Desktop, 1); + if (!desktop) return NULL; + + desktop->orig_path = strdup(file); + desktop->load_time = ecore_file_mod_time(file); + + desktop->ref = 1; + + return desktop; +} + +EAPI Efreet_Desktop * +efreet_desktop_new(const char *file) +{ + Efreet_Desktop *desktop = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + desktop = efreet_cache_desktop_find(file); + if (desktop) + { + desktop->ref++; + if (!efreet_desktop_environment_check(desktop)) + { + efreet_desktop_free(desktop); + return NULL; + } + return desktop; + efreet_desktop_free(desktop); + } + return efreet_desktop_uncached_new(file); +} + +EAPI Efreet_Desktop * +efreet_desktop_uncached_new(const char *file) +{ + Efreet_Desktop *desktop = NULL; + char rp[PATH_MAX]; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + if (!realpath(file, rp)) return NULL; + if (!ecore_file_exists(rp)) return NULL; + + desktop = NEW(Efreet_Desktop, 1); + if (!desktop) return NULL; + desktop->orig_path = strdup(rp); + desktop->ref = 1; + if (!efreet_desktop_read(desktop)) + { + efreet_desktop_free(desktop); + return NULL; + } + + return desktop; +} + +EAPI int +efreet_desktop_save(Efreet_Desktop *desktop) +{ + Efreet_Desktop_Type_Info *info; + Efreet_Ini *ini; + int ok = 1; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + + ini = efreet_ini_new(NULL); + if (!ini) return 0; + efreet_ini_section_add(ini, "Desktop Entry"); + efreet_ini_section_set(ini, "Desktop Entry"); + + info = eina_list_nth(efreet_desktop_types, desktop->type); + if (info) + { + efreet_ini_string_set(ini, "Type", info->type); + if (info->save_func) info->save_func(desktop, ini); + } + else + ok = 0; + + if (ok) + { + char *val; + + if (desktop->only_show_in) + { + val = efreet_desktop_string_list_join(desktop->only_show_in); + if (val) + { + efreet_ini_string_set(ini, "OnlyShowIn", val); + FREE(val); + } + } + if (desktop->not_show_in) + { + val = efreet_desktop_string_list_join(desktop->not_show_in); + if (val) + { + efreet_ini_string_set(ini, "NotShowIn", val); + FREE(val); + } + } + efreet_desktop_generic_fields_save(desktop, ini); + /* When we save the file, it should be updated to the + * latest version that we support! */ + efreet_ini_string_set(ini, "Version", DESKTOP_VERSION); + + if (!efreet_ini_save(ini, desktop->orig_path)) ok = 0; + } + efreet_ini_free(ini); + return ok; +} + +EAPI int +efreet_desktop_save_as(Efreet_Desktop *desktop, const char *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); + + /* If we save data from eet as new, we will be in trouble */ + if (desktop->eet) return 0; + + IF_FREE(desktop->orig_path); + desktop->orig_path = strdup(file); + return efreet_desktop_save(desktop); +} + +EAPI void +efreet_desktop_free(Efreet_Desktop *desktop) +{ + if (!desktop) return; + + desktop->ref--; + if (desktop->ref > 0) return; + + if (desktop->eet) + { + efreet_cache_desktop_free(desktop); + } + else + { + IF_FREE(desktop->orig_path); + + IF_FREE(desktop->version); + IF_FREE(desktop->name); + IF_FREE(desktop->generic_name); + IF_FREE(desktop->comment); + IF_FREE(desktop->icon); + IF_FREE(desktop->url); + + IF_FREE(desktop->try_exec); + IF_FREE(desktop->exec); + IF_FREE(desktop->path); + IF_FREE(desktop->startup_wm_class); + + IF_FREE_LIST(desktop->only_show_in, eina_stringshare_del); + IF_FREE_LIST(desktop->not_show_in, eina_stringshare_del); + + IF_FREE_LIST(desktop->categories, eina_stringshare_del); + IF_FREE_LIST(desktop->mime_types, eina_stringshare_del); + + IF_FREE_HASH(desktop->x); + + if (desktop->type_data) + { + Efreet_Desktop_Type_Info *info; + info = eina_list_nth(efreet_desktop_types, desktop->type); + if (info->free_func) + info->free_func(desktop->type_data); + } + free(desktop); + } +} + +EAPI void +efreet_desktop_environment_set(const char *environment) +{ + if (desktop_environment) eina_stringshare_del(desktop_environment); + if (environment) desktop_environment = eina_stringshare_add(environment); + else desktop_environment = NULL; +} + +EAPI const char * +efreet_desktop_environment_get(void) +{ + return desktop_environment; +} + +EAPI unsigned int +efreet_desktop_category_count_get(Efreet_Desktop *desktop) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + return eina_list_count(desktop->categories); +} + +EAPI void +efreet_desktop_category_add(Efreet_Desktop *desktop, const char *category) +{ + EINA_SAFETY_ON_NULL_RETURN(desktop); + EINA_SAFETY_ON_NULL_RETURN(category); + + if (eina_list_search_unsorted(desktop->categories, + EINA_COMPARE_CB(strcmp), category)) return; + + desktop->categories = eina_list_append(desktop->categories, + (void *)eina_stringshare_add(category)); +} + +EAPI int +efreet_desktop_category_del(Efreet_Desktop *desktop, const char *category) +{ + char *found = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + + if ((found = eina_list_search_unsorted(desktop->categories, + EINA_COMPARE_CB(strcmp), category))) + { + eina_stringshare_del(found); + desktop->categories = eina_list_remove(desktop->categories, found); + + return 1; + } + + return 0; +} + +EAPI int +efreet_desktop_type_add(const char *type, Efreet_Desktop_Type_Parse_Cb parse_func, + Efreet_Desktop_Type_Save_Cb save_func, + Efreet_Desktop_Type_Free_Cb free_func) +{ + int id; + Efreet_Desktop_Type_Info *info; + + info = NEW(Efreet_Desktop_Type_Info, 1); + if (!info) return 0; + + id = eina_list_count(efreet_desktop_types); + + info->id = id; + info->type = eina_stringshare_add(type); + info->parse_func = parse_func; + info->save_func = save_func; + info->free_func = free_func; + + efreet_desktop_types = eina_list_append(efreet_desktop_types, info); + + return id; +} + +EAPI int +efreet_desktop_type_alias(int from_type, const char *alias) +{ + Efreet_Desktop_Type_Info *info; + info = eina_list_nth(efreet_desktop_types, from_type); + if (!info) return -1; + + return efreet_desktop_type_add(alias, info->parse_func, info->save_func, info->free_func); +} + +EAPI Eina_Bool +efreet_desktop_x_field_set(Efreet_Desktop *desktop, const char *key, const char *data) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE); + + if (!desktop->x) + desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + + eina_hash_del_by_key(desktop->x, key); + eina_hash_add(desktop->x, key, eina_stringshare_add(data)); + + return EINA_TRUE; +} + +EAPI const char * +efreet_desktop_x_field_get(Efreet_Desktop *desktop, const char *key) +{ + const char *ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, NULL); + EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), NULL); + + ret = eina_hash_find(desktop->x, key); + if (!ret) + return NULL; + + return eina_stringshare_add(ret); +} + +EAPI Eina_Bool +efreet_desktop_x_field_del(Efreet_Desktop *desktop, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, EINA_FALSE); + EINA_SAFETY_ON_TRUE_RETURN_VAL(strncmp(key, "X-", 2), EINA_FALSE); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->x, EINA_FALSE); + + return eina_hash_del_by_key(desktop->x, key); +} + +EAPI void * +efreet_desktop_type_data_get(Efreet_Desktop *desktop) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL); + return desktop->type_data; +} + +EAPI Eina_List * +efreet_desktop_string_list_parse(const char *string) +{ + Eina_List *list = NULL; + char *tmp; + char *s, *p; + size_t len; + + EINA_SAFETY_ON_NULL_RETURN_VAL(string, NULL); + + len = strlen(string) + 1; + tmp = alloca(len); + memcpy(tmp, string, len); + s = tmp; + + while ((p = strchr(s, ';'))) + { + if (p > tmp && *(p-1) == '\\') continue; + *p = '\0'; + list = eina_list_append(list, (void *)eina_stringshare_add(s)); + s = p + 1; + } + /* If this is true, the .desktop file does not follow the standard */ + if (*s) + { +#ifdef STRICT_SPEC + WRN("[Efreet]: Found a string list without ';' " + "at the end: %s", string); +#endif + list = eina_list_append(list, (void *)eina_stringshare_add(s)); + } + + return list; +} + +EAPI char * +efreet_desktop_string_list_join(Eina_List *list) +{ + Eina_List *l; + const char *elem; + char *string; + size_t size, pos, len; + + if (!list) return strdup(""); + + size = 1024; + string = malloc(size); + if (!string) return NULL; + pos = 0; + + EINA_LIST_FOREACH(list, l, elem) + { + len = strlen(elem); + /* +1 for ';' */ + if ((len + pos + 1) >= size) + { + char *tmp; + size = len + pos + 1024; + tmp = realloc(string, size); + if (!tmp) + { + free(string); + return NULL; + } + string = tmp; + } + strcpy(string + pos, elem); + pos += len; + strcpy(string + pos, ";"); + pos += 1; + } + return string; +} + +/** + * @internal + * @param desktop The desktop to fill + * @return Returns 1 on success, 0 on failure + * @brief initialize an Efreet_Desktop from the contents of @a file + */ +static int +efreet_desktop_read(Efreet_Desktop *desktop) +{ + Efreet_Ini *ini; + int error = 0; + int ok; + + ini = efreet_ini_new(desktop->orig_path); + if (!ini) return 0; + if (!ini->data) + { + efreet_ini_free(ini); + return 0; + } + + ok = efreet_ini_section_set(ini, "Desktop Entry"); + if (!ok) ok = efreet_ini_section_set(ini, "KDE Desktop Entry"); + if (!ok) + { + ERR("efreet_desktop_new error: no Desktop Entry section"); + error = 1; + } + + if (!error) + { + Efreet_Desktop_Type_Info *info; + + info = efreet_desktop_type_parse(efreet_ini_string_get(ini, "Type")); + if (info) + { + const char *val; + + desktop->type = info->id; + val = efreet_ini_string_get(ini, "Version"); + if (val) desktop->version = strdup(val); + + if (info->parse_func) + desktop->type_data = info->parse_func(desktop, ini); + } + else + error = 1; + } + + if (!error && !efreet_desktop_generic_fields_parse(desktop, ini)) error = 1; + if (!error && !efreet_desktop_environment_check(desktop)) error = 1; + if (!error) + eina_hash_foreach(ini->section, efreet_desktop_x_fields_parse, desktop); + + efreet_ini_free(ini); + + desktop->load_time = ecore_file_mod_time(desktop->orig_path); + + if (error) return 0; + + return 1; +} + +/** + * @internal + * @param type_str the type as a string + * @return the parsed type + * @brief parse the type string into an Efreet_Desktop_Type + */ +static Efreet_Desktop_Type_Info * +efreet_desktop_type_parse(const char *type_str) +{ + Efreet_Desktop_Type_Info *info; + Eina_List *l; + + if (!type_str) return NULL; + + EINA_LIST_FOREACH(efreet_desktop_types, l, info) + { + if (!strcmp(info->type, type_str)) + return info; + } + + return NULL; +} + +/** + * @internal + * @brief Free an Efreet Desktop_Type_Info struct + */ +static void +efreet_desktop_type_info_free(Efreet_Desktop_Type_Info *info) +{ + if (!info) return; + IF_RELEASE(info->type); + free(info); +} + +/** + * @internal + * @param desktop the Efreet_Desktop to store parsed fields in + * @param ini the Efreet_Ini to parse fields from + * @return No value + * @brief Parse application specific desktop fields + */ +static void * +efreet_desktop_application_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + const char *val; + + val = efreet_ini_string_get(ini, "TryExec"); + if (val) desktop->try_exec = strdup(val); + + val = efreet_ini_string_get(ini, "Exec"); + if (val) desktop->exec = strdup(val); + + val = efreet_ini_string_get(ini, "Path"); + if (val) desktop->path = strdup(val); + + val = efreet_ini_string_get(ini, "StartupWMClass"); + if (val) desktop->startup_wm_class = strdup(val); + + val = efreet_ini_string_get(ini, "Categories"); + if (val) + desktop->categories = efreet_desktop_string_list_parse(val); + val = efreet_ini_string_get(ini, "MimeType"); + if (val) desktop->mime_types = efreet_desktop_string_list_parse(val); + + desktop->terminal = efreet_ini_boolean_get(ini, "Terminal"); + desktop->startup_notify = efreet_ini_boolean_get(ini, "StartupNotify"); + + return NULL; +} + +/** + * @internal + * @param desktop the Efreet_Desktop to save fields from + * @param ini the Efreet_Ini to save fields to + * @return Returns no value + * @brief Save application specific desktop fields + */ +static void +efreet_desktop_application_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + char *val; + + if (desktop->try_exec) + efreet_ini_string_set(ini, "TryExec", desktop->try_exec); + + if (desktop->exec) + efreet_ini_string_set(ini, "Exec", desktop->exec); + + if (desktop->path) + efreet_ini_string_set(ini, "Path", desktop->path); + + if (desktop->startup_wm_class) + efreet_ini_string_set(ini, "StartupWMClass", desktop->startup_wm_class); + + if (desktop->categories) + { + val = efreet_desktop_string_list_join(desktop->categories); + if (val) + { + efreet_ini_string_set(ini, "Categories", val); + FREE(val); + } + } + + if (desktop->mime_types) + { + val = efreet_desktop_string_list_join(desktop->mime_types); + if (val) + { + efreet_ini_string_set(ini, "MimeType", val); + FREE(val); + } + } + + efreet_ini_boolean_set(ini, "Terminal", desktop->terminal); + efreet_ini_boolean_set(ini, "StartupNotify", desktop->startup_notify); +} + +/** + * @internal + * @param desktop the Efreet_Desktop to store parsed fields in + * @param ini the Efreet_Ini to parse fields from + * @return Returns no value + * @brief Parse link specific desktop fields + */ +static void * +efreet_desktop_link_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + const char *val; + + val = efreet_ini_string_get(ini, "URL"); + if (val) desktop->url = strdup(val); + return NULL; +} + +/** + * @internal + * @param desktop the Efreet_Desktop to save fields from + * @param ini the Efreet_Ini to save fields in + * @return Returns no value + * @brief Save link specific desktop fields + */ +static void +efreet_desktop_link_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + if (desktop->url) efreet_ini_string_set(ini, "URL", desktop->url); +} + +/** + * @internal + * @param desktop the Efreet_Desktop to store parsed fields in + * @param ini the Efreet_Ini to parse fields from + * @return 1 if parsed successfully, 0 otherwise + * @brief Parse desktop fields that all types can include + */ +static int +efreet_desktop_generic_fields_parse(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + const char *val; + const char *not_show_in = NULL, *only_show_in = NULL; + + val = efreet_ini_localestring_get(ini, "Name"); +#ifndef STRICT_SPEC + if (!val) val = efreet_ini_localestring_get(ini, "_Name"); +#endif + if (val) desktop->name = strdup(val); + else + { + ERR("efreet_desktop_generic_fields_parse error: no Name or _Name fields"); + return 0; + } + + val = efreet_ini_localestring_get(ini, "GenericName"); + if (val) desktop->generic_name = strdup(val); + + val = efreet_ini_localestring_get(ini, "Comment"); +#ifndef STRICT_SPEC + if (!val) val = efreet_ini_localestring_get(ini, "_Comment"); +#endif + if (val) desktop->comment = strdup(val); + + val = efreet_ini_localestring_get(ini, "Icon"); + if (val) desktop->icon = strdup(val); + + desktop->no_display = efreet_ini_boolean_get(ini, "NoDisplay"); + desktop->hidden = efreet_ini_boolean_get(ini, "Hidden"); + + only_show_in = efreet_ini_string_get(ini, "OnlyShowIn"); + not_show_in = efreet_ini_string_get(ini, "NotShowIn"); + if (only_show_in && not_show_in) + WRN("Both OnlyShowIn and NotShowIn in %s, preferring OnlyShowIn", desktop->orig_path); + if (only_show_in) desktop->only_show_in = efreet_desktop_string_list_parse(only_show_in); + else if (not_show_in) desktop->not_show_in = efreet_desktop_string_list_parse(not_show_in); + + return 1; +} + +/** + * @internal + * @param desktop the Efreet_Desktop to save fields from + * @param ini the Efreet_Ini to save fields to + * @return Returns nothing + * @brief Save desktop fields that all types can include + */ +static void +efreet_desktop_generic_fields_save(Efreet_Desktop *desktop, Efreet_Ini *ini) +{ + const char *val; + + if (desktop->name) + { + efreet_ini_localestring_set(ini, "Name", desktop->name); + val = efreet_ini_string_get(ini, "Name"); + if (!val) + efreet_ini_string_set(ini, "Name", desktop->name); + } + if (desktop->generic_name) + { + efreet_ini_localestring_set(ini, "GenericName", desktop->generic_name); + val = efreet_ini_string_get(ini, "GenericName"); + if (!val) + efreet_ini_string_set(ini, "GenericName", desktop->generic_name); + } + if (desktop->comment) + { + efreet_ini_localestring_set(ini, "Comment", desktop->comment); + val = efreet_ini_string_get(ini, "Comment"); + if (!val) + efreet_ini_string_set(ini, "Comment", desktop->comment); + } + if (desktop->icon) + { + efreet_ini_localestring_set(ini, "Icon", desktop->icon); + val = efreet_ini_string_get(ini, "Icon"); + if (!val) + efreet_ini_string_set(ini, "Icon", desktop->icon); + } + + efreet_ini_boolean_set(ini, "NoDisplay", desktop->no_display); + efreet_ini_boolean_set(ini, "Hidden", desktop->hidden); + + if (desktop->x) eina_hash_foreach(desktop->x, efreet_desktop_x_fields_save, + ini); +} + +/** + * @internal + * @param node The node to work with + * @param desktop The desktop file to work with + * @return Returns always true, to be used in eina_hash_foreach() + * @brief Parses out an X- key from @a node and stores in @a desktop + */ +static Eina_Bool +efreet_desktop_x_fields_parse(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata) +{ + Efreet_Desktop * desktop = fdata; + + if (!desktop) return EINA_TRUE; + if (strncmp(key, "X-", 2)) return EINA_TRUE; + + if (!desktop->x) + desktop->x = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + eina_hash_del_by_key(desktop->x, key); + eina_hash_add(desktop->x, key, (void *)eina_stringshare_add(value)); + + return EINA_TRUE; +} + +/** + * @internal + * @param node The node to work with + * @param ini The ini file to work with + * @return Returns no value + * @brief Stores an X- key from @a node and stores in @a ini + */ +static Eina_Bool +efreet_desktop_x_fields_save(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata) +{ + Efreet_Ini *ini = fdata; + efreet_ini_string_set(ini, key, value); + + return EINA_TRUE; +} + + +/** + * @internal + * @param ini The Efreet_Ini to parse values from + * @return 1 if desktop should be included in current environement, 0 otherwise + * @brief Determines if a desktop should be included in the current environment, + * based on the values of the OnlyShowIn and NotShowIn fields + */ +static int +efreet_desktop_environment_check(Efreet_Desktop *desktop) +{ + Eina_List *list; + int found = 0; + char *val; + + if (!desktop_environment) + { + //if (desktop->only_show_in) return 0; + return 1; + } + + if (desktop->only_show_in) + { + EINA_LIST_FOREACH(desktop->only_show_in, list, val) + { + if (!strcmp(val, desktop_environment)) + { + found = 1; + break; + } + } + return found; + } + + + if (desktop->not_show_in) + { + EINA_LIST_FOREACH(desktop->not_show_in, list, val) + { + if (!strcmp(val, desktop_environment)) + { + found = 1; + break; + } + } + return !found; + } + + return 1; +} + +static void +efreet_desktop_changes_listen(void) +{ + Efreet_Cache_Array_String *arr; + Eina_List *dirs; + const char *path; + + if (!efreet_cache_update) return; + + change_monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del)); + if (!change_monitors) return; + + dirs = efreet_default_dirs_get(efreet_data_home_get(), + efreet_data_dirs_get(), "applications"); + + EINA_LIST_FREE(dirs, path) + { + if (ecore_file_is_dir(path)) + efreet_desktop_changes_listen_recursive(path); + eina_stringshare_del(path); + } + + arr = efreet_cache_desktop_dirs(); + if (arr) + { + unsigned int i; + + for (i = 0; i < arr->array_count; i++) + efreet_desktop_changes_monitor_add(arr->array[i]); + efreet_cache_array_string_free(arr); + } +} + +static void +efreet_desktop_changes_listen_recursive(const char *path) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *info; + + efreet_desktop_changes_monitor_add(path); + + it = eina_file_direct_ls(path); + if (!it) return; + EINA_ITERATOR_FOREACH(it, info) + { + if (ecore_file_is_dir(info->path)) efreet_desktop_changes_listen_recursive(info->path); + } + eina_iterator_free(it); +} + +static void +efreet_desktop_changes_monitor_add(const char *path) +{ + char rp[PATH_MAX]; + + if (!realpath(path, rp)) return; + if (eina_hash_find(change_monitors, rp)) return; + eina_hash_add(change_monitors, rp, + ecore_file_monitor_add(rp, + efreet_desktop_changes_cb, + NULL)); +} + +static void +efreet_desktop_changes_cb(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__, + Ecore_File_Event event, const char *path) +{ + const char *ext; + + /* TODO: If we get a stale symlink, we need to rerun cache creation */ + /* TODO: Check for desktop*.cache, as this will be created when app is installed */ + /* TODO: Do efreet_cache_icon_update() when app is installed, as it has the same + * symlink problem */ + switch (event) + { + case ECORE_FILE_EVENT_NONE: + /* noop */ + break; + + case ECORE_FILE_EVENT_CREATED_FILE: + case ECORE_FILE_EVENT_DELETED_FILE: + case ECORE_FILE_EVENT_MODIFIED: + case ECORE_FILE_EVENT_CLOSED: + ext = strrchr(path, '.'); + if (ext && (!strcmp(ext, ".desktop") || !strcmp(ext, ".directory"))) + efreet_cache_desktop_update(); + break; + + case ECORE_FILE_EVENT_DELETED_SELF: + case ECORE_FILE_EVENT_DELETED_DIRECTORY: + eina_hash_del_by_key(change_monitors, path); + efreet_cache_desktop_update(); + break; + + case ECORE_FILE_EVENT_CREATED_DIRECTORY: + efreet_desktop_changes_monitor_add(path); + efreet_cache_desktop_update(); + break; + } +} diff --git a/src/lib/efreet_desktop.h b/src/lib/efreet_desktop.h new file mode 100644 index 0000000..f7dfe51 --- /dev/null +++ b/src/lib/efreet_desktop.h @@ -0,0 +1,370 @@ +#ifndef EFREET_DESKTOP_H +#define EFREET_DESKTOP_H + +/** + * @file efreet_desktop.h + * @brief Contains the structures and methods used to support the + * FDO desktop entry specificiation. + * @addtogroup Efreet_Desktop Efreet_Desktop: The FDO Desktop Entry + * Specification functions and structures + * + * @{ + */ + + +/** + * @param desktop the desktop entry + * @param files an eina list of file names to execute, as either absolute paths, + * relative paths, or uris + * @param func a callback to call for each prepared command line + * @param data user data passed to the callback + * @return Returns the return value of @p func on success or NULL on failure + * @brief Get a command to use to execute a desktop entry. + */ +EAPI extern int EFREET_DESKTOP_TYPE_APPLICATION; +EAPI extern int EFREET_DESKTOP_TYPE_LINK; +EAPI extern int EFREET_DESKTOP_TYPE_DIRECTORY; + +/** + * Event id for cache update. All users of efreet_desktop_get must listen to + * this event and refetch. The old eet cache will be closed and mem will + * be invalidated. + */ +EAPI extern int EFREET_EVENT_DESKTOP_CACHE_UPDATE; +/** + * Event id for cache build complete. + * @since 1.1.0 + */ +EAPI extern int EFREET_EVENT_DESKTOP_CACHE_BUILD; + +/** + * Efreet_Desktop + */ +typedef struct _Efreet_Desktop Efreet_Desktop; + +/** + * A callback used with efreet_desktop_command_get() + */ +typedef void *(*Efreet_Desktop_Command_Cb) (void *data, Efreet_Desktop *desktop, + char *command, int remaining); + +/** + * A callback used to get download progress of remote uris + */ +typedef int (*Efreet_Desktop_Progress_Cb) (void *data, Efreet_Desktop *desktop, + char *uri, long int total, long int current); + +/** + * A callback used to parse data for custom types + */ +typedef void *(*Efreet_Desktop_Type_Parse_Cb) (Efreet_Desktop *desktop, Efreet_Ini *ini); + +/** + * A callback used to save data for custom types + */ +typedef void (*Efreet_Desktop_Type_Save_Cb) (Efreet_Desktop *desktop, Efreet_Ini *ini); + +/** + * A callback used to free data for custom types + */ +typedef void *(*Efreet_Desktop_Type_Free_Cb) (void *data); + +/** + * Efreet_Desktop + * @brief a parsed representation of a .desktop file + */ +struct _Efreet_Desktop +{ + int type; /**< type of desktop file */ + + int ref; /**< reference count - internal */ + + char *version; /**< version of spec file conforms to */ + + char *orig_path; /**< original path to .desktop file */ + long long load_time; /**< modified time of .desktop on disk */ + + char *name; /**< Specific name of the application */ + char *generic_name; /**< Generic name of the application */ + char *comment; /**< Tooltip for the entry */ + char *icon; /**< Icon to display in file manager, menus, etc */ + char *try_exec; /**< Binary to determine if app is installed */ + char *exec; /**< Program to execute */ + char *path; /**< Working directory to run app in */ + char *startup_wm_class; /**< If specified will map at least one window with + the given string as it's WM class or WM name */ + char *url; /**< URL to access if type is EFREET_TYPE_LINK */ + + Eina_List *only_show_in; /**< list of environments that should + display the icon */ + Eina_List *not_show_in; /**< list of environments that shoudn't + display the icon */ + Eina_List *categories; /**< Categories in which item should be shown */ + Eina_List *mime_types; /**< The mime types supppored by this app */ + + unsigned char no_display; /**< Don't display this application in menus */ + unsigned char hidden; /**< User delete the item */ + unsigned char terminal; /**< Does the program run in a terminal */ + unsigned char startup_notify; /**< The starup notify settings of the app */ + unsigned char eet:1; /**< The desktop file is in eet cache */ + + Eina_Hash *x; /**< Keep track of all user extensions, keys that begin with X- */ + void *type_data; /**< Type specific data for custom types */ +}; + + +/** + * @param file The file to get the Efreet_Desktop from + * @return Returns a reference to a cached Efreet_Desktop on success, NULL + * on failure + * @brief Gets a reference to an Efreet_Desktop structure representing the + * contents of @a file or NULL if @a file is not a valid .desktop file. + * + * By using efreet_desktop_get the Efreet_Desktop will be saved in an internal + * cache for quicker loading. + * + * Users of this command should listen to EFREET_EVENT_DESKTOP_CACHE_UPDATE + * event, if the application is to keep the reference. When the event fires + * the Efreet_Desktop struct should be invalidated and reloaded from a new + * cache file. + */ +EAPI Efreet_Desktop *efreet_desktop_get(const char *file); + +/** + * @param desktop The Efreet_Desktop to ref + * @return Returns the new reference count + * @brief Increases reference count on desktop + */ +EAPI int efreet_desktop_ref(Efreet_Desktop *desktop); + +/** + * @param file The file to create the Efreet_Desktop from + * @return Returns a new empty_Efreet_Desktop on success, NULL on failure + * @brief Creates a new empty Efreet_Desktop structure or NULL on failure + */ +EAPI Efreet_Desktop *efreet_desktop_empty_new(const char *file); + +/** + * @param file The file to get the Efreet_Desktop from + * @return Returns a reference to a cached Efreet_Desktop on success, NULL + * on failure + * @brief Gets a reference to an Efreet_Desktop structure representing the + * contents of @a file or NULL if @a file is not a valid .desktop file. + * + * Users of this command should listen to EFREET_EVENT_DESKTOP_CACHE_UPDATE + * event, if the application is to keep the reference. When the event fires + * the Efreet_Desktop struct should be invalidated and reloaded from a new + * cache file. + */ +EAPI Efreet_Desktop *efreet_desktop_new(const char *file); + +/** + * @param file The file to create the Efreet_Desktop from + * @return Returns a new Efreet_Desktop on success, NULL on failure + * @brief Creates a new Efreet_Desktop structure initialized from the + * contents of @a file or NULL on failure + * + * By using efreet_desktop_uncached_new the Efreet_Desktop structure will be + * read from disk, and not from any cache. + * + * Data in the structure is allocated with strdup, so use free and strdup to + * change values. + */ +EAPI Efreet_Desktop *efreet_desktop_uncached_new(const char *file); + +/** + * @param desktop The Efreet_Desktop to work with + * @return Returns no value + * @brief Frees the Efreet_Desktop structure and all of it's data + */ +EAPI void efreet_desktop_free(Efreet_Desktop *desktop); + +/** + * @def efreet_desktop_unref(desktop) + * Alias for efreet_desktop_free(desktop) + */ +#define efreet_desktop_unref(desktop) efreet_desktop_free((desktop)) + + +/** + * @param desktop The desktop file to save + * @return Returns 1 on success or 0 on failure + * @brief Saves any changes made to @a desktop back to the file on the + * filesystem + */ +EAPI int efreet_desktop_save(Efreet_Desktop *desktop); + +/** + * @param desktop The desktop file to save + * @param file The filename to save as + * @return Returns 1 on success or 0 on failure + * @brief Saves @a desktop to @a file + * + * Please use efreet_desktop_uncached_new() on an existing file + * before using efreet_desktop_save_as() + */ +EAPI int efreet_desktop_save_as(Efreet_Desktop *desktop, + const char *file); + + +/** + * @param desktop The desktop file to work with + * @param files The files to be substituted into the exec line + * @param data The data pointer to pass + * @return Returns the Ecore_Exce for @a desktop + * @brief Parses the @a desktop exec line and returns an Ecore_Exe. + */ +EAPI void efreet_desktop_exec(Efreet_Desktop *desktop, + Eina_List *files, void *data); + + +/** + * @param environment the environment name + * @brief sets the global desktop environment name + */ +EAPI void efreet_desktop_environment_set(const char *environment); + +/** + * @return environment the environment name + * @brief sets the global desktop environment name + */ +EAPI const char *efreet_desktop_environment_get(void); + +/** + * @param desktop the desktop entry + * @param files an eina list of file names to execute, as either absolute paths, + * relative paths, or uris + * @param cb_command a callback to call for each prepared command line + * @param cb_prog a callback to get progress for the downloads + * @param data user data passed to the callback + * @return Returns 1 on success or 0 on failure + * @brief Get a command to use to execute a desktop entry, and receive progress + * updates for downloading of remote URI's passed in. + */ +EAPI void *efreet_desktop_command_progress_get(Efreet_Desktop *desktop, + Eina_List *files, + Efreet_Desktop_Command_Cb cb_command, + Efreet_Desktop_Progress_Cb cb_prog, + void *data); +EAPI void *efreet_desktop_command_get(Efreet_Desktop *desktop, + Eina_List *files, + Efreet_Desktop_Command_Cb func, + void *data); + +/** + * @param desktop the desktop entry + * @param files an eina list of local files, as absolute paths, local paths, or file// uris (or NULL to get exec string with no files appended) + * @return Returns an eina list of exec strings + * @brief Get the command to use to execute a desktop entry + * + * The returned list and each of its elements must be freed. + */ +EAPI Eina_List * efreet_desktop_command_local_get(Efreet_Desktop *desktop, + Eina_List *files); + + +/** + * @param desktop The desktop to work with + * @return Returns the number of categories assigned to this desktop + * @brief Retrieves the number of categories the given @a desktop belongs + * too + */ +EAPI unsigned int efreet_desktop_category_count_get(Efreet_Desktop *desktop); + +/** + * @param desktop the desktop + * @param category the category name + * @brief add a category to a desktop + */ +EAPI void efreet_desktop_category_add(Efreet_Desktop *desktop, + const char *category); + +/** + * @param desktop the desktop + * @param category the category name + * @brief removes a category from a desktop + * @return 1 if the desktop had his category listed, 0 otherwise + */ +EAPI int efreet_desktop_category_del(Efreet_Desktop *desktop, + const char *category); + + +/** + * @param type The type to add to the list of matching types + * @param parse_func a function to parse out custom fields + * @param save_func a function to save data returned from @a parse_func + * @param free_func a function to free data returned from @a parse_func + * @return Returns the id of the new type + * @brief Adds the given type to the list of types in the system + */ +EAPI int efreet_desktop_type_add(const char *type, + Efreet_Desktop_Type_Parse_Cb parse_func, + Efreet_Desktop_Type_Save_Cb save_func, + Efreet_Desktop_Type_Free_Cb free_func); + +/** + * @brief Add an alias for an existing desktop type. + * @param from_type the type to alias (e.g. EFREE_DESKTOP_TYPE_APPLICATION) + * @param alias the alias + * @return the new type id, or -1 if @p from_type was not valid + * + * This allows applications to add non-standard types that behave exactly as standard types. + */ +EAPI int efreet_desktop_type_alias (int from_type, + const char *alias); + +/** + * @brief get type specific data for custom desktop types + * @param desktop the desktop + * @return type specific data, or NULL if there is none + */ +EAPI void *efreet_desktop_type_data_get(Efreet_Desktop *desktop); + + +/** + * @param string the raw string list + * @return an Eina_List of ecore string's + * @brief Parse ';' separate list of strings according to the desktop spec + */ +EAPI Eina_List *efreet_desktop_string_list_parse(const char *string); + +/** + * @param list Eina_List with strings + * @return a raw string list + * @brief Create a ';' separate list of strings according to the desktop spec + */ +EAPI char *efreet_desktop_string_list_join(Eina_List *list); + + +/** + * @brief Set the value for a X- field (Non spec) in the structure + * @param desktop the desktop + * @param key the key name to set + * @param data the value to set + * @return EINA_TRUE on success + * + * The key has to start with "X-" + */ +EAPI Eina_Bool efreet_desktop_x_field_set(Efreet_Desktop *desktop, const char *key, const char *data); + +/** + * @brief Get the value for a X- field (Non spec) in the structure + * @param desktop the desktop + * @param key the key + * @return The value referenced by the key, or NULL if the key does not exist + */ +EAPI const char * efreet_desktop_x_field_get(Efreet_Desktop *desktop, const char *key); + +/** + * @brief Delete the key and value for a X- field (Non spec) in the structure + * @param desktop the desktop + * @param key the key + * @return EINA_TRUE if the key existed + */ +EAPI Eina_Bool efreet_desktop_x_field_del(Efreet_Desktop *desktop, const char *key); + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_desktop_command.c b/src/lib/efreet_desktop_command.c new file mode 100644 index 0000000..bf97f8f --- /dev/null +++ b/src/lib/efreet_desktop_command.c @@ -0,0 +1,919 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <unistd.h> +#include <ctype.h> + +#ifdef _WIN32 +# include <winsock2.h> +#endif + +#include <Ecore.h> +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_desktop_log_dom +extern int _efreet_desktop_log_dom; + +#include "Efreet.h" +#include "efreet_private.h" + +/** + * @internal + * The different types of commands in an Exec entry + */ +typedef enum Efreet_Desktop_Command_Flag +{ + EFREET_DESKTOP_EXEC_FLAG_FULLPATH = 0x0001, + EFREET_DESKTOP_EXEC_FLAG_URI = 0x0002 +} Efreet_Desktop_Command_Flag; + +/** + * @internal + * Efreet_Desktop_Command + */ +typedef struct Efreet_Desktop_Command Efreet_Desktop_Command; + +/** + * @internal + * Holds information on a desktop Exec command entry + */ +struct Efreet_Desktop_Command +{ + Efreet_Desktop *desktop; + int num_pending; + + Efreet_Desktop_Command_Flag flags; + + Efreet_Desktop_Command_Cb cb_command; + Efreet_Desktop_Progress_Cb cb_progress; + void *data; + + Eina_List *files; /**< list of Efreet_Desktop_Command_File */ +}; + +/** + * @internal + * Efreet_Desktop_Command_File + */ +typedef struct Efreet_Desktop_Command_File Efreet_Desktop_Command_File; + +/** + * @internal + * Stores information on a file passed to the desktop Exec command + */ +struct Efreet_Desktop_Command_File +{ + Efreet_Desktop_Command *command; + char *dir; + char *file; + char *fullpath; + char *uri; + + int pending; +}; + +static int efreet_desktop_command_file_id = 0; + +static void *efreet_desktop_exec_cb(void *data, Efreet_Desktop *desktop, + char *exec, int remaining); +static int efreet_desktop_command_flags_get(Efreet_Desktop *desktop); +static void *efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs); + +static Eina_List *efreet_desktop_command_build(Efreet_Desktop_Command *command); +static void efreet_desktop_command_free(Efreet_Desktop_Command *command); +static char *efreet_desktop_command_append_quoted(char *dest, int *size, + int *len, char *src); +static char *efreet_desktop_command_append_multiple(char *dest, int *size, int *len, + Efreet_Desktop_Command *command, + char type); +static char *efreet_desktop_command_append_single(char *dest, int *size, int *len, + Efreet_Desktop_Command_File *file, + char type); +static char *efreet_desktop_command_append_icon(char *dest, int *size, int *len, + Efreet_Desktop *desktop); + +static Efreet_Desktop_Command_File *efreet_desktop_command_file_process( + Efreet_Desktop_Command *command, + const char *file); +static const char *efreet_desktop_command_file_uri_process(const char *uri); +static void efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file); + +static void efreet_desktop_cb_download_complete(void *data, const char *file, + int status); +static int efreet_desktop_cb_download_progress(void *data, const char *file, + long int dltotal, long int dlnow, + long int ultotal, long int ulnow); + +static char *efreet_desktop_command_path_absolute(const char *path); + +static char *efreet_string_append(char *dest, int *size, + int *len, const char *src); +static char *efreet_string_append_char(char *dest, int *size, + int *len, char c); + + +EAPI void +efreet_desktop_exec(Efreet_Desktop *desktop, Eina_List *files, void *data) +{ + efreet_desktop_command_get(desktop, files, efreet_desktop_exec_cb, data); +} + +EAPI void * +efreet_desktop_command_get(Efreet_Desktop *desktop, Eina_List *files, + Efreet_Desktop_Command_Cb func, void *data) +{ + return efreet_desktop_command_progress_get(desktop, files, func, NULL, data); +} + +EAPI Eina_List * +efreet_desktop_command_local_get(Efreet_Desktop *desktop, Eina_List *files) +{ + Efreet_Desktop_Command *command; + char *file; + Eina_List *execs, *l; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->exec, NULL); + + command = NEW(Efreet_Desktop_Command, 1); + if (!command) return 0; + + command->desktop = desktop; + + command->flags = efreet_desktop_command_flags_get(desktop); + /* get the required info for each file passed in */ + if (files) + { + EINA_LIST_FOREACH(files, l, file) + { + Efreet_Desktop_Command_File *dcf; + + dcf = efreet_desktop_command_file_process(command, file); + if (!dcf) continue; + if (dcf->pending) + { + efreet_desktop_command_file_free(dcf); + continue; + } + command->files = eina_list_append(command->files, dcf); + } + } + + execs = efreet_desktop_command_build(command); + efreet_desktop_command_free(command); + + return execs; +} + +EAPI void * +efreet_desktop_command_progress_get(Efreet_Desktop *desktop, Eina_List *files, + Efreet_Desktop_Command_Cb cb_command, + Efreet_Desktop_Progress_Cb cb_progress, + void *data) +{ + Efreet_Desktop_Command *command; + Eina_List *l; + char *file; + void *ret = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop->exec, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(cb_command, NULL); + + command = NEW(Efreet_Desktop_Command, 1); + if (!command) return NULL; + + command->cb_command = cb_command; + command->cb_progress = cb_progress; + command->data = data; + command->desktop = desktop; + + command->flags = efreet_desktop_command_flags_get(desktop); + /* get the required info for each file passed in */ + if (files) + { + EINA_LIST_FOREACH(files, l, file) + { + Efreet_Desktop_Command_File *dcf; + + dcf = efreet_desktop_command_file_process(command, file); + if (!dcf) continue; + command->files = eina_list_append(command->files, dcf); + command->num_pending += dcf->pending; + } + } + + if (command->num_pending == 0) + { + Eina_List *execs; + + execs = efreet_desktop_command_build(command); + if (execs) + { + ret = efreet_desktop_command_execs_process(command, execs); + eina_list_free(execs); + } + efreet_desktop_command_free(command); + } + + return ret; +} + +static void * +efreet_desktop_exec_cb(void *data, + Efreet_Desktop *desktop __UNUSED__, + char *exec, + int remaining __UNUSED__) +{ + ecore_exe_run(exec, data); + free(exec); + + return NULL; +} + +/** + * @internal + * + * @brief Determine which file related field codes are present in the Exec string of a .desktop + * @params desktop and Efreet Desktop + * @return a bitmask of file field codes present in exec string + */ +static int +efreet_desktop_command_flags_get(Efreet_Desktop *desktop) +{ + int flags = 0; + const char *p; + /* first, determine which fields are present in the Exec string */ + p = strchr(desktop->exec, '%'); + while (p) + { + p++; + switch(*p) + { + case 'f': + case 'F': + flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH; + break; + case 'u': + case 'U': + flags |= EFREET_DESKTOP_EXEC_FLAG_URI; + break; + case '%': + p++; + break; + default: + break; + } + + p = strchr(p, '%'); + } +#ifdef SLOPPY_SPEC + /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that + * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is + * unlikely to be fixed in distributions etc. in the long run as gnome/kde + * seem to have workarounds too so no one notices. + */ + if (!flags) flags |= EFREET_DESKTOP_EXEC_FLAG_FULLPATH; +#endif + + return flags; +} + + +/** + * @internal + * + * @brief Call the command callback for each exec in the list + * @param command + * @param execs + */ +static void * +efreet_desktop_command_execs_process(Efreet_Desktop_Command *command, Eina_List *execs) +{ + Eina_List *l; + char *exec; + int num; + void *ret = NULL; + + num = eina_list_count(execs); + EINA_LIST_FOREACH(execs, l, exec) + { + ret = command->cb_command(command->data, command->desktop, exec, --num); + } + return ret; +} + + +/** + * @brief Builds the actual exec string from the raw string and a list of + * processed filename information. The callback passed in to + * efreet_desktop_command_get is called for each exec string created. + * + * @param command the command to build + * @return a list of executable strings + */ +static Eina_List * +efreet_desktop_command_build(Efreet_Desktop_Command *command) +{ + Eina_List *execs = NULL; + const Eina_List *l; + char *exec; + + /* if the Exec field appends multiple, that will run the list to the end, + * causing this loop to only run once. otherwise, this loop will generate a + * command for each file in the list. if the list is empty, this + * will run once, removing any file field codes */ + l = command->files; + do + { + const char *p; + int len = 0; + int size = PATH_MAX; + int file_added = 0; + Efreet_Desktop_Command_File *file = eina_list_data_get(l); + int single; + + exec = malloc(size); + if (!exec) goto error; + p = command->desktop->exec; + len = 0; + + single = 0; + while (*p) + { + if (len >= size - 1) + { + char *tmp; + + size = len + 1024; + tmp = realloc(exec, size); + if (!tmp) goto error; + exec = tmp; + } + + /* XXX handle fields inside quotes? */ + if (*p == '%') + { + p++; + switch (*p) + { + case 'f': + case 'u': + case 'd': + case 'n': + if (file) + { + exec = efreet_desktop_command_append_single(exec, &size, + &len, file, *p); + if (!exec) goto error; + file_added = 1; + single = 1; + } + break; + case 'F': + case 'U': + case 'D': + case 'N': + if (file) + { + exec = efreet_desktop_command_append_multiple(exec, &size, + &len, command, *p); + fprintf(stderr, "EXE: '%s'\n", exec); + if (!exec) goto error; + file_added = 1; + } + break; + case 'i': + exec = efreet_desktop_command_append_icon(exec, &size, &len, + command->desktop); + if (!exec) goto error; + break; + case 'c': + exec = efreet_desktop_command_append_quoted(exec, &size, &len, + command->desktop->name); + if (!exec) goto error; + break; + case 'k': + exec = efreet_desktop_command_append_quoted(exec, &size, &len, + command->desktop->orig_path); + if (!exec) goto error; + break; + case 'v': + case 'm': + WRN("[Efreet]: Deprecated conversion char: '%c' in file '%s'", + *p, command->desktop->orig_path); + break; + case '%': + exec[len++] = *p; + break; + default: +#ifdef STRICT_SPEC + WRN("[Efreet_desktop]: Unknown conversion character: '%c'", *p); +#endif + break; + } + } + else exec[len++] = *p; + p++; + } + +#ifdef SLOPPY_SPEC + /* NON-SPEC!!! this is to work around LOTS of 'broken' .desktop files that + * do not specify %U/%u, %F/F etc. etc. at all. just a command. this is + * unlikely to be fixed in distributions etc. in the long run as gnome/kde + * seem to have workarounds too so no one notices. + */ + if ((file) && (!file_added)) + { + WRN("Efreet_desktop: %s\n" + " command: %s\n" + " has no file path/uri spec info for executing this app WITH a\n" + " file/uri as a parameter. This is unlikely to be the intent.\n" + " please check the .desktop file and fix it by adding a %%U or %%F\n" + " or something appropriate.", + command->desktop->orig_path, command->desktop->exec); + if (len >= size - 1) + { + char *tmp; + size = len + 1024; + tmp = realloc(exec, size); + if (!tmp) goto error; + exec = tmp; + } + exec[len++] = ' '; + exec = efreet_desktop_command_append_multiple(exec, &size, + &len, command, 'F'); + if (!exec) goto error; + file_added = 1; + } +#endif + exec[len++] = '\0'; + + if ((single) || (!execs)) + { + execs = eina_list_append(execs, exec); + exec = NULL; + } + + /* If no file was added, then the Exec field doesn't contain any file + * fields (fFuUdDnN). We only want to run the app once in this case. */ + if (!file_added) break; + } + while ((l = eina_list_next(l))); + + return execs; +error: + IF_FREE(exec); + EINA_LIST_FREE(execs, exec) + free(exec); + return NULL; +} + +static void +efreet_desktop_command_free(Efreet_Desktop_Command *command) +{ + Efreet_Desktop_Command_File *dcf; + + if (!command) return; + + while (command->files) + { + dcf = eina_list_data_get(command->files); + efreet_desktop_command_file_free(dcf); + command->files = eina_list_remove_list(command->files, + command->files); + } + FREE(command); +} + +static char * +efreet_desktop_command_append_quoted(char *dest, int *size, int *len, char *src) +{ + if (!src) return dest; + dest = efreet_string_append(dest, size, len, "'"); + if (!dest) return NULL; + + /* single quotes in src need to be escaped */ + if (strchr(src, '\'')) + { + char *p; + p = src; + while (*p) + { + if (*p == '\'') + { + dest = efreet_string_append(dest, size, len, "\'\\\'"); + if (!dest) return NULL; + } + + dest = efreet_string_append_char(dest, size, len, *p); + if (!dest) return NULL; + p++; + } + } + else + { + dest = efreet_string_append(dest, size, len, src); + if (!dest) return NULL; + } + + dest = efreet_string_append(dest, size, len, "'"); + if (!dest) return NULL; + + return dest; +} + +static char * +efreet_desktop_command_append_multiple(char *dest, int *size, int *len, + Efreet_Desktop_Command *command, + char type) +{ + Efreet_Desktop_Command_File *file; + Eina_List *l; + int first = 1; + + if (!command->files) return dest; + + EINA_LIST_FOREACH(command->files, l, file) + { + if (first) + first = 0; + else + { + dest = efreet_string_append_char(dest, size, len, ' '); + if (!dest) return NULL; + } + + dest = efreet_desktop_command_append_single(dest, size, len, + file, tolower(type)); + if (!dest) return NULL; + } + + return dest; +} + +static char * +efreet_desktop_command_append_single(char *dest, int *size, int *len, + Efreet_Desktop_Command_File *file, + char type) +{ + char *str; + switch(type) + { + case 'f': + str = file->fullpath; + break; + case 'u': + str = file->uri; + break; + case 'd': + str = file->dir; + break; + case 'n': + str = file->file; + break; + default: + ERR("Invalid type passed to efreet_desktop_command_append_single:" + " '%c'", type); + return dest; + } + + if (!str) return dest; + + dest = efreet_desktop_command_append_quoted(dest, size, len, str); + if (!dest) return NULL; + + return dest; +} + +static char * +efreet_desktop_command_append_icon(char *dest, int *size, int *len, + Efreet_Desktop *desktop) +{ + if (!desktop->icon || !desktop->icon[0]) return dest; + + dest = efreet_string_append(dest, size, len, "--icon "); + if (!dest) return NULL; + dest = efreet_desktop_command_append_quoted(dest, size, len, desktop->icon); + if (!dest) return NULL; + + return dest; +} + +/** + * @param command the Efreet_Desktop_Comand that this file is for + * @param file the filname as either an absolute path, relative path, or URI + */ +static Efreet_Desktop_Command_File * +efreet_desktop_command_file_process(Efreet_Desktop_Command *command, const char *file) +{ + Efreet_Desktop_Command_File *f; + const char *uri, *base; + int nonlocal = 0; +/* + DBG("FLAGS: %d, %d, %d, %d\n", + command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH ? 1 : 0, + command->flags & EFREET_DESKTOP_EXEC_FLAG_URI ? 1 : 0); +*/ + f = NEW(Efreet_Desktop_Command_File, 1); + if (!f) return NULL; + + f->command = command; + + /* handle uris */ + if (!strncmp(file, "http://", 7) || !strncmp(file, "ftp://", 6)) + { + uri = file; + base = ecore_file_file_get(file); + + nonlocal = 1; + } + else if (!strncmp(file, "file:", 5)) + { + file = efreet_desktop_command_file_uri_process(file); + if (!file) + { + efreet_desktop_command_file_free(f); + return NULL; + } + } + + if (nonlocal) + { + /* process non-local uri */ + if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH) + { + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "/tmp/%d-%d-%s", getpid(), + efreet_desktop_command_file_id++, base); + f->fullpath = strdup(buf); + f->pending = 1; + + ecore_file_download(uri, f->fullpath, efreet_desktop_cb_download_complete, + efreet_desktop_cb_download_progress, f, NULL); + } + + if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI) + f->uri = strdup(uri); + } + else + { + char *absol = efreet_desktop_command_path_absolute(file); + if (!absol) goto error; + /* process local uri/path */ + if (command->flags & EFREET_DESKTOP_EXEC_FLAG_FULLPATH) + f->fullpath = strdup(absol); + + if (command->flags & EFREET_DESKTOP_EXEC_FLAG_URI) + { + const char *buf; + Efreet_Uri ef_uri; + ef_uri.protocol = "file"; + ef_uri.hostname = ""; + ef_uri.path = absol; + buf = efreet_uri_encode(&ef_uri); + + f->uri = strdup(buf); + + eina_stringshare_del(buf); + } + + free(absol); + } +#if 0 + INF(" fullpath: %s", f->fullpath); + INF(" uri: %s", f->uri); + INF(" dir: %s", f->dir); + INF(" file: %s", f->file); +#endif + return f; +error: + IF_FREE(f); + return NULL; +} + +/** + * @brief Find the local path portion of a file uri. + * @param uri a uri beginning with "file" + * @return the location of the path portion of the uri, + * or NULL if the file is not on this machine + */ +static const char * +efreet_desktop_command_file_uri_process(const char *uri) +{ + const char *path = NULL; + int len = strlen(uri); + + /* uri:foo/bar => relative path foo/bar*/ + if (len >= 4 && uri[5] != '/') + path = uri + strlen("file:"); + + /* uri:/foo/bar => absolute path /foo/bar */ + else if (len >= 5 && uri[6] != '/') + path = uri + strlen("file:"); + + /* uri://foo/bar => absolute path /bar on machine foo */ + else if (len >= 6 && uri[7] != '/') + { + char *tmp, *p; + char hostname[PATH_MAX]; + size_t len2; + + len2 = strlen(uri + 7) + 1; + tmp = alloca(len2); + memcpy(tmp, uri + 7, len2); + p = strchr(tmp, '/'); + if (p) + { + *p = '\0'; + if (!strcmp(tmp, "localhost")) + path = uri + strlen("file://localhost"); + else + { + int ret; + + ret = gethostname(hostname, PATH_MAX); + if ((ret == 0) && !strcmp(tmp, hostname)) + path = uri + strlen("file://") + strlen(hostname); + } + } + } + + /* uri:///foo/bar => absolute path /foo/bar on local machine */ + else if (len >= 7) + path = uri + strlen("file://"); + + return path; +} + +static void +efreet_desktop_command_file_free(Efreet_Desktop_Command_File *file) +{ + if (!file) return; + + IF_FREE(file->fullpath); + IF_FREE(file->uri); + IF_FREE(file->dir); + IF_FREE(file->file); + + FREE(file); +} + + +static void +efreet_desktop_cb_download_complete(void *data, const char *file __UNUSED__, + int status __UNUSED__) +{ + Efreet_Desktop_Command_File *f; + + f = data; + + /* XXX check status... error handling, etc */ + f->pending = 0; + f->command->num_pending--; + + if (f->command->num_pending <= 0) + { + Eina_List *execs; + + execs = efreet_desktop_command_build(f->command); + if (execs) + { + /* TODO: Need to handle the return value from efreet_desktop_command_execs_process */ + efreet_desktop_command_execs_process(f->command, execs); + eina_list_free(execs); + } + efreet_desktop_command_free(f->command); + } +} + +static int +efreet_desktop_cb_download_progress(void *data, + const char *file __UNUSED__, + long int dltotal, long int dlnow, + long int ultotal __UNUSED__, + long int ulnow __UNUSED__) +{ + Efreet_Desktop_Command_File *dcf; + + dcf = data; + if (dcf->command->cb_progress) + return dcf->command->cb_progress(dcf->command->data, + dcf->command->desktop, + dcf->uri, dltotal, dlnow); + + return 0; +} + +/** + * @brief Build an absolute path from an absolute or relative one. + * @param path an absolute or relative path + * @return an allocated absolute path (must be freed) + */ +static char * +efreet_desktop_command_path_absolute(const char *path) +{ + char *buf; + int size = PATH_MAX; + int len = 0; + + /* relative url */ + if (path[0] != '/') + { + if (!(buf = malloc(size))) return NULL; + if (!getcwd(buf, size)) + { + FREE(buf); + return NULL; + } + len = strlen(buf); + + if (buf[len-1] != '/') buf = efreet_string_append(buf, &size, &len, "/"); + if (!buf) return NULL; + buf = efreet_string_append(buf, &size, &len, path); + if (!buf) return NULL; + + return buf; + } + + /* just dup an already absolute buffer */ + return strdup(path); +} + +/** + * Append a string to a buffer, reallocating as necessary. + */ +static char * +efreet_string_append(char *dest, int *size, int *len, const char *src) +{ + int l; + int off = 0; + + l = eina_strlcpy(dest + *len, src, *size - *len); + + while (l > *size - *len) + { + char *tmp; + /* we successfully appended this much */ + off += *size - *len - 1; + *len = *size - 1; + *size += 1024; + tmp = realloc(dest, *size); + if (!tmp) + { + free(dest); + return NULL; + } + dest = tmp; + *(dest + *len) = '\0'; + + l = eina_strlcpy(dest + *len, src + off, *size - *len); + } + *len += l; + + return dest; +} + +static char * +efreet_string_append_char(char *dest, int *size, int *len, char c) +{ + if (*len >= *size - 1) + { + char *tmp; + *size += 1024; + tmp = realloc(dest, *size); + if (!tmp) + { + free(dest); + return NULL; + } + dest = tmp; + } + + dest[(*len)++] = c; + dest[*len] = '\0'; + + return dest; +} + diff --git a/src/lib/efreet_icon.c b/src/lib/efreet_icon.c new file mode 100644 index 0000000..526e0ec --- /dev/null +++ b/src/lib/efreet_icon.c @@ -0,0 +1,910 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <Ecore.h> +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_icon_log_dom +static int _efreet_icon_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" + +static const char *efreet_icon_deprecated_user_dir = NULL; +static const char *efreet_icon_user_dir = NULL; +static Eina_List *efreet_icon_extensions = NULL; +static Eina_List *efreet_extra_icon_dirs = NULL; + +static Eina_Hash *change_monitors = NULL; + +typedef struct Efreet_Icon_Cache Efreet_Icon_Cache; +struct Efreet_Icon_Cache +{ + const char *key; + const char *path; + time_t lasttime; +}; + +static char *efreet_icon_remove_extension(const char *icon); + +static Efreet_Icon *efreet_icon_new(const char *path); +static void efreet_icon_populate(Efreet_Icon *icon, const char *file); + +static const char *efreet_icon_lookup_icon(Efreet_Cache_Icon *icon, unsigned int size); +static const char *efreet_icon_list_lookup_icon(Efreet_Icon_Theme *theme, Eina_List *icons, unsigned int size); +static int efreet_icon_size_match(Efreet_Cache_Icon_Element *elem, unsigned int size); +static double efreet_icon_size_distance(Efreet_Cache_Icon_Element *elem, unsigned int size); +static const char *efreet_icon_lookup_path(Efreet_Cache_Icon_Element *elem); +static const char *efreet_icon_lookup_path_path(Efreet_Cache_Icon_Element *elem, const char *path); +static const char *efreet_icon_fallback_lookup_path(Efreet_Cache_Fallback_Icon *icon); +static const char *efreet_icon_fallback_lookup_path_path(Efreet_Cache_Fallback_Icon *icon, + const char *path); + +static void efreet_icon_changes_listen(void); +static void efreet_icon_changes_monitor_add(const char *path); +static void efreet_icon_changes_cb(void *data, Ecore_File_Monitor *em, + Ecore_File_Event event, const char *path); + + +/** + * @internal + * @return Returns 1 on success or 0 on failure + * @brief Initializes the icon system + */ +int +efreet_icon_init(void) +{ + const char *default_exts[] = {".png", ".xpm", ".svg", NULL}; + int i; + + _efreet_icon_log_dom = eina_log_domain_register + ("efreet_icon", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_icon_log_dom < 0) + return 0; + + /* setup the default extension list */ + for (i = 0; default_exts[i]; i++) + efreet_icon_extensions = eina_list_append(efreet_icon_extensions, eina_stringshare_add(default_exts[i])); + + efreet_icon_changes_listen(); + + efreet_extra_icon_dirs = NULL; + + return 1; +} + +/** + * @internal + * @return Returns no value + * @brief Shuts down the icon system + */ +void +efreet_icon_shutdown(void) +{ + IF_RELEASE(efreet_icon_user_dir); + IF_RELEASE(efreet_icon_deprecated_user_dir); + + IF_FREE_LIST(efreet_icon_extensions, eina_stringshare_del); + efreet_extra_icon_dirs = eina_list_free(efreet_extra_icon_dirs); + + eina_log_domain_unregister(_efreet_icon_log_dom); + _efreet_icon_log_dom = -1; + IF_FREE_HASH(change_monitors); +} + +EAPI const char * +efreet_icon_deprecated_user_dir_get(void) +{ + const char *user; + char *tmp; + int len; + + if (efreet_icon_deprecated_user_dir) return efreet_icon_deprecated_user_dir; + + user = efreet_home_dir_get(); + len = strlen(user) + strlen("/.icons") + 1; + tmp = alloca(len); + snprintf(tmp, len, "%s/.icons", user); + + efreet_icon_deprecated_user_dir = eina_stringshare_add_length(tmp, len - 1); + + return efreet_icon_deprecated_user_dir; +} + +EAPI const char * +efreet_icon_user_dir_get(void) +{ + const char *user; + char *tmp; + int len; + + if (efreet_icon_user_dir) return efreet_icon_user_dir; + + user = efreet_data_home_get(); + len = strlen(user) + strlen("/icons") + 1; + tmp = alloca(len); + snprintf(tmp, len, "%s/icons", user); + + efreet_icon_user_dir = eina_stringshare_add_length(tmp, len - 1); + + return efreet_icon_user_dir; +} + +EAPI void +efreet_icon_extension_add(const char *ext) +{ + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN(ext); + + ext = eina_stringshare_add(ext); + + if ((l = eina_list_data_find_list(efreet_icon_extensions, ext))) + { + efreet_icon_extensions = eina_list_promote_list(efreet_icon_extensions, l); + eina_stringshare_del(ext); + } + else + efreet_icon_extensions = eina_list_prepend(efreet_icon_extensions, ext); +} + +EAPI Eina_List ** +efreet_icon_extra_list_get(void) +{ + return &efreet_extra_icon_dirs; +} + +EAPI Eina_List * +efreet_icon_extensions_list_get(void) +{ + return efreet_icon_extensions; +} + +EAPI Eina_List * +efreet_icon_theme_list_get(void) +{ + return efreet_cache_icon_theme_list(); +} + +EAPI Efreet_Icon_Theme * +efreet_icon_theme_find(const char *theme_name) +{ + if (!theme_name) return NULL; + + return efreet_cache_icon_theme_find(theme_name); +} + +/** + * @internal + * @param icon The icon name to strip extension + * @return Extension removed if in list of extensions, else untouched. + * @brief Removes extension from icon name if in list of extensions. + */ +static char * +efreet_icon_remove_extension(const char *icon) +{ + Eina_List *l; + char *tmp = NULL, *ext = NULL; + + if (!icon) return NULL; + + tmp = strdup(icon); + ext = strrchr(tmp, '.'); + if (ext) + { + const char *ext2; + EINA_LIST_FOREACH(efreet_icon_extensions, l, ext2) + { + if (!strcmp(ext, ext2)) + { +#ifdef STRICT_SPEC + WRN("[Efreet]: Requesting an icon with an extension: %s", + icon); +#endif + *ext = '\0'; + break; + } + } + } + + return tmp; +} + +EAPI const char * +efreet_icon_path_find(const char *theme_name, const char *icon, unsigned int size) +{ + char *tmp; + const char *value = NULL; + Efreet_Icon_Theme *theme; + + EINA_SAFETY_ON_NULL_RETURN_VAL(icon, NULL); + + theme = efreet_icon_theme_find(theme_name); + +#ifdef SLOPPY_SPEC + tmp = efreet_icon_remove_extension(icon); + if (!tmp) return NULL; +#else + tmp = icon; +#endif + + if (theme) + { + Efreet_Cache_Icon *cache; + cache = efreet_cache_icon_find(theme, tmp); + value = efreet_icon_lookup_icon(cache, size); + if (!value) INF("lookup for `%s` failed in theme `%s` with %p.", icon, theme_name, cache); + } + + /* we didn't find the icon in the theme or in the inherited directories + * then just look for a non theme icon + */ + if (!value) + { + Efreet_Cache_Fallback_Icon *cache; + + cache = efreet_cache_icon_fallback_find(tmp); + value = efreet_icon_fallback_lookup_path(cache); + if (!value) INF("lookup for `%s` failed in fallback too with %p.", icon, cache); + } + +#ifdef SLOPPY_SPEC + FREE(tmp); +#endif + return value; +} + +EAPI const char * +efreet_icon_list_find(const char *theme_name, Eina_List *icons, + unsigned int size) +{ + Eina_List *l; + Eina_List *tmps = NULL; + const char *icon = NULL; + const char *value = NULL; + char *data; + Efreet_Icon_Theme *theme; + + EINA_SAFETY_ON_NULL_RETURN_VAL(icons, NULL); + + theme = efreet_icon_theme_find(theme_name); + +#ifdef SLOPPY_SPEC + EINA_LIST_FOREACH(icons, l, icon) + { + data = efreet_icon_remove_extension(icon); + if (!data) return NULL; + tmps = eina_list_append(tmps, data); + } +#else + tmps = icons; +#endif + + if (theme) + { + Eina_List *tmps2 = NULL; + Efreet_Cache_Icon *cache; + + EINA_LIST_FOREACH(tmps, l, icon) + { + cache = efreet_cache_icon_find(theme, icon); + if (cache) + { + /* If the icon is in the asked for theme, return it */ + if (!strcmp(cache->theme, theme->name.internal)) + { + value = efreet_icon_lookup_icon(cache, size); + break; + } + else + tmps2 = eina_list_append(tmps2, cache); + } + } + if (tmps2) + { + if (!value) + value = efreet_icon_list_lookup_icon(theme, tmps2, size); + eina_list_free(tmps2); + } + } + + /* we didn't find the icons in the theme or in the inherited directories + * then just look for a non theme icon + */ + if (!value) + { + Efreet_Cache_Fallback_Icon *cache; + EINA_LIST_FOREACH(tmps, l, icon) + { + cache = efreet_cache_icon_fallback_find(icon); + value = efreet_icon_fallback_lookup_path(cache); + if (value) + break; + } + } + +#ifdef SLOPPY_SPEC + EINA_LIST_FREE(tmps, data) + free(data); +#endif + + return value; +} + +EAPI Efreet_Icon * +efreet_icon_find(const char *theme_name, const char *icon, unsigned int size) +{ + const char *path; + + EINA_SAFETY_ON_NULL_RETURN_VAL(icon, NULL); + + path = efreet_icon_path_find(theme_name, icon, size); + if (path) + { + Efreet_Icon *ic; + + ic = efreet_icon_new(path); + return ic; + } + + return NULL; +} + +/** + * @internal + * @return Returns a new Efreet_Icon struct on success or NULL on failure + * @brief Creates a new Efreet_Icon struct + */ +static Efreet_Icon * +efreet_icon_new(const char *path) +{ + Efreet_Icon *icon; + char *p; + + icon = NEW(Efreet_Icon, 1); + if (!icon) return NULL; + icon->path = eina_stringshare_add(path); + + /* load the .icon file if it's available */ + p = strrchr(icon->path, '.'); + if (p) + { + char ico_path[PATH_MAX]; + + *p = '\0'; + + snprintf(ico_path, sizeof(ico_path), "%s.icon", icon->path); + *p = '.'; + + if (ecore_file_exists(ico_path)) + efreet_icon_populate(icon, ico_path); + } + + if (!icon->name) + { + const char *file; + + file = ecore_file_file_get(icon->path); + p = strrchr(icon->path, '.'); + if (p) *p = '\0'; + icon->name = eina_stringshare_add(file); + if (p) *p = '.'; + } + + return icon; +} + +EAPI void +efreet_icon_free(Efreet_Icon *icon) +{ + if (!icon) return; + + icon->ref_count --; + if (icon->ref_count > 0) return; + + IF_RELEASE(icon->path); + IF_RELEASE(icon->name); + IF_FREE_LIST(icon->attach_points, free); + + FREE(icon); +} + +/** + * @internal + * @param icon The icon to populate + * @param file The file to populate from + * @return Returns no value + * @brief Tries to populate the icon information from the given file + */ +static void +efreet_icon_populate(Efreet_Icon *icon, const char *file) +{ + Efreet_Ini *ini; + const char *tmp; + + ini = efreet_ini_new(file); + if (!ini) return; + if (!ini->data) + { + efreet_ini_free(ini); + return; + } + + efreet_ini_section_set(ini, "Icon Data"); + tmp = efreet_ini_localestring_get(ini, "DisplayName"); + if (tmp) icon->name = eina_stringshare_add(tmp); + + tmp = efreet_ini_string_get(ini, "EmbeddedTextRectangle"); + if (tmp) + { + int points[4]; + char *t, *s, *p; + int i; + size_t len; + + len = strlen(tmp) + 1; + t = alloca(len); + memcpy(t, tmp, len); + s = t; + for (i = 0; i < 4; i++) + { + if (s) + { + p = strchr(s, ','); + + if (p) *p = '\0'; + points[i] = atoi(s); + + if (p) s = ++p; + else s = NULL; + } + else + { + points[i] = 0; + } + } + + icon->has_embedded_text_rectangle = 1; + icon->embedded_text_rectangle.x0 = points[0]; + icon->embedded_text_rectangle.y0 = points[1]; + icon->embedded_text_rectangle.x1 = points[2]; + icon->embedded_text_rectangle.y1 = points[3]; + } + + tmp = efreet_ini_string_get(ini, "AttachPoints"); + if (tmp) + { + char *t, *s, *p; + size_t len; + + len = strlen(tmp) + 1; + t = alloca(len); + memcpy(t, tmp, len); + s = t; + while (s) + { + Efreet_Icon_Point *point; + + p = strchr(s, ','); + /* If this happens there is something wrong with the .icon file */ + if (!p) break; + + point = NEW(Efreet_Icon_Point, 1); + if (!point) goto error; + + *p = '\0'; + point->x = atoi(s); + + s = ++p; + p = strchr(s, '|'); + if (p) *p = '\0'; + + point->y = atoi(s); + + icon->attach_points = eina_list_append(icon->attach_points, point); + + if (p) s = ++p; + else s = NULL; + } + } + +error: + efreet_ini_free(ini); +} + +static const char * +efreet_icon_lookup_icon(Efreet_Cache_Icon *icon, unsigned int size) +{ + const char *path = NULL; + double minimal_distance = INT_MAX; + unsigned int ret_size = 0; + unsigned int i; + + if (!icon) return NULL; + + /* search for allowed size == requested size */ + for (i = 0; i < icon->icons_count; ++i) + { + if (!efreet_icon_size_match(icon->icons[i], size)) continue; + path = efreet_icon_lookup_path(icon->icons[i]); + if (path) return path; + } + + /* search for any icon that matches */ + for (i = 0; i < icon->icons_count; ++i) + { + const char *tmp = NULL; + double distance; + + distance = efreet_icon_size_distance(icon->icons[i], size); + if (distance > minimal_distance) continue; + // prefer downsizing + if ((distance == minimal_distance) && (icon->icons[i]->normal < ret_size)) continue; + + tmp = efreet_icon_lookup_path(icon->icons[i]); + + if (tmp) + { + path = tmp; + minimal_distance = distance; + ret_size = icon->icons[i]->normal; + } + } + + return path; +} + +static const char * +efreet_icon_list_lookup_icon(Efreet_Icon_Theme *theme, Eina_List *icons, unsigned int size) +{ + const char *value = NULL; + Efreet_Cache_Icon *cache; + Eina_List *l; + + EINA_LIST_FOREACH(icons, l, cache) + { + if (!strcmp(cache->theme, theme->name.internal)) + { + value = efreet_icon_lookup_icon(cache, size); + if (value) break; + } + } + if (value) return value; + if (theme->inherits) + { + const char *parent; + EINA_LIST_FOREACH(theme->inherits, l, parent) + { + Efreet_Icon_Theme *parent_theme; + + parent_theme = efreet_icon_theme_find(parent); + if ((!parent_theme) || (parent_theme == theme)) continue; + + value = efreet_icon_list_lookup_icon(parent_theme, icons, size); + if (value) break; + } + } + /* if this isn't the hicolor theme, and we have no other fallbacks + * check hicolor */ + else if (strcmp(theme->name.internal, "hicolor")) + { + Efreet_Icon_Theme *parent_theme; + + parent_theme = efreet_icon_theme_find("hicolor"); + if (parent_theme) + value = efreet_icon_list_lookup_icon(parent_theme, icons, size); + } + return value; +} + +static int +efreet_icon_size_match(Efreet_Cache_Icon_Element *elem, unsigned int size) +{ + if (elem->type == EFREET_ICON_SIZE_TYPE_FIXED) + return (elem->normal == size); + + if ((elem->type == EFREET_ICON_SIZE_TYPE_SCALABLE) || + (elem->type == EFREET_ICON_SIZE_TYPE_THRESHOLD)) + return ((elem->min < size) && (size < elem->max)); + + return 0; +} + +static double +efreet_icon_size_distance(Efreet_Cache_Icon_Element *elem, unsigned int size) +{ + if (elem->type == EFREET_ICON_SIZE_TYPE_FIXED) + return (abs(elem->normal - size)); + + if ((elem->type == EFREET_ICON_SIZE_TYPE_SCALABLE) || + (elem->type == EFREET_ICON_SIZE_TYPE_THRESHOLD)) + { +#ifdef STRICT_SPEC + if (size < elem->min) + return (elem->min - size); + if (elem->max < size) + return (size - elem->max); +#else + if (size < elem->min) + return (elem->min / (double)size); + if (elem->max < size) + return (size / (double)elem->max); +#endif + } + + return 0; +} + +static const char * +efreet_icon_lookup_path(Efreet_Cache_Icon_Element *elem) +{ + Eina_List *xdg_dirs, *l; + const char *path; + const char *dir; + char buf[PATH_MAX]; + + if (elem->paths_count == 1) + { + const char *pp, *ext; + + pp = strrchr(elem->paths[0], '.'); + if (!pp) return NULL; + + EINA_LIST_FOREACH(efreet_icon_extensions, l, ext) + if (!strcmp(pp, ext)) + return elem->paths[0]; + return NULL; + } + + path = efreet_icon_lookup_path_path(elem, efreet_icon_deprecated_user_dir_get()); + if (path) return path; + + path = efreet_icon_lookup_path_path(elem, efreet_icon_user_dir_get()); + if (path) return path; + +#if 0 + EINA_LIST_FOREACH(efreet_extra_icon_dirs, l, dir) + { + path = efreet_icon_lookup_path_path(elem, dir); + if (path) return path; + } +#endif + + xdg_dirs = efreet_data_dirs_get(); + + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/icons", dir); + + path = efreet_icon_lookup_path_path(elem, buf); + if (path) return path; + } + + return NULL; +} + +static const char * +efreet_icon_lookup_path_path(Efreet_Cache_Icon_Element *elem, const char *path) +{ + Eina_List *ll; + const char *ext, *pp; + unsigned int i; + int len; + + len = strlen(path); + + for (i = 0; i < elem->paths_count; ++i) + { + if (strncmp(path, elem->paths[i], len)) continue; + pp = strrchr(elem->paths[i], '.'); + if (!pp) continue; + + EINA_LIST_FOREACH(efreet_icon_extensions, ll, ext) + if (!strcmp(pp, ext)) + return elem->paths[i]; + } + + return NULL; +} + +static const char * +efreet_icon_fallback_lookup_path(Efreet_Cache_Fallback_Icon *icon) +{ + const char *path; + Eina_List *xdg_dirs, *l; + const char *dir; + char buf[PATH_MAX]; + + if (!icon) return NULL; + + if (icon->icons_count == 1) + { + const char *pp, *ext; + + pp = strrchr(icon->icons[0], '.'); + if (!pp) return NULL; + + EINA_LIST_FOREACH(efreet_icon_extensions, l, ext) + if (!strcmp(pp, ext)) + return icon->icons[0]; + return NULL; + } + + path = efreet_icon_fallback_lookup_path_path(icon, efreet_icon_deprecated_user_dir_get()); + if (path) return path; + + path = efreet_icon_fallback_lookup_path_path(icon, efreet_icon_user_dir_get()); + if (path) return path; + + EINA_LIST_FOREACH(efreet_extra_icon_dirs, l, dir) + { + path = efreet_icon_fallback_lookup_path_path(icon, dir); + if (path) return path; + } + + xdg_dirs = efreet_data_dirs_get(); + + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/icons", dir); + + path = efreet_icon_fallback_lookup_path_path(icon, buf); + if (path) return path; + } + +#ifndef STRICT_SPEC + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/pixmaps", dir); + + path = efreet_icon_fallback_lookup_path_path(icon, buf); + if (path) return path; + } +#endif + + path = efreet_icon_fallback_lookup_path_path(icon, "/usr/share/pixmaps"); + if (path) return path; + + return NULL; +} + +static const char * +efreet_icon_fallback_lookup_path_path(Efreet_Cache_Fallback_Icon *icon, const char *path) +{ + Eina_List *ll; + const char *ext, *pp; + unsigned int i; + int len; + + len = strlen(path); + + for (i = 0; i < icon->icons_count; ++i) + { + if (strncmp(path, icon->icons[i], len)) continue; + + pp = strrchr(icon->icons[i], '.'); + if (!pp) continue; + + EINA_LIST_FOREACH(efreet_icon_extensions, ll, ext) + if (!strcmp(pp, ext)) + return icon->icons[i]; + } + + return NULL; +} + +static void +efreet_icon_changes_listen(void) +{ + Eina_List *l; + Eina_List *xdg_dirs; + char buf[PATH_MAX]; + const char *dir; + + if (!efreet_cache_update) return; + + change_monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del)); + if (!change_monitors) return; + + efreet_icon_changes_monitor_add(efreet_icon_deprecated_user_dir_get()); + efreet_icon_changes_monitor_add(efreet_icon_user_dir_get()); + EINA_LIST_FOREACH(efreet_extra_icon_dirs, l, dir) + efreet_icon_changes_monitor_add(dir); + + xdg_dirs = efreet_data_dirs_get(); + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/icons", dir); + efreet_icon_changes_monitor_add(buf); + } + +#ifndef STRICT_SPEC + EINA_LIST_FOREACH(xdg_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/pixmaps", dir); + efreet_icon_changes_monitor_add(buf); + } +#endif + + efreet_icon_changes_monitor_add("/usr/share/pixmaps"); +} + +static void +efreet_icon_changes_monitor_add(const char *path) +{ + char rp[PATH_MAX]; + + if (!realpath(path, rp)) return; + if (!ecore_file_is_dir(rp)) return; + if (eina_hash_find(change_monitors, rp)) return; + eina_hash_add(change_monitors, rp, + ecore_file_monitor_add(rp, + efreet_icon_changes_cb, + NULL)); + + if (ecore_file_is_dir(rp)) + { + Eina_Iterator *it; + const char *ent; + + it = eina_file_ls(rp); + if (!it) return; + EINA_ITERATOR_FOREACH(it, ent) + { + if (!realpath(ent, rp)) continue; + if (!ecore_file_is_dir(rp)) continue; + eina_hash_add(change_monitors, rp, + ecore_file_monitor_add(rp, + efreet_icon_changes_cb, + NULL)); + } + eina_iterator_free(it); + } +} + +static void +efreet_icon_changes_cb(void *data __UNUSED__, Ecore_File_Monitor *em __UNUSED__, + Ecore_File_Event event, const char *path) +{ + /* TODO: If we get a stale symlink, we need to rerun cache creation */ + switch (event) + { + case ECORE_FILE_EVENT_NONE: + /* noop */ + break; + + case ECORE_FILE_EVENT_CREATED_FILE: + case ECORE_FILE_EVENT_DELETED_FILE: + case ECORE_FILE_EVENT_MODIFIED: + case ECORE_FILE_EVENT_CLOSED: + case ECORE_FILE_EVENT_DELETED_DIRECTORY: + case ECORE_FILE_EVENT_CREATED_DIRECTORY: + efreet_cache_icon_update(); + break; + + case ECORE_FILE_EVENT_DELETED_SELF: + eina_hash_del_by_key(change_monitors, path); + efreet_cache_icon_update(); + break; + } +} diff --git a/src/lib/efreet_icon.h b/src/lib/efreet_icon.h new file mode 100644 index 0000000..e6454ad --- /dev/null +++ b/src/lib/efreet_icon.h @@ -0,0 +1,249 @@ +#ifndef EFREET_ICON_H +#define EFREET_ICON_H + +/** + * @file efreet_icon.h + * @brief Contains the structures and methods used to support the FDO icon + * theme specificiation. + * @addtogroup Efreet_Icon Efreet_Icon: The FDO Icon Theme + * Specification functions and structures + * + * @{ + */ + + +/** + * Event id for cache update. + */ +EAPI extern int EFREET_EVENT_ICON_CACHE_UPDATE; + +/** + * The possible contexts for an icon directory + */ +typedef enum Efreet_Icon_Theme_Context +{ + EFREET_ICON_THEME_CONTEXT_NONE, + EFREET_ICON_THEME_CONTEXT_ACTIONS, + EFREET_ICON_THEME_CONTEXT_DEVICES, + EFREET_ICON_THEME_CONTEXT_FILESYSTEMS, + EFREET_ICON_THEME_CONTEXT_MIMETYPES +} Efreet_Icon_Theme_Context; + +/** + * The possible size types for an icon directory + */ +typedef enum Efreet_Icon_Size_Type +{ + EFREET_ICON_SIZE_TYPE_NONE, + EFREET_ICON_SIZE_TYPE_FIXED, + EFREET_ICON_SIZE_TYPE_SCALABLE, + EFREET_ICON_SIZE_TYPE_THRESHOLD +} Efreet_Icon_Size_Type; + +/** + * Efreet_Icon_Theme + */ +typedef struct Efreet_Icon_Theme Efreet_Icon_Theme; + +/** + * Efreet_Icon_Theme + * @brief contains all of the known information about a given theme + */ +struct Efreet_Icon_Theme +{ + struct + { + const char *internal; /**< The internal theme name */ + const char *name; /**< The user visible name */ + } name; /**< The different names for the theme */ + + const char *comment; /**< String describing the theme */ + const char *example_icon; /**< Icon to use as an example of the theme */ + + /* An icon theme can have multiple directories that store it's icons. We + * need to be able to find a search each one. */ + + Eina_List *paths; /**< The paths */ + Eina_List *inherits; /**< Icon themes we inherit from */ + Eina_List *directories; /**< List of subdirectories for this theme */ +}; + +/** + * Efreet_Icon_Theme_Directory + */ +typedef struct Efreet_Icon_Theme_Directory Efreet_Icon_Theme_Directory; + +/** + * Efreet_Icon_Theme_Directory + * @brief Contains all the information about a sub-directory of a theme + */ +struct Efreet_Icon_Theme_Directory +{ + const char *name; /**< The directory name */ + Efreet_Icon_Theme_Context context; /**< The type of icons in the dir */ + Efreet_Icon_Size_Type type; /**< The size type for the icons */ + + struct + { + unsigned int normal; /**< The size for this directory */ + unsigned int min; /**< The minimum size for this directory */ + unsigned int max; /**< The maximum size for this directory */ + unsigned int threshold; /**< Size difference threshold */ + } size; /**< The size settings for the icon theme */ +}; + +/** + * Efreet_Icon + */ +typedef struct Efreet_Icon Efreet_Icon; + +/** + * Efreet_Icon + * @brief Contains all the information about a given icon + */ +struct Efreet_Icon +{ + const char *path; /**< Full path to the icon */ + const char *name; /**< Translated UTF8 string that can + be used for the icon name */ + + struct + { + int x0, /**< x0 position */ + y0, /**< y0 position */ + x1, /**< x1 position */ + y1; /**< y1 position */ + } embedded_text_rectangle; /**< Rectangle where text can + be displayed on the icon */ + + Eina_List *attach_points; /**< List of points to be used as anchor + points for emblems/overlays */ + + unsigned int ref_count; /**< References to this icon */ + unsigned char has_embedded_text_rectangle:1; /**< Has the embedded + rectangle set */ +}; + +/** + * Efreet_Icon_Point + */ +typedef struct Efreet_Icon_Point Efreet_Icon_Point; + +/** + * Efreet_Icon_Point + * @brief Stores an x, y point. + */ +struct Efreet_Icon_Point +{ + int x; /**< x coord */ + int y; /**< y coord */ +}; + +/** + * @return Returns the user icon directory + * @brief Returns the user icon directory + */ +EAPI const char *efreet_icon_user_dir_get(void); + +/** + * @return Returns the deprecated user icon directory + * @brief Returns the deprecated user icon directory + */ +EAPI const char *efreet_icon_deprecated_user_dir_get(void); + +/** + * @param ext The extension to add to the list of checked extensions + * @return Returns no value. + * @brief Adds the given extension to the list of possible icon extensions + */ +EAPI void efreet_icon_extension_add(const char *ext); + + +/** + * @return Returns a list of strings that are paths to other icon directories + * @brief Gets the list of all extra directories to look for icons. These + * directories are used to look for icons after looking in the user icon dir + * and before looking in standard system directories. The order of search is + * from first to last directory in this list. the strings in the list should + * be created with eina_stringshare_add(). + */ +EAPI Eina_List **efreet_icon_extra_list_get(void); + +/** + * @return Returns a list of strings that are icon extensions to look for + * @brief Gets the list of all icon extensions to look for + */ +EAPI Eina_List *efreet_icon_extensions_list_get(void); + +/** + * @return Returns a list of Efreet_Icon structs for all the non-hidden icon + * themes + * @brief Retrieves all of the non-hidden icon themes available on the system. + * The returned list must be freed. Do not free the list data. + */ +EAPI Eina_List *efreet_icon_theme_list_get(void); + +/** + * @param theme_name The theme to look for + * @return Returns the icon theme related to the given theme name or NULL if + * none exists. + * @brief Tries to get the icon theme structure for the given theme name + */ +EAPI Efreet_Icon_Theme *efreet_icon_theme_find(const char *theme_name); + +/** + * @param theme_name The icon theme to look for + * @param icon The icon to look for + * @param size The icon size to look for + * @return Returns the Efreet_Icon structure representing this icon or NULL + * if the icon is not found + * @brief Retrieves all of the information about the given icon. + */ +EAPI Efreet_Icon *efreet_icon_find(const char *theme_name, + const char *icon, + unsigned int size); + +/** + * @param theme_name The icon theme to look for + * @param icons List of icons to look for + * @param size; The icon size to look for + * @return Returns the path representing first found icon or + * NULL if none of the icons are found + * @brief Retrieves all of the information about the first found icon in + * the list. + * @note This function will search the given theme for all icons before falling + * back. This is useful when searching for mimetype icons. + * + * There is no guarantee for how long the pointer to the path will be valid. + * If the pointer is to be kept, the user must create a copy of the path. + */ +EAPI const char *efreet_icon_list_find(const char *theme_name, + Eina_List *icons, + unsigned int size); + +/** + * @param theme_name The icon theme to look for + * @param icon The icon to look for + * @param size; The icon size to look for + * @return Returns the path to the given icon or NULL if none found + * @brief Retrives the path to the given icon. + * + * There is no guarantee for how long the pointer to the path will be valid. + * If the pointer is to be kept, the user must create a copy of the path. + */ +EAPI const char *efreet_icon_path_find(const char *theme_name, + const char *icon, + unsigned int size); + +/** + * @param icon The Efreet_Icon to cleanup + * @return Returns no value. + * @brief Free's the given icon and all its internal data. + */ +EAPI void efreet_icon_free(Efreet_Icon *icon); + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_ini.c b/src/lib/efreet_ini.c new file mode 100644 index 0000000..375fda1 --- /dev/null +++ b/src/lib/efreet_ini.c @@ -0,0 +1,629 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <ctype.h> +#include <sys/stat.h> +#include <unistd.h> +#include <sys/mman.h> + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_ini_log_dom +static int _efreet_ini_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" + +static Eina_Hash *efreet_ini_parse(const char *file); +static const char *efreet_ini_unescape(const char *str) EINA_ARG_NONNULL(1); +static Eina_Bool +efreet_ini_section_save(const Eina_Hash *hash, const void *key, void *data, void *fdata); +static Eina_Bool +efreet_ini_value_save(const Eina_Hash *hash, const void *key, void *data, void *fdata); + +/** + * @internal + * @return Returns > 0 on success or 0 on failure + * @brief Initialize the Ini parser subsystem + */ +int +efreet_ini_init(void) +{ + _efreet_ini_log_dom = eina_log_domain_register + ("efreet_ini", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_ini_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_ini"); + return 0; + } + return 1; +} + +/** + * @internal + * @returns the number of initializations left for this system + * @brief Attempts to shut down the subsystem if nothing else is using it + */ +void +efreet_ini_shutdown(void) +{ + eina_log_domain_unregister(_efreet_ini_log_dom); + _efreet_ini_log_dom = -1; +} + +EAPI Efreet_Ini * +efreet_ini_new(const char *file) +{ + Efreet_Ini *ini; + + ini = NEW(Efreet_Ini, 1); + if (!ini) return NULL; + + /* This can validly be NULL at the moment as _parse() will return NULL + * if the input file doesn't exist. Should we change _parse() to create + * the hash and only return NULL on failed parse? */ + ini->data = efreet_ini_parse(file); + + return ini; +} + +/** + * @internal + * @param file The file to parse + * @return Returns an Eina_Hash with the contents of @a file, or NULL if the + * file fails to parse or if the file doesn't exist + * @brief Parses the ini file @a file into an Eina_Hash + */ +static Eina_Hash * +efreet_ini_parse(const char *file) +{ + const char *buffer, *line_start; + FILE *f; + Eina_Hash *data, *section = NULL; + struct stat file_stat; + int line_length, left; + + if (!file) return NULL; + + f = fopen(file, "rb"); + if (!f) return NULL; + + if (fstat(fileno(f), &file_stat) || (file_stat.st_size < 1)) + { + fclose(f); + return NULL; + } + if (!S_ISREG(file_stat.st_mode)) /* if not a regular file - close */ + { + fclose(f); + return NULL; + } + + left = file_stat.st_size; + /* let's make mmap safe and just get 0 pages for IO erro */ + eina_mmap_safety_enabled_set(EINA_TRUE); + + buffer = mmap(NULL, left, PROT_READ, MAP_SHARED, fileno(f), 0); + if (buffer == MAP_FAILED) + { + fclose(f); + return NULL; + } + + data = eina_hash_string_small_new(EINA_FREE_CB(eina_hash_free)); + + line_start = buffer; + while (left > 0) + { + int sep; + + /* find the end of line */ + for (line_length = 0; + (line_length < left) && + (line_start[line_length] != '\n'); line_length++) + ; + + /* check for all white space */ + while (isspace(line_start[0]) && (line_length > 0)) + { + line_start++; + line_length--; + } + + /* skip empty lines and comments */ + if ((line_length == 0) || (line_start[0] == '\r') || + (line_start[0] == '\n') || (line_start[0] == '#') || + (line_start[0] == '\0')) + goto next_line; + + /* new section */ + if (line_start[0] == '[') + { + int header_length; + + /* find the ']' */ + for (header_length = 1; + (header_length < line_length) && + (line_start[header_length] != ']'); ++header_length) + ; + + if (line_start[header_length] == ']') + { + const char *header; + + header = alloca(header_length * sizeof(unsigned char)); + if (!header) goto next_line; + + memcpy((char*)header, line_start + 1, header_length - 1); + ((char*)header)[header_length - 1] = '\0'; + + section = eina_hash_string_small_new(EINA_FREE_CB(eina_stringshare_del)); + + eina_hash_del_by_key(data, header); +// if (old) INF("[efreet] Warning: duplicate section '%s' " + // "in file '%s'", header, file); + + eina_hash_add(data, header, section); + } + else + { + /* invalid file - skip line? or refuse to parse file? */ + /* just printf for now till we figure out what to do */ +// ERR("Invalid file (%s) (missing ] on group name)", file); + } + goto next_line; + } + + if (!section) + { + INF("Invalid file (%s) (missing section)", file); + goto error; + } + + /* find for '=' */ + for (sep = 0; (sep < line_length) && (line_start[sep] != '='); ++sep) + ; + + if (sep < line_length && line_start[sep] == '=') + { + char *key, *value; + int key_end, value_start, value_end; + + /* trim whitespace from end of key */ + for (key_end = sep - 1; + (key_end > 0) && isspace(line_start[key_end]); --key_end) + ; + + if (!isspace(line_start[key_end])) key_end++; + + /* trim whitespace from start of value */ + for (value_start = sep + 1; + (value_start < line_length) && + isspace(line_start[value_start]); ++value_start) + ; + + /* trim \n off of end of value */ + for (value_end = line_length; + (value_end > value_start) && + ((line_start[value_end] == '\n') || + (line_start[value_end] == '\r')); --value_end) + ; + + if (line_start[value_end] != '\n' + && line_start[value_end] != '\r' + && value_end < line_length) + value_end++; + + /* make sure we have a key. blank values are allowed */ + if (key_end <= 0) + { + /* invalid file... */ +// INF("Invalid file (%s) (invalid key=value pair)", file); + + goto next_line; + } + + key = alloca(key_end + 1); + value = alloca(value_end - value_start + 1); + if (!key || !value) goto next_line; + + memcpy(key, line_start, key_end); + key[key_end] = '\0'; + + memcpy(value, line_start + value_start, + value_end - value_start); + value[value_end - value_start] = '\0'; + + eina_hash_del_by_key(section, key); + eina_hash_add(section, key, efreet_ini_unescape(value)); + } + else + { + /* invalid file... */ + INF("Invalid file (%s) (missing = from key=value pair)", file); + goto error; + } + +next_line: + left -= line_length + 1; + line_start += line_length + 1; + } + munmap((char*) buffer, file_stat.st_size); + fclose(f); + +#if 0 + if (!eina_hash_population(data)) + { + eina_hash_free(data); + return NULL; + } +#endif + return data; +error: + if (data) eina_hash_free(data); + return NULL; +} + +EAPI void +efreet_ini_free(Efreet_Ini *ini) +{ + if (!ini) return; + + IF_FREE_HASH(ini->data); + FREE(ini); +} + +EAPI int +efreet_ini_save(Efreet_Ini *ini, const char *file) +{ + char *dir; + FILE *f; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->data, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(file, 0); + + dir = ecore_file_dir_get(file); + if (!ecore_file_mkpath(dir)) + { + free(dir); + return 0; + } + free(dir); + f = fopen(file, "wb"); + if (!f) return 0; + eina_hash_foreach(ini->data, efreet_ini_section_save, f); + fclose(f); + + return 1; +} + +EAPI int +efreet_ini_section_set(Efreet_Ini *ini, const char *section) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->data, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(section, 0); + + ini->section = eina_hash_find(ini->data, section); + return (ini->section ? 1 : 0); +} + +EAPI void +efreet_ini_section_add(Efreet_Ini *ini, const char *section) +{ + Eina_Hash *hash; + + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(section); + + if (!ini->data) + ini->data = eina_hash_string_small_new(EINA_FREE_CB(eina_hash_free)); + if (eina_hash_find(ini->data, section)) return; + + hash = eina_hash_string_small_new(EINA_FREE_CB(eina_stringshare_del)); + eina_hash_add(ini->data, section, hash); +} + +EAPI const char * +efreet_ini_string_get(Efreet_Ini *ini, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->section, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL); + + return eina_hash_find(ini->section, key); +} + +EAPI void +efreet_ini_string_set(Efreet_Ini *ini, const char *key, const char *value) +{ + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + eina_hash_del_by_key(ini->section, key); + eina_hash_add(ini->section, key, eina_stringshare_add(value)); +} + +EAPI int +efreet_ini_int_get(Efreet_Ini *ini, const char *key) +{ + const char *str; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->section, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(key, -1); + + str = efreet_ini_string_get(ini, key); + if (str) return atoi(str); + + return -1; +} + +EAPI void +efreet_ini_int_set(Efreet_Ini *ini, const char *key, int value) +{ + char str[12]; + + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + snprintf(str, 12, "%d", value); + efreet_ini_string_set(ini, key, str); +} + +EAPI double +efreet_ini_double_get(Efreet_Ini *ini, const char *key) +{ + const char *str; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->section, -1); + EINA_SAFETY_ON_NULL_RETURN_VAL(key, -1); + + str = efreet_ini_string_get(ini, key); + if (str) return atof(str); + + return -1; +} + +EAPI void +efreet_ini_double_set(Efreet_Ini *ini, const char *key, double value) +{ + char str[512]; + size_t len; + + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + snprintf(str, 512, "%.6f", value); + len = strlen(str) - 1; + /* Strip trailing zero's */ + while (str[len] == '0' && str[len - 1] != '.') str[len--] = '\0'; + efreet_ini_string_set(ini, key, str); +} + +EAPI unsigned int +efreet_ini_boolean_get(Efreet_Ini *ini, const char *key) +{ + const char *str; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->section, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(key, 0); + + str = efreet_ini_string_get(ini, key); + if (str && !strcmp("true", str)) return 1; + + return 0; +} + +EAPI void +efreet_ini_boolean_set(Efreet_Ini *ini, const char *key, unsigned int value) +{ + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + if (value) efreet_ini_string_set(ini, key, "true"); + else efreet_ini_string_set(ini, key, "false"); +} + +EAPI const char * +efreet_ini_localestring_get(Efreet_Ini *ini, const char *key) +{ + const char *lang, *country, *modifier; + const char *val = NULL; + char *buf; + int maxlen = 5; /* _, @, [, ] and \0 */ + int found = 0; + + EINA_SAFETY_ON_NULL_RETURN_VAL(ini, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(ini->section, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(key, NULL); + + lang = efreet_lang_get(); + country = efreet_lang_country_get(); + modifier = efreet_lang_modifier_get(); + + maxlen += strlen(key); + if (lang) maxlen += strlen(lang); + if (country) maxlen += strlen(country); + if (modifier) maxlen += strlen(modifier); + + buf = alloca(maxlen); + + if (lang && modifier && country) + { + snprintf(buf, maxlen, "%s[%s_%s@%s]", key, lang, country, modifier); + val = efreet_ini_string_get(ini, buf); + if (val && (*val != '\0')) found = 1; + } + + if (!found && lang && country) + { + snprintf(buf, maxlen, "%s[%s_%s]", key, lang, country); + val = efreet_ini_string_get(ini, buf); + if (val && (*val != '\0')) found = 1; + } + + if (!found && lang && modifier) + { + snprintf(buf, maxlen, "%s[%s@%s]", key, lang, modifier); + val = efreet_ini_string_get(ini, buf); + if (val && (*val != '\0')) found = 1; + } + + if (!found && lang) + { + snprintf(buf, maxlen, "%s[%s]", key, lang); + val = efreet_ini_string_get(ini, buf); + if (val && (*val != '\0')) found = 1; + } + + if (!found) + val = efreet_ini_string_get(ini, key); + + return val; +} + +EAPI void +efreet_ini_localestring_set(Efreet_Ini *ini, const char *key, const char *value) +{ + const char *lang, *country, *modifier; + char *buf; + int maxlen = 5; /* _, @, [, ] and \0 */ + + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + lang = efreet_lang_get(); + country = efreet_lang_country_get(); + modifier = efreet_lang_modifier_get(); + + maxlen += strlen(key); + if (lang) maxlen += strlen(lang); + if (country) maxlen += strlen(country); + if (modifier) maxlen += strlen(modifier); + + buf = alloca(maxlen); + + if (lang && modifier && country) + snprintf(buf, maxlen, "%s[%s_%s@%s]", key, lang, country, modifier); + else if (lang && country) + snprintf(buf, maxlen, "%s[%s_%s]", key, lang, country); + else if (lang && modifier) + snprintf(buf, maxlen, "%s[%s@%s]", key, lang, modifier); + else if (lang) + snprintf(buf, maxlen, "%s[%s]", key, lang); + else + return; + + efreet_ini_string_set(ini, buf, value); +} + +EAPI void +efreet_ini_key_unset(Efreet_Ini *ini, const char *key) +{ + EINA_SAFETY_ON_NULL_RETURN(ini); + EINA_SAFETY_ON_NULL_RETURN(ini->section); + EINA_SAFETY_ON_NULL_RETURN(key); + + eina_hash_del_by_key(ini->section, key); +} + +/** + * @param str The string to unescape + * @return An allocated unescaped string + * @brief Unescapes backslash escapes in a string + */ +static const char * +efreet_ini_unescape(const char *str) +{ + char *buf, *dest; + const char *p; + + if (!strchr(str, '\\')) return eina_stringshare_add(str); + buf = alloca(strlen(str) + 1); + + p = str; + dest = buf; + while (*p) + { + if ((*p == '\\') && (p[1] != '\0')) + { + p++; + switch (*p) + { + case 's': + *(dest++) = ' '; + break; + case 'n': + *(dest++) = '\n'; + break; + case 't': + *(dest++) = '\t'; + break; + case 'r': + *(dest++) = '\r'; + break; + case '\\': + *(dest++) = '\\'; + break; + default: + (*dest++) = '\\'; + (*dest++) = *p; + } + } + else + *(dest++) = *p; + + p++; + } + + *(dest) = '\0'; + return eina_stringshare_add(buf); +} + +static Eina_Bool +efreet_ini_section_save(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata) +{ + FILE *f = fdata; + + fprintf(f, "[%s]\n", (char *)key); + eina_hash_foreach(value, efreet_ini_value_save, f); + return EINA_TRUE; +} + +static Eina_Bool +efreet_ini_value_save(const Eina_Hash *hash __UNUSED__, const void *key, void *value, void *fdata) +{ + FILE *f = fdata; + + fprintf(f, "%s=%s\n", (char *)key, (char *)value); + return EINA_TRUE; +} diff --git a/src/lib/efreet_ini.h b/src/lib/efreet_ini.h new file mode 100644 index 0000000..f5b8a9e --- /dev/null +++ b/src/lib/efreet_ini.h @@ -0,0 +1,181 @@ +#ifndef EFREET_INI_H +#define EFREET_INI_H + +/** + * @internal + * @file efreet_ini.h + * @brief A simple and fast INI parser + * @addtogroup Efreet_Ini Efreet_Ini: An INI parser + * + * @{ + */ + +/** + * Efreet_Ini + */ +typedef struct Efreet_Ini Efreet_Ini; + +/** + * Efreet_Ini + * @brief Contains all the information about an ini file. + */ +struct Efreet_Ini +{ + Eina_Hash *data; /**< Hash of string => (Hash of string => string) */ + Eina_Hash *section; /**< currently selected section */ +}; + + +/** + * @param file The file to parse + * @return Returns a new Efreet_Ini structure initialized with the contents + * of @a file, or NULL on memory allocation failure + * @brief Creates and initializes a new Ini structure with the contents of + * @a file, or NULL on failure + */ +EAPI Efreet_Ini *efreet_ini_new(const char *file); + +/** + * @param ini The Efreet_Ini to work with + * @return Returns no value + * @brief Frees the given Efree_Ini structure. + */ +EAPI void efreet_ini_free(Efreet_Ini *ini); + +/** + * @param ini The Efreet_Ini to work with + * @param file The file to load + * @return Returns no value + * @brief Saves the given Efree_Ini structure. + */ +EAPI int efreet_ini_save(Efreet_Ini *ini, const char *path); + + +/** + * @param ini The Efreet_Ini to work with + * @param section The section of the ini file we want to get values from + * @return Returns 1 if the section exists, otherwise 0 + * @brief Sets the current working section of the ini file to @a section + */ +EAPI int efreet_ini_section_set(Efreet_Ini *ini, const char *section); + +/** + * @param ini The Efreet_Ini to work with + * @param section The section of the ini file we want to add + * @return Returns no value + * @brief Adds a new working section of the ini file to @a section + */ +EAPI void efreet_ini_section_add(Efreet_Ini *ini, const char *section); + + +/** + * @param ini The Efree_Ini to work with + * @param key The key to lookup + * @return Returns the string associated with the given key or NULL if not + * found. + * @brief Retrieves the value for the given key or NULL if none found. + */ +EAPI const char *efreet_ini_string_get(Efreet_Ini *ini, const char *key); + +/** + * @param ini The Efree_Ini to work with + * @param key The key to use + * @param value The value to set + * @return Returns no value + * @brief Sets the value for the given key + */ +EAPI void efreet_ini_string_set(Efreet_Ini *ini, const char *key, + const char *value); + + +/** + * @param ini The ini struct to work with + * @param key The key to search for + * @return Returns the utf8 encoded string associated with @a key, or NULL + * if none found + * @brief Retrieves the utf8 encoded string associated with @a key in the current locale or NULL if none found + */ +EAPI const char *efreet_ini_localestring_get(Efreet_Ini *ini, const char *key); + +/** + * @param ini The ini struct to work with + * @param key The key to use + * @param value The value to set + * @return Returns no value + * @brief Sets the value for the given key + */ +EAPI void efreet_ini_localestring_set(Efreet_Ini *ini, const char *key, + const char *value); + + +/** + * @param ini The ini struct to work with + * @param key The key to search for + * @return Returns 1 if the boolean is true, 0 otherwise + * @brief Retrieves the boolean value at key @a key from the ini @a ini + */ +EAPI unsigned int efreet_ini_boolean_get(Efreet_Ini *ini, const char *key); + +/** + * @param ini The ini struct to work with + * @param key The key to use + * @param value The value to set + * @return Returns no value + * @brief Sets the value for the given key + */ +EAPI void efreet_ini_boolean_set(Efreet_Ini *ini, const char *key, + unsigned int value); + + +/** + * @param ini The Efree_Ini to work with + * @param key The key to lookup + * @return Returns the integer associated with the given key or -1 if not + * found. + * @brief Retrieves the value for the given key or -1 if none found. + */ +EAPI int efreet_ini_int_get(Efreet_Ini *ini, const char *key); + +/** + * @param ini The Efree_Ini to work with + * @param key The key to use + * @param value The value to set + * @return Returns no value + * @brief Sets the value for the given key + */ +EAPI void efreet_ini_int_set(Efreet_Ini *ini, const char *key, int value); + + +/** + * @param ini The Efree_Ini to work with + * @param key The key to lookup + * @return Returns the double associated with the given key or -1 if not + * found. + * @brief Retrieves the value for the given key or -1 if none found. + */ +EAPI double efreet_ini_double_get(Efreet_Ini *ini, const char *key); + +/** + * @param ini The Efree_Ini to work with + * @param key The key to use + * @param value The value to set + * @return Returns no value + * @brief Sets the value for the given key + */ +EAPI void efreet_ini_double_set(Efreet_Ini *ini, const char *key, + double value); + + +/** + * @param ini The ini struct to work with + * @param key The key to remove + * @return Returns no value + * @brief Remove the given key from the ini struct + */ +EAPI void efreet_ini_key_unset(Efreet_Ini *ini, const char *key); + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_menu.c b/src/lib/efreet_menu.c new file mode 100644 index 0000000..e612ba1 --- /dev/null +++ b/src/lib/efreet_menu.c @@ -0,0 +1,3887 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_menu_log_dom +static int _efreet_menu_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_xml.h" + +typedef struct Efreet_Menu_Move Efreet_Menu_Move; + +struct Efreet_Menu_Move +{ + const char *old_name; /**< The menu path to move from */ + const char *new_name; /**< The menu path to move too */ +}; + +typedef struct Efreet_Menu_Internal Efreet_Menu_Internal; + +struct Efreet_Menu_Internal +{ + struct + { + const char *path; /**< The base file path */ + const char *name; /**< The filename for this menu */ + } file; /**< The menu file information */ + + struct + { + const char *internal; /**< The menu name */ + const char *name; /**< Name to use in the menus */ + } name; /**< The names for this menu */ + + Efreet_Desktop *directory; /**< The directory */ + Eina_List *directories; /**< All the directories set in the menu file */ + + Efreet_Menu_Move *current_move; /**< The current move */ + + Eina_List *app_dirs; /**< .desktop application directories */ + + Eina_List *app_pool; /**< application pool */ + Eina_List *applications; /**< applications in this menu */ + + Eina_List *directory_dirs; /**< .directory file directories */ + Eina_Hash *directory_cache; /**< .directory dirs */ + + Eina_List *moves; /**< List of moves to be handled by the menu */ + Eina_List *filters; /**< Include and Exclude filters */ + + Efreet_Menu_Internal *parent; /**< Our parent menu */ + Eina_List *sub_menus; /**< Our sub menus */ + + Eina_List *layout; /**< This menus layout */ + Eina_List *default_layout; /**< Default layout */ + signed char show_empty; /**< Whether to show empty menus */ + signed char in_line; /**< Whether this meny can be inlined */ + signed char inline_limit; /**< Number of elements which triggers inline */ + signed char inline_header; /**< Whether we should use the header name when this menu is inlined */ + signed char inline_alias; /**< Whether we should use the menu name when inlining */ + + unsigned char seen_allocated:1; /**< have we set the only_unallocated */ + unsigned char only_unallocated:1; /**< Show only unallocated .desktops */ + + unsigned char seen_deleted:1; /**< Have we seen the deleted item yet */ + unsigned char deleted:1; /**< The menu is deleted */ +}; + +typedef struct Efreet_Menu_App_Dir Efreet_Menu_App_Dir; + +struct Efreet_Menu_App_Dir +{ + const char *path; /**< directory path */ + const char *prefix; /**< If it's legacy it can have a prefix */ + unsigned int legacy:1; /**< is this a legacy dir */ +}; + +enum Efreet_Menu_Filter_Op_Type +{ + EFREET_MENU_FILTER_OP_OR, + EFREET_MENU_FILTER_OP_AND, + EFREET_MENU_FILTER_OP_NOT +}; + +typedef enum Efreet_Menu_Filter_Op_Type Efreet_Menu_Filter_Op_Type; + +enum Efreet_Menu_Filter_Type +{ + EFREET_MENU_FILTER_INCLUDE, + EFREET_MENU_FILTER_EXCLUDE +}; + +typedef enum Efreet_Menu_Filter_Type Efreet_Menu_Filter_Type; + +typedef struct Efreet_Menu_Filter_Op Efreet_Menu_Filter_Op; + +struct Efreet_Menu_Filter_Op +{ + Efreet_Menu_Filter_Op_Type type; /**< The type of operation */ + Eina_List *categories; /**< The categories this op applies too */ + Eina_List *filenames; /**< The filenames this op applies too */ + + Eina_List *filters; /**< Child filters */ + + unsigned char all:1; /**< Applies to all .desktop files */ +}; + +typedef struct Efreet_Menu_Filter Efreet_Menu_Filter; + +struct Efreet_Menu_Filter +{ + Efreet_Menu_Filter_Type type; /**< The type of filter */ + Efreet_Menu_Filter_Op *op; /**< The filter operations */ +}; + +enum Efreet_Menu_Layout_Type +{ + EFREET_MENU_LAYOUT_MENUNAME, + EFREET_MENU_LAYOUT_FILENAME, + EFREET_MENU_LAYOUT_SEPARATOR, + EFREET_MENU_LAYOUT_MERGE +}; + +typedef enum Efreet_Menu_Layout_Type Efreet_Menu_Layout_Type; + +typedef struct Efreet_Menu_Layout Efreet_Menu_Layout; + +struct Efreet_Menu_Layout +{ + Efreet_Menu_Layout_Type type; /**< The type of layout */ + const char *name; /**< The name of the element */ + + /* The items below are for Menuname Layout elements */ + signed char show_empty; /**< Whether to show empty menus */ + signed char in_line; /**< Whether this meny can be inlined */ + signed char inline_limit; /**< Number of elements which triggers inline */ + signed char inline_header; /**< Whether we should use the header name when this menu is inlined */ + signed char inline_alias; /**< Whether we should use the menu name when inlining */ +}; + +typedef struct Efreet_Menu_Desktop Efreet_Menu_Desktop; + +struct Efreet_Menu_Desktop +{ + Efreet_Desktop *desktop; /**< The desktop we refer too */ + const char *id; /**< The desktop file id */ + unsigned char allocated:1; /**< If this desktop has been allocated */ +}; + +static const char *efreet_menu_prefix = NULL; /**< The $XDG_MENU_PREFIX env var */ +Eina_List *efreet_menu_kde_legacy_dirs = NULL; /**< The directories to use for KDELegacy entries */ +static const char *efreet_tag_menu = NULL; +static const char *efreet_menu_file = NULL; /**< A menu file set explicityl as default */ + +static Eina_Hash *efreet_merged_menus = NULL; +static Eina_Hash *efreet_merged_dirs = NULL; + +static Eina_Hash *efreet_menu_handle_cbs = NULL; +static Eina_Hash *efreet_menu_filter_cbs = NULL; +static Eina_Hash *efreet_menu_move_cbs = NULL; +static Eina_Hash *efreet_menu_layout_cbs = NULL; + +static const char *efreet_menu_prefix_get(void); + +static Efreet_Menu_Internal *efreet_menu_by_name_find(Efreet_Menu_Internal *internal, + const char *name, + Efreet_Menu_Internal **parent); +static int efreet_menu_cb_compare_names(Efreet_Menu_Internal *internal, const char *name); +static int efreet_menu_cb_md_compare_ids(Efreet_Menu_Desktop *md, const char *name); + +static int efreet_menu_cb_entry_compare_menu(Efreet_Menu *entry, Efreet_Menu_Internal *internal); +static int efreet_menu_cb_entry_compare_desktop(Efreet_Menu *entry, Efreet_Desktop *desktop); + +static int efreet_menu_cb_move_compare(Efreet_Menu_Move *move, const char *old); + +static int efreet_menu_process(Efreet_Menu_Internal *internal, unsigned int only_unallocated); +static int efreet_menu_process_dirs(Efreet_Menu_Internal *internal); +static int efreet_menu_app_dirs_process(Efreet_Menu_Internal *internal); +static int efreet_menu_app_dir_scan(Efreet_Menu_Internal *internal, + const char *path, + const char *id, + int legacy); +static int efreet_menu_directory_dirs_process(Efreet_Menu_Internal *internal); +static int efreet_menu_directory_dir_scan(const char *path, + const char *relative_path, + Eina_Hash *cache); +static Efreet_Desktop *efreet_menu_directory_get(Efreet_Menu_Internal *internal, + const char *path); +static void efreet_menu_process_filters(Efreet_Menu_Internal *internal, + unsigned int only_unallocated); +static Eina_List *efreet_menu_process_app_pool(Eina_List *pool, + Eina_List *applications, + Eina_Hash *matches, + Efreet_Menu_Filter *filter, + unsigned int only_unallocated); +static int efreet_menu_filter_matches(Efreet_Menu_Filter_Op *op, + Efreet_Menu_Desktop *md); +static int efreet_menu_filter_or_matches(Efreet_Menu_Filter_Op *op, + Efreet_Menu_Desktop *md); +static int efreet_menu_filter_and_matches(Efreet_Menu_Filter_Op *op, + Efreet_Menu_Desktop *md); +static int efreet_menu_filter_not_matches(Efreet_Menu_Filter_Op *op, + Efreet_Menu_Desktop *md); + +static Efreet_Menu *efreet_menu_layout_menu(Efreet_Menu_Internal *internal); +static Efreet_Menu *efreet_menu_layout_desktop(Efreet_Menu_Desktop *md); +static void efreet_menu_layout_entries_get(Efreet_Menu *entry, Efreet_Menu_Internal *internal, + Efreet_Menu_Layout *layout); +static int efreet_menu_layout_is_empty(Efreet_Menu *entry); + +static Efreet_Menu_Internal *efreet_menu_internal_new(void); +static void efreet_menu_internal_free(Efreet_Menu_Internal *internal); +static void efreet_menu_create_sub_menu_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_app_dirs_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_directory_dirs_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_directories_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_move_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_filter_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_layout_list(Efreet_Menu_Internal *internal); +static void efreet_menu_create_default_layout_list(Efreet_Menu_Internal *internal); +static const char *efreet_menu_path_get(Efreet_Menu_Internal *internal, const char *suffix); + +static Efreet_Menu_App_Dir *efreet_menu_app_dir_new(void); +static void efreet_menu_app_dir_free(Efreet_Menu_App_Dir *dir); + +static Efreet_Menu_Move *efreet_menu_move_new(void); +static void efreet_menu_move_free(Efreet_Menu_Move *move); + +static Efreet_Menu_Filter *efreet_menu_filter_new(void); +static void efreet_menu_filter_free(Efreet_Menu_Filter *filter); + +static Efreet_Menu_Layout *efreet_menu_layout_new(void); +static void efreet_menu_layout_free(Efreet_Menu_Layout *layout); + +static Efreet_Menu_Filter_Op *efreet_menu_filter_op_new(void); +static void efreet_menu_filter_op_free(Efreet_Menu_Filter_Op *op); + +static Efreet_Menu_Desktop *efreet_menu_desktop_new(void); +static void efreet_menu_desktop_free(Efreet_Menu_Desktop *md); + +static Efreet_Menu *efreet_menu_entry_new(void); + +static int efreet_menu_handle_menu(Efreet_Menu_Internal *internal, Efreet_Xml *xml); +static int efreet_menu_handle_name(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + +static int efreet_menu_handle_sub_menu(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_app_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_default_app_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_directory_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_default_directory_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_directory(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_not_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_not_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_include(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_exclude(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_filename(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_category(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_all(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_and(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_or(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_not(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_merge_file(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_default_merge_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_legacy_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static Efreet_Menu_Internal *efreet_menu_handle_legacy_dir_helper(Efreet_Menu_Internal *root, + Efreet_Menu_Internal *parent, + const char *legacy_dir, + const char *prefix); +static int efreet_menu_handle_kde_legacy_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_move(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_old(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_new(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml); +static int efreet_menu_handle_default_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + +static int efreet_menu_handle_filter(Efreet_Menu_Internal *parent, Efreet_Xml *xml, + Efreet_Menu_Filter_Type type); +static int efreet_menu_handle_filter_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); +static int efreet_menu_handle_filter_child_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml, + Efreet_Menu_Filter_Op_Type type); + +static int efreet_menu_handle_layout_menuname(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); +static int efreet_menu_handle_layout_filename(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); +static int efreet_menu_handle_layout_separator(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); +static int efreet_menu_handle_layout_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); + +static int efreet_menu_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path); +static int efreet_menu_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path); + +static int efreet_menu_cb_app_dirs_compare(Efreet_Menu_App_Dir *a, const char *b); + +static void efreet_menu_resolve_moves(Efreet_Menu_Internal *internal); +static void efreet_menu_concatenate(Efreet_Menu_Internal *dest, Efreet_Menu_Internal *src); + +static int efreet_menu_cb_menu_compare(Efreet_Menu_Internal *a, Efreet_Menu_Internal *b); +static int efreet_menu_cb_md_compare(const Efreet_Menu_Desktop *a, const Efreet_Menu_Desktop *b); + +static int efreet_menu_save_menu(Efreet_Menu *menu, FILE *f, int indent); +static int efreet_menu_save_indent(FILE *f, int indent); + +static void efreet_menu_path_set(Efreet_Menu_Internal *internal, const char *path); + +int +efreet_menu_init(void) +{ + int i; + + struct + { + const char *key; + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + } menu_cbs[] = { + {"Menu", efreet_menu_handle_sub_menu}, + {"AppDir", efreet_menu_handle_app_dir}, + {"DefaultAppDirs", efreet_menu_handle_default_app_dirs}, + {"DirectoryDir", efreet_menu_handle_directory_dir}, + {"DefaultDirectoryDirs", efreet_menu_handle_default_directory_dirs}, + {"Name", efreet_menu_handle_name}, + {"Directory", efreet_menu_handle_directory}, + {"OnlyUnallocated", efreet_menu_handle_only_unallocated}, + {"NotOnlyUnallocated", efreet_menu_handle_not_only_unallocated}, + {"Deleted", efreet_menu_handle_deleted}, + {"NotDeleted", efreet_menu_handle_not_deleted}, + {"Include", efreet_menu_handle_include}, + {"Exclude", efreet_menu_handle_exclude}, + {"MergeFile", efreet_menu_handle_merge_file}, + {"MergeDir", efreet_menu_handle_merge_dir}, + {"DefaultMergeDirs", efreet_menu_handle_default_merge_dirs}, + {"LegacyDir", efreet_menu_handle_legacy_dir}, + {"KDELegacyDirs", efreet_menu_handle_kde_legacy_dirs}, + {"Move", efreet_menu_handle_move}, + {"Layout", efreet_menu_handle_layout}, + {"DefaultLayout", efreet_menu_handle_default_layout}, + {NULL, NULL} + }; + + struct + { + const char *key; + int (*cb)(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); + } filter_cbs[] = { + {"Filename", efreet_menu_handle_filename}, + {"Category", efreet_menu_handle_category}, + {"All", efreet_menu_handle_all}, + {"And", efreet_menu_handle_and}, + {"Or", efreet_menu_handle_or}, + {"Not", efreet_menu_handle_not}, + {NULL, NULL} + }; + + struct + { + const char *key; + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + } move_cbs[] = { + {"Old", efreet_menu_handle_old}, + {"New", efreet_menu_handle_new}, + {NULL, NULL} + }; + + struct + { + const char *key; + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); + } layout_cbs[] = { + {"Menuname", efreet_menu_handle_layout_menuname}, + {"Filename", efreet_menu_handle_layout_filename}, + {"Separator", efreet_menu_handle_layout_separator}, + {"Merge", efreet_menu_handle_layout_merge}, + {NULL, NULL} + }; + + _efreet_menu_log_dom = eina_log_domain_register + ("efreet_menu", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_menu_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_menu"); + return 0; + } + + efreet_menu_handle_cbs = eina_hash_string_superfast_new(NULL); + efreet_menu_filter_cbs = eina_hash_string_superfast_new(NULL); + efreet_menu_move_cbs = eina_hash_string_superfast_new(NULL); + efreet_menu_layout_cbs = eina_hash_string_superfast_new(NULL); + if (!efreet_menu_handle_cbs || !efreet_menu_filter_cbs + || !efreet_menu_move_cbs || !efreet_menu_layout_cbs) + { + eina_log_domain_unregister(_efreet_menu_log_dom); + _efreet_menu_log_dom = -1; + return 0; + } + + /* set Menu into it's own so we can check the XML is valid before trying + * to handle it */ + efreet_tag_menu = eina_stringshare_add(menu_cbs[0].key); + + for (i = 0; menu_cbs[i].key; i++) + { + eina_hash_del(efreet_menu_handle_cbs, + menu_cbs[i].key, + NULL); + eina_hash_add(efreet_menu_handle_cbs, + menu_cbs[i].key, + menu_cbs[i].cb); + } + for (i = 0; filter_cbs[i].key; i++) + { + eina_hash_del(efreet_menu_filter_cbs, + filter_cbs[i].key, + NULL); + eina_hash_add(efreet_menu_filter_cbs, + filter_cbs[i].key, + filter_cbs[i].cb); + } + for (i = 0; move_cbs[i].key; i++) + { + eina_hash_del(efreet_menu_move_cbs, + move_cbs[i].key, + NULL); + eina_hash_add(efreet_menu_move_cbs, + move_cbs[i].key, + move_cbs[i].cb); + } + for (i = 0; layout_cbs[i].key; i++) + { + eina_hash_del(efreet_menu_layout_cbs, + layout_cbs[i].key, + NULL); + eina_hash_add(efreet_menu_layout_cbs, + layout_cbs[i].key, + layout_cbs[i].cb); + } + return 1; +} + +EAPI int +efreet_menu_kde_legacy_init(void) +{ + FILE *f; + char buf[PATH_MAX]; + char *p, *s; + + IF_FREE_LIST(efreet_menu_kde_legacy_dirs, eina_stringshare_del); + + f = popen("kde-config --path apps", "r"); + if (!f) return 0; + + /* XXX if the return from kde-config is a line longer than PATH_MAX, + * this won't be correct (increase buffer and get the rest...) */ + if (!fgets(buf, sizeof(buf), f)) + { + ERR("Error initializing KDE legacy information"); + return 0; + } + s = buf; + + p = strchr(s, ':'); + while (p) + { + *p = '\0'; + efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs, + (void *)eina_stringshare_add(s)); + s = p + 1; + p = strchr(s, ':'); + } + + if (*s) + efreet_menu_kde_legacy_dirs = eina_list_append(efreet_menu_kde_legacy_dirs, + (void *)eina_stringshare_add(s)); + + pclose(f); + return 1; +} + +void +efreet_menu_shutdown(void) +{ + IF_RELEASE(efreet_menu_file); + + IF_FREE_HASH(efreet_menu_handle_cbs); + IF_FREE_HASH(efreet_menu_filter_cbs); + IF_FREE_HASH(efreet_menu_move_cbs); + IF_FREE_HASH(efreet_menu_layout_cbs); + + IF_FREE_LIST(efreet_menu_kde_legacy_dirs, eina_stringshare_del); + + IF_FREE_HASH(efreet_merged_menus); + IF_FREE_HASH(efreet_merged_dirs); + + IF_RELEASE(efreet_tag_menu); + + eina_log_domain_unregister(_efreet_menu_log_dom); + _efreet_menu_log_dom = -1; +} + +EAPI Efreet_Menu * +efreet_menu_new(const char *name) +{ + Efreet_Menu *menu; + + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + + menu = efreet_menu_entry_new(); + menu->type = EFREET_MENU_ENTRY_MENU; + menu->name = eina_stringshare_add(name); + return menu; +} + +EAPI void +efreet_menu_file_set(const char *file) +{ + IF_RELEASE(efreet_menu_file); + efreet_menu_file = NULL; + if (file) efreet_menu_file = eina_stringshare_add(file); +} + +EAPI Efreet_Menu * +efreet_menu_get(void) +{ + char menu[PATH_MAX]; + const char *dir; + Eina_List *config_dirs, *l; + +#ifndef STRICT_SPEC + /* prefer user set menu */ + if (efreet_menu_file) + { + if (ecore_file_exists(efreet_menu_file)) + return efreet_menu_parse(efreet_menu_file); + } +#endif + + /* check the users config directory first */ + snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu", + efreet_config_home_get(), efreet_menu_prefix_get()); + if (ecore_file_exists(menu)) + return efreet_menu_parse(menu); + + /* fallback to the XDG_CONFIG_DIRS */ + config_dirs = efreet_config_dirs_get(); + EINA_LIST_FOREACH(config_dirs, l, dir) + { + snprintf(menu, sizeof(menu), "%s/menus/%sapplications.menu", + dir, efreet_menu_prefix_get()); + if (ecore_file_exists(menu)) + return efreet_menu_parse(menu); + } + + return NULL; +} + +EAPI Efreet_Menu * +efreet_menu_parse(const char *path) +{ + Efreet_Xml *xml; + Efreet_Menu_Internal *internal = NULL; + Efreet_Menu *entry = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); + + xml = efreet_xml_new(path); + if (!xml) return NULL; + + /* make sure we've got a <Menu> to start with */ + if (xml->tag != efreet_tag_menu) + { + WRN("Efreet_menu: Menu file didn't start with <Menu> tag."); + efreet_xml_del(xml); + return NULL; + } + + IF_FREE_HASH(efreet_merged_menus); + efreet_merged_menus = eina_hash_string_superfast_new(NULL); + + IF_FREE_HASH(efreet_merged_dirs); + efreet_merged_dirs = eina_hash_string_superfast_new(NULL); + + /* split apart the filename and the path */ + internal = efreet_menu_internal_new(); + if (!internal) return NULL; + + /* Set default values */ + internal->show_empty = 0; + internal->in_line = 0; + internal->inline_limit = 4; + internal->inline_header = 1; + internal->inline_alias = 0; + + efreet_menu_path_set(internal, path); + if (!efreet_menu_handle_menu(internal, xml)) + { + efreet_xml_del(xml); + efreet_menu_internal_free(internal); + return NULL; + } + efreet_xml_del(xml); + + efreet_menu_resolve_moves(internal); + + if (!efreet_menu_process_dirs(internal)) + { + efreet_menu_internal_free(internal); + return NULL; + } + + /* handle all .desktops */ + if (!efreet_menu_process(internal, 0)) + { + efreet_menu_internal_free(internal); + return NULL; + } + + /* handle menus with only unallocated .desktops */ + if (!efreet_menu_process(internal, 1)) + { + efreet_menu_internal_free(internal); + return NULL; + } + + /* layout menu */ + entry = efreet_menu_layout_menu(internal); + efreet_menu_internal_free(internal); + return entry; +} + +EAPI int +efreet_menu_save(Efreet_Menu *menu, const char *path) +{ + FILE *f; + int ret; + + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(path, 0); + + f = fopen(path, "w"); + if (!f) return 0; + fprintf(f, "<?xml version=\"1.0\"?>\n"); + fprintf(f, "<!DOCTYPE Menu PUBLIC \"-//freedesktop//DTD Menu 1.0//EN\" " + "\"http://standards.freedesktop.org/menu-spec/menu-1.0.dtd\">\n"); + ret = efreet_menu_save_menu(menu, f, 0); + fclose(f); + return ret; +} + +static int +efreet_menu_save_menu(Efreet_Menu *menu, FILE *f, int indent) +{ + Eina_List *l; + + efreet_menu_save_indent(f, indent); + fprintf(f, "<Menu>\n"); + if (menu->name) + { + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<Name>%s</Name>\n", menu->name); + } + + if (indent == 0) + { + /* Only save these for the root element */ + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<DefaultAppDirs/>\n"); + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<DefaultDirectoryDirs/>\n"); + } + + if (menu->desktop) + { + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<Directory>%s</Directory>\n", menu->desktop->orig_path); + } + + if (menu->entries) + { + Efreet_Menu *entry; + int has_desktop = 0, has_menu = 0; + + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<Layout>\n"); + EINA_LIST_FOREACH(menu->entries, l, entry) + { + if (entry->type == EFREET_MENU_ENTRY_MENU) + { + efreet_menu_save_indent(f, indent + 2); + fprintf(f, "<Menuname>%s</Menuname>\n", entry->id); + has_menu = 1; + } + else if (entry->type == EFREET_MENU_ENTRY_DESKTOP) + { + efreet_menu_save_indent(f, indent + 2); + fprintf(f, "<Filename>%s</Filename>\n", entry->id); + has_desktop = 1; + } + else if (entry->type == EFREET_MENU_ENTRY_SEPARATOR) + { + efreet_menu_save_indent(f, indent + 2); + fprintf(f, "<Separator/>\n"); + } + } + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "</Layout>\n"); + + if (has_desktop) + { + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "<Include>\n"); + EINA_LIST_FOREACH(menu->entries, l, entry) + { + if (entry->type == EFREET_MENU_ENTRY_DESKTOP) + { + efreet_menu_save_indent(f, indent + 2); + fprintf(f, "<Filename>%s</Filename>\n", entry->id); + } + } + efreet_menu_save_indent(f, indent + 1); + fprintf(f, "</Include>\n"); + } + + if (has_menu) + { + EINA_LIST_FOREACH(menu->entries, l, entry) + { + if (entry->type == EFREET_MENU_ENTRY_MENU) + efreet_menu_save_menu(entry, f, indent + 1); + } + } + } + efreet_menu_save_indent(f, indent); + fprintf(f, "</Menu>\n"); + return 1; +} + +static int +efreet_menu_save_indent(FILE *f, int indent) +{ + int i; + + for (i = 0; i < indent; i++) + fprintf(f, " "); + return 1; +} + +EAPI int +efreet_menu_desktop_insert(Efreet_Menu *menu, Efreet_Desktop *desktop, int pos) +{ + Efreet_Menu *entry; + const char *id; + + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + + id = efreet_util_path_to_file_id(desktop->orig_path); + if (!id) return 0; + + entry = efreet_menu_entry_new(); + entry->type = EFREET_MENU_ENTRY_DESKTOP; + entry->id = eina_stringshare_add(id); + entry->name = eina_stringshare_add(desktop->name); + if (desktop->icon) entry->icon = eina_stringshare_add(desktop->icon); + efreet_desktop_ref(desktop); + entry->desktop = desktop; + + if (pos < 0 || (unsigned int)pos >= eina_list_count(menu->entries)) + menu->entries = eina_list_append(menu->entries, entry); + else + { + menu->entries = eina_list_append_relative(menu->entries, entry, + eina_list_nth(menu->entries, pos)); + } + return 1; +} + +EAPI int +efreet_menu_desktop_remove(Efreet_Menu *menu, Efreet_Desktop *desktop) +{ + Efreet_Menu *entry; + + EINA_SAFETY_ON_NULL_RETURN_VAL(menu, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(desktop, 0); + + entry = eina_list_search_unsorted(menu->entries, + EINA_COMPARE_CB(efreet_menu_cb_entry_compare_desktop), + desktop); + if (entry) + { + menu->entries = eina_list_remove(menu->entries, entry); + efreet_menu_free(entry); + return 1; + } + return 0; +} + +EAPI void +efreet_menu_dump(Efreet_Menu *menu, const char *indent) +{ + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN(menu); + EINA_SAFETY_ON_NULL_RETURN(indent); + + INF("%s%s: ", indent, menu->name); + INF("%s", (menu->icon ? menu->icon : "No icon")); + + /* XXX dump the rest of the menu info */ + + if (menu->entries) + { + Efreet_Menu *entry; + char *new_indent; + size_t len; + + len = strlen(indent) + 3; + new_indent = alloca(len); + snprintf(new_indent, len, "%s ", indent); + + EINA_LIST_FOREACH(menu->entries, l, entry) + { + if (entry->type == EFREET_MENU_ENTRY_SEPARATOR) + INF("%s|---", new_indent); + else if (entry->type == EFREET_MENU_ENTRY_DESKTOP) + INF("%s|-%s", new_indent, entry->name); + else if (entry->type == EFREET_MENU_ENTRY_MENU) + efreet_menu_dump(entry, new_indent); + else if (entry->type == EFREET_MENU_ENTRY_HEADER) + INF("%s|---%s", new_indent, entry->name); + } + } +} + +/** + * @internal + * @param user_dir The user directory to work with + * @param system_dirs The system directories to work with + * @param suffix The path suffix to add + * @return Returns the list of directories + * @brief Creates the list of directories based on the user + * dir, system dirs and given suffix. + * + * Needs EAPI because of helper binaries + */ +EAPI Eina_List * +efreet_default_dirs_get(const char *user_dir, Eina_List *system_dirs, + const char *suffix) +{ + const char *xdg_dir; + char dir[PATH_MAX]; + Eina_List *list = NULL; + Eina_List *l; + + EINA_SAFETY_ON_NULL_RETURN_VAL(user_dir, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(suffix, NULL); + + snprintf(dir, sizeof(dir), "%s/%s", user_dir, suffix); + list = eina_list_append(list, eina_stringshare_add(dir)); + + EINA_LIST_FOREACH(system_dirs, l, xdg_dir) + { + snprintf(dir, sizeof(dir), "%s/%s", xdg_dir, suffix); + list = eina_list_append(list, eina_stringshare_add(dir)); + } + + return list; +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Internal struct + * @brief Allocates and initializes a new Efreet_Menu_Internal structure + */ +static Efreet_Menu_Internal * +efreet_menu_internal_new(void) +{ + Efreet_Menu_Internal *internal; + + internal = NEW(Efreet_Menu_Internal, 1); + if (!internal) return NULL; + internal->show_empty = -1; + internal->in_line = -1; + internal->inline_limit = -1; + internal->inline_header = -1; + internal->inline_alias = -1; + + return internal; +} + +/** + * @param menu The menu to free + * @return Returns no value + * @brief Frees up the given menu structure + */ +void +efreet_menu_internal_free(Efreet_Menu_Internal *internal) +{ + if (!internal) return; + + IF_RELEASE(internal->file.path); + IF_RELEASE(internal->file.name); + + IF_RELEASE(internal->name.internal); + internal->name.name = NULL; + + internal->applications = eina_list_free(internal->applications); + + IF_FREE_LIST(internal->directories, eina_stringshare_del); + IF_FREE_LIST(internal->app_dirs, efreet_menu_app_dir_free); + IF_FREE_LIST(internal->app_pool, efreet_menu_desktop_free); + IF_FREE_LIST(internal->directory_dirs, eina_stringshare_del); + IF_FREE_HASH(internal->directory_cache); + + IF_FREE_LIST(internal->moves, efreet_menu_move_free); + IF_FREE_LIST(internal->filters, efreet_menu_filter_free); + + IF_FREE_LIST(internal->sub_menus, efreet_menu_internal_free); + + IF_FREE_LIST(internal->layout, efreet_menu_layout_free); + IF_FREE_LIST(internal->default_layout, efreet_menu_layout_free); + + FREE(internal); +} + +/** + * @internal + * @return Returns the XDG_MENU_PREFIX env variable or "" if none set + * @brief Retrieves the XDG_MENU_PREFIX or "" if not set. + */ +static const char * +efreet_menu_prefix_get(void) +{ + if (efreet_menu_prefix) return efreet_menu_prefix; + + efreet_menu_prefix = getenv("XDG_MENU_PREFIX"); + if (!efreet_menu_prefix) efreet_menu_prefix = ""; + + return efreet_menu_prefix; +} + +/** + * @internal + * @param menu The menu to populate + * @param xml The xml dom tree to populate from + * @return Returns 1 if this XML tree is valid, 0 otherwise + * @brief Populates the given menu from the given xml structure + * + * We walk the Menu children backwards. The reason for this is so that we + * can deal with all the things that make us select the 'last' element + * (MergeFile, Directory, etc). We'll see the last one first and can deal + * with it right away. + */ +static int +efreet_menu_handle_menu(Efreet_Menu_Internal *internal, Efreet_Xml *xml) +{ + Efreet_Xml *child; + Eina_List *l; + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + + EINA_LIST_REVERSE_FOREACH(xml->children, l, child) + { + cb = eina_hash_find(efreet_menu_handle_cbs, child->tag); + if (cb) + { + if (!cb(internal, child)) + return 0; + } + else + { + WRN("Unknown XML tag: %s", child->tag); + return 0; + } + } + return 1; +} + +/** + * @internal + * @param parent The parent Menu + * @param xml The xml that defines the menu + * @return Returns 1 on success or 0 on failure + * @brief Handles the sub-menu nodes of the XML file + */ +static int +efreet_menu_handle_sub_menu(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Efreet_Menu_Internal *internal, *match; + + efreet_menu_create_sub_menu_list(parent); + + internal = efreet_menu_internal_new(); + if (!internal) return 0; + internal->file.path = eina_stringshare_add(parent->file.path); + if (!efreet_menu_handle_menu(internal, xml)) + { + efreet_menu_internal_free(internal); + return 0; + } + + /* if this menu already exists we just take this one and stick it on the + * start of the existing one */ + if ((match = eina_list_search_unsorted(parent->sub_menus, + EINA_COMPARE_CB(efreet_menu_cb_menu_compare), + internal))) + { + + efreet_menu_concatenate(match, internal); + efreet_menu_internal_free(internal); + } + else + parent->sub_menus = eina_list_prepend(parent->sub_menus, internal); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the AppDir tag + */ +static int +efreet_menu_handle_app_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + const char *path; + Efreet_Menu_App_Dir *app_dir; + + if (!parent || !xml) return 0; + + efreet_menu_create_app_dirs_list(parent); + path = efreet_menu_path_get(parent, xml->text); + if (!path) return 0; + + /* we've already got this guy in our list we can skip it */ + if (eina_list_search_unsorted(parent->app_dirs, + EINA_COMPARE_CB(efreet_menu_cb_app_dirs_compare), + path)) + { + eina_stringshare_del(path); + return 1; + } + + app_dir = efreet_menu_app_dir_new(); + app_dir->path = path; + + parent->app_dirs = eina_list_prepend(parent->app_dirs, app_dir); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml UNUSED + * @return Returns 1 on success or 0 on failure + * @brief Handles the DefaultAppDirs + */ +static int +efreet_menu_handle_default_app_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml __UNUSED__) +{ + Eina_List *prepend = NULL; + Eina_List *dirs; + char *dir; + + if (!parent) return 0; + + efreet_menu_create_app_dirs_list(parent); + dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(), + "applications"); + EINA_LIST_FREE(dirs, dir) + { + if (!eina_list_search_unsorted(parent->app_dirs, + EINA_COMPARE_CB(efreet_menu_cb_app_dirs_compare), + dir)) + { + Efreet_Menu_App_Dir *app_dir; + + app_dir = efreet_menu_app_dir_new(); + app_dir->path = eina_stringshare_ref(dir); + + prepend = eina_list_append(prepend, app_dir); + } + + eina_stringshare_del(dir); + } + parent->app_dirs = eina_list_merge(prepend, parent->app_dirs); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the DirectoryDir tag + */ +static int +efreet_menu_handle_directory_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + const char *path; + + if (!parent || !xml) return 0; + + efreet_menu_create_directory_dirs_list(parent); + path = efreet_menu_path_get(parent, xml->text); + if (!path) return 0; + + /* we've already got this guy in our list we can skip it */ + if (eina_list_search_unsorted(parent->directory_dirs, EINA_COMPARE_CB(strcmp), path)) + { + eina_stringshare_del(path); + return 1; + } + + parent->directory_dirs = eina_list_prepend(parent->directory_dirs, path); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml UNUSED + * @return Returns 1 on success or 0 on failure + * @brief Handles the DefaultDirectoryDirs tag + */ +static int +efreet_menu_handle_default_directory_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml __UNUSED__) +{ + Eina_List *dirs; + char *dir; + + if (!parent) return 0; + + efreet_menu_create_directory_dirs_list(parent); + dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(), + "desktop-directories"); + EINA_LIST_FREE(dirs, dir) + { + if (!eina_list_search_unsorted(parent->directory_dirs, EINA_COMPARE_CB(strcmp), dir)) + parent->directory_dirs = eina_list_prepend(parent->directory_dirs, eina_stringshare_ref(dir)); + eina_stringshare_del(dir); + } + + return 1; +} + +/** + * @internal + * @param parent The parent Menu + * @param xml The xml to work with + * @return Returns 1 on success or 0 on failure + * @brief Sets the menu name from the given XML fragment. + */ +static int +efreet_menu_handle_name(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + /* not allowed to have two Name settings in a menu */ + if (parent->name.internal) + { + INF("efreet_menu_handle_name() setting second name into menu"); + return 0; + } + /* ignore the name if it is empty */ + if (!xml->text) return 1; + + /* ignore the name if it contains a / */ + if (strchr(xml->text, '/')) return 1; + + parent->name.internal = eina_stringshare_add(xml->text); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Directory tag + * + * This just adds the given directory path to a list which we'll walk once + * we've traversed the entire menu into memory. + */ +static int +efreet_menu_handle_directory(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml) return 0; + + efreet_menu_create_directories_list(parent); + parent->directories = eina_list_prepend(parent->directories, eina_stringshare_add(xml->text)); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the OnlyUnallocated tag + */ +static int +efreet_menu_handle_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml) return 0; + + /* a later instance has been seen so we can ignore this one */ + if (parent->seen_allocated) return 1; + + parent->seen_allocated = 1; + parent->only_unallocated = 1; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the NotOnlyUnallocated tag + */ +static int +efreet_menu_handle_not_only_unallocated(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml) return 0; + + /* a later instance has been seen so we can ignore this one */ + if (parent->seen_allocated) return 1; + + parent->seen_allocated = 1; + parent->only_unallocated = 0; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Deleted tag + */ +static int +efreet_menu_handle_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml) return 0; + + /* a later instance has been seen so we can ignore this one */ + if (parent->seen_deleted) return 1; + + parent->seen_deleted = 1; + parent->deleted = 1; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the NotDeleted tag + */ +static int +efreet_menu_handle_not_deleted(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml) return 0; + + /* a later instance has been seen so we can ignore this one */ + if (parent->seen_deleted) return 1; + + parent->seen_deleted = 1; + parent->deleted = 0; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The XML tree to work with + * @return Returns 1 on success or 0 on failure + * @brief Handles parsing the Include tag and all subtags + */ +static int +efreet_menu_handle_include(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + return efreet_menu_handle_filter(parent, xml, + EFREET_MENU_FILTER_INCLUDE); +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Exclude tag and all subtags + */ +static int +efreet_menu_handle_exclude(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + return efreet_menu_handle_filter(parent, xml, + EFREET_MENU_FILTER_EXCLUDE); +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Filename tag + */ +static int +efreet_menu_handle_filename(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + op->filenames = eina_list_append(op->filenames, eina_stringshare_add(xml->text)); + + return 1; +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Category tag + */ +static int +efreet_menu_handle_category(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + + op->categories = eina_list_append(op->categories, eina_stringshare_add(xml->text)); + + return 1; +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the All tag and all subtags + */ +static int +efreet_menu_handle_all(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + op->all = 1; + + return 1; +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the And tag and all subtags + */ +static int +efreet_menu_handle_and(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + return efreet_menu_handle_filter_child_op(op, xml, + EFREET_MENU_FILTER_OP_AND); +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Or tag and all subtags + */ +static int +efreet_menu_handle_or(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + return efreet_menu_handle_filter_child_op(op, xml, + EFREET_MENU_FILTER_OP_OR); +} + +/** + * @internal + * @param op The filter operation + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Not tag and all subtags + */ +static int +efreet_menu_handle_not(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + if (!op || !xml) return 0; + + return efreet_menu_handle_filter_child_op(op, xml, + EFREET_MENU_FILTER_OP_NOT); +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the MergeFile tag + */ +static int +efreet_menu_handle_merge_file(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Eina_List *l; + const char *path = NULL; + const char *attr = NULL; + int is_path = 1; + int ret = 1; + + if (!parent || !xml) return 0; + + /* check to see if this is a path or parent type */ + attr = efreet_xml_attribute_get(xml, "type"); + if (attr && !strcmp(attr, "parent")) + is_path = 0; + + /* we're given a path */ + if (is_path) + path = efreet_menu_path_get(parent, xml->text); + + /* need to find the next menu with the same name as ours in the config + * dir after ours (if we're in a config dir) */ + else + { + Eina_List *search_dirs; + const char *dir, *p; + + if (!parent->file.path) + { + INF("efreet_menu_handle_merge_file() missing menu path ..."); + return 0; + } + + search_dirs = efreet_config_dirs_get(); + + /* we need to find the next menu with the same name in the directory + * after the on the the menu was found in. to do that we first check + * if it's in the config_home_directory() if so we need to search + * all of the dirs. If it isn't in the config home directory then we + * scan the search dirs and look for it. The search_dirs list will + * be left at the next pointer so we can start looking for the menu + * from that point */ + + dir = efreet_config_home_get(); + if (strncmp(dir, parent->file.path, eina_stringshare_strlen(dir))) + { + EINA_LIST_FOREACH(search_dirs, l, dir) + { + if (!strncmp(dir, parent->file.path, eina_stringshare_strlen(dir))) + break; + } + } + + if (!dir) + { + INF("efreet_menu_handle_merge_file() failed to find " + "menu parent directory"); + return 0; + } + + /* the parent file path may have more path then just the base + * directory so we need to append that as well */ + p = parent->file.path + eina_stringshare_strlen(dir); + + /* whatever dirs are left in the search dir we need to look for the + * menu with the same relative filename */ + EINA_LIST_FOREACH(search_dirs, l, dir) + { + char file[PATH_MAX]; + + snprintf(file, sizeof(file), "%s/%s/%s", dir, (p ? p : ""), + parent->file.name); + if (ecore_file_exists(file)) + { + path = eina_stringshare_add(file); + break; + } + } + } + + /* nothing to do if no file found */ + if (!path) return 1; + + if (!efreet_menu_merge(parent, xml, path)) + ret = 0; + + eina_stringshare_del(path); + + return ret; +} + +/** + * @internal + * @param parent The parent menu to merge into + * @param xml The XML to be merged + * @param path The path to the .menu file to merge + */ +static int +efreet_menu_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path) +{ + Efreet_Xml *merge_xml; + Efreet_Menu_Internal *internal; + char rp[PATH_MAX]; + + if (!parent || !xml || !path) return 0; + + /* do nothing if the file doesn't exist */ + if (!ecore_file_exists(path)) return 1; + + if (!realpath(path, rp)) + { + INF("efreet_menu_merge() unable to get real path for %s", path); + return 0; + } + + /* don't merge the same path twice */ + if (eina_hash_find(efreet_merged_menus, rp)) + { + return 1; + } + + eina_hash_add(efreet_merged_menus, rp, (void *)1); + + merge_xml = efreet_xml_new(rp); + + if (!merge_xml) + { + INF("efreet_menu_merge() failed to read in the " + "merge file (%s)", rp); + return 0; + } + + internal = efreet_menu_internal_new(); + if (!internal) return 0; + efreet_menu_path_set(internal, path); + efreet_menu_handle_menu(internal, merge_xml); + efreet_menu_concatenate(parent, internal); + efreet_menu_internal_free(internal); + + efreet_xml_del(merge_xml); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the MergeDir tag + */ +static int +efreet_menu_handle_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + const char *path; + int ret; + + if (!parent || !xml || !xml->text) return 0; + + path = efreet_menu_path_get(parent, xml->text); + if (!path) return 1; + if (!ecore_file_exists(path)) + { + eina_stringshare_del(path); + return 1; + } + + ret = efreet_menu_merge_dir(parent, xml, path); + eina_stringshare_del(path); + + return ret; +} + +/** + * @internal + * @param parent the parent menu of the merge + * @param xml The xml tree + * @param path The path to the merge directory + * @return Returns 1 on success or 0 on failure + * @brief Find all of the .menu files in the given directory and merge them + * into the @a parent menu. + */ +static int +efreet_menu_merge_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml, const char *path) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *info; + + if (!parent || !xml || !path) return 0; + + /* check to see if we've merged this directory already */ + if (eina_hash_find(efreet_merged_dirs, path)) return 1; + eina_hash_add(efreet_merged_dirs, path, (void *)1); + + it = eina_file_direct_ls(path); + if (!it) return 1; + + EINA_ITERATOR_FOREACH(it, info) + { + char *p; + + p = strrchr(info->path + info->name_start, '.'); + if (!p) continue; + if (strcmp(p, ".menu")) continue; + + if (!efreet_menu_merge(parent, xml, info->path)) + { + eina_iterator_free(it); + return 0; + } + } + eina_iterator_free(it); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the DefaultMergeDirs tag + */ +static int +efreet_menu_handle_default_merge_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Eina_List *dirs; + char path[PATH_MAX], *p, *pp; +#ifndef STRICT_SPEC + char parent_path[PATH_MAX]; +#endif + const char *prefix; + + if (!parent || !xml) return 0; + + prefix = efreet_menu_prefix_get(); + if (!strcmp(prefix, "gnome-") && + (!strcmp(parent->file.name, "gnome-applications.menu"))) + { + p = alloca(sizeof("applications")); + memcpy(p, "applications", sizeof("applications")); + } + else if ((!strcmp(prefix, "kde-") && + (!strcmp(parent->file.name, "kde-applications.menu")))) + { + p = alloca(sizeof("applications")); + memcpy(p, "applications", sizeof("applications")); + } + else + { + char *s; + size_t len; + + len = strlen(parent->file.name) + 1; + p = alloca(len); + memcpy(p, parent->file.name, len); + s = strrchr(p, '.'); + if (s) *s = '\0'; + } + snprintf(path, sizeof(path), "menus/%s-merged", p); + + dirs = efreet_default_dirs_get(efreet_config_home_get(), + efreet_config_dirs_get(), path); + + EINA_LIST_FREE(dirs, pp) + { + efreet_menu_merge_dir(parent, xml, pp); + eina_stringshare_del(pp); + } +#ifndef STRICT_SPEC + /* Also check the path of the parent file */ + snprintf(parent_path, sizeof(parent_path), "%s/%s", parent->file.path, path); + efreet_menu_merge_dir(parent, xml, parent_path); +#endif + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the LegacyDir tag + */ +static int +efreet_menu_handle_legacy_dir(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Efreet_Menu_Internal *legacy; + + if (!parent || !xml) return 0; + + legacy = efreet_menu_handle_legacy_dir_helper(NULL, parent, xml->text, + efreet_xml_attribute_get(xml, "prefix")); + if (legacy) + { + efreet_menu_concatenate(parent, legacy); + efreet_menu_internal_free(legacy); + } + + return 1; + +} + +/** + * @internal + * @param parent The parent menu + * @param legacy_dir The legacy directory path + * @param prefix The legacy directory prefix if one set + * @return Returns the Efreet_Menu_Internal representing the legacy hierarchy + * @brief Handles the process of merging @a legacy_dir into @a parent menu + */ +static Efreet_Menu_Internal * +efreet_menu_handle_legacy_dir_helper(Efreet_Menu_Internal *root, + Efreet_Menu_Internal *parent, + const char *legacy_dir, + const char *prefix) +{ + const char *path; + Efreet_Menu_Internal *legacy_internal; + Efreet_Menu_Filter *filter; + Efreet_Menu_App_Dir *app_dir; + int count = 0; + Eina_Iterator *it; + + if (!parent || !legacy_dir) return 0; + + path = efreet_menu_path_get(parent, legacy_dir); + + /* nothing to do if the legacy path doesn't exist */ + if (!path || !ecore_file_exists(path)) + { + eina_stringshare_del(path); + return NULL; + } + + legacy_internal = efreet_menu_internal_new(); + if (!legacy_internal) + return NULL; + legacy_internal->name.internal = eina_stringshare_add(ecore_file_file_get(path)); + + /* add the legacy dir as an app dir */ + app_dir = efreet_menu_app_dir_new(); + app_dir->path = eina_stringshare_add(path); + app_dir->legacy = 1; + if (prefix && !strchr(prefix, '/')) app_dir->prefix = eina_stringshare_add(prefix); + + efreet_menu_create_app_dirs_list(legacy_internal); + legacy_internal->app_dirs = eina_list_append(legacy_internal->app_dirs, app_dir); +#ifndef STRICT_SPEC + if (root) + { + /* XXX This seems wrong, but it makes efreet pass the fdo tests */ + app_dir = efreet_menu_app_dir_new(); + app_dir->path = eina_stringshare_add(path); + app_dir->legacy = 1; + if (prefix && !strchr(prefix, '/')) app_dir->prefix = eina_stringshare_add(prefix); + root->app_dirs = eina_list_append(root->app_dirs, app_dir); + } +#endif + + /* add the legacy dir as a directory dir */ + efreet_menu_create_directory_dirs_list(legacy_internal); + legacy_internal->directory_dirs = eina_list_append(legacy_internal->directory_dirs, eina_stringshare_add(path)); + + /* setup a filter for all the conforming .desktop files in the legacy + * dir */ + filter = efreet_menu_filter_new(); + if (!filter) + { + efreet_menu_internal_free(legacy_internal); + return NULL; + } + filter->type = EFREET_MENU_FILTER_INCLUDE; + + filter->op->type = EFREET_MENU_FILTER_OP_OR; + + efreet_menu_create_filter_list(legacy_internal); + legacy_internal->filters = eina_list_append(legacy_internal->filters, filter); + + it = eina_file_direct_ls(path); + if (it) + { + Eina_File_Direct_Info *info; + + EINA_ITERATOR_FOREACH(it, info) + { + Efreet_Desktop *desktop = NULL; + char buf[PATH_MAX]; + char *exten; + const char *fname; + + fname = info->path + info->name_start; + /* recurse into sub directories */ + if (ecore_file_is_dir(info->path)) + { + Efreet_Menu_Internal *ret; + + ret = efreet_menu_handle_legacy_dir_helper(root ? root : legacy_internal, + legacy_internal, info->path, prefix); + if (!ret) + { + efreet_menu_internal_free(legacy_internal); + eina_stringshare_del(path); + eina_iterator_free(it); + return NULL; + } + + efreet_menu_create_sub_menu_list(legacy_internal); + legacy_internal->sub_menus = eina_list_prepend(legacy_internal->sub_menus, ret); + + continue; + } + + if (!strcmp(fname, ".directory")) + { + legacy_internal->directory = efreet_desktop_get(info->path); + if (legacy_internal->directory + && legacy_internal->directory->type != EFREET_DESKTOP_TYPE_DIRECTORY) + { + efreet_desktop_free(legacy_internal->directory); + legacy_internal->directory = NULL; + } + continue; + } + + exten = strrchr(fname, '.'); + + if (exten && !strcmp(exten, ".desktop")) + desktop = efreet_desktop_get(info->path); + + if (!desktop) continue; + + /* if the .desktop has categories it isn't legacy */ + if (efreet_desktop_category_count_get(desktop) != 0) + { + efreet_desktop_free(desktop); + continue; + } + + /* XXX: This will disappear when the .desktop is free'd */ + efreet_desktop_category_add(desktop, "Legacy"); + + if (prefix) + { + snprintf(buf, sizeof(buf), "%s%s", prefix, fname); + filter->op->filenames = eina_list_append(filter->op->filenames, eina_stringshare_add(buf)); + } + else + filter->op->filenames = eina_list_append(filter->op->filenames, eina_stringshare_add(fname)); + + count++; + efreet_desktop_free(desktop); + } + eina_iterator_free(it); + } + + eina_stringshare_del(path); + return legacy_internal; +} + +/** + * @internal + * @param parent The parent menu + * @param xml UNUSED + * @return Returns 1 on success or 0 on failure + * @brief Handles the KDELegacyDirs tag + */ +static int +efreet_menu_handle_kde_legacy_dirs(Efreet_Menu_Internal *parent, Efreet_Xml *xml __UNUSED__) +{ + Eina_List *l; + const char *dir; + + if (!parent) return 0; + + if (!efreet_menu_kde_legacy_dirs) return 1; + + /* XXX if one _helper() call succeeds, we return success. should this be flipped? + * (return fail if on of them failed) */ + EINA_LIST_FOREACH(efreet_menu_kde_legacy_dirs, l, dir) + { + Efreet_Menu_Internal *kde; + + kde = efreet_menu_handle_legacy_dir_helper(NULL, parent, dir, "kde"); + if (kde) + { + efreet_menu_concatenate(parent, kde); + efreet_menu_internal_free(kde); + return 1; + } + } + + return 0; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Move tag and all subtags + */ +static int +efreet_menu_handle_move(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Efreet_Xml *child; + Eina_List *l; + + if (!parent || !xml) return 0; + + efreet_menu_create_move_list(parent); + + EINA_LIST_FOREACH(xml->children, l, child) + { + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml); + + cb = eina_hash_find(efreet_menu_move_cbs, child->tag); + if (cb) + { + if (!cb(parent, child)) + return 0; + } + else + { + INF("efreet_menu_handle_move() unknown tag found " + "in Move (%s)", child->tag); + return 0; + } + } + + parent->current_move = NULL; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Old tag + */ +static int +efreet_menu_handle_old(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Efreet_Menu_Move *move; + + if (!parent || !xml || !xml->text) return 0; + + if (parent->current_move) + { + INF("efreet_menu_handle_old() saw second <Old> " + "before seeing <New>"); + return 0; + } + + /* If we already moved this menu, remove the old move */ + /* XXX This seems wrong, but it makes efreet pass the fdo tests */ +#ifndef STRICT_SPEC + move = eina_list_search_unsorted(parent->moves, + EINA_COMPARE_CB(efreet_menu_cb_move_compare), + xml->text); + if (move) + { + efreet_menu_move_free(move); + parent->moves = eina_list_remove(parent->moves, move); + } +#endif + + move = efreet_menu_move_new(); + move->old_name = eina_stringshare_add(xml->text); + + parent->current_move = move; + parent->moves = eina_list_append(parent->moves, move); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the New tag + */ +static int +efreet_menu_handle_new(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + if (!parent || !xml || !xml->text) return 0; + + if (!parent->current_move) + { + INF("efreet_menu_handle_new() saw New before seeing Old"); + return 0; + } + + parent->current_move->new_name = eina_stringshare_add(xml->text); + parent->current_move = NULL; + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the Layout tag and all subtags + */ +static int +efreet_menu_handle_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + Efreet_Xml *child; + Eina_List *l; + + if (!parent || !xml) return 0; + + /* We use the last existing layout */ + if (parent->layout) return 1; + + efreet_menu_create_layout_list(parent); + + EINA_LIST_FOREACH(xml->children, l, child) + { + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); + + cb = eina_hash_find(efreet_menu_layout_cbs, child->tag); + if (cb) + { + if (!cb(parent, child, 0)) + return 0; + } + else + { + INF("efreet_menu_handle_move() unknown tag found " + "in Layout (%s)", child->tag); + return 0; + } + } + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The xml tree + * @return Returns 1 on success or 0 on failure + * @brief Handles the DefaultLayout tag + */ +static int +efreet_menu_handle_default_layout(Efreet_Menu_Internal *parent, Efreet_Xml *xml) +{ + const char *val; + Efreet_Xml *child; + Eina_List *l; + + if (!parent || !xml) return 0; + + /* We use the last existing layout */ + if (parent->default_layout) return 1; + + val = efreet_xml_attribute_get(xml, "show_empty"); + if (val) parent->show_empty = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline"); + if (val) parent->in_line = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline_limit"); + if (val) parent->inline_limit = atoi(val); + + val = efreet_xml_attribute_get(xml, "inline_header"); + if (val) parent->inline_header = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline_alias"); + if (val) parent->inline_alias = !strcmp(val, "true"); + + efreet_menu_create_default_layout_list(parent); + + EINA_LIST_FOREACH(xml->children, l, child) + { + int (*cb)(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def); + + cb = eina_hash_find(efreet_menu_layout_cbs, child->tag); + if (cb) + { + if (!cb(parent, child, 1)) + return 0; + } + else + { + INF("efreet_menu_handle_move() unknown tag found in " + "DefaultLayout (%s)", child->tag); + return 0; + } + } + + return 1; +} + +static int +efreet_menu_handle_layout_menuname(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def) +{ + Efreet_Menu_Layout *layout; + const char *val; + + if (!parent || !xml) return 0; + + if (!xml->text) + { + INF("efreet_menu_handle_layout_menuname() The Menuname tag in " + "layout needs a filename."); + return 0; + } + + layout = efreet_menu_layout_new(); + layout->type = EFREET_MENU_LAYOUT_MENUNAME; + layout->name = eina_stringshare_add(xml->text); + + val = efreet_xml_attribute_get(xml, "show_empty"); + if (val) layout->show_empty = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline"); + if (val) layout->in_line = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline_limit"); + if (val) layout->inline_limit = atoi(val); + + val = efreet_xml_attribute_get(xml, "inline_header"); + if (val) layout->inline_header = !strcmp(val, "true"); + + val = efreet_xml_attribute_get(xml, "inline_alias"); + if (val) layout->inline_alias = !strcmp(val, "true"); + + if (def) parent->default_layout = eina_list_append(parent->default_layout, layout); + else parent->layout = eina_list_append(parent->layout, layout); + + return 1; +} + +static int +efreet_menu_handle_layout_filename(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def) +{ + Efreet_Menu_Layout *layout; + + if (!parent || !xml) return 0; + + if (!xml->text) + { + INF("efreet_menu_handle_layout_filename() The Filename tag in " + "layout needs a filename."); + return 0; + } + + layout = efreet_menu_layout_new(); + layout->type = EFREET_MENU_LAYOUT_FILENAME; + layout->name = eina_stringshare_add(xml->text); + + if (def) parent->default_layout = eina_list_append(parent->default_layout, layout); + else parent->layout = eina_list_append(parent->layout, layout); + + return 1; +} + +static int +efreet_menu_handle_layout_separator(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def) +{ + Efreet_Menu_Layout *layout; + + if (!parent || !xml) return 0; + + layout = efreet_menu_layout_new(); + layout->type = EFREET_MENU_LAYOUT_SEPARATOR; + if (def) + parent->default_layout = eina_list_append(parent->default_layout, layout); + else + parent->layout = eina_list_append(parent->layout, layout); + return 1; +} + +static int +efreet_menu_handle_layout_merge(Efreet_Menu_Internal *parent, Efreet_Xml *xml, int def) +{ + Efreet_Menu_Layout *layout; + const char *attr; + + if (!parent || !xml) return 0; + + attr = efreet_xml_attribute_get(xml, "type"); + if (!attr) + { + INF("efreet_menu_handle_layout_merge() The Merge tag in layout " + "needs a type attribute."); + return 0; + } + + if (strcmp(attr, "files") && strcmp(attr, "menus") && strcmp(attr, "all")) + { + INF("efreet_menu_handle_layout_merge() The type attribute for " + "the Merge tag contains an unknown value (%s).", attr); + return 0; + } + + layout = efreet_menu_layout_new(); + layout->type = EFREET_MENU_LAYOUT_MERGE; + layout->name = eina_stringshare_add(attr); + + if (def) parent->default_layout = eina_list_append(parent->default_layout, layout); + else parent->layout = eina_list_append(parent->layout, layout); + + return 1; +} + +/** + * @internal + * @param parent The parent menu + * @param xml The XML tree to parse + * @param type The type of filter + * @return Returns 1 on success or 0 on failure + * @brief Parses the given XML tree and adds the filter to the parent menu + */ +static int +efreet_menu_handle_filter(Efreet_Menu_Internal *parent, Efreet_Xml *xml, + Efreet_Menu_Filter_Type type) +{ + Efreet_Menu_Filter *filter; + + efreet_menu_create_filter_list(parent); + + /* filters have a default or relationship */ + filter = efreet_menu_filter_new(); + if (!filter) return 0; + filter->type = type; + filter->op->type = EFREET_MENU_FILTER_OP_OR; + + if (!efreet_menu_handle_filter_op(filter->op, xml)) + { + efreet_menu_filter_free(filter); + return 0; + } + + parent->filters = eina_list_prepend(parent->filters, filter); + + return 1; +} + +/** + * @internal + * @param op The operation to work with + * @param xml The XML tree representing this operation + * @return Returns 1 on success or 0 on failure + * @brief Parses the given XML tree and populates the operation + */ +static int +efreet_menu_handle_filter_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml) +{ + Efreet_Xml *child; + Eina_List *l; + + EINA_LIST_FOREACH(xml->children, l, child) + { + int (*cb)(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml); + + cb = eina_hash_find(efreet_menu_filter_cbs, child->tag); + if (cb) + { + if (!cb(op, child)) + return 0; + } + else + { + INF("efreet_menu_handle_filter_op() unknown tag in filter (%s)", child->tag); + return 0; + } + } + return 1; +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Filter on success or NULL on failure + * @brief Creates and initializes an Efreet_Menu_Filter object + */ +static Efreet_Menu_Filter * +efreet_menu_filter_new(void) +{ + Efreet_Menu_Filter *filter; + + filter = NEW(Efreet_Menu_Filter, 1); + if (!filter) return NULL; + filter->op = efreet_menu_filter_op_new(); + if (!filter->op) + { + FREE(filter); + return NULL; + } + + return filter; +} + +/** + * @internal + * @param filter The filter to work with + * @return Returns no data + * @brief Frees the given filter and all data + */ +static void +efreet_menu_filter_free(Efreet_Menu_Filter *filter) +{ + if (!filter) return; + + if (filter->op) efreet_menu_filter_op_free(filter->op); + filter->op = NULL; + + FREE(filter); +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Layout on success or NULL on failure + * @brief Creates and initializes an Efreet_Menu_Layout object + */ +static Efreet_Menu_Layout * +efreet_menu_layout_new(void) +{ + Efreet_Menu_Layout *layout; + + layout = NEW(Efreet_Menu_Layout, 1); + layout->show_empty = -1; + layout->in_line = -1; + layout->inline_limit = -1; + layout->inline_header = -1; + layout->inline_alias = -1; + + return layout; +} + +/** + * @internal + * @param filter The filter to work with + * @return Returns no data + * @brief Frees the given filter and all data + */ +static void +efreet_menu_layout_free(Efreet_Menu_Layout *layout) +{ + if (!layout) return; + + IF_RELEASE(layout->name); + FREE(layout); +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Filter_Op on success or NULL on failure + * @brief Creates and initializes an Efreet_Menu_Filter_Op structure + */ +static Efreet_Menu_Filter_Op * +efreet_menu_filter_op_new(void) +{ + Efreet_Menu_Filter_Op *op; + + op = NEW(Efreet_Menu_Filter_Op, 1); + + return op; +} + +/** + * @internal + * @param op The operation to work with + * @return Returns no value. + * @brief Frees the given operation and all sub data + */ +static void +efreet_menu_filter_op_free(Efreet_Menu_Filter_Op *op) +{ + if (!op) return; + + IF_FREE_LIST(op->categories, eina_stringshare_del); + IF_FREE_LIST(op->filenames, eina_stringshare_del); + IF_FREE_LIST(op->filters, efreet_menu_filter_op_free); + + FREE(op); +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Desktop on success or NULL on failure + * @brief Creates and returns an Efreet_Menu_Desktop + */ +static Efreet_Menu_Desktop * +efreet_menu_desktop_new(void) +{ + Efreet_Menu_Desktop *md; + + md = NEW(Efreet_Menu_Desktop, 1); + + return md; +} + +/** + * @internal + * @param md The Efreet_Menu_Desktop to free + * @return Returns no value + * @brief Frees the given structure + */ +static void +efreet_menu_desktop_free(Efreet_Menu_Desktop *md) +{ + IF_RELEASE(md->id); + if (md->desktop) efreet_desktop_free(md->desktop); + FREE(md); +} + +/** + * @internal + * @return Returns a new Efreet_Menu on success or NULL on failure + * @brief Creates and returns an Efreet_Menu + */ +static Efreet_Menu * +efreet_menu_entry_new(void) +{ + Efreet_Menu *entry; + + entry = NEW(Efreet_Menu, 1); + + return entry; +} + +EAPI void +efreet_menu_free(Efreet_Menu *entry) +{ + Efreet_Menu *sub; + + if (!entry) return; + + IF_RELEASE(entry->name); + IF_RELEASE(entry->icon); + EINA_LIST_FREE(entry->entries, sub) + efreet_menu_free(sub); + IF_RELEASE(entry->id); + if (entry->desktop) efreet_desktop_free(entry->desktop); + FREE(entry); +} + +/** + * @internal + * @param op The op to add a child too + * @param xml The XML tree of the child + * @param type The type of child to add + * @return Returns 1 on success or 0 on failure + * @brief Parses the given XML tree and populates a new child operation. + */ +static int +efreet_menu_handle_filter_child_op(Efreet_Menu_Filter_Op *op, Efreet_Xml *xml, + Efreet_Menu_Filter_Op_Type type) +{ + Efreet_Menu_Filter_Op *child_op; + + child_op = efreet_menu_filter_op_new(); + child_op->type = type; + + if (!efreet_menu_handle_filter_op(child_op, xml)) + { + efreet_menu_filter_op_free(child_op); + return 0; + } + + op->filters = eina_list_append(op->filters, child_op); + + return 1; +} + +/** + * @internal + * @param menu The menu to work with + * @param only_unallocated Do we only look for unallocated items? + * @return Returns 1 if we've successfully processed the menu, 0 otherwise + * @brief Handles the processing of the menu data to retrieve the .desktop + * files for the menu + */ +static int +efreet_menu_process(Efreet_Menu_Internal *internal, unsigned int only_unallocated) +{ + Eina_List *l; + + /* a menu _MUST_ have a name */ + if (!internal->name.internal || (internal->name.internal[0] == '\0')) + return 0; + + /* handle filtering out .desktop files as needed. This deals with all + * .desktop files */ + efreet_menu_process_filters(internal, only_unallocated); + + if (internal->sub_menus) + { + Efreet_Menu_Internal *sub_internal; + + EINA_LIST_FOREACH(internal->sub_menus, l, sub_internal) + { + sub_internal->parent = internal; + efreet_menu_process(sub_internal, only_unallocated); + } + } + + return 1; +} + +/* This will walk through all of the app dirs and load all the .desktop + * files into the cache for the menu. The .desktop files will have their + * allocated flag set to 0 */ +static int +efreet_menu_process_dirs(Efreet_Menu_Internal *internal) +{ + Eina_List *l; + + /* Scan application directories for .desktop files */ + if (!efreet_menu_app_dirs_process(internal)) + return 0; + + /* Scan directory directories for .directory file */ + if (!efreet_menu_directory_dirs_process(internal)) + return 0; + + if (internal->sub_menus) + { + Efreet_Menu_Internal *sub_internal; + + EINA_LIST_FOREACH(internal->sub_menus, l, sub_internal) + { + sub_internal->parent = internal; + efreet_menu_process_dirs(sub_internal); + } + } + + return 1; +} + +/** + * @internal + * @param menu the menu to process + * @param only_unallocated Only handle menus that deal with unallocated items + * @return Returns no value + * @brief Handles the processing of the filters attached to the given menu. + * + * For each include filter we'll add the items to our applications array. Each + * exclude filter will remove items from the applications array + */ +static void +efreet_menu_process_filters(Efreet_Menu_Internal *internal, unsigned int only_unallocated) +{ + Efreet_Menu_Filter *filter; + Efreet_Menu_Desktop *md; + Eina_List *l, *ll; + + int included = 0; + + /* nothing to do if we're checking the other option */ + if (only_unallocated != internal->only_unallocated) return; + + internal->applications = eina_list_free(internal->applications); + + if (!internal->filters) return; + + EINA_LIST_FOREACH(internal->filters, l, filter) + { + /* skip excludes until we get an include */ + if (!included && (filter->type == EFREET_MENU_FILTER_EXCLUDE)) + continue; + included = 1; + + if (filter->type == EFREET_MENU_FILTER_INCLUDE) + { + Eina_Hash *matches; + + matches = eina_hash_string_superfast_new(NULL); + internal->applications = efreet_menu_process_app_pool(internal->app_pool, internal->applications, + matches, filter, internal->only_unallocated); + if (internal->parent) + { + Efreet_Menu_Internal *parent; + + parent = internal->parent; + do { + internal->applications = efreet_menu_process_app_pool(parent->app_pool, + internal->applications, matches, filter, + internal->only_unallocated); + } while ((parent = parent->parent)); + } + eina_hash_free(matches); + } + else + { + /* check each item in our menu so far and see if it's excluded */ + l = internal->applications; + while ((md = eina_list_data_get(l))) + { + ll = eina_list_next(l); + if (efreet_menu_filter_matches(filter->op, md)) + internal->applications = eina_list_remove_list(internal->applications, l); + l = ll; + } + } + } + + /* sort the menu applications. we do this in process filters so it will only + * be done once per menu.*/ + if (eina_list_count(internal->applications)) + { + Eina_List *l2; + + EINA_LIST_FOREACH_SAFE(internal->applications, l, l2, md) + { + if (md->desktop->no_display) + internal->applications = eina_list_remove_list(internal->applications, l); + } + internal->applications = eina_list_sort(internal->applications, + eina_list_count(internal->applications), + EINA_COMPARE_CB(efreet_menu_cb_md_compare)); + } +} + +/** + * @internal + * @param pool The app pool to iterate + * @param applications The list of applications to append too + * @param matches The hash of previously matched ids + * @param filter The menu filter to run on the pool items + * @param only_unallocated Do we check only unallocated pool items? + * @return Returns no value. + * @brief This will iterate the items in @a pool and append them to @a + * applications if they match the @a filter given and aren't previoulsy entered + * in @a matches. If @a only_unallocated is set we'll only only at the + * .desktop files that haven't been previoulsy matched + */ +static Eina_List * +efreet_menu_process_app_pool(Eina_List *pool, Eina_List *applications, + Eina_Hash *matches, Efreet_Menu_Filter *filter, + unsigned int only_unallocated) +{ + Efreet_Menu_Desktop *md; + Eina_List *l; + + EINA_LIST_FOREACH(pool, l, md) + { + if (eina_hash_find(matches, md->id)) continue; + if (only_unallocated && md->allocated) continue; + if (efreet_menu_filter_matches(filter->op, md)) + { + applications = eina_list_append(applications, md); + eina_hash_direct_add(matches, (void *)md->id, md); + md->allocated = 1; + } + } + return applications; +} + +/** + * @internal + * @param op The filter operation to execute + * @param md The desktop to run the filter on + * @return Returns 1 if this desktop matches the given filter, 0 otherwise + * @brief This will execute the given @a filter on the given desktop + */ +static int +efreet_menu_filter_matches(Efreet_Menu_Filter_Op *op, Efreet_Menu_Desktop *md) +{ + if (op->type == EFREET_MENU_FILTER_OP_OR) + return efreet_menu_filter_or_matches(op, md); + + if (op->type == EFREET_MENU_FILTER_OP_AND) + return efreet_menu_filter_and_matches(op, md); + + if (op->type == EFREET_MENU_FILTER_OP_NOT) + return efreet_menu_filter_not_matches(op, md); + + return 0; +} + +/** + * @internal + * @param op The filter operation to execute + * @param md The desktop to execute on + * @return Returns 1 if the desktop matches, 0 otherwise + * @brief Executes the OR operation, @a op, on the desktop, @a md. + */ +static int +efreet_menu_filter_or_matches(Efreet_Menu_Filter_Op *op, Efreet_Menu_Desktop *md) +{ + Efreet_Menu_Filter_Op *child; + Eina_List *l; + char *t; + + if (op->all) return 1; + + if (op->categories && md->desktop->categories) + { + EINA_LIST_FOREACH(op->categories, l, t) + { + if (eina_list_search_unsorted(md->desktop->categories, + EINA_COMPARE_CB(strcmp), t)) + return 1; + } + } + + if (op->filenames) + { + EINA_LIST_FOREACH(op->filenames, l, t) + if (t == md->id) return 1; + } + + if (op->filters) + { + EINA_LIST_FOREACH(op->filters, l, child) + { + if (efreet_menu_filter_matches(child, md)) + return 1; + } + } + + return 0; +} + +/** + * @internal + * @param op The filter operation to execute + * @param md The desktop to execute on + * @return Returns 1 if the desktop matches, 0 otherwise + * @brief Executes the AND operation, @a op, on the desktop, @a md. + */ +static int +efreet_menu_filter_and_matches(Efreet_Menu_Filter_Op *op, Efreet_Menu_Desktop *md) +{ + Efreet_Menu_Filter_Op *child; + Eina_List *l; + char *t; + + if (op->categories) + { + if ((eina_list_count(op->categories) > 0) && !md->desktop->categories) + return 0; + + EINA_LIST_FOREACH(op->categories, l, t) + { + if (!eina_list_search_unsorted(md->desktop->categories, + EINA_COMPARE_CB(strcmp), t)) + return 0; + } + } + + if (op->filenames) + { + EINA_LIST_FOREACH(op->filenames, l, t) + { + if (t != md->id) return 0; + } + } + + if (op->filters) + { + EINA_LIST_FOREACH(op->filters, l, child) + { + if (!efreet_menu_filter_matches(child, md)) + return 0; + } + } + + return 1; +} + +/** + * @internal + * @param op The filter operation to execute + * @param md The desktop to execute on + * @return Returns 1 if the desktop matches, 0 otherwise + * @brief Executes the NOT operation, @a op, on the desktop, @a md. + */ +static int +efreet_menu_filter_not_matches(Efreet_Menu_Filter_Op *op, Efreet_Menu_Desktop *md) +{ + Efreet_Menu_Filter_Op *child; + Eina_List *l; + char *t; + + /* !all means no desktops match */ + if (op->all) return 0; + + if (op->categories) + { + if ((eina_list_count(op->categories) > 0) && !md->desktop->categories) + return 1; + + EINA_LIST_FOREACH(op->categories, l, t) + { + if (eina_list_search_unsorted(md->desktop->categories, + EINA_COMPARE_CB(strcmp), t)) + return 0; + } + } + + if (op->filenames) + { + EINA_LIST_FOREACH(op->filenames, l, t) + { + if (t == md->id) return 0; + } + } + + if (op->filters) + { + EINA_LIST_FOREACH(op->filters, l, child) + { + if (efreet_menu_filter_matches(child, md)) + return 0; + } + } + + return 1; +} + +/** + * @internal + * @param dest The destination menu + * @param src The source menu + * @return Returns no value + * @brief Takes the child elements of the menu @a src and puts then on the + * _start_ of the menu @a dest. + */ +static void +efreet_menu_concatenate(Efreet_Menu_Internal *dest, Efreet_Menu_Internal *src) +{ + Efreet_Menu_Internal *submenu; + + if (!dest || !src) return; + + if (!dest->directory && src->directory) + { + dest->directory = src->directory; + src->directory = NULL; + } + + if (!dest->seen_allocated && src->seen_allocated) + { + dest->only_unallocated = src->only_unallocated; + dest->seen_allocated = 1; + } + + if (!dest->seen_deleted && src->seen_deleted) + { + dest->deleted = src->deleted; + dest->seen_deleted = 1; + } + + if (src->directories) + { + efreet_menu_create_directories_list(dest); + dest->directories = eina_list_merge(src->directories, dest->directories); + src->directories = NULL; + } + + if (src->app_dirs) + { + efreet_menu_create_app_dirs_list(dest); + dest->app_dirs = eina_list_merge(src->app_dirs, dest->app_dirs); + src->app_dirs = NULL; + } + + if (src->directory_dirs) + { + efreet_menu_create_directory_dirs_list(dest); + dest->directory_dirs = eina_list_merge(src->directory_dirs, dest->directory_dirs); + src->directory_dirs = NULL; + } + + if (src->moves) + { + efreet_menu_create_move_list(dest); + dest->moves = eina_list_merge(src->moves, dest->moves); + src->moves = NULL; + } + + if (src->filters) + { + efreet_menu_create_filter_list(dest); + dest->filters = eina_list_merge(src->filters, dest->filters); + src->filters = NULL; + } + + if (src->sub_menus) + { + efreet_menu_create_sub_menu_list(dest); + + while ((submenu = eina_list_data_get(eina_list_last(src->sub_menus)))) + { + Efreet_Menu_Internal *match; + + src->sub_menus = eina_list_remove(src->sub_menus, submenu); + /* if this menu is in the list already we just add to that */ + if ((match = eina_list_search_unsorted(dest->sub_menus, + EINA_COMPARE_CB(efreet_menu_cb_menu_compare), + submenu))) + { + efreet_menu_concatenate(match, submenu); + efreet_menu_internal_free(submenu); + } + else + dest->sub_menus = eina_list_prepend(dest->sub_menus, submenu); + } + } +} + +/** + * @internal + * @param menu The menu to work with + * @return Returns no value + * @brief Handles any \<Move\> commands in the menus + */ +static void +efreet_menu_resolve_moves(Efreet_Menu_Internal *internal) +{ + Efreet_Menu_Internal *child; + Efreet_Menu_Move *move; + Eina_List *l; + + /* child moves are handled before parent moves */ + if (internal->sub_menus) + { + EINA_LIST_FOREACH(internal->sub_menus, l, child) + efreet_menu_resolve_moves(child); + } + + /* nothing to do if this menu has no moves */ + if (!internal->moves) return; + + EINA_LIST_FOREACH(internal->moves, l, move) + { + Efreet_Menu_Internal *origin, *dest, *parent; + + /* if the origin path doesn't exist we do nothing */ + origin = efreet_menu_by_name_find(internal, move->old_name, &parent); + if (!origin) continue; + + /* remove the origin menu from the parent */ + parent->sub_menus = eina_list_remove(parent->sub_menus, origin); + + /* if the destination path doesn't exist we just rename the origin + * menu and append to the parents list of children */ + dest = efreet_menu_by_name_find(internal, move->new_name, &parent); + if (!dest) + { + char *path, *tmp, *t; + size_t len; + + /* if the dest path has /'s in it then we need to add menus to + * fill out the paths */ + len = strlen(move->new_name) + 1; + t = alloca(len); + memcpy(t, move->new_name, len); + tmp = t; + path = strchr(tmp, '/'); + while (path) + { + Efreet_Menu_Internal *ancestor; + + *path = '\0'; + + ancestor = efreet_menu_internal_new(); + if (!ancestor) goto error; + ancestor->name.internal = eina_stringshare_add(tmp); + + efreet_menu_create_sub_menu_list(parent); + parent->sub_menus = eina_list_append(parent->sub_menus, ancestor); + + parent = ancestor; + tmp = ++path; + path = strchr(tmp, '/'); + } + + IF_RELEASE(origin->name.internal); + origin->name.internal = eina_stringshare_add(tmp); + + efreet_menu_create_sub_menu_list(parent); + parent->sub_menus = eina_list_append(parent->sub_menus, origin); + } + else + { + efreet_menu_concatenate(dest, origin); + efreet_menu_internal_free(origin); + } + } +error: + IF_FREE_LIST(internal->moves, efreet_menu_move_free); +} + +/** + * @internal + * @param menu The menu to start searching from + * @param name The menu name to find + * @param parent The parent of the found menu + * @return Returns the menu with the given @a name or NULL if none found + * @brief Searches the menu tree starting at @a menu looking for a menu with + * @a name. + */ +static Efreet_Menu_Internal * +efreet_menu_by_name_find(Efreet_Menu_Internal *internal, const char *name, Efreet_Menu_Internal **parent) +{ + char *part, *tmp, *ptr; + size_t len; + + if (parent) *parent = internal; + + /* find the correct parent menu */ + len = strlen(name) + 1; + tmp = alloca(len); + memcpy(tmp, name, len); + ptr = tmp; + part = strchr(ptr, '/'); + while (part) + { + *part = '\0'; + + if (!(internal = eina_list_search_unsorted(internal->sub_menus, + EINA_COMPARE_CB(efreet_menu_cb_compare_names), + ptr))) + { + return NULL; + } + + ptr = ++part; + part = strchr(ptr, '/'); + } + + if (parent) *parent = internal; + + /* find the menu in the parent list */ + if (!(internal = eina_list_search_unsorted(internal->sub_menus, + EINA_COMPARE_CB(efreet_menu_cb_compare_names), + ptr))) + { + return NULL; + } + + return internal; +} + +static void +efreet_menu_path_set(Efreet_Menu_Internal *internal, const char *path) +{ + char *tmp, *p; + size_t len; + + len = strlen(path) + 1; + tmp = alloca(len); + memcpy(tmp, path, len); + p = strrchr(tmp, '/'); + if (p) + { + *p = '\0'; + p++; + + internal->file.path = eina_stringshare_add(tmp); + internal->file.name = eina_stringshare_add(p); + } +} + +/** + * @internal + * @return Returns a new Efreet_Menu_Move struct on success or NULL on failure + * @brief Creates an returns a new Efreet_Menu_Move struct or NULL on failure + */ +static Efreet_Menu_Move * +efreet_menu_move_new(void) +{ + Efreet_Menu_Move *move; + + move = NEW(Efreet_Menu_Move, 1); + + return move; +} + +/** + * @internal + * @param move The Efreet_Menu_Move to free + * @return Returns no value. + * @brief Frees the given move structure + */ +static void +efreet_menu_move_free(Efreet_Menu_Move *move) +{ + if (!move) return; + + IF_RELEASE(move->old_name); + IF_RELEASE(move->new_name); + + FREE(move); +} + +/** + * @internal + * @return Returns a new Efreet_Menu_App_Dir on success or NULL on failure + * @brief Creates and initializes a new Efreet_Menu_App_Dir structure + */ +static Efreet_Menu_App_Dir * +efreet_menu_app_dir_new(void) +{ + Efreet_Menu_App_Dir *dir; + + dir = NEW(Efreet_Menu_App_Dir, 1); + + return dir; +} + +/** + * @internal + * @param dir The Efreet_Menu_App_Dir to free + * @return Returns no value. + * @brief Frees the given dir structure + */ +static void +efreet_menu_app_dir_free(Efreet_Menu_App_Dir *dir) +{ + if (!dir) return; + + IF_RELEASE(dir->path); + IF_RELEASE(dir->prefix); + FREE(dir); +} + +/** + * @internal + * @param a The app dir to compare too + * @param b The path to compare too + * @return Returns 0 if the strings are equals, != 0 otherwise + * @brief Compares the too strings + */ +static int +efreet_menu_cb_app_dirs_compare(Efreet_Menu_App_Dir *a, const char *b) +{ + if (!a->path || !b) return 1; + if (a->path == b) return 0; + return strcmp(a->path, b); +} + +static void +efreet_menu_create_sub_menu_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->sub_menus) return; + + internal->sub_menus = NULL; +} + +static void +efreet_menu_create_app_dirs_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->app_dirs) return; + + internal->app_dirs = NULL; +} + +static void +efreet_menu_create_directory_dirs_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->directory_dirs) return; + + internal->directory_dirs = NULL; +} + +static void +efreet_menu_create_move_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->moves) return; + + internal->moves = NULL; +} + +static void +efreet_menu_create_filter_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->filters) return; + + internal->filters = NULL; +} + +static void +efreet_menu_create_layout_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->layout) return; + + internal->layout = NULL; +} + +static void +efreet_menu_create_default_layout_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->default_layout) return; + + internal->default_layout = NULL; +} + +static void +efreet_menu_create_directories_list(Efreet_Menu_Internal *internal) +{ + if (!internal || internal->directories) return; + + internal->directories = NULL; +} + +static const char * +efreet_menu_path_get(Efreet_Menu_Internal *internal, const char *suffix) +{ + char path[PATH_MAX]; + size_t len; + + /* see if we've got an absolute or relative path */ + if (suffix[0] == '/') + snprintf(path, sizeof(path), "%s", suffix); + + else + { + if (!internal->file.path) + { + INF("efreet_menu_handle_app_dir() missing menu path ..."); + return NULL; + } + snprintf(path, sizeof(path), "%s/%s", internal->file.path, suffix); + } + + len = strlen(path); + while (path[len] == '/') path[len--] = '\0'; + + return eina_stringshare_add(path); +} + +static int +efreet_menu_cb_menu_compare(Efreet_Menu_Internal *a, Efreet_Menu_Internal *b) +{ + if (!a->name.internal || !b->name.internal) return 1; + if (a->name.internal == b->name.internal) return 0; + return strcmp(a->name.internal, b->name.internal); +} + +static int +efreet_menu_app_dirs_process(Efreet_Menu_Internal *internal) +{ + Efreet_Menu_App_Dir *app_dir; + Efreet_Menu_Desktop *md; + Eina_List *l; + + EINA_LIST_FREE(internal->app_pool, md) + efreet_menu_desktop_free(md); + + EINA_LIST_FOREACH(internal->app_dirs, l, app_dir) + efreet_menu_app_dir_scan(internal, app_dir->path, app_dir->prefix, app_dir->legacy); + + return 1; +} + +static int +efreet_menu_app_dir_scan(Efreet_Menu_Internal *internal, const char *path, const char *id, int legacy) +{ + Efreet_Desktop *desktop; + Efreet_Menu_Desktop *menu_desktop; + char buf2[PATH_MAX]; + Eina_Iterator *it; + Eina_File_Direct_Info *info; + + it = eina_file_direct_ls(path); + if (!it) return 1; + + EINA_ITERATOR_FOREACH(it, info) + { + const char *fname; + + fname = info->path + info->name_start; + if (id) + snprintf(buf2, sizeof(buf2), "%s-%s", id, fname); + else + strcpy(buf2, fname); + + if (ecore_file_is_dir(info->path)) + { + if (!legacy) + efreet_menu_app_dir_scan(internal, info->path, buf2, legacy); + } + else + { + const char *ext; + + ext = strrchr(fname, '.'); + + if (!ext || strcmp(ext, ".desktop")) continue; + desktop = efreet_desktop_get(info->path); + + if (!desktop || desktop->type != EFREET_DESKTOP_TYPE_APPLICATION) + { + if (desktop) efreet_desktop_free(desktop); + continue; + } + /* Don't add two files with the same id in the app pool */ + if (eina_list_search_unsorted(internal->app_pool, + EINA_COMPARE_CB(efreet_menu_cb_md_compare_ids), + buf2)) + { + if (desktop) efreet_desktop_free(desktop); + continue; + } + + menu_desktop = efreet_menu_desktop_new(); + menu_desktop->desktop = desktop; + menu_desktop->id = eina_stringshare_add(buf2); + internal->app_pool = eina_list_prepend(internal->app_pool, menu_desktop); + } + } + eina_iterator_free(it); + + return 1; +} + +/** + * @internal + * @param menu The menu to work with + * @return Returns 1 on success or 0 on failure + * @brief Process the directory dirs in @a menu + */ +static int +efreet_menu_directory_dirs_process(Efreet_Menu_Internal *internal) +{ + const char *path; + Eina_List *l; + + if (internal->directory_dirs) + { + internal->directory_cache = + eina_hash_string_superfast_new(EINA_FREE_CB(efreet_desktop_free)); + + EINA_LIST_REVERSE_FOREACH(internal->directory_dirs, l, path) + efreet_menu_directory_dir_scan(path, NULL, internal->directory_cache); + } + + if (internal->directories) + { + EINA_LIST_REVERSE_FOREACH(internal->directories, l, path) + { + internal->directory = efreet_menu_directory_get(internal, path); + if (internal->directory) break; + } + } + if (!internal->directory) + internal->name.name = internal->name.internal; + else + internal->name.name = internal->directory->name; + + return 1; +} + +/** + * @internal + * @param path The path to scan + * @param relative_path The relative portion of the path + * @param cache The cache to populate + * @return Returns 1 on success or 0 on failure + * @brief Scans the given directory dir for .directory files and adds the + * applications to the cache + */ +static int +efreet_menu_directory_dir_scan(const char *path, const char *relative_path, + Eina_Hash *cache) +{ + Efreet_Desktop *desktop; + char buf2[PATH_MAX]; + Eina_Iterator *it; + Eina_File_Direct_Info *info; + char *ext; + + it = eina_file_direct_ls(path); + if (!it) return 1; + + EINA_ITERATOR_FOREACH(it, info) + { + const char *fname; + + fname = info->path + info->name_start; + if (relative_path) + snprintf(buf2, sizeof(buf2), "%s/%s", relative_path, fname); + else + strcpy(buf2, fname); + + if (ecore_file_is_dir(info->path)) + efreet_menu_directory_dir_scan(info->path, buf2, cache); + + else + { + ext = strrchr(fname, '.'); + if (!ext || strcmp(ext, ".directory")) continue; + + desktop = efreet_desktop_get(info->path); + if (!desktop || desktop->type != EFREET_DESKTOP_TYPE_DIRECTORY) + { + efreet_desktop_free(desktop); + continue; + } + + eina_hash_del(cache, buf2, NULL); + eina_hash_add(cache, buf2, desktop); + } + } + eina_iterator_free(it); + + return 1; +} + +/** + * @internal + * @param menu The menu to work with + * @param path The path to work with + * @return Returns the desktop file for this path or NULL if none exists + * @brief Finds the desktop file for the given path. + */ +static Efreet_Desktop * +efreet_menu_directory_get(Efreet_Menu_Internal *internal, const char *path) +{ + Efreet_Desktop *dir; + + if (internal->directory_cache) + { + dir = eina_hash_find(internal->directory_cache, path); + if (dir) return dir; + } + + if (internal->parent) + return efreet_menu_directory_get(internal->parent, path); + + return NULL; +} + +/** + * @internal + * @param a The first desktop + * @param b The second desktop + * @return Returns the comparison of the desktop files + * @brief Compares the desktop files. + */ +static int +efreet_menu_cb_md_compare(const Efreet_Menu_Desktop *a, const Efreet_Menu_Desktop *b) +{ +#ifdef STRICT_SPEC + return strcmp(ecore_file_file_get(a->desktop->orig_path), ecore_file_file_get(b->desktop->orig_path)); +#else + if (a->desktop->name == b->desktop->name) return 0; + return strcasecmp(a->desktop->name, b->desktop->name); +#endif +} + +static int +efreet_menu_cb_compare_names(Efreet_Menu_Internal *internal, const char *name) +{ + if (internal->name.internal == name) return 0; + return strcmp(internal->name.internal, name); +} + +static int +efreet_menu_cb_md_compare_ids(Efreet_Menu_Desktop *md, const char *name) +{ + if (md->id == name) return 0; + return strcmp(md->id, name); +} + +static Efreet_Menu * +efreet_menu_layout_menu(Efreet_Menu_Internal *internal) +{ + Efreet_Menu *entry; + Eina_List *layout = NULL; + Eina_List *l; + + if (internal->parent) + { + /* Copy default layout rules */ + if (internal->show_empty == -1) internal->show_empty = internal->parent->show_empty; + if (internal->in_line == -1) internal->in_line = internal->parent->in_line; + if (internal->inline_limit == -1) internal->inline_limit = internal->parent->inline_limit; + if (internal->inline_header == -1) internal->inline_header = internal->parent->inline_header; + if (internal->inline_alias == -1) internal->inline_alias = internal->parent->inline_alias; + } + + if (internal->layout) + layout = internal->layout; + + else if (internal->parent) + { + Efreet_Menu_Internal *parent; + parent = internal->parent; + do + { + layout = parent->default_layout; + parent = parent->parent; + } while (!layout && parent); + } + + /* init entry */ + entry = efreet_menu_entry_new(); + entry->type = EFREET_MENU_ENTRY_MENU; + entry->id = eina_stringshare_add(internal->name.internal); + entry->name = eina_stringshare_add(internal->name.name); + if (internal->directory) + { + entry->icon = eina_stringshare_add(internal->directory->icon); + efreet_desktop_ref(internal->directory); + entry->desktop = internal->directory; + } + entry->entries = NULL; + +#if 1 //STRICT_SPEC + if (internal->sub_menus) + { + internal->sub_menus = eina_list_sort(internal->sub_menus, + 0, + EINA_COMPARE_CB(efreet_menu_cb_menu_compare)); + } +#endif + + if (layout) + { + Efreet_Menu_Layout *lay; + + EINA_LIST_FOREACH(layout, l, lay) + efreet_menu_layout_entries_get(entry, internal, lay); + } + else + { + /* Default layout, first menus, then desktop */ + if (internal->sub_menus) + { + Efreet_Menu_Internal *sub; + + EINA_LIST_FOREACH(internal->sub_menus, l, sub) + { + Efreet_Menu *sub_entry; + if ((sub->directory && sub->directory->no_display) || sub->deleted) continue; + sub_entry = efreet_menu_layout_menu(sub); + /* Don't show empty menus */ + if (!sub_entry->entries) + { + efreet_menu_free(sub_entry); + continue; + } + entry->entries = eina_list_append(entry->entries, sub_entry); + } + } + + if (internal->applications) + { + Efreet_Menu_Desktop *md; + + EINA_LIST_FOREACH(internal->applications, l, md) + { + Efreet_Menu *sub_entry; + sub_entry = efreet_menu_layout_desktop(md); + entry->entries = eina_list_append(entry->entries, sub_entry); + } + } + } + + /* Don't keep this list around if it is empty */ + + return entry; +} + +static Efreet_Menu * +efreet_menu_layout_desktop(Efreet_Menu_Desktop *md) +{ + Efreet_Menu *entry; + + /* init entry */ + entry = efreet_menu_entry_new(); + entry->type = EFREET_MENU_ENTRY_DESKTOP; + entry->id = eina_stringshare_add(md->id); + entry->name = eina_stringshare_add(md->desktop->name); + if (md->desktop->icon) entry->icon = eina_stringshare_add(md->desktop->icon); + efreet_desktop_ref(md->desktop); + entry->desktop = md->desktop; + + return entry; +} + +static void +efreet_menu_layout_entries_get(Efreet_Menu *entry, Efreet_Menu_Internal *internal, + Efreet_Menu_Layout *layout) +{ + Efreet_Menu *sub_entry; + + if (internal->sub_menus && layout->type == EFREET_MENU_LAYOUT_MENUNAME) + { + Efreet_Menu_Internal *sub; + + /* Efreet_Menu_Layout might be from DefaultLayout, so we need a local copy */ + int show_empty, in_line, inline_limit, inline_header, inline_alias; + + if (layout->show_empty == -1) show_empty = internal->show_empty; + else show_empty = layout->show_empty; + + if (layout->in_line == -1) in_line = internal->in_line; + else in_line = layout->in_line; + + if (layout->inline_limit == -1) inline_limit = internal->inline_limit; + else inline_limit = layout->inline_limit; + + if (layout->inline_header == -1) inline_header = internal->inline_header; + else inline_header = layout->inline_header; + + if (layout->inline_alias == -1) inline_alias = internal->inline_alias; + else inline_alias = layout->inline_alias; + + sub = eina_list_search_unsorted(internal->sub_menus, + EINA_COMPARE_CB(efreet_menu_cb_compare_names), layout->name); + if (sub) + { + if (!(sub->directory && sub->directory->no_display) && !sub->deleted) + { + sub_entry = efreet_menu_layout_menu(sub); + if (!show_empty && efreet_menu_layout_is_empty(sub_entry)) + efreet_menu_free(sub_entry); + else if (in_line && + ((inline_limit == 0) || + (!sub_entry->entries || + (inline_limit > 0 && eina_list_count(sub_entry->entries) <= (unsigned int)inline_limit)))) + { + /* Inline */ + if (!sub_entry->entries) + { + /* Can't inline an empty submenu */ + entry->entries = eina_list_append(entry->entries, sub_entry); + } + else if (inline_alias && (eina_list_count(sub_entry->entries) == 1)) + { + Efreet_Menu *tmp; + + tmp = eina_list_data_get(sub_entry->entries); + sub_entry->entries = eina_list_remove_list(sub_entry->entries, sub_entry->entries); + IF_RELEASE(tmp->name); + tmp->name = sub_entry->name; + sub_entry->name = NULL; + IF_RELEASE(tmp->icon); + tmp->icon = sub_entry->icon; + sub_entry->icon = NULL; + entry->entries = eina_list_append(entry->entries, tmp); + efreet_menu_free(sub_entry); + } + else + { + Efreet_Menu *tmp; + + if (inline_header) + { + tmp = efreet_menu_entry_new(); + tmp->type = EFREET_MENU_ENTRY_HEADER; + tmp->name = sub_entry->name; + sub_entry->name = NULL; + tmp->icon = sub_entry->icon; + sub_entry->icon = NULL; + entry->entries = eina_list_append(entry->entries, tmp); + } + while ((tmp = eina_list_data_get(sub_entry->entries))) + { + sub_entry->entries = eina_list_remove_list(sub_entry->entries, sub_entry->entries); + entry->entries = eina_list_append(entry->entries, tmp); + } + efreet_menu_free(sub_entry); + } + } + else + entry->entries = eina_list_append(entry->entries, sub_entry); + } + internal->sub_menus = eina_list_remove(internal->sub_menus, sub); + efreet_menu_internal_free(sub); + } + } + else if (internal->applications && layout->type == EFREET_MENU_LAYOUT_FILENAME) + { + Efreet_Menu_Desktop *md; + md = eina_list_search_unsorted(internal->applications, + EINA_COMPARE_CB(efreet_menu_cb_md_compare_ids), layout->name); + if (md) + { + sub_entry = efreet_menu_layout_desktop(md); + entry->entries = eina_list_append(entry->entries, sub_entry); + internal->applications = eina_list_remove(internal->applications, md); + } + } + else if (layout->type == EFREET_MENU_LAYOUT_MERGE) + { + if (internal->applications && !strcmp(layout->name, "files")) + { + Efreet_Menu_Desktop *md; + + while ((md = eina_list_data_get(internal->applications))) + { + internal->applications = eina_list_remove_list(internal->applications, + internal->applications); + sub_entry = eina_list_search_unsorted(entry->entries, + EINA_COMPARE_CB(efreet_menu_cb_entry_compare_desktop), + md->desktop); + if (!sub_entry) + { + sub_entry = efreet_menu_layout_desktop(md); + entry->entries = eina_list_append(entry->entries, sub_entry); + } + } + internal->applications = eina_list_free(internal->applications); + } + else if (internal->sub_menus && !strcmp(layout->name, "menus")) + { + Efreet_Menu_Internal *sub; + + while ((sub = eina_list_data_get(internal->sub_menus))) + { + internal->sub_menus = eina_list_remove_list(internal->sub_menus, internal->sub_menus); + if ((sub->directory && sub->directory->no_display) || sub->deleted) + { + efreet_menu_internal_free(sub); + continue; + } + sub_entry = eina_list_search_unsorted(entry->entries, + EINA_COMPARE_CB(efreet_menu_cb_entry_compare_menu), + sub); + if (!sub_entry) + { + sub_entry = efreet_menu_layout_menu(sub); + if (!internal->show_empty && efreet_menu_layout_is_empty(sub_entry)) + efreet_menu_free(sub_entry); + else if (internal->in_line && + ((internal->inline_limit == 0) || + (!sub_entry->entries || + (internal->inline_limit > 0 && eina_list_count(sub_entry->entries) <= (unsigned int)internal->inline_limit)))) + { + /* Inline */ + if (!sub_entry->entries) + { + /* Can't inline an empty submenu */ + entry->entries = eina_list_append(entry->entries, sub_entry); + } + else if (internal->inline_alias && (eina_list_count(sub_entry->entries) == 1)) + { + Efreet_Menu *tmp; + + tmp = eina_list_data_get(sub_entry->entries); + sub_entry->entries = eina_list_remove_list(sub_entry->entries, sub_entry->entries); + eina_stringshare_del(tmp->name); + tmp->name = sub_entry->name; + sub_entry->name = NULL; + IF_RELEASE(tmp->icon); + if (sub_entry->icon) + { + tmp->icon = sub_entry->icon; + sub_entry->icon = NULL; + } + entry->entries = eina_list_append(entry->entries, tmp); + efreet_menu_free(sub_entry); + } + else + { + Efreet_Menu *tmp; + + if (internal->inline_header) + { + tmp = efreet_menu_entry_new(); + tmp->type = EFREET_MENU_ENTRY_HEADER; + tmp->name = sub_entry->name; + sub_entry->name = NULL; + if (sub_entry->icon) tmp->icon = sub_entry->icon; + sub_entry->icon = NULL; + entry->entries = eina_list_append(entry->entries, tmp); + } + while ((tmp = eina_list_data_get(sub_entry->entries))) + { + sub_entry->entries = eina_list_remove_list(sub_entry->entries, + sub_entry->entries); + entry->entries = eina_list_append(entry->entries, tmp); + } + efreet_menu_free(sub_entry); + } + } + else + entry->entries = eina_list_append(entry->entries, sub_entry); + } + efreet_menu_internal_free(sub); + } + IF_FREE_LIST(internal->sub_menus, efreet_menu_internal_free); + } + else if (internal->sub_menus && !strcmp(layout->name, "all")) + { + const char *orig; + + orig = layout->name; + layout->name = "menus"; + efreet_menu_layout_entries_get(entry, internal, layout); + layout->name = "files"; + efreet_menu_layout_entries_get(entry, internal, layout); + layout->name = orig; + } + } + else if (layout->type == EFREET_MENU_LAYOUT_SEPARATOR) + { + sub_entry = efreet_menu_entry_new(); + sub_entry->type = EFREET_MENU_ENTRY_SEPARATOR; + entry->entries = eina_list_append(entry->entries, sub_entry); + } +} + +static int +efreet_menu_cb_entry_compare_menu(Efreet_Menu *entry, Efreet_Menu_Internal *internal) +{ + if (entry->type != EFREET_MENU_ENTRY_MENU) return 1; + if (!entry->name || !internal->name.name) return 1; + if (entry->name == internal->name.name) return 0; + return strcmp(entry->name, internal->name.name); +} + +static int +efreet_menu_cb_entry_compare_desktop(Efreet_Menu *entry, Efreet_Desktop *desktop) +{ + if (entry->type != EFREET_MENU_ENTRY_DESKTOP) return -1; + if (!entry->name || !desktop->name) return -1; + if (entry->name == desktop->name) return 0; + return strcmp(entry->name, desktop->name); +} + +static int +efreet_menu_cb_move_compare(Efreet_Menu_Move *move, const char *old) +{ + if (!move->old_name || !old) return 1; + if (move->old_name == old) return 0; + return 1; +} + +static int +efreet_menu_layout_is_empty(Efreet_Menu *entry) +{ + Efreet_Menu *sub_entry; + Eina_List *l; + + if (!entry->entries) return 1; + + EINA_LIST_FOREACH(entry->entries, l, sub_entry) + { + if (sub_entry->type == EFREET_MENU_ENTRY_MENU) return 0; + if (sub_entry->type == EFREET_MENU_ENTRY_DESKTOP) return 0; + } + return 1; +} diff --git a/src/lib/efreet_menu.h b/src/lib/efreet_menu.h new file mode 100644 index 0000000..8531cd8 --- /dev/null +++ b/src/lib/efreet_menu.h @@ -0,0 +1,138 @@ +#ifndef EFREET_MENU_H +#define EFREET_MENU_H + +/** + * @file efreet_menu.h + * @brief Contains the structures and methods to support the Desktop + * Menu Specification. + * @addtogroup Efreet_Menu Efreet_Menu: The FDO Desktop Menu Specification + * functions and structures + * + * @{ + */ + +/** + * The type of entry + */ +typedef enum Efreet_Menu_Entry_Type +{ + EFREET_MENU_ENTRY_MENU, + EFREET_MENU_ENTRY_DESKTOP, + EFREET_MENU_ENTRY_SEPARATOR, + EFREET_MENU_ENTRY_HEADER +} Efreet_Menu_Entry_Type; + +/** + * Efreet_Menu + */ +typedef struct Efreet_Menu Efreet_Menu; + +/** + * Efreet_Menu + * Stores information on a entry in the menu + */ +struct Efreet_Menu +{ + Efreet_Menu_Entry_Type type; + const char *id; /**< File-id for desktop and relative name for menu */ + + const char *name; /**< Name this entry should show */ + const char *icon; /**< Icon for this entry */ + + Efreet_Desktop *desktop; /**< The desktop we refer too */ + Eina_List *entries; /**< The menu items */ +}; + + +/** + * @return Returns no value + * @brief Initialize legacy kde support. This function blocks while + * the kde-config script is run. + */ +EAPI int efreet_menu_kde_legacy_init(void); + +/** + * @param name The internal name of the menu + * @return Returns the Efreet_Menu on success or + * NULL on failure + * @brief Creates a new menu + */ +EAPI Efreet_Menu *efreet_menu_new(const char *name); + +/** + * @brief Override which file is used for menu creation + * @param file The file to use for menu creation + * + * This file is only used if it exists, else the standard files will be used + * for the menu. + */ +EAPI void efreet_menu_file_set(const char *file); + +/** + * @return Returns the Efreet_Menu_Internal representation of the default menu or + * NULL if none found + * @brief Creates the default menu representation + */ +EAPI Efreet_Menu *efreet_menu_get(void); + +/** + * @param path The path of the menu to load + * @return Returns the Efreet_Menu_Internal representation on success or NULL on + * failure + * @brief Parses the given .menu file and creates the menu representation + */ +EAPI Efreet_Menu *efreet_menu_parse(const char *path); + +/** + * @param menu The menu to work with + * @param path The path where the menu should be saved + * @return Returns 1 on success, 0 on failure + * @brief Saves the menu to file + */ +EAPI int efreet_menu_save(Efreet_Menu *menu, const char *path); + +/** + * @param menu The Efreet_Menu to free + * @return Returns no value + * @brief Frees the given structure + */ +EAPI void efreet_menu_free(Efreet_Menu *menu); + + +/** + * @param menu The menu to work with + * @param desktop The desktop to insert + * @param pos The position to place the new desktop + * @return Returns 1 on success, 0 on failure + * @brief Insert a desktop element in a menu structure. Only accepts desktop files + * in default directories. + */ +EAPI int efreet_menu_desktop_insert(Efreet_Menu *menu, + Efreet_Desktop *desktop, + int pos); + +/** + * @param menu The menu to work with + * @param desktop The desktop to remove + * @return Returns 1 on success, 0 on failure + * @brief Remove a desktop element in a menu structure. Only accepts desktop files + * in default directories. + */ +EAPI int efreet_menu_desktop_remove(Efreet_Menu *menu, + Efreet_Desktop *desktop); + + +/** + * @param menu The menu to work with + * @param menu The menu to work with + * @param indent The indent level to print the menu at + * @return Returns no value + * @brief Dumps the contents of the menu to the command line + */ +EAPI void efreet_menu_dump(Efreet_Menu *menu, const char *indent); + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_mime.c b/src/lib/efreet_mime.c new file mode 100644 index 0000000..9343d90 --- /dev/null +++ b/src/lib/efreet_mime.c @@ -0,0 +1,1622 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <ctype.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> +#include <fnmatch.h> + +#ifdef _WIN32 +# include <winsock2.h> +#endif + +#ifdef HAVE_NETINET_IN_H +# include <netinet/in.h> +#endif + +#ifdef HAVE_ARPA_INET_H +# include <arpa/inet.h> +#endif + +#include <Ecore.h> +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_mime_log_dom +static int _efreet_mime_log_dom = -1; + +#include "Efreet.h" +#include "Efreet_Mime.h" +#include "efreet_private.h" + +static Eina_List *globs = NULL; /* contains Efreet_Mime_Glob structs */ +static Eina_List *magics = NULL; /* contains Efreet_Mime_Magic structs */ +static Eina_Hash *wild = NULL; /* contains *.ext and mime.types globs*/ +static Eina_Hash *monitors = NULL; /* contains file monitors */ +static Eina_Hash *mime_icons = NULL; /* contains cache with mime->icons */ +static Eina_Inlist *mime_icons_lru = NULL; +static unsigned int _efreet_mime_init_count = 0; + +static const char *_mime_inode_symlink = NULL; +static const char *_mime_inode_fifo = NULL; +static const char *_mime_inode_chardevice = NULL; +static const char *_mime_inode_blockdevice = NULL; +static const char *_mime_inode_socket = NULL; +static const char *_mime_inode_mountpoint = NULL; +static const char *_mime_inode_directory = NULL; +static const char *_mime_application_x_executable = NULL; +static const char *_mime_application_octet_stream = NULL; +static const char *_mime_text_plain = NULL; + +/** + * @internal + * @brief Holds whether we are big/little endian + * @note This is set during efreet_mime_init based on + * a runtime check. + */ +static enum +{ + EFREET_ENDIAN_BIG = 0, + EFREET_ENDIAN_LITTLE = 1 +} efreet_mime_endianess = EFREET_ENDIAN_BIG; + +/* + * Buffer sized used for magic checks. The default is good enough for the + * current set of magic rules. This setting is only here for the future. + */ +#define EFREET_MIME_MAGIC_BUFFER_SIZE 512 + +/* + * Minimum timeout in seconds between mime-icons cache flush. + */ +#define EFREET_MIME_ICONS_FLUSH_TIMEOUT 60 + +/* + * Timeout in seconds, when older mime-icons items are expired. + */ +#define EFREET_MIME_ICONS_EXPIRE_TIMEOUT 600 + +/* + * mime-icons maximum population. + */ +#define EFREET_MIME_ICONS_MAX_POPULATION 512 + +/* + * If defined, dump mime-icons statistics after flush. + */ +//#define EFREET_MIME_ICONS_DEBUG + +typedef struct Efreet_Mime_Glob Efreet_Mime_Glob; +struct Efreet_Mime_Glob +{ + const char *glob; + const char *mime; +}; + +typedef struct Efreet_Mime_Magic Efreet_Mime_Magic; +struct Efreet_Mime_Magic +{ + unsigned int priority; + const char *mime; + Eina_List *entries; +}; + +typedef struct Efreet_Mime_Magic_Entry Efreet_Mime_Magic_Entry; +struct Efreet_Mime_Magic_Entry +{ + unsigned int indent; + unsigned int offset; + unsigned int word_size; + unsigned int range_len; + unsigned short value_len; + char *mask; + char *value; +}; + +typedef struct Efreet_Mime_Icon_Entry_Head Efreet_Mime_Icon_Entry_Head; +struct Efreet_Mime_Icon_Entry_Head +{ + EINA_INLIST; /* node of mime_icons_lru */ + Eina_Inlist *list; + const char *mime; + double timestamp; +}; + +typedef struct Efreet_Mime_Icon_Entry Efreet_Mime_Icon_Entry; +struct Efreet_Mime_Icon_Entry +{ + EINA_INLIST; + const char *icon; + const char *theme; + unsigned int size; +}; + +static int efreet_mime_glob_remove(const char *glob); +static void efreet_mime_mime_types_load(const char *file); +static void efreet_mime_shared_mimeinfo_globs_load(const char *file); +static void efreet_mime_shared_mimeinfo_magic_load(const char *file); +static void efreet_mime_shared_mimeinfo_magic_parse(char *data, int size); +static const char *efreet_mime_magic_check_priority(const char *file, + unsigned int start, + unsigned int end); +static int efreet_mime_init_files(void); +static const char *efreet_mime_special_check(const char *file); +static const char *efreet_mime_fallback_check(const char *file); +static void efreet_mime_glob_free(void *data); +static void efreet_mime_magic_free(void *data); +static void efreet_mime_magic_entry_free(void *data); +static int efreet_mime_glob_match(const char *str, const char *glob); +static int efreet_mime_glob_case_match(char *str, const char *glob); +static int efreet_mime_endian_check(void); + +static void efreet_mime_monitor_add(const char *file); +static void efreet_mime_cb_update_file(void *data, + Ecore_File_Monitor *monitor, + Ecore_File_Event event, + const char *path); + +static void efreet_mime_icons_flush(double now); +static void efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry); +static void efreet_mime_icon_entry_add(const char *mime, + const char *icon, + const char *theme, + unsigned int size); +static const char *efreet_mime_icon_entry_find(const char *mime, + const char *theme, + unsigned int size); +static void efreet_mime_icons_debug(void); + +EAPI int +efreet_mime_init(void) +{ + if (++_efreet_mime_init_count != 1) + return _efreet_mime_init_count; + + if (!ecore_init()) + return --_efreet_mime_init_count; + + if (!ecore_file_init()) + goto shutdown_ecore; + + if (!efreet_init()) + goto shutdown_ecore_file; + + _efreet_mime_log_dom = eina_log_domain_register + ("efreet_mime", EFREET_DEFAULT_LOG_COLOR); + + if (_efreet_mime_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_mime."); + goto shutdown_efreet; + } + + efreet_mime_endianess = efreet_mime_endian_check(); + + monitors = eina_hash_string_superfast_new(EINA_FREE_CB(ecore_file_monitor_del)); + + efreet_mime_type_cache_clear(); + + if (!efreet_mime_init_files()) + goto unregister_log_domain; + + return _efreet_mime_init_count; + +unregister_log_domain: + eina_log_domain_unregister(_efreet_mime_log_dom); + _efreet_mime_log_dom = -1; +shutdown_efreet: + efreet_shutdown(); +shutdown_ecore_file: + ecore_file_shutdown(); +shutdown_ecore: + ecore_shutdown(); + + return --_efreet_mime_init_count; +} + +EAPI int +efreet_mime_shutdown(void) +{ + if (--_efreet_mime_init_count != 0) + return _efreet_mime_init_count; + + efreet_mime_icons_debug(); + + IF_RELEASE(_mime_inode_symlink); + IF_RELEASE(_mime_inode_fifo); + IF_RELEASE(_mime_inode_chardevice); + IF_RELEASE(_mime_inode_blockdevice); + IF_RELEASE(_mime_inode_socket); + IF_RELEASE(_mime_inode_mountpoint); + IF_RELEASE(_mime_inode_directory); + IF_RELEASE(_mime_application_x_executable); + IF_RELEASE(_mime_application_octet_stream); + IF_RELEASE(_mime_text_plain); + + IF_FREE_LIST(globs, efreet_mime_glob_free); + IF_FREE_LIST(magics, efreet_mime_magic_free); + IF_FREE_HASH(monitors); + IF_FREE_HASH(wild); + IF_FREE_HASH(mime_icons); + eina_log_domain_unregister(_efreet_mime_log_dom); + _efreet_mime_log_dom = -1; + efreet_shutdown(); + ecore_file_shutdown(); + ecore_shutdown(); + + return _efreet_mime_init_count; +} + +EAPI const char * +efreet_mime_type_get(const char *file) +{ + const char *type = NULL; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + if ((type = efreet_mime_special_check(file))) + return type; + + /* Check magics with priority > 80 */ + if ((type = efreet_mime_magic_check_priority(file, 0, 80))) + return type; + + /* Check globs */ + if ((type = efreet_mime_globs_type_get(file))) + return type; + + /* Check rest of magics */ + if ((type = efreet_mime_magic_check_priority(file, 80, 0))) + return type; + + return efreet_mime_fallback_check(file); +} + +EAPI const char * +efreet_mime_type_icon_get(const char *mime, const char *theme, unsigned int size) +{ + const char *icon = NULL; + char *data; + Eina_List *icons = NULL; + const char *env = NULL; + char *p = NULL, *pp = NULL, *ppp = NULL; + char buf[PATH_MAX]; + const char *cache; + + EINA_SAFETY_ON_NULL_RETURN_VAL(mime, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(theme, NULL); + + mime = eina_stringshare_add(mime); + theme = eina_stringshare_add(theme); + cache = efreet_mime_icon_entry_find(mime, theme, size); + if (cache) + { + eina_stringshare_del(mime); + eina_stringshare_del(theme); + return cache; + } + + /* Standard icon name */ + p = strdup(mime); + pp = p; + while (*pp) + { + if (*pp == '/') *pp = '-'; + pp++; + } + icons = eina_list_append(icons, p); + + /* Environment Based icon names */ + if ((env = efreet_desktop_environment_get())) + { + snprintf(buf, sizeof(buf), "%s-mime-%s", env, p); + icons = eina_list_append(icons, strdup(buf)); + + snprintf(buf, sizeof(buf), "%s-%s", env, p); + icons = eina_list_append(icons, strdup(buf)); + } + + /* Mime prefixed icon names */ + snprintf(buf, sizeof(buf), "mime-%s", p); + icons = eina_list_append(icons, strdup(buf)); + + /* Generic icons */ + pp = strdup(p); + while ((ppp = strrchr(pp, '-'))) + { + *ppp = '\0'; + + snprintf(buf, sizeof(buf), "%s-x-generic", pp); + icons = eina_list_append(icons, strdup(buf)); + + snprintf(buf, sizeof(buf), "%s-generic", pp); + icons = eina_list_append(icons, strdup(buf)); + + snprintf(buf, sizeof(buf), "%s", pp); + icons = eina_list_append(icons, strdup(buf)); + } + FREE(pp); + + /* Search for icons using list */ + icon = efreet_icon_list_find(theme, icons, size); + while (icons) + { + data = eina_list_data_get(icons); + free(data); + icons = eina_list_remove_list(icons, icons); + } + + efreet_mime_icon_entry_add(mime, eina_stringshare_add(icon), theme, size); + + return icon; +} + +EAPI void +efreet_mime_type_cache_clear(void) +{ + if (mime_icons) + { + eina_hash_free(mime_icons); + mime_icons_lru = NULL; + } + mime_icons = eina_hash_stringshared_new(EINA_FREE_CB(efreet_mime_icon_entry_head_free)); +} + +EAPI void +efreet_mime_type_cache_flush(void) +{ + efreet_mime_icons_flush(ecore_loop_time_get()); +} + + +EAPI const char * +efreet_mime_magic_type_get(const char *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + return efreet_mime_magic_check_priority(file, 0, 0); +} + +EAPI const char * +efreet_mime_globs_type_get(const char *file) +{ + Eina_List *l; + Efreet_Mime_Glob *g; + char *sl, *p; + const char *s; + char *ext, *mime; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + + /* Check in the extension hash for the type */ + ext = strchr(file, '.'); + if (ext) + { + sl = alloca(strlen(ext) + 1); + for (s = ext, p = sl; *s; s++, p++) *p = tolower(*s); + *p = 0; + p = sl; + while (p) + { + p++; + if (p && (mime = eina_hash_find(wild, p))) return mime; + p = strchr(p, '.'); + } + } + + /* Fallback to the other globs if not found */ + EINA_LIST_FOREACH(globs, l, g) + { + if (efreet_mime_glob_match(file, g->glob)) + return g->mime; + } + + ext = alloca(strlen(file) + 1); + for (s = file, p = ext; *s; s++, p++) *p = tolower(*s); + *p = 0; + EINA_LIST_FOREACH(globs, l, g) + { + if (efreet_mime_glob_case_match(ext, g->glob)) + return g->mime; + } + return NULL; +} + +EAPI const char * +efreet_mime_special_type_get(const char *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + return efreet_mime_special_check(file); +} + +EAPI const char * +efreet_mime_fallback_type_get(const char *file) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(file, NULL); + return efreet_mime_fallback_check(file); +} + +/** + * @internal + * @return Returns the endianess + * @brief Retreive the endianess of the machine + */ +static int +efreet_mime_endian_check(void) +{ + int test = 1; + return (*((char*)(&test))); +} + +/** + * @internal + * @param file File to monitor + * @return Returns no value. + * @brief Creates a new file monitor if we aren't already monitoring the + * given file + */ +static void +efreet_mime_monitor_add(const char *file) +{ + Ecore_File_Monitor *fm = NULL; + + /* if this is already in our hash then we're already monitoring so no + * reason to re-monitor */ + if (eina_hash_find(monitors, file)) + return; + + if ((fm = ecore_file_monitor_add(file, efreet_mime_cb_update_file, NULL))) + { + eina_hash_del(monitors, file, NULL); + eina_hash_add(monitors, file, fm); + } +} + +/** + * @internal + * @param datadirs List of XDG data dirs + * @param datahome Path to XDG data home directory + * @return Returns no value + * @brief Read all glob files in XDG data/home dirs. + * Also reads the /etc/mime.types file. + */ +static void +efreet_mime_load_globs(Eina_List *datadirs, const char *datahome) +{ + Eina_List *l; + char buf[4096]; + const char *datadir = NULL; + + IF_FREE_HASH(wild); + wild = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + while (globs) + { + efreet_mime_glob_free(eina_list_data_get(globs)); + globs = eina_list_remove_list(globs, globs); + } + + /* + * This is here for legacy reasons. It is mentioned briefly + * in the spec and seems to still be quite valid. It is + * loaded first so the globs files will override anything + * in here. + */ + efreet_mime_mime_types_load("/etc/mime.types"); + + datadir = datahome; + snprintf(buf, sizeof(buf), "%s/mime/globs", datadir); + efreet_mime_shared_mimeinfo_globs_load(buf); + + EINA_LIST_FOREACH(datadirs, l, datadir) + { + snprintf(buf, sizeof(buf), "%s/mime/globs", datadir); + efreet_mime_shared_mimeinfo_globs_load(buf); + } +} + +/** + * @internal + * @param datadirs List of XDG data dirs + * @param datahome Path to XDG data home directory + * @return Returns no value + * @brief Read all magic files in XDG data/home dirs. + */ +static void +efreet_mime_load_magics(Eina_List *datadirs, const char *datahome) +{ + Eina_List *l; + char buf[4096]; + const char *datadir = NULL; + + while (magics) + { + efreet_mime_magic_free(eina_list_data_get(magics)); + magics = eina_list_remove_list(magics, magics); + } + + datadir = datahome; + snprintf(buf, sizeof(buf), "%s/mime/magic", datadir); + efreet_mime_shared_mimeinfo_magic_load(buf); + + EINA_LIST_FOREACH(datadirs, l, datadir) + { + snprintf(buf, sizeof(buf), "%s/mime/magic", datadir); + efreet_mime_shared_mimeinfo_magic_load(buf); + } +} + +/** + * @internal + * @param data Data pointer passed to monitor_add + * @param monitor Ecore_File_Monitor associated with this event + * @param event The type of event + * @param path Path to the file that was updated + * @return Returns no value + * @brief Callback for all file monitors. Just reloads the appropriate + * list depending on which file changed. If it was a magic file + * only the magic list is updated. If it was a glob file or /etc/mime.types, + * the globs are updated. + */ +static void +efreet_mime_cb_update_file(void *data __UNUSED__, + Ecore_File_Monitor *monitor __UNUSED__, + Ecore_File_Event event __UNUSED__, + const char *path) +{ + Eina_List *datadirs = NULL; + const char *datahome = NULL; + + if (!(datahome = efreet_data_home_get())) + return; + + if (!(datadirs = efreet_data_dirs_get())) + return; + + if (strstr(path, "magic")) + efreet_mime_load_magics(datadirs, datahome); + else + efreet_mime_load_globs(datadirs, datahome); +} + +/** + * @internal + * @param datadirs List of XDG data dirs + * @param datahome Path to XDG data home directory + * @return Returns 1 on success, 0 on failure + * @brief Initializes globs, magics, and monitors lists. + */ +static int +efreet_mime_init_files(void) +{ + Eina_List *l; + Eina_List *datadirs = NULL; + char buf[PATH_MAX]; + const char *datahome, *datadir = NULL; + + if (!(datahome = efreet_data_home_get())) + return 0; + + if (!(datadirs = efreet_data_dirs_get())) + return 0; + + /* + * Add our file monitors + * We watch the directories so we can watch for new files + */ + datadir = datahome; + snprintf(buf, sizeof(buf), "%s/mime", datadir); + efreet_mime_monitor_add(buf); + + EINA_LIST_FOREACH(datadirs, l, datadir) + { + snprintf(buf, sizeof(buf), "%s/mime", datadir); + efreet_mime_monitor_add(buf); + } + efreet_mime_monitor_add("/etc/mime.types"); + + /* Load our mime information */ + efreet_mime_load_globs(datadirs, datahome); + efreet_mime_load_magics(datadirs, datahome); + + _mime_inode_symlink = eina_stringshare_add("inode/symlink"); + _mime_inode_fifo = eina_stringshare_add("inode/fifo"); + _mime_inode_chardevice = eina_stringshare_add("inode/chardevice"); + _mime_inode_blockdevice = eina_stringshare_add("inode/blockdevice"); + _mime_inode_socket = eina_stringshare_add("inode/socket"); + _mime_inode_mountpoint = eina_stringshare_add("inode/mountpoint"); + _mime_inode_directory = eina_stringshare_add("inode/directory"); + _mime_application_x_executable = eina_stringshare_add("application/x-executable"); + _mime_application_octet_stream = eina_stringshare_add("application/octet-stream"); + _mime_text_plain = eina_stringshare_add("text/plain"); + + return 1; +} + +/** + * @internal + * @param file File to examine + * @return Returns mime type if special file, else NULL + * @brief Returns a mime type based on the stat of a file. + * This is used first to catch directories and other special + * files. A NULL return doesn't necessarily mean failure, but + * can also mean the file is regular. + * @note Mapping of file types to mime types: + * Stat Macro File Type Mime Type + * S_IFREG regular NULL + * S_IFIFO named pipe (fifo) inode/fifo + * S_IFCHR character special inode/chardevice + * S_IFDIR directory inode/directory + * S_IFBLK block special inode/blockdevice + * S_IFLNK symbolic link inode/symlink + * S_IFSOCK socket inode/socket + * + * This function can also return inode/mount-point. + * This is calculated by comparing the st_dev of the directory + * against that of it's parent directory. If they differ it + * is considered a mount point. + */ +static const char * +efreet_mime_special_check(const char *file) +{ + struct stat s; + int path_len = 0; + + /* no link on Windows < Vista */ +#ifdef _WIN32 + if (!stat(file, &s)) +#else + if (!lstat(file, &s)) +#endif + { + if (S_ISREG(s.st_mode)) + return NULL; + +#ifndef _WIN32 + if (S_ISLNK(s.st_mode)) + return _mime_inode_symlink; +#endif + + if (S_ISFIFO(s.st_mode)) + return _mime_inode_fifo; + + if (S_ISCHR(s.st_mode)) + return _mime_inode_chardevice; + + if (S_ISBLK(s.st_mode)) + return _mime_inode_blockdevice; + +#ifndef _WIN32 + if (S_ISSOCK(s.st_mode)) + return _mime_inode_socket; +#endif + + if (S_ISDIR(s.st_mode)) + { + struct stat s2; + char parent[PATH_MAX]; + char path[PATH_MAX]; + + strncpy(path, file, PATH_MAX); + + path_len = strlen(file); + strncpy(parent, path, PATH_MAX); + + /* Kill any trailing slash */ + parent[--path_len] = '\0'; + + /* Truncate to last slash */ + while (parent[--path_len] != '/') parent[path_len] = '\0'; + +#ifdef _WIN32 + if (!stat(file, &s2)) +#else + if (!lstat(parent, &s2)) +#endif + { + if (s.st_dev != s2.st_dev) + return _mime_inode_mountpoint; + } + + return _mime_inode_directory; + } + + return NULL; + } + + return NULL; +} + +/** + * @internal + * @param file File to examine + * @return Returns mime type or NULL if the file doesn't exist + * @brief Returns text/plain if the file appears to contain text and + * returns application/octet-stream if it appears to be binary. + */ +static const char * +efreet_mime_fallback_check(const char *file) +{ + FILE *f = NULL; + char buf[32]; + int i; + + if (ecore_file_can_exec(file)) + return _mime_application_x_executable; + + if (!(f = fopen(file, "r"))) return NULL; + + i = fread(buf, 1, sizeof(buf), f); + fclose(f); + + if (i == 0) return _mime_application_octet_stream; + + /* + * Check for ASCII control characters in the first 32 bytes. + * Line Feeds, carriage returns, and tabs are ignored as they are + * quite common in text files in the first 32 chars. + */ + for (i -= 1; i >= 0; --i) + { + if ((buf[i] < 0x20) && + (buf[i] != '\n') && /* Line Feed */ + (buf[i] != '\r') && /* Carriage Return */ + (buf[i] != '\t')) /* Tab */ + return _mime_application_octet_stream; + } + + return _mime_text_plain; +} + +/** + * @internal + * @param glob Glob to search for + * @return Returns 1 on success, 0 on failure + * @brief Removes a glob from the list + */ +static int +efreet_mime_glob_remove(const char *glob) +{ + Efreet_Mime_Glob *mime = NULL; + + if ((mime = eina_list_search_unsorted(globs, EINA_COMPARE_CB(strcmp), glob))) + { + globs = eina_list_remove(globs, mime); + IF_RELEASE(mime->glob); + IF_RELEASE(mime->mime); + FREE(mime); + return 1; + } + + return 0; +} + +static inline const char * +efreet_eat_space(const char *head, const Eina_File_Line *ln, Eina_Bool not) +{ + if (not) + { + while (!isspace(*head) && (head < ln->end)) + head++; + } + else + { + while (isspace(*head) && (head < ln->end)) + head++; + } + + return head; +} + +/** + * @internal + * @param file mime.types file to load + * @return Returns no value + * @brief Loads values from a mime.types style file + * into the globs list. + * @note Format: + * application/msaccess mdb + * application/msword doc dot + */ +static void +efreet_mime_mime_types_load(const char *file) +{ + const Eina_File_Line *ln; + Eina_Iterator *it; + Eina_File *f; + const char *head_line; + const char *word_start; + const char *mimetype; + + f = eina_file_open(file, 0); + if (!f) return ; + + it = eina_file_map_lines(f); + if (it) + { + Eina_Strbuf *ext; + + ext = eina_strbuf_new(); + + EINA_ITERATOR_FOREACH(it, ln) + { + head_line = efreet_eat_space(ln->start, ln, EINA_FALSE); + if (head_line == ln->end) continue ; + + if (*head_line == '#') continue ; + + word_start = head_line; + head_line = efreet_eat_space(head_line, ln, EINA_TRUE); + + if (head_line == ln->end) continue ; + mimetype = eina_stringshare_add_length(word_start, head_line - word_start); + do + { + head_line = efreet_eat_space(head_line, ln, EINA_FALSE); + if (head_line == ln->end) break ; + + word_start = head_line; + head_line = efreet_eat_space(head_line, ln, EINA_TRUE); + + eina_strbuf_append_length(ext, word_start, head_line - word_start); + + eina_hash_del(wild, + eina_strbuf_string_get(ext), + NULL); + eina_hash_add(wild, + eina_strbuf_string_get(ext), + eina_stringshare_ref(mimetype)); + + eina_strbuf_reset(ext); + } + while (head_line < ln->end); + + eina_stringshare_del(mimetype); + } + + eina_strbuf_free(ext); + eina_iterator_free(it); + } + eina_file_close(f); +} + +/** + * @internal + * @param file globs file to load + * @return Returns no value + * @brief Loads values from a mime.types style file + * into the globs list. + * @note Format: + * text/vnd.wap.wml:*.wml + * application/x-7z-compressed:*.7z + * application/vnd.corel-draw:*.cdr + * text/spreadsheet:*.sylk + */ +static void +efreet_mime_shared_mimeinfo_globs_load(const char *file) +{ + FILE *f = NULL; + char buf[4096], mimetype[4096], ext[4096], *p, *pp; + Efreet_Mime_Glob *mime = NULL; + + f = fopen(file, "rb"); + if (!f) return; + + while (fgets(buf, sizeof(buf), f)) + { + p = buf; + while (isspace(*p) && (*p != 0) && (*p != '\n')) p++; + + if (*p == '#') continue; + if ((*p == '\n') || (*p == 0)) continue; + + pp = p; + while ((*p != ':') && (*p != 0) && (*p != '\n')) p++; + + if ((*p == '\n') || (*p == 0)) continue; + strncpy(mimetype, pp, (p - pp)); + mimetype[p - pp] = 0; + p++; + pp = ext; + + while ((*p != 0) && (*p != '\n')) + { + *pp = *p; + pp++; + p++; + } + + *pp = 0; + + if (ext[0] == '*' && ext[1] == '.') + { + eina_hash_del(wild, &(ext[2]), NULL); + eina_hash_add(wild, &(ext[2]), + (void*)eina_stringshare_add(mimetype)); + } + else + { + mime = NEW(Efreet_Mime_Glob, 1); + if (mime) + { + mime->mime = eina_stringshare_add(mimetype); + mime->glob = eina_stringshare_add(ext); + if ((!mime->mime) || (!mime->glob)) + { + IF_RELEASE(mime->mime); + IF_RELEASE(mime->glob); + FREE(mime); + } + else + { + efreet_mime_glob_remove(ext); + globs = eina_list_append(globs, mime); + } + } + } + } + + fclose(f); +} + +/** + * @internal + * @param in Number to count the digits + * @return Returns number of digits + * @brief Calculates and returns the number of digits + * in a number. + */ +static int +efreet_mime_count_digits(int in) +{ + int i = 1, j = in; + + if (j < 10) return 1; + while ((j /= 10) > 0) ++i; + + return i; +} + +/** + * @internal + * @param file File to parse + * @return Returns no value + * @brief Loads a magic file and adds information to magics list + */ +static void +efreet_mime_shared_mimeinfo_magic_load(const char *file) +{ + int fd = -1, size; + char *data = (void *)-1; + + if (!file) return; + + size = ecore_file_size(file); + if (size <= 0) return; + + fd = open(file, O_RDONLY); + if (fd == -1) return; + + /* let's make mmap safe and just get 0 pages for IO erro */ + eina_mmap_safety_enabled_set(EINA_TRUE); + + data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) + { + close(fd); + return; + } + + efreet_mime_shared_mimeinfo_magic_parse(data, size); + + munmap(data, size); + close(fd); +} + +/** + * @param data The data from the file + * @return Returns no value + * @brief Parses a magic file + * @note Format: + * + * ---------------------------------------------------------------------- + * | HEX | ASCII | + * ---------------------------------------------------------------------- + * |4D 49 4D 45 2D 4D 61 67 69 63 00 0A 5B 39 30 3A | MIME-Magic..[90: | + * |61 70 70 6C 69 63 61 74 69 6F 6E 2F 64 6F 63 62 | application/docb | + * |6F 6F 6B 2B 78 6D 6C 5D 0A 3E 30 3D 00 05 3C 3F | ook+xml].>0=..<? | + * |78 6D 6C 0A 31 3E 30 3D 00 19 2D 2F 2F 4F 41 53 | xml.1>0=..-//OAS | + * |49 53 2F 2F 44 54 44 20 44 6F 63 42 6F 6F 6B 20 | IS//DTD DocBook | + * |58 4D 4C 2B 31 30 31 0A 31 3E 30 3D 00 17 2D 2F | XML+101.1>0=..-/ | + * ---------------------------------------------------------------------- + * + * indent + * The nesting depth of the rule, corresponding to the number of '>' + * characters in the traditional file format. + * ">" start-offset + * The offset into the file to look for a match. + * "=" value + * Two bytes giving the (big-endian) length of the value, followed by the + * value itself. + * "&" mask + * The mask, which (if present) is exactly the same length as the value. + * "~" word-size + * On little-endian machines, the size of each group to byte-swap. + * "+" range-length + * The length of the region in the file to check. + * + * The indent, range-length, word-size and mask components are optional. + * If missing, indent defaults to 0, range-length to 1, the word-size to 1, + * and the mask to all 'one' bits. In our case, mask is null as it is + * quicker, uses less memory and will achieve the same exact effect. + */ +static void +efreet_mime_shared_mimeinfo_magic_parse(char *data, int size) +{ + Efreet_Mime_Magic *mime = NULL; + Efreet_Mime_Magic_Entry *entry = NULL; + char *ptr; + + ptr = data; + + /* make sure we're a magic file */ + if (!ptr || (size < 12) || strncmp(ptr, "MIME-Magic\0\n", 12)) + return; + + ptr += 12; + + for (; (ptr - data) < size; ) + { + if (*ptr == '[') + { + char *val, buf[512]; + + mime = NEW(Efreet_Mime_Magic, 1); + magics = eina_list_append(magics, mime); + + val = ++ptr; + while ((*val != ':')) val++; + memcpy(&buf, ptr, val - ptr); + buf[val - ptr] = '\0'; + + mime->priority = atoi(buf); + ptr = ++val; + + while ((*val != ']')) val++; + memcpy(&buf, ptr, val - ptr); + buf[val - ptr] = '\0'; + + mime->mime = eina_stringshare_add(buf); + ptr = ++val; + + while (*ptr != '\n') ptr++; + ptr++; + } + else + { + short tshort; + + if (!mime) continue; + if (!entry) + { + if (!(entry = NEW(Efreet_Mime_Magic_Entry, 1))) + { + IF_FREE_LIST(magics, efreet_mime_magic_free); + return; + } + + entry->indent = 0; + entry->offset = 0; + entry->value_len = 0; + entry->word_size = 1; + entry->range_len = 1; + entry->mask = NULL; + entry->value = NULL; + + mime->entries = eina_list_append(mime->entries, entry); + } + + switch(*ptr) + { + case '>': + ptr ++; + entry->offset = atoi(ptr); + ptr += efreet_mime_count_digits(entry->offset); + break; + + case '=': + ptr++; + + tshort = 0; + memcpy(&tshort, ptr, sizeof(short)); + entry->value_len = ntohs(tshort); + ptr += 2; + + entry->value = NEW(1, entry->value_len); + memcpy(entry->value, ptr, entry->value_len); + ptr += entry->value_len; + break; + + case '&': + ptr++; + entry->mask = NEW(1, entry->value_len); + memcpy(entry->mask, ptr, entry->value_len); + ptr += entry->value_len; + break; + + case '~': + ptr++; + entry->word_size = atoi(ptr); + if ((entry->word_size != 0) && (((entry->word_size != 1) + && (entry->word_size != 2) + && (entry->word_size != 4)) + || (entry->value_len % entry->word_size))) + { + /* Invalid, Destroy */ + FREE(entry->value); + FREE(entry->mask); + FREE(entry); + + while (*ptr != '\n') ptr++; + break; + } + + if (efreet_mime_endianess == EFREET_ENDIAN_LITTLE) + { + int j; + + for (j = 0; j < entry->value_len; j += entry->word_size) + { + if (entry->word_size == 2) + { + ((short*)entry->value)[j] = + ntohs(((short*)entry->value)[j]); + + if (entry->mask) + ((short*)entry->mask)[j] = + ntohs(((short*)entry->mask)[j]); + } + else if (entry->word_size == 4) + { + ((int*)entry->value)[j] = + ntohl(((int*)entry->value)[j]); + + if (entry->mask) + ((int*)entry->mask)[j] = + ntohl(((int*)entry->mask)[j]); + } + } + } + + ptr += efreet_mime_count_digits(entry->word_size); + break; + + case '+': + ptr++; + entry->range_len = atoi(ptr); + ptr += efreet_mime_count_digits(entry->range_len); + break; + + case '\n': + ptr++; + entry = NULL; + break; + + default: + if (isdigit(*ptr)) + { + entry->indent = atoi(ptr); + ptr += efreet_mime_count_digits(entry->indent); + } + break; + } + } + } +/* + if (entry) + { + IF_FREE(entry->value); + IF_FREE(entry->mask); + FREE(entry); + } + */ +} + +/** + * @internal + * @param file File to check + * @param start Start priority, if 0 start at beginning + * @param end End priority, should be less then start + * unless start + * @return Returns mime type for file if found, NULL if not + * @brief Applies magic rules to a file given a start and end priority + */ +static const char * +efreet_mime_magic_check_priority(const char *file, + unsigned int start, + unsigned int end) +{ + Efreet_Mime_Magic *m = NULL; + Efreet_Mime_Magic_Entry *e = NULL; + Eina_List *l, *ll; + FILE *f = NULL; + unsigned int i = 0, offset = 0,level = 0, match = 0, bytes_read = 0; + const char *last_mime = NULL; + char c, v, buf[EFREET_MIME_MAGIC_BUFFER_SIZE]; + + f = fopen(file, "rb"); + if (!f) return NULL; + + if (!magics) + { + fclose(f); + return NULL; + } + + if ((bytes_read = fread(buf, 1, sizeof(buf), f)) == 0) + { + fclose(f); + return NULL; + } + + EINA_LIST_FOREACH(magics, l, m) + { + if ((start != 0) && (m->priority > start)) + continue; + + if (m->priority < end) + break; + + EINA_LIST_FOREACH(m->entries, ll, e) + { + if ((level < e->indent) && !match) + continue; + + if ((level >= e->indent) && !match) + level = e->indent; + + else if ((level > e->indent) && match) + { + fclose(f); + return last_mime; + } + + for (offset = e->offset; offset < e->offset + e->range_len; offset++) + { + if (((offset + e->value_len) > bytes_read) && + (fseek(f, offset, SEEK_SET) == -1)) + break; + + match = 1; + for (i = 0; i < e->value_len; ++i) + { + if (offset + e->value_len > bytes_read) + c = fgetc(f); + else + c = buf[offset + i]; + + v = e->value[i]; + if (e->mask) v &= e->mask[i]; + + if (!(c == v)) + { + match = 0; + break; + } + } + + if (match) + { + level += 1; + last_mime = m->mime; + break; + } + } + } + + if (match) + { + fclose(f); + return last_mime; + } + } + fclose(f); + + return NULL; +} + +/** + * @internal + * @param data Data pointer that is being destroyed + * @return Returns no value + * @brief Callback for globs destroy + */ +static void +efreet_mime_glob_free(void *data) +{ + Efreet_Mime_Glob *m = data; + + IF_RELEASE(m->mime); + IF_RELEASE(m->glob); + IF_FREE(m); +} + +/** + * @internal + * @param data Data pointer that is being destroyed + * @return Returns no value + * @brief Callback for magics destroy + */ +static void +efreet_mime_magic_free(void *data) +{ + Efreet_Mime_Magic *m = data; + + IF_RELEASE(m->mime); + IF_FREE_LIST(m->entries, efreet_mime_magic_entry_free); + IF_FREE(m); +} + +/** + * @internal + * @param data Data pointer that is being destroyed + * @return Returns no value + * @brief Callback for magic entry destroy + */ +static void +efreet_mime_magic_entry_free(void *data) +{ + Efreet_Mime_Magic_Entry *e = data; + + IF_FREE(e->mask); + IF_FREE(e->value); + IF_FREE(e); +} + + +/** + * @internal + * @param str String (filename) to match + * @param glob Glob to match str to + * @return Returns 1 on success, 0 on failure + * @brief Compares str to glob, case sensitive + */ +static int +efreet_mime_glob_match(const char *str, const char *glob) +{ + if (!str || !glob) return 0; + if (glob[0] == 0) + { + if (str[0] == 0) return 1; + return 0; + } + if (!fnmatch(glob, str, 0)) return 1; + return 0; +} + +/** + * @internal + * @param str String (filename) to match + * @param glob Glob to match str to + * @return Returns 1 on success, 0 on failure + * @brief Compares str to glob, case insensitive (expects str already in lower case) + */ +static int +efreet_mime_glob_case_match(char *str, const char *glob) +{ + const char *p; + char *tglob, *tp; + + if (!str || !glob) return 0; + if (glob[0] == 0) + { + if (str[0] == 0) return 1; + return 0; + } + tglob = alloca(strlen(glob) + 1); + for (tp = tglob, p = glob; *p; p++, tp++) *tp = tolower(*p); + *tp = 0; + if (!fnmatch(str, tglob, 0)) return 1; + return 0; +} + +static void +efreet_mime_icons_flush(double now) +{ + Eina_Inlist *l; + static double old = 0; + int todo; + + if (now - old < EFREET_MIME_ICONS_FLUSH_TIMEOUT) + return; + old = now; + + todo = eina_hash_population(mime_icons) - EFREET_MIME_ICONS_MAX_POPULATION; + if (todo <= 0) + return; + + l = mime_icons_lru->last; /* mime_icons_lru is not NULL, since todo > 0 */ + for (; todo > 0; todo--) + { + Efreet_Mime_Icon_Entry_Head *entry = (Efreet_Mime_Icon_Entry_Head *)l; + Eina_Inlist *prev = l->prev; + + mime_icons_lru = eina_inlist_remove(mime_icons_lru, l); + eina_hash_del_by_key(mime_icons, entry->mime); + l = prev; + } + + efreet_mime_icons_debug(); +} + +static void +efreet_mime_icon_entry_free(Efreet_Mime_Icon_Entry *node) +{ + eina_stringshare_del(node->icon); + eina_stringshare_del(node->theme); + free(node); +} + +static void +efreet_mime_icon_entry_head_free(Efreet_Mime_Icon_Entry_Head *entry) +{ + while (entry->list) + { + Efreet_Mime_Icon_Entry *n = (Efreet_Mime_Icon_Entry *)entry->list; + entry->list = eina_inlist_remove(entry->list, entry->list); + efreet_mime_icon_entry_free(n); + } + + eina_stringshare_del(entry->mime); + free(entry); +} + +static Efreet_Mime_Icon_Entry * +efreet_mime_icon_entry_new(const char *icon, + const char *theme, + unsigned int size) +{ + Efreet_Mime_Icon_Entry *entry; + + entry = malloc(sizeof(*entry)); + if (!entry) + return NULL; + + entry->icon = icon; + entry->theme = theme; + entry->size = size; + + return entry; +} + +static void +efreet_mime_icon_entry_add(const char *mime, + const char *icon, + const char *theme, + unsigned int size) +{ + Efreet_Mime_Icon_Entry_Head *entry; + Efreet_Mime_Icon_Entry *n; + + n = efreet_mime_icon_entry_new(icon, theme, size); + if (!n) + return; + entry = eina_hash_find(mime_icons, mime); + + if (entry) + { + Eina_Inlist *l; + + l = EINA_INLIST_GET(n); + entry->list = eina_inlist_prepend(entry->list, l); + + l = EINA_INLIST_GET(entry); + mime_icons_lru = eina_inlist_promote(mime_icons_lru, l); + } + else + { + Eina_Inlist *l; + + entry = malloc(sizeof(*entry)); + if (!entry) + { + efreet_mime_icon_entry_free(n); + return; + } + + l = EINA_INLIST_GET(n); + entry->list = eina_inlist_prepend(NULL, l); + entry->mime = mime; + eina_hash_direct_add(mime_icons, mime, entry); + + l = EINA_INLIST_GET(entry); + mime_icons_lru = eina_inlist_prepend(mime_icons_lru, l); + } + + entry->timestamp = ecore_loop_time_get(); + efreet_mime_icons_flush(entry->timestamp); +} + +static const char * +efreet_mime_icon_entry_find(const char *mime, + const char *theme, + unsigned int size) +{ + Efreet_Mime_Icon_Entry_Head *entry; + Efreet_Mime_Icon_Entry *n; + + entry = eina_hash_find(mime_icons, mime); + if (!entry) + return NULL; + + EINA_INLIST_FOREACH(entry->list, n) + { + if ((n->theme == theme) && (n->size == size)) + { + Eina_Inlist *l; + + l = EINA_INLIST_GET(n); + if (entry->list != l) + entry->list = eina_inlist_promote(entry->list, l); + + l = EINA_INLIST_GET(entry); + if (mime_icons_lru != l) + mime_icons_lru = eina_inlist_promote(mime_icons_lru, l); + + entry->timestamp = ecore_loop_time_get(); + return n->icon; + } + } + + return NULL; +} + +#ifdef EFREET_MIME_ICONS_DEBUG +static void +efreet_mime_icons_debug(void) +{ + double now = ecore_loop_time_get(); + Efreet_Mime_Icon_Entry_Head *entry; + EINA_INLIST_FOREACH(mime_icons_lru, entry) + { + Efreet_Mime_Icon_Entry *n; + + if ((now > 0) && + (now - entry->timestamp >= EFREET_MIME_ICONS_EXPIRE_TIMEOUT)) + { + puts("*** FOLLOWING ENTRIES ARE AGED AND CAN BE EXPIRED ***"); + now = 0; + } + + DBG("mime-icon entry: '%s' last used: %s", + entry->mime, ctime(&entry->timestamp)); + + EINA_INLIST_FOREACH(entry->list, n) + DBG("\tsize: %3u theme: '%s' icon: '%s'", + n->theme, n->size, n->icon); + } +} +#else +static void +efreet_mime_icons_debug(void) +{ +} +#endif diff --git a/src/lib/efreet_private.h b/src/lib/efreet_private.h new file mode 100644 index 0000000..ac43c4a --- /dev/null +++ b/src/lib/efreet_private.h @@ -0,0 +1,227 @@ +#ifndef EFREET_PRIVATE_H +#define EFREET_PRIVATE_H + +#ifdef ENABLE_NLS +# include <libintl.h> +# define _(str) dgettext(PACKAGE, str) +#else +# define _(str) (str) +#endif + +/** + * @file efreet_private.h + * @brief Contains methods and defines that are private to the Efreet + * implementaion + * @addtogroup Efreet_Private Efreet_Private: Private methods and defines + * + * @{ + */ + +/** + * @def NEW(x, c) + * Allocate and zero out c structures of type x + */ +#define NEW(x, c) calloc(c, sizeof(x)) + +/** + * @def FREE(x) + * Free x and set to NULL + */ +#define FREE(x) do { free(x); x = NULL; } while (0) + +/** + * @def IF_FREE(x) + * If x is set, free x and set to NULL + */ +#define IF_FREE(x) do { if (x) FREE(x); } while (0) + +/** + * @def IF_RELEASE(x) + * If x is set, eina_stringshare_del x and set to NULL + */ +#define IF_RELEASE(x) do { \ + if (x) { \ + const char *__tmp; __tmp = (x); (x) = NULL; eina_stringshare_del(__tmp); \ + } \ + (x) = NULL; \ +} while (0) + +/** + * @def IF_FREE_LIST(x) + * If x is a valid pointer destroy x and set to NULL + */ +#define IF_FREE_LIST(list, free_cb) do { \ + void *_data; \ + EINA_LIST_FREE(list, _data) \ + free_cb(_data); \ + list = NULL; \ +} while (0) + +/** + * @def IF_FREE_HASH(x) + * If x is a valid pointer destroy x and set to NULL + */ +#define IF_FREE_HASH(x) do { \ + if (x) { \ + Eina_Hash *__tmp; __tmp = (x); (x) = NULL; eina_hash_free(__tmp); \ + } \ + (x) = NULL; \ +} while (0) + +/** + * @def IF_FREE_HASH_CB(x, cb) + * If x is a valid pointer destroy x with cb and set to NULL + */ +#define IF_FREE_HASH_CB(x, cb) do { \ + if (x) { \ + Eina_Hash *__tmp; __tmp = (x); (x) = NULL; efreet_hash_free(__tmp, cb); \ + } \ + (x) = NULL; \ +} while (0) + +#ifdef EFREET_DEFAULT_LOG_COLOR +#undef EFREET_DEFAULT_LOG_COLOR +#endif +#define EFREET_DEFAULT_LOG_COLOR "\033[36m" + +#ifndef EFREET_MODULE_LOG_DOM +#error "Need to define a log domain" +#endif + +/** + * macros that are used all around the code for message processing + * four macros are defined ERR, WRN, DGB, INF. + * EFREET_MODULE_LOG_DOM should be defined individually for each module + */ +#ifdef ERR +#undef ERR +#endif +#define ERR(...) EINA_LOG_DOM_ERR(EFREET_MODULE_LOG_DOM, __VA_ARGS__) +#ifdef DBG +#undef DBG +#endif +#define DBG(...) EINA_LOG_DOM_DBG(EFREET_MODULE_LOG_DOM, __VA_ARGS__) +#ifdef INF +#undef INF +#endif +#define INF(...) EINA_LOG_DOM_INFO(EFREET_MODULE_LOG_DOM, __VA_ARGS__) +#ifdef WRN +#undef WRN +#endif +#define WRN(...) EINA_LOG_DOM_WARN(EFREET_MODULE_LOG_DOM, __VA_ARGS__) + +typedef struct _Efreet_Cache_Icon Efreet_Cache_Icon; +typedef struct _Efreet_Cache_Icon_Element Efreet_Cache_Icon_Element; +typedef struct _Efreet_Cache_Fallback_Icon Efreet_Cache_Fallback_Icon; + +struct _Efreet_Cache_Icon +{ + const char *theme; + + Efreet_Cache_Icon_Element **icons; + unsigned int icons_count; +}; + +struct _Efreet_Cache_Icon_Element +{ + const char **paths; /* possible paths for icon */ + unsigned int paths_count; + + unsigned short type; /* size type of icon */ + + unsigned short normal; /* The size for this icon */ + unsigned short min; /* The minimum size for this icon */ + unsigned short max; /* The maximum size for this icon */ +}; + +struct _Efreet_Cache_Fallback_Icon +{ + const char *theme; + const char **icons; + unsigned int icons_count; +}; + +typedef struct _Efreet_Cache_Version Efreet_Cache_Version; +struct _Efreet_Cache_Version +{ + unsigned char major; + unsigned char minor; +}; + +typedef struct _Efreet_Cache_Hash Efreet_Cache_Hash; +struct _Efreet_Cache_Hash +{ + Eina_Hash *hash; +}; + +typedef struct _Efreet_Cache_Array_String Efreet_Cache_Array_String; +struct _Efreet_Cache_Array_String +{ + const char **array; + unsigned int array_count; +}; + +int efreet_base_init(void); +void efreet_base_shutdown(void); + +int efreet_cache_init(void); +void efreet_cache_shutdown(void); + +int efreet_icon_init(void); +void efreet_icon_shutdown(void); + +int efreet_menu_init(void); +void efreet_menu_shutdown(void); +EAPI Eina_List *efreet_default_dirs_get(const char *user_dir, + Eina_List *system_dirs, + const char *suffix); + +int efreet_ini_init(void); +void efreet_ini_shutdown(void); + +int efreet_desktop_init(void); +void efreet_desktop_shutdown(void); + +int efreet_util_init(void); +int efreet_util_shutdown(void); + +const char *efreet_home_dir_get(void); +void efreet_dirs_reset(void); + +const char *efreet_lang_get(void); +const char *efreet_lang_country_get(void); +const char *efreet_lang_modifier_get(void); + +size_t efreet_array_cat(char *buffer, size_t size, const char *strs[]); + +void efreet_cache_desktop_update(void); +void efreet_cache_desktop_close(void); +void efreet_cache_icon_update(void); + +Efreet_Desktop *efreet_cache_desktop_find(const char *file); +void efreet_cache_desktop_free(Efreet_Desktop *desktop); +void efreet_cache_desktop_add(Efreet_Desktop *desktop); +Efreet_Cache_Array_String *efreet_cache_desktop_dirs(void); + +Efreet_Cache_Icon *efreet_cache_icon_find(Efreet_Icon_Theme *theme, const char *icon); +Efreet_Cache_Fallback_Icon *efreet_cache_icon_fallback_find(const char *icon); +Efreet_Icon_Theme *efreet_cache_icon_theme_find(const char *theme); +Eina_List *efreet_cache_icon_theme_list(void); + +Efreet_Cache_Hash *efreet_cache_util_hash_string(const char *key); +Efreet_Cache_Hash *efreet_cache_util_hash_array_string(const char *key); +Efreet_Cache_Array_String *efreet_cache_util_names(const char *key); + +EAPI void efreet_cache_array_string_free(Efreet_Cache_Array_String *array); + +EAPI void efreet_hash_free(Eina_Hash *hash, Eina_Free_Cb free_cb); +EAPI void efreet_setowner(const char *path); +EAPI void efreet_fsetowner(int fd); + +EAPI extern int efreet_cache_update; + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_trash.c b/src/lib/efreet_trash.c new file mode 100644 index 0000000..27cc2b1 --- /dev/null +++ b/src/lib/efreet_trash.c @@ -0,0 +1,288 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <sys/stat.h> +#include <unistd.h> +#include <libgen.h> +#include <errno.h> + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_trash_log_dom +static int _efreet_trash_log_dom = -1; + +#include "Efreet.h" +#include "Efreet_Trash.h" +#include "efreet_private.h" + +static unsigned int _efreet_trash_init_count = 0; +static const char *efreet_trash_dir = NULL; + +#ifdef _WIN32 +# define getuid() GetCurrentProcessId() +#endif + +EAPI int +efreet_trash_init(void) +{ + if (++_efreet_trash_init_count != 1) + return _efreet_trash_init_count; + + if (!eina_init()) + return --_efreet_trash_init_count; + + _efreet_trash_log_dom = eina_log_domain_register + ("efreet_trash", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_trash_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_trash"); + eina_shutdown(); + return --_efreet_trash_init_count; + } + return _efreet_trash_init_count; +} + +EAPI int +efreet_trash_shutdown(void) +{ + if (--_efreet_trash_init_count != 0) + return _efreet_trash_init_count; + + IF_RELEASE(efreet_trash_dir); + eina_log_domain_unregister(_efreet_trash_log_dom); + _efreet_trash_log_dom = -1; + eina_shutdown(); + + return _efreet_trash_init_count; +} + +EAPI const char* +efreet_trash_dir_get(const char *file) +{ + char buf[PATH_MAX]; + struct stat s_dest; + struct stat s_src; + const char *trash_dir = NULL; + + if (file) + { + if (stat(efreet_data_home_get(), &s_dest) != 0) + return NULL; + + if (stat(file, &s_src) != 0) + return NULL; + } + + if (!file || s_src.st_dev == s_dest.st_dev) + { + if (efreet_trash_dir && ecore_file_exists(efreet_trash_dir)) + { + eina_stringshare_ref(efreet_trash_dir); + return efreet_trash_dir; + } + + snprintf(buf, sizeof(buf), "%s/Trash", efreet_data_home_get()); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + IF_RELEASE(efreet_trash_dir); + efreet_trash_dir = eina_stringshare_add(buf); + trash_dir = eina_stringshare_ref(efreet_trash_dir); + } + else + { + char *dir; + char path[PATH_MAX]; + + strncpy(buf, file, PATH_MAX); + buf[PATH_MAX - 1] = 0; + path[0] = 0; + + while (strlen(buf) > 1) + { + strncpy(path, buf, PATH_MAX); + dir = dirname(buf); + + if (stat(dir, &s_dest) == 0) + { + if (s_src.st_dev == s_dest.st_dev){ + + strncpy(buf, dir, PATH_MAX); + continue; + } + else + { + /* other device */ + break; + } + } + path[0] = 0; + break; + } + + if (path[0]) + { + snprintf(buf, sizeof(buf), "%s/.Trash-%d", path, getuid()); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + return NULL; + + trash_dir = eina_stringshare_add(buf); + } + } + if (trash_dir) + { + snprintf(buf, sizeof(buf), "%s/files", trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + { + eina_stringshare_del(trash_dir); + return NULL; + } + + snprintf(buf, sizeof(buf), "%s/info", trash_dir); + if (!ecore_file_exists(buf) && !ecore_file_mkpath(buf)) + { + eina_stringshare_del(trash_dir); + return NULL; + } + } + + return trash_dir; +} + +EAPI int +efreet_trash_delete_uri(Efreet_Uri *uri, int force_delete) +{ + char dest[PATH_MAX]; + char times[64]; + const char *fname; + const char *escaped; + const char *trash_dir; + int i = 1; + time_t now; + FILE *f; + + EINA_SAFETY_ON_NULL_RETURN_VAL(uri, 0); + EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, 0); + EINA_SAFETY_ON_FALSE_RETURN_VAL(ecore_file_can_write(uri->path), 0); + + fname = ecore_file_file_get(uri->path); + + trash_dir = efreet_trash_dir_get(uri->path); + if (!trash_dir) + { + ERR("EFREET TRASH ERROR: No trash directory."); + return 0; + } + snprintf(dest, sizeof(dest), "%s/files/%s", trash_dir, fname); + + /* search for a free filename */ + while (ecore_file_exists(dest) && (i < 100)) + snprintf(dest, sizeof(dest), "%s/files/%s$%d", + trash_dir, fname, i++); + + fname = ecore_file_file_get(dest); + + /* move file to trash dir */ + if (rename(uri->path, dest)) + { + if (errno == EXDEV) + { + if (!force_delete) + { + eina_stringshare_del(trash_dir); + return -1; + } + + if (!ecore_file_recursive_rm(uri->path)) + { + ERR("EFREET TRASH ERROR: Can't delete file."); + eina_stringshare_del(trash_dir); + return 0; + } + } + else + { + ERR("EFREET TRASH ERROR: Can't move file to trash."); + eina_stringshare_del(trash_dir); + return 0; + } + } + + /* create info file */ + snprintf(dest, sizeof(dest), "%s/info/%s.trashinfo", trash_dir, fname); + + if ((f = fopen(dest, "w"))) + { + fputs("[Trash Info]\n", f); + + fputs("Path=", f); + escaped = efreet_uri_encode(uri); + fputs(escaped + 7, f); // +7 == don't write 'file://' + IF_RELEASE(escaped); + + time(&now); + strftime(times, sizeof(times), "%Y-%m-%dT%H:%M:%S", localtime(&now)); + fputs("\nDeletionDate=", f); + fputs(times, f); + fputs("\n", f); + fclose(f); + } + else + { + ERR("EFREET TRASH ERROR: Can't create trash info file."); + return 0; + } + + return 1; +} + +EAPI int +efreet_trash_is_empty(void) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + + /* TODO Check also trash in other filesystems */ + return ecore_file_dir_is_empty(buf); +} + +EAPI int +efreet_trash_empty_trash(void) +{ + char buf[PATH_MAX]; + + snprintf(buf, sizeof(buf), "%s/info", efreet_trash_dir_get(NULL)); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + if (!ecore_file_recursive_rm(buf)) return 0; + ecore_file_mkdir(buf); + + /* TODO Empty also trash in other filesystems */ + return 1; +} + +EAPI Eina_List* +efreet_trash_ls(void) +{ + char *infofile; + char buf[PATH_MAX]; + Eina_List *files, *l; + + // NOTE THIS FUNCTION NOW IS NOT COMPLETE AS I DON'T NEED IT + // TODO read the name from the infofile instead of the filename + + snprintf(buf, sizeof(buf), "%s/files", efreet_trash_dir_get(NULL)); + files = ecore_file_ls(buf); + + if (eina_log_domain_level_check(_efreet_trash_log_dom, EINA_LOG_LEVEL_INFO)) + EINA_LIST_FOREACH(files, l, infofile) + INF("FILE: %s\n", infofile); + + return files; +} + diff --git a/src/lib/efreet_uri.c b/src/lib/efreet_uri.c new file mode 100644 index 0000000..20ebe39 --- /dev/null +++ b/src/lib/efreet_uri.c @@ -0,0 +1,119 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> + +#ifndef _POSIX_HOST_NAME_MAX +#define _POSIX_HOST_NAME_MAX 255 +#endif + +#ifdef HAVE_EVIL +# include <Evil.h> +#endif + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM /* no logging in this file */ + +#include "Efreet.h" +#include "efreet_private.h" + + +EAPI Efreet_Uri * +efreet_uri_decode(const char *full_uri) +{ + Efreet_Uri *uri; + const char *p; + char protocol[64], hostname[_POSIX_HOST_NAME_MAX], path[PATH_MAX]; + int i = 0; + + EINA_SAFETY_ON_NULL_RETURN_VAL(full_uri, NULL); + + /* An uri should be in the form <protocol>://<hostname>/<path> */ + if (!strstr(full_uri, "://")) return NULL; + + memset(protocol, 0, 64); + memset(hostname, 0, _POSIX_HOST_NAME_MAX); + memset(path, 0, PATH_MAX); + + /* parse protocol */ + p = full_uri; + for (i = 0; *p != ':' && *p != '\0' && i < 64; p++, i++) + protocol[i] = *p; + protocol[i] = '\0'; + + /* parse hostname */ + p += 3; + if (*p != '/') + { + for (i = 0; *p != '/' && *p != '\0' && i < _POSIX_HOST_NAME_MAX; p++, i++) + hostname[i] = *p; + hostname[i] = '\0'; + } + else + hostname[0] = '\0'; + + /* parse path */ + /* See http://www.faqs.org/rfcs/rfc1738.html for the escaped chars */ + for (i = 0; *p != '\0' && i < PATH_MAX; i++, p++) + { + if (*p == '%') + { + path[i] = *(++p); + path[i + 1] = *(++p); + path[i] = (char)strtol(&(path[i]), NULL, 16); + path[i + 1] = '\0'; + } + else + path[i] = *p; + } + + uri = NEW(Efreet_Uri, 1); + if (!uri) return NULL; + + uri->protocol = eina_stringshare_add(protocol); + uri->hostname = eina_stringshare_add(hostname); + uri->path = eina_stringshare_add(path); + + return uri; +} + +EAPI const char * +efreet_uri_encode(Efreet_Uri *uri) +{ + char dest[PATH_MAX * 3 + 4]; + const char *p; + int i; + + EINA_SAFETY_ON_NULL_RETURN_VAL(uri, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(uri->path, NULL); + EINA_SAFETY_ON_NULL_RETURN_VAL(uri->protocol, NULL); + + memset(dest, 0, PATH_MAX * 3 + 4); + snprintf(dest, strlen(uri->protocol) + 4, "%s://", uri->protocol); + + /* Most app doesn't handle the hostname in the uri so it's put to NULL */ + for (i = strlen(uri->protocol) + 3, p = uri->path; *p != '\0'; p++, i++) + { + if (isalnum(*p) || strchr("/$-_.+!*'()", *p)) + dest[i] = *p; + else + { + snprintf(&(dest[i]), 4, "%%%02X", (unsigned char) *p); + i += 2; + } + } + + return eina_stringshare_add(dest); +} + +EAPI void +efreet_uri_free(Efreet_Uri *uri) +{ + if (!uri) return; + + IF_RELEASE(uri->protocol); + IF_RELEASE(uri->path); + IF_RELEASE(uri->hostname); + FREE(uri); +} diff --git a/src/lib/efreet_uri.h b/src/lib/efreet_uri.h new file mode 100644 index 0000000..32aaeee --- /dev/null +++ b/src/lib/efreet_uri.h @@ -0,0 +1,62 @@ +#ifndef EFREET_URI_H +#define EFREET_URI_H + +/** + * @file efreet_uri.h + * @brief Contains the methods used to support the FDO URI specification. + * @addtogroup Efreet_Uri Efreet_Uri: The FDO URI Specification functions + * @{ + */ + + +/** + * Efreet_Uri + */ +typedef struct Efreet_Uri Efreet_Uri; + +/** + * Efreet_Uri + * @brief Contains a simple rappresentation of an uri. The string don't have + * special chars escaped. + */ +struct Efreet_Uri +{ + const char *protocol; /**< The protocol used (usually 'file')*/ + const char *hostname; /**< The name of the host if any, or NULL */ + const char *path; /**< The full file path whitout protocol nor host*/ +}; + + + +/** + * @param uri Create an URI string from an Efreet_Uri struct + * @return The string rapresentation of uri (ex: 'file:///home/my%20name') + * @brief Get the string rapresentation of the given uri struct escaping + * illegal caracters. Remember to free the string with eina_stringshare_del() + * when you don't need it anymore. + * @note The resulting string will contain the protocol and the path but not + * the hostname, as many apps doesn't handle it. + */ +EAPI const char *efreet_uri_encode(Efreet_Uri *uri); + +/** + * @param val a valid uri string to parse + * @return Return The corresponding Efreet_Uri structure. Or NULL on errors. + * @brief Read a single uri and return an Efreet_Uri struct. If there's no + * hostname in the uri then the hostname parameter will be NULL. All the uri + * escaped chars will be converted to normal. + */ +EAPI Efreet_Uri *efreet_uri_decode(const char *val); + +/** + * @param uri The uri to free + * @brief Free the given uri structure. + */ +EAPI void efreet_uri_free(Efreet_Uri *uri); + + +/** + * @} + */ + +#endif diff --git a/src/lib/efreet_utils.c b/src/lib/efreet_utils.c new file mode 100644 index 0000000..dab85ef --- /dev/null +++ b/src/lib/efreet_utils.c @@ -0,0 +1,488 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +/* TODO: add no_display check, as we might want only displayable items */ + +#undef alloca +#ifdef HAVE_ALLOCA_H +# include <alloca.h> +#elif defined __GNUC__ +# define alloca __builtin_alloca +#elif defined _AIX +# define alloca __alloca +#elif defined _MSC_VER +# include <malloc.h> +# define alloca _alloca +#else +# include <stddef.h> +# ifdef __cplusplus +extern "C" +# endif +void *alloca (size_t); +#endif + +#include <fnmatch.h> + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_utils_log_dom +static int _efreet_utils_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" + +static char *efreet_util_path_in_default(const char *section, const char *path); + +static int efreet_util_glob_match(const char *str, const char *glob); + +static Eina_List *efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir); + +static Efreet_Desktop *efreet_util_cache_find(const char *search, const char *what1, const char *what2); +static Eina_List *efreet_util_cache_list(const char *search, const char *what); +static Eina_List *efreet_util_cache_glob_list(const char *search, const char *what); + +static Eina_Hash *file_id_by_desktop_path = NULL; + +static int init = 0; + +int +efreet_util_init(void) +{ + if (init++) return init; + _efreet_utils_log_dom = eina_log_domain_register + ("efreet_util", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_utils_log_dom < 0) + { + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_util"); + return 0; + } + + file_id_by_desktop_path = eina_hash_string_superfast_new(EINA_FREE_CB(eina_stringshare_del)); + + return init; +} + +int +efreet_util_shutdown(void) +{ + if (--init) return init; + + eina_log_domain_unregister(_efreet_utils_log_dom); + _efreet_utils_log_dom = -1; + IF_FREE_HASH(file_id_by_desktop_path); + + return init; +} + +static char * +efreet_util_path_in_default(const char *section, const char *path) +{ + Eina_List *dirs; + char *ret = NULL; + char *dir; + + dirs = efreet_default_dirs_get(efreet_data_home_get(), efreet_data_dirs_get(), + section); + + EINA_LIST_FREE(dirs, dir) + { + if (!strncmp(path, dir, strlen(dir))) + ret = dir; + else + eina_stringshare_del(dir); + } + + return ret; +} + +EAPI const char * +efreet_util_path_to_file_id(const char *path) +{ + size_t len, len2; + char *tmp, *p; + char *base; + const char *file_id; + + EINA_SAFETY_ON_NULL_RETURN_VAL(path, NULL); + + file_id = eina_hash_find(file_id_by_desktop_path, path); + if (file_id) return file_id; + + base = efreet_util_path_in_default("applications", path); + if (!base) return NULL; + + len = strlen(base); + if (strlen(path) <= len) + { + eina_stringshare_del(base); + return NULL; + } + if (strncmp(path, base, len)) + { + eina_stringshare_del(base); + return NULL; + } + + len2 = strlen(path + len + 1) + 1; + tmp = alloca(len2); + memcpy(tmp, path + len + 1, len2); + p = tmp; + while (*p) + { + if (*p == '/') *p = '-'; + p++; + } + eina_stringshare_del(base); + file_id = eina_stringshare_add(tmp); + eina_hash_add(file_id_by_desktop_path, path, (void *)file_id); + return file_id; +} + +EAPI Eina_List * +efreet_util_desktop_mime_list(const char *mime) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(mime, NULL); + return efreet_util_cache_list("mime_types", mime); +} + +EAPI Efreet_Desktop * +efreet_util_desktop_wm_class_find(const char *wmname, const char *wmclass) +{ + EINA_SAFETY_ON_TRUE_RETURN_VAL((!wmname) && (!wmclass), NULL); + return efreet_util_cache_find("startup_wm_class", wmname, wmclass); +} + +EAPI Efreet_Desktop * +efreet_util_desktop_file_id_find(const char *file_id) +{ + Efreet_Cache_Hash *hash; + Efreet_Desktop *ret = NULL; + const char *str; + + EINA_SAFETY_ON_NULL_RETURN_VAL(file_id, NULL); + + hash = efreet_cache_util_hash_string("file_id"); + if (!hash) return NULL; + str = eina_hash_find(hash->hash, file_id); + if (str) + ret = efreet_desktop_get(str); + return ret; +} + +EAPI Efreet_Desktop * +efreet_util_desktop_exec_find(const char *exec) +{ + Efreet_Cache_Hash *hash = NULL; + Efreet_Desktop *ret = NULL; + Efreet_Cache_Array_String *names = NULL; + unsigned int i; + + EINA_SAFETY_ON_NULL_RETURN_VAL(exec, NULL); + + names = efreet_cache_util_names("exec_list"); + if (!names) return NULL; + for (i = 0; i < names->array_count; i++) + { + const char *file; + char *exe; + unsigned int j; + Efreet_Cache_Array_String *array; + + exe = ecore_file_app_exe_get(names->array[i]); + if (!exe) continue; + file = ecore_file_file_get(exe); + if (!file) continue; + if (strcmp(exec, exe) && strcmp(exec, file)) + { + free(exe); + continue; + } + free(exe); + + if (!hash) + hash = efreet_cache_util_hash_array_string("exec_hash"); + if (!hash) return NULL; + array = eina_hash_find(hash->hash, names->array[i]); + if (!array) continue; + for (j = 0; j < array->array_count; j++) + { + ret = efreet_desktop_get(array->array[j]); + if (ret) break; + } + if (ret) break; + } + return ret; +} + +EAPI Efreet_Desktop * +efreet_util_desktop_name_find(const char *name) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(name, NULL); + return efreet_util_cache_find("name", name, NULL); +} + +EAPI Efreet_Desktop * +efreet_util_desktop_generic_name_find(const char *generic_name) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(generic_name, NULL); + return efreet_util_cache_find("generic_name", generic_name, NULL); +} + +EAPI Eina_List * +efreet_util_desktop_name_glob_list(const char *glob) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL); + return efreet_util_cache_glob_list("name", glob); +} + +EAPI Eina_List * +efreet_util_desktop_exec_glob_list(const char *glob) +{ + Efreet_Cache_Hash *hash = NULL; + Eina_List *ret = NULL; + Efreet_Cache_Array_String *names = NULL; + unsigned int i; + + EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL); + + if (!strcmp(glob, "*")) + glob = NULL; + + names = efreet_cache_util_names("exec_list"); + if (!names) return NULL; + for (i = 0; i < names->array_count; i++) + { + Efreet_Cache_Array_String *array; + unsigned int j; + char *exe; + Efreet_Desktop *desk; + + exe = ecore_file_app_exe_get(names->array[i]); + if (!exe) continue; + if (glob && !efreet_util_glob_match(exe, glob)) + { + free(exe); + continue; + } + free(exe); + + if (!hash) + hash = efreet_cache_util_hash_array_string("exec_hash"); + if (!hash) return NULL; + + array = eina_hash_find(hash->hash, names->array[i]); + if (!array) continue; + for (j = 0; j < array->array_count; j++) + { + desk = efreet_desktop_get(array->array[j]); + if (desk) + ret = eina_list_append(ret, desk); + } + } + return ret; +} + +EAPI Eina_List * +efreet_util_desktop_generic_name_glob_list(const char *glob) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL); + return efreet_util_cache_glob_list("generic_name", glob); +} + +EAPI Eina_List * +efreet_util_desktop_comment_glob_list(const char *glob) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(glob, NULL); + return efreet_util_cache_glob_list("comment", glob); +} + +EAPI Eina_List * +efreet_util_desktop_categories_list(void) +{ + Efreet_Cache_Array_String *array; + Eina_List *ret = NULL; + unsigned int i; + + array = efreet_cache_util_names("categories_list"); + if (!array) return NULL; + for (i = 0; i < array->array_count; i++) + ret = eina_list_append(ret, array->array[i]); + return ret; +} + +EAPI Eina_List * +efreet_util_desktop_category_list(const char *category) +{ + EINA_SAFETY_ON_NULL_RETURN_VAL(category, NULL); + return efreet_util_cache_list("categories", category); +} + +static int +efreet_util_glob_match(const char *str, const char *glob) +{ + if (!str || !glob) + return 0; + if (glob[0] == '\0') + { + if (str[0] == '\0') return 1; + return 0; + } + if (!strcmp(glob, "*")) return 1; + if (!fnmatch(glob, str, 0)) return 1; + return 0; +} + +EAPI Eina_List * +efreet_util_menus_find(void) +{ + Eina_List *menus = NULL; + Eina_List *dirs, *l; + const char *dir; + + menus = efreet_util_menus_find_helper(menus, efreet_config_home_get()); + + dirs = efreet_config_dirs_get(); + EINA_LIST_FOREACH(dirs, l, dir) + menus = efreet_util_menus_find_helper(menus, dir); + + return menus; +} + +static Eina_List * +efreet_util_menus_find_helper(Eina_List *menus, const char *config_dir) +{ + Eina_Iterator *it; + Eina_File_Direct_Info *info; + char dbuf[PATH_MAX]; + + snprintf(dbuf, sizeof(dbuf), "%s/menus", config_dir); + it = eina_file_direct_ls(dbuf); + if (!it) return menus; + EINA_ITERATOR_FOREACH(it, info) + { + const char *exten; + exten = strrchr(info->path + info->name_start, '.'); + if (!exten) continue; + if (strcmp(".menu", exten)) continue; + + if (ecore_file_is_dir(info->path)) continue; + + menus = eina_list_append(menus, strdup(info->path)); + } + eina_iterator_free(it); + return menus; +} + +static Efreet_Desktop * +efreet_util_cache_find(const char *search, const char *what1, const char *what2) +{ + Efreet_Cache_Hash *hash; + Efreet_Desktop *ret = NULL; + Efreet_Cache_Array_String *array = NULL; + char key[256]; + + if ((!what1) && (!what2)) return NULL; + + snprintf(key, sizeof(key), "%s_hash", search); + hash = efreet_cache_util_hash_array_string(key); + if (!hash) return NULL; + if (what1) + array = eina_hash_find(hash->hash, what1); + if (!array && what2) array = eina_hash_find(hash->hash, what2); + if (array) + { + unsigned int i; + + for (i = 0; i < array->array_count; i++) + { + ret = efreet_desktop_get(array->array[i]); + if (ret) break; + } + } + return ret; +} + +static Eina_List * +efreet_util_cache_list(const char *search, const char *what) +{ + Efreet_Cache_Hash *hash; + Efreet_Cache_Array_String *array; + Eina_List *ret = NULL; + char key[256]; + + if (!what) return NULL; + + snprintf(key, sizeof(key), "%s_hash", search); + hash = efreet_cache_util_hash_array_string(key); + if (!hash) return NULL; + array = eina_hash_find(hash->hash, what); + if (array) + { + unsigned int i; + Efreet_Desktop *desk; + + for (i = 0; i < array->array_count; i++) + { + desk = efreet_desktop_get(array->array[i]); + if (desk) + ret = eina_list_append(ret, desk); + } + } + return ret; +} + +static Eina_List * +efreet_util_cache_glob_list(const char *search, const char *what) +{ + Efreet_Cache_Hash *hash = NULL; + Eina_List *ret = NULL; + Efreet_Cache_Array_String *names = NULL; + char key[256]; + unsigned int i; + + if (!what) return NULL; + if (!strcmp(what, "*")) + what = NULL; + + snprintf(key, sizeof(key), "%s_list", search); + names = efreet_cache_util_names(key); + if (!names) return NULL; + for (i = 0; i < names->array_count; i++) + { + Efreet_Cache_Array_String *array; + unsigned int j; + Efreet_Desktop *desk; + + if (what && !efreet_util_glob_match(names->array[i], what)) continue; + + if (!hash) + { + snprintf(key, sizeof(key), "%s_hash", search); + hash = efreet_cache_util_hash_array_string(key); + } + if (!hash) return NULL; + + array = eina_hash_find(hash->hash, names->array[i]); + if (!array) continue; + for (j = 0; j < array->array_count; j++) + { + desk = efreet_desktop_get(array->array[j]); + if (desk) + ret = eina_list_append(ret, desk); + } + } + return ret; +} + +/* + * Needs EAPI because of helper binaries + */ +EAPI void +efreet_hash_free(Eina_Hash *hash, Eina_Free_Cb free_cb) +{ + eina_hash_free_cb_set(hash, free_cb); + eina_hash_free(hash); +} + diff --git a/src/lib/efreet_utils.h b/src/lib/efreet_utils.h new file mode 100644 index 0000000..6a5e69e --- /dev/null +++ b/src/lib/efreet_utils.h @@ -0,0 +1,157 @@ +#ifndef EFREET_UTILS_H +#define EFREET_UTILS_H + +/** + * @file efreet_utils.h + * @brief Contains utility functions to ease usage of Efreet. + * FDO desktop entry specificiation. + * @addtogroup Efreet_Utils Efreet utilities for FDO + * + * @{ + */ + + +/** + * Returns the fdo file id for a given path. If the file isn't inside + * a default fdo path it will return NULL. + * + * @param path The path to find the file id for + * + * @return File id for path or NULL + */ +EAPI const char *efreet_util_path_to_file_id(const char *path); + + +/** + * Find all desktops for a given mime type + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param mime the mime type + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_mime_list(const char *mime); + + +/** + * Find all desktops for a given wm class + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param wmname the wm name + * @param wmclass the wm class + * @return a list of desktops + */ +EAPI Efreet_Desktop *efreet_util_desktop_wm_class_find(const char *wmname, const char *wmclass); + +/** + * Find a desktop by file id + * + * return value must be freed by efreet_desktop_free + * + * @param file_id the file id + * @return a desktop + */ +EAPI Efreet_Desktop *efreet_util_desktop_file_id_find(const char *file_id); + +/** + * Find a desktop by exec + * + * return value must be freed by efreet_desktop_free + * + * @param exec the exec name + * @return a desktop + */ +EAPI Efreet_Desktop *efreet_util_desktop_exec_find(const char *exec); + +/** + * Find a desktop by name + * + * return value must be freed by efreet_desktop_free + * + * @param name the name + * @return a desktop + */ +EAPI Efreet_Desktop *efreet_util_desktop_name_find(const char *name); + +/** + * Find a desktop by generic name + * + * return value must be freed by efreet_desktop_free + * + * @param generic_name the generic name + * @return a desktop + */ +EAPI Efreet_Desktop *efreet_util_desktop_generic_name_find(const char *generic_name); + + +/** + * Find all desktops where name matches a glob pattern + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param glob the pattern to match + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_name_glob_list(const char *glob); + +/** + * Find all desktops where exec matches a glob pattern + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param glob the pattern to match + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_exec_glob_list(const char *glob); + +/** + * Find all desktops where generic name matches a glob pattern + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param glob the pattern to match + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_generic_name_glob_list(const char *glob); + +/** + * Find all desktops where comment matches a glob pattern + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param glob the pattern to match + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_comment_glob_list(const char *glob); + + +/** + * Find all desktop categories + * This list must be freed using EINA_LIST_FREE + * + * @return an Eina_List of category names (const char *) + */ +EAPI Eina_List *efreet_util_desktop_categories_list(void); + +/** + * Find all desktops in a given category + * + * This list must be freed using EINA_LIST_FREE / efreet_desktop_free + * + * @param category the category name + * @return a list of desktops + */ +EAPI Eina_List *efreet_util_desktop_category_list(const char *category); + + +/** + * Returns a list of .menu files found in the various config dirs. + * @return An eina list of menu file paths (const char *). This must be freed with EINA_LIST_FREE. + */ +EAPI Eina_List *efreet_util_menus_find(void); + +/** + * @} + */ +#endif diff --git a/src/lib/efreet_xml.c b/src/lib/efreet_xml.c new file mode 100644 index 0000000..9767d75 --- /dev/null +++ b/src/lib/efreet_xml.c @@ -0,0 +1,609 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <ctype.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <sys/mman.h> + +#include <Ecore_File.h> + +/* define macros and variable for using the eina logging system */ +#define EFREET_MODULE_LOG_DOM _efreet_xml_log_dom +static int _efreet_xml_log_dom = -1; + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_xml.h" + +#if 0 +static void efreet_xml_dump(Efreet_Xml *xml, int level); +#endif + +static Efreet_Xml *efreet_xml_parse(char **data, int *size); +static int efreet_xml_tag_parse(char **data, int *size, const char **tag); +static void efreet_xml_attributes_parse(char **data, int *size, + Efreet_Xml_Attribute ***attributes); +static void efreet_xml_text_parse(char **data, int *size, const char **text); + +static int efreet_xml_tag_empty(char **data, int *size); +static int efreet_xml_tag_close(char **data, int *size, const char *tag); + +static void efreet_xml_cb_attribute_free(void *data); +static void efreet_xml_comment_skip(char **data, int *size); + +static int error = 0; + +static int _efreet_xml_init_count = 0; + +/** + * @internal + * @return Returns > 0 on success or 0 on failure + * @brief Initialize the XML parser subsystem + */ +int +efreet_xml_init(void) +{ + _efreet_xml_init_count++; + if (_efreet_xml_init_count > 1) return _efreet_xml_init_count; + _efreet_xml_log_dom = eina_log_domain_register + ("efreet_xml", EFREET_DEFAULT_LOG_COLOR); + if (_efreet_xml_log_dom < 0) + { + _efreet_xml_init_count--; + EINA_LOG_ERR("Efreet: Could not create a log domain for efreet_xml."); + return _efreet_xml_init_count; + } + return _efreet_xml_init_count; +} + +/** + * @internal + * @returns the number of initializations left for this system + * @brief Attempts to shut down the subsystem if nothing else is using it + */ +void +efreet_xml_shutdown(void) +{ + _efreet_xml_init_count--; + if (_efreet_xml_init_count > 0) return; + eina_log_domain_unregister(_efreet_xml_log_dom); + _efreet_xml_log_dom = -1; +} + +/** + * @internal + * @param file The file to parse + * @return Returns an Efreet_Xml structure for the given file @a file or + * NULL on failure + * @brief Parses the given file into an Efreet_Xml structure. + */ +Efreet_Xml * +efreet_xml_new(const char *file) +{ + Efreet_Xml *xml = NULL; + int size, fd = -1; + char *data = MAP_FAILED; + + if (!file) return NULL; + if (!ecore_file_exists(file)) return NULL; + + size = ecore_file_size(file); + if (size <= 0) goto efreet_error; + + fd = open(file, O_RDONLY); + if (fd == -1) goto efreet_error; + + /* let's make mmap safe and just get 0 pages for IO erro */ + eina_mmap_safety_enabled_set(EINA_TRUE); + + data = mmap(NULL, size, PROT_READ, MAP_SHARED, fd, 0); + if (data == MAP_FAILED) goto efreet_error; + + error = 0; + xml = efreet_xml_parse(&data, &size); + if (!xml || error) goto efreet_error; + + munmap(data, size); + close(fd); + return xml; + +efreet_error: + ERR("could not parse xml file"); + if (data != MAP_FAILED) munmap(data, size); + if (fd != -1) close(fd); + if (xml) efreet_xml_del(xml); + return NULL; +} + +/** + * @internal + * @param xml The Efree_Xml to free + * @return Returns no value + * @brief Frees up the given Efreet_Xml structure + */ +void +efreet_xml_del(Efreet_Xml *xml) +{ + IF_FREE_LIST(xml->children, efreet_xml_cb_attribute_free); + + if (xml->tag) eina_stringshare_del(xml->tag); + if (xml->attributes) + { + Efreet_Xml_Attribute **curr; + + curr = xml->attributes; + while (*curr) + { + eina_stringshare_del((*curr)->key); + eina_stringshare_del((*curr)->value); + + FREE(*curr); + curr++; + } + FREE(xml->attributes); + } + IF_RELEASE(xml->text); + FREE(xml); +} + +/** + * @param xml The xml struct to work with + * @param key The attribute key to look for + * @return Returns the value for the given key, or NULL if none found + * @brief Retrieves the value for the given attribute key + */ +const char * +efreet_xml_attribute_get(Efreet_Xml *xml, const char *key) +{ + Efreet_Xml_Attribute **curr; + + if (!xml || !key || !xml->attributes) return NULL; + + for (curr = xml->attributes; *curr; curr++) + { + if (!strcmp((*curr)->key, key)) + return (*curr)->value; + } + return NULL; +} + +static void +efreet_xml_cb_attribute_free(void *data) +{ + efreet_xml_del(data); +} + +#if 0 +static void +efreet_xml_dump(Efreet_Xml *xml, int level) +{ + int i; + + for (i = 0; i < level; i++) + printf("\t"); + printf("<%s", xml->tag); + if (xml->attributes) + { + Efreet_Xml_Attribute **curr; + for (curr = xml->attributes; *curr; curr++) + printf(" %s=\"%s\"", (*curr)->key, (*curr)->value); + } + + if (xml->children) + { + Efreet_Xml *child; + Eina_List *l; + + printf(">"); + + EINA_LIST_FOREACH(xml->children, l, child) + efreet_xml_dump(child, level + 1); + + for (i = 0; i < level; i++) + printf("\t"); + printf("</%s>", xml->tag); + } + else if (xml->text) + printf(">%s</%s>\n", xml->text, xml->tag); + else + printf("/>\n"); +} +#endif + +static Efreet_Xml * +efreet_xml_parse(char **data, int *size) +{ + Efreet_Xml *xml, *sub_xml; + const char *tag = NULL; + + /* parse this tag */ + if (!efreet_xml_tag_parse(data, size, &(tag))) return NULL; + xml = NEW(Efreet_Xml, 1); + if (!xml) + { + eina_stringshare_del(tag); + return NULL; + } + + xml->children = NULL; + + xml->tag = tag; + efreet_xml_attributes_parse(data, size, &(xml->attributes)); + + /* Check wether element is empty */ + if (efreet_xml_tag_empty(data, size)) return xml; + efreet_xml_text_parse(data, size, &(xml->text)); + + /* Check wether element is closed */ + if (efreet_xml_tag_close(data, size, xml->tag)) return xml; + + while ((sub_xml = efreet_xml_parse(data, size))) + xml->children = eina_list_append(xml->children, sub_xml); + + efreet_xml_tag_close(data, size, xml->tag); + + return xml; +} + +static int +efreet_xml_tag_parse(char **data, int *size, const char **tag) +{ + const char *start = NULL, *end = NULL; + char buf[256]; + int buf_size; + + /* Search for tag */ + while (*size > 1) + { + /* Check for tag start */ + if (**data == '<') + { + /* Check for end tag */ + if (*(*data + 1) == '/') return 0; + + /* skip comments */ + if (*size > 3 && *(*data + 1) == '!' && *(*data + 2) == '-' && *(*data + 3) == '-') + { + (*data) += 3; + (*size) -= 3; + efreet_xml_comment_skip(data, size); + continue; + } + + /* Check for xml directives (and ignore them) */ + else if ((*(*data + 1) != '!') && (*(*data + 1) != '?')) + { + (*size)--; + (*data)++; + start = *data; + break; + } + } + (*size)--; + (*data)++; + } + + if (!start) + { + ERR("missing start tag"); + error = 1; + return 0; + } + + while (*size > 0) + { + if (!isalpha(**data)) + { + end = *data; + break; + } + (*size)--; + (*data)++; + } + + if (!end) + { + ERR("no end of tag"); + error = 1; + return 0; + } + + buf_size = end - start + 1; + if (buf_size <= 1) + { + ERR("no tag name"); + error = 1; + return 0; + } + + if (buf_size > 256) buf_size = 256; + memcpy(buf, start, buf_size - 1); + buf[buf_size - 1] = '\0'; + *tag = eina_stringshare_add(buf); + + return 1; +} + +static void +efreet_xml_attributes_parse(char **data, int *size, + Efreet_Xml_Attribute ***attributes) +{ + Efreet_Xml_Attribute attr[10]; + int i, count = 0; + + while (*size > 0) + { + if (**data == '>') + { + (*size)++; + (*data)--; + break; + } + else if ((count < 10) && (isalpha(**data))) + { + /* beginning of key */ + const char *start = NULL, *end = NULL; + char buf[256]; + int buf_size; + + attr[count].key = NULL; + attr[count].value = NULL; + + start = *data; + while ((*size > 0) && ((isalpha(**data)) || (**data == '_'))) + { + (*size)--; + (*data)++; + } + + end = *data; + buf_size = end - start + 1; + if (buf_size <= 1) + { + ERR("zero length key"); + goto efreet_error; + } + + if (buf_size > 256) buf_size = 256; + memcpy(buf, start, buf_size - 1); + buf[buf_size - 1] = '\0'; + attr[count].key = eina_stringshare_add(buf); + + /* search for '=', key/value seperator */ + start = NULL; + while (*size > 0) + { + if (**data == '=') + { + start = *data; + break; + } + (*size)--; + (*data)++; + } + + if (!start) + { + ERR("missing value for attribute!"); + goto efreet_error; + } + + /* search for '"', beginning of value */ + start = NULL; + while (*size > 0) + { + if (**data == '"') + { + start = *data; + break; + } + (*size)--; + (*data)++; + } + + if (!start) + { + ERR("erroneous value for attribute!"); + goto efreet_error; + } + + /* skip '"' */ + start++; + (*size)--; + (*data)++; + + /* search for '"', end of value */ + end = NULL; + while (*size > 0) + { + if (**data == '"') + { + end = *data; + break; + } + (*size)--; + (*data)++; + } + + if (!end) + { + ERR("erroneous value for attribute!"); + goto efreet_error; + } + + buf_size = end - start + 1; + if (buf_size <= 1) + { + ERR("zero length value"); + goto efreet_error; + } + + if (buf_size > 256) buf_size = 256; + memcpy(buf, start, buf_size - 1); + buf[buf_size - 1] = '\0'; + attr[count].value = eina_stringshare_add(buf); + + count++; + } + + (*size)--; + (*data)++; + } + + *attributes = NEW(Efreet_Xml_Attribute *, count + 1); + if (!*attributes) goto efreet_error; + for (i = 0; i < count; i++) + { + (*attributes)[i] = malloc(sizeof(Efreet_Xml_Attribute)); + (*attributes)[i]->key = attr[i].key; + (*attributes)[i]->value = attr[i].value; + } + return; + +efreet_error: + while (count >= 0) + { + if (attr[count].key) eina_stringshare_del(attr[count].key); + if (attr[count].value) eina_stringshare_del(attr[count].value); + count--; + } + error = 1; + return; +} + +static void +efreet_xml_text_parse(char **data, int *size, const char **text) +{ + const char *start = NULL, *end = NULL; + int buf_size; + + /* skip leading whitespace */ + while (*size > 0) + { + if (!isspace(**data)) + { + start = *data; + break; + } + (*size)--; + (*data)++; + } + + if (!start) return; + + /* find next tag */ + while (*size > 0) + { + if (**data == '<') + { + end = *data; + break; + } + (*size)--; + (*data)++; + } + if (!end) return; + + /* skip trailing whitespace */ + while (isspace(*(end - 1))) end--; + + /* copy text */ + buf_size = end - start + 1; + if (buf_size <= 1) return; + + *text = eina_stringshare_add_length(start, buf_size - 1); +} + +static int +efreet_xml_tag_empty(char **data, int *size) +{ + while (*size > 1) + { + if (**data == '/') + { + (*size)--; + (*data)++; + if (**data == '>') + { + (*size)--; + (*data)++; + return 1; + } + } + else if (**data == '>') + { + (*size)--; + (*data)++; + return 0; + } + (*size)--; + (*data)++; + } + ERR("missing end of tag"); + error = 1; + + return 1; +} + +static int +efreet_xml_tag_close(char **data, int *size, const char *tag) +{ + while (*size > 1) + { + if (**data == '<') + { + if (*(*data + 1) == '/') + { + (*size) -= 2; + (*data) += 2; + if ((int)strlen(tag) > *size) + { + ERR("wrong end tag"); + error = 1; + return 1; + } + else + { + char *tmp; + tmp = *data; + while ((*tag) && (*tmp == *tag)) + { + tmp++; + tag++; + } + + if (*tag) + { + ERR("wrong end tag"); + error = 1; + return 1; + } + } + return 1; + } + else return 0; + } + (*size)--; + (*data)++; + } + return 0; +} + +static void +efreet_xml_comment_skip(char **data, int *size) +{ + while (*size > 2) + { + if (**data == '-' && *(*data + 1) == '-' && *(*data + 2) == '>') + { + (*data) += 3; + (*size) -= 3; + return; + } + (*data)++; + (*size)--; + } +} diff --git a/src/lib/efreet_xml.h b/src/lib/efreet_xml.h new file mode 100644 index 0000000..77473cc --- /dev/null +++ b/src/lib/efreet_xml.h @@ -0,0 +1,59 @@ +#ifndef EFREET_XML_H +#define EFREET_XML_H + +/** + * @internal + * @file efreet_xml.h + * @brief A simple and fast XML parser + * @addtogroup Efreet_Xml Efreet_Xml: An XML parser + * + * @{ + */ + +/** + * Efreet_Xml_Attributes + */ +typedef struct Efreet_Xml_Attribute Efreet_Xml_Attribute; + +/** + * Efreet_Xml_Attributes + * @brief Contains information about a given XML attribute + */ +struct Efreet_Xml_Attribute +{ + const char *key; /**< The attribute key */ + const char *value; /**< The attribute value */ +}; + +/** + * Efreet_Xml + */ +typedef struct Efreet_Xml Efreet_Xml; + +/** + * Efreet_Xml + * @brief Contains the XML tree for a given XML document + */ +struct Efreet_Xml +{ + const char *text; /**< The XML text for this node */ + const char *tag; /**< The tag for this node */ + + Efreet_Xml_Attribute **attributes; /**< The attributes for this node */ + + Eina_List *children; /**< Child nodes */ +}; + +int efreet_xml_init(void); +void efreet_xml_shutdown(void); + +Efreet_Xml *efreet_xml_new(const char *file); +void efreet_xml_del(Efreet_Xml *xml); + +const char *efreet_xml_attribute_get(Efreet_Xml *xml, const char *key); + +/** + * @} + */ + +#endif diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am new file mode 100644 index 0000000..13c1274 --- /dev/null +++ b/src/tests/Makefile.am @@ -0,0 +1,66 @@ + +SUBDIRS = data compare + +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +-DPKG_DATA_DIR=\"$(pkgdatadir)\" \ +@EFREET_CFLAGS@ + +bin_PROGRAMS = \ +efreet_test \ +efreet_spec_test \ +efreet_cache_test \ +efreet_icon_cache_dump + +efreet_test_LDADD = $(top_builddir)/src/lib/libefreet.la \ + $(top_builddir)/src/lib/libefreet_mime.la \ + @EFREET_LIBS@ +efreet_test_SOURCES = \ +ef_test.h \ +ef_data_dirs.c \ +ef_icon_theme.c \ +ef_ini.c \ +ef_utils.c \ +ef_desktop.c \ +ef_menu.c \ +ef_mime.c \ +main.c + +if DEFAULT_VISIBILITY +efreet_test_SOURCES += \ +ef_locale.c +endif + +efreet_spec_test_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_spec_test_SOURCES = \ +efreet_spec_test.c + +efreet_cache_test_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_cache_test_SOURCES = \ +ef_cache.c + +if EFL_ENABLE_TESTS + +check_PROGRAMS = efreet_suite + +efreet_suite_SOURCES = \ +efreet_suite.c \ +efreet_test_efreet.c \ +efreet_test_efreet_cache.c + +efreet_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ + +endif + +efreet_icon_cache_dump_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_icon_cache_dump_SOURCES = \ +efreet_icon_cache_dump.c diff --git a/src/tests/Makefile.in b/src/tests/Makefile.in new file mode 100644 index 0000000..b57b113 --- /dev/null +++ b/src/tests/Makefile.in @@ -0,0 +1,847 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = efreet_test$(EXEEXT) efreet_spec_test$(EXEEXT) \ + efreet_cache_test$(EXEEXT) efreet_icon_cache_dump$(EXEEXT) +@DEFAULT_VISIBILITY_TRUE@am__append_1 = \ +@DEFAULT_VISIBILITY_TRUE@ef_locale.c + +@EFL_ENABLE_TESTS_TRUE@check_PROGRAMS = efreet_suite$(EXEEXT) +subdir = src/tests +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_efreet_cache_test_OBJECTS = ef_cache.$(OBJEXT) +efreet_cache_test_OBJECTS = $(am_efreet_cache_test_OBJECTS) +efreet_cache_test_DEPENDENCIES = $(top_builddir)/src/lib/libefreet.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_efreet_icon_cache_dump_OBJECTS = efreet_icon_cache_dump.$(OBJEXT) +efreet_icon_cache_dump_OBJECTS = $(am_efreet_icon_cache_dump_OBJECTS) +efreet_icon_cache_dump_DEPENDENCIES = \ + $(top_builddir)/src/lib/libefreet.la +am_efreet_spec_test_OBJECTS = efreet_spec_test.$(OBJEXT) +efreet_spec_test_OBJECTS = $(am_efreet_spec_test_OBJECTS) +efreet_spec_test_DEPENDENCIES = $(top_builddir)/src/lib/libefreet.la +am__efreet_suite_SOURCES_DIST = efreet_suite.c efreet_test_efreet.c \ + efreet_test_efreet_cache.c +@EFL_ENABLE_TESTS_TRUE@am_efreet_suite_OBJECTS = \ +@EFL_ENABLE_TESTS_TRUE@ efreet_suite.$(OBJEXT) \ +@EFL_ENABLE_TESTS_TRUE@ efreet_test_efreet.$(OBJEXT) \ +@EFL_ENABLE_TESTS_TRUE@ efreet_test_efreet_cache.$(OBJEXT) +efreet_suite_OBJECTS = $(am_efreet_suite_OBJECTS) +@EFL_ENABLE_TESTS_TRUE@efreet_suite_DEPENDENCIES = \ +@EFL_ENABLE_TESTS_TRUE@ $(top_builddir)/src/lib/libefreet.la +am__efreet_test_SOURCES_DIST = ef_test.h ef_data_dirs.c \ + ef_icon_theme.c ef_ini.c ef_utils.c ef_desktop.c ef_menu.c \ + ef_mime.c main.c ef_locale.c +@DEFAULT_VISIBILITY_TRUE@am__objects_1 = ef_locale.$(OBJEXT) +am_efreet_test_OBJECTS = ef_data_dirs.$(OBJEXT) \ + ef_icon_theme.$(OBJEXT) ef_ini.$(OBJEXT) ef_utils.$(OBJEXT) \ + ef_desktop.$(OBJEXT) ef_menu.$(OBJEXT) ef_mime.$(OBJEXT) \ + main.$(OBJEXT) $(am__objects_1) +efreet_test_OBJECTS = $(am_efreet_test_OBJECTS) +efreet_test_DEPENDENCIES = $(top_builddir)/src/lib/libefreet.la \ + $(top_builddir)/src/lib/libefreet_mime.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(efreet_cache_test_SOURCES) \ + $(efreet_icon_cache_dump_SOURCES) $(efreet_spec_test_SOURCES) \ + $(efreet_suite_SOURCES) $(efreet_test_SOURCES) +DIST_SOURCES = $(efreet_cache_test_SOURCES) \ + $(efreet_icon_cache_dump_SOURCES) $(efreet_spec_test_SOURCES) \ + $(am__efreet_suite_SOURCES_DIST) \ + $(am__efreet_test_SOURCES_DIST) +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +SUBDIRS = data compare +MAINTAINERCLEANFILES = Makefile.in +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +-DPACKAGE_BIN_DIR=\"$(bindir)\" \ +-DPACKAGE_LIB_DIR=\"$(libdir)\" \ +-DPACKAGE_DATA_DIR=\"$(datadir)\" \ +-DPKG_DATA_DIR=\"$(pkgdatadir)\" \ +@EFREET_CFLAGS@ + +efreet_test_LDADD = $(top_builddir)/src/lib/libefreet.la \ + $(top_builddir)/src/lib/libefreet_mime.la \ + @EFREET_LIBS@ + +efreet_test_SOURCES = ef_test.h ef_data_dirs.c ef_icon_theme.c \ + ef_ini.c ef_utils.c ef_desktop.c ef_menu.c ef_mime.c main.c \ + $(am__append_1) +efreet_spec_test_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_spec_test_SOURCES = \ +efreet_spec_test.c + +efreet_cache_test_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_cache_test_SOURCES = \ +ef_cache.c + +@EFL_ENABLE_TESTS_TRUE@efreet_suite_SOURCES = \ +@EFL_ENABLE_TESTS_TRUE@efreet_suite.c \ +@EFL_ENABLE_TESTS_TRUE@efreet_test_efreet.c \ +@EFL_ENABLE_TESTS_TRUE@efreet_test_efreet_cache.c + +@EFL_ENABLE_TESTS_TRUE@efreet_suite_LDADD = @CHECK_LIBS@ $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_icon_cache_dump_LDADD = \ +$(top_builddir)/src/lib/libefreet.la \ +@EFREET_LIBS@ + +efreet_icon_cache_dump_SOURCES = \ +efreet_icon_cache_dump.c + +all: all-recursive + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tests/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +efreet_cache_test$(EXEEXT): $(efreet_cache_test_OBJECTS) $(efreet_cache_test_DEPENDENCIES) + @rm -f efreet_cache_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_cache_test_OBJECTS) $(efreet_cache_test_LDADD) $(LIBS) +efreet_icon_cache_dump$(EXEEXT): $(efreet_icon_cache_dump_OBJECTS) $(efreet_icon_cache_dump_DEPENDENCIES) + @rm -f efreet_icon_cache_dump$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_icon_cache_dump_OBJECTS) $(efreet_icon_cache_dump_LDADD) $(LIBS) +efreet_spec_test$(EXEEXT): $(efreet_spec_test_OBJECTS) $(efreet_spec_test_DEPENDENCIES) + @rm -f efreet_spec_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_spec_test_OBJECTS) $(efreet_spec_test_LDADD) $(LIBS) +efreet_suite$(EXEEXT): $(efreet_suite_OBJECTS) $(efreet_suite_DEPENDENCIES) + @rm -f efreet_suite$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_suite_OBJECTS) $(efreet_suite_LDADD) $(LIBS) +efreet_test$(EXEEXT): $(efreet_test_OBJECTS) $(efreet_test_DEPENDENCIES) + @rm -f efreet_test$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_test_OBJECTS) $(efreet_test_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_data_dirs.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_desktop.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_icon_theme.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_ini.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_locale.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_menu.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_mime.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ef_utils.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_icon_cache_dump.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_spec_test.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_suite.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_test_efreet.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_test_efreet_cache.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/main.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) +check: check-recursive +all-am: Makefile $(PROGRAMS) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) check-am \ + ctags-recursive install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-binPROGRAMS \ + clean-checkPROGRAMS clean-generic clean-libtool ctags \ + ctags-recursive distclean distclean-compile distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-binPROGRAMS \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags tags-recursive uninstall uninstall-am \ + uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tests/compare/Makefile.am b/src/tests/compare/Makefile.am new file mode 100644 index 0000000..bb43591 --- /dev/null +++ b/src/tests/compare/Makefile.am @@ -0,0 +1,15 @@ +MAINTAINERCLEANFILES = Makefile.in + +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +@EFREET_CFLAGS@ + +bin_PROGRAMS = efreet_alloc efreet_menu_alloc + +efreet_menu_alloc_SOURCES = efreet_menu_alloc.c comp.h +efreet_menu_alloc_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ + +efreet_alloc_SOURCES = efreet_alloc.c comp.h +efreet_alloc_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ + diff --git a/src/tests/compare/Makefile.in b/src/tests/compare/Makefile.in new file mode 100644 index 0000000..f813d18 --- /dev/null +++ b/src/tests/compare/Makefile.in @@ -0,0 +1,598 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = efreet_alloc$(EXEEXT) efreet_menu_alloc$(EXEEXT) +subdir = src/tests/compare +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" +PROGRAMS = $(bin_PROGRAMS) +am_efreet_alloc_OBJECTS = efreet_alloc.$(OBJEXT) +efreet_alloc_OBJECTS = $(am_efreet_alloc_OBJECTS) +efreet_alloc_DEPENDENCIES = $(top_builddir)/src/lib/libefreet.la +AM_V_lt = $(am__v_lt_$(V)) +am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +am__v_lt_0 = --silent +am_efreet_menu_alloc_OBJECTS = efreet_menu_alloc.$(OBJEXT) +efreet_menu_alloc_OBJECTS = $(am_efreet_menu_alloc_OBJECTS) +efreet_menu_alloc_DEPENDENCIES = $(top_builddir)/src/lib/libefreet.la +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__depfiles_maybe = depfiles +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_$(V)) +am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY)) +am__v_CC_0 = @echo " CC " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_$(V)) +am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY)) +am__v_CCLD_0 = @echo " CCLD " $@; +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +SOURCES = $(efreet_alloc_SOURCES) $(efreet_menu_alloc_SOURCES) +DIST_SOURCES = $(efreet_alloc_SOURCES) $(efreet_menu_alloc_SOURCES) +ETAGS = etags +CTAGS = ctags +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +MAINTAINERCLEANFILES = Makefile.in +AM_CPPFLAGS = \ +-I. \ +-I$(top_srcdir)/src/lib \ +@EFREET_CFLAGS@ + +efreet_menu_alloc_SOURCES = efreet_menu_alloc.c comp.h +efreet_menu_alloc_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +efreet_alloc_SOURCES = efreet_alloc.c comp.h +efreet_alloc_LDADD = $(top_builddir)/src/lib/libefreet.la @EFREET_LIBS@ +all: all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .o .obj +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/compare/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tests/compare/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)" + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p || test -f $$p1; \ + then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +efreet_alloc$(EXEEXT): $(efreet_alloc_OBJECTS) $(efreet_alloc_DEPENDENCIES) + @rm -f efreet_alloc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_alloc_OBJECTS) $(efreet_alloc_LDADD) $(LIBS) +efreet_menu_alloc$(EXEEXT): $(efreet_menu_alloc_OBJECTS) $(efreet_menu_alloc_DEPENDENCIES) + @rm -f efreet_menu_alloc$(EXEEXT) + $(AM_V_CCLD)$(LINK) $(efreet_menu_alloc_OBJECTS) $(efreet_menu_alloc_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_alloc.Po@am__quote@ +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/efreet_menu_alloc.Po@am__quote@ + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(COMPILE) -c `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $< + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(PROGRAMS) +installdirs: + for dir in "$(DESTDIR)$(bindir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -rf ./$(DEPDIR) + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS + +.MAKE: install-am install-strip + +.PHONY: CTAGS GTAGS all all-am check check-am clean clean-binPROGRAMS \ + clean-generic clean-libtool ctags distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am install-dvi \ + install-dvi-am install-exec install-exec-am install-html \ + install-html-am install-info install-info-am install-man \ + install-pdf install-pdf-am install-ps install-ps-am \ + install-strip installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ + pdf pdf-am ps ps-am tags uninstall uninstall-am \ + uninstall-binPROGRAMS + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tests/compare/comp.h b/src/tests/compare/comp.h new file mode 100644 index 0000000..c02eebe --- /dev/null +++ b/src/tests/compare/comp.h @@ -0,0 +1,527 @@ +#ifndef COMP_H +#define COMP_H + +#define LOOPS 1000 +#define THEME "Tango" +#define SIZE 16 + +#define ADDRESS_BOOK_NEW "address-book-new" +#define APPLICATION_EXIT "application-exit" +#define APPOINTMENT_NEW "appointment-new" +#define CONTACT_NEW "contact-new" +#define DIALOG_APPLY "dialog-apply" +#define DIALOG_CANCEL "dialog-cancel" +#define DIALOG_CLOSE "dialog-close" +#define DIALOG_OK "dialog-ok" +#define DOCUMENT_NEW "document-new" +#define DOCUMENT_OPEN "document-open" +#define DOCUMENT_OPEN_RECENT "document-open-recent" +#define DOCUMENT_PAGE_SETUP "document-page-setup" +#define DOCUMENT_PRINT "document-print" +#define DOCUMENT_PRINT_PREVIEW "document-print-preview" +#define DOCUMENT_PROPERTIES "document-properties" +#define DOCUMENT_REVERT "document-revert" +#define DOCUMENT_SAVE "document-save" +#define DOCUMENT_SAVE_AS "document-save-as" +#define EDIT_COPY "edit-copy" +#define EDIT_CUT "edit-cut" +#define EDIT_DELETE "edit-delete" +#define EDIT_FIND "edit-find" +#define EDIT_FIND_REPLACE "edit-find-replace" +#define EDIT_PASTE "edit-paste" +#define EDIT_REDO "edit-redo" +#define EDIT_SELECT_ALL "edit-select-all" +#define EDIT_UNDO "edit-undo" +#define FORMAT_INDENT_LESS "format-indent-less" +#define FORMAT_INDENT_MORE "format-indent-more" +#define FORMAT_JUSTIFY_CENTER "format-justify-center" +#define FORMAT_JUSTIFY_FILL "format-justify-fill" +#define FORMAT_JUSTIFY_LEFT "format-justify-left" +#define FORMAT_JUSTIFY_RIGHT "format-justify-right" +#define FORMAT_TEXT_DIRECTION_LTR "format-text-direction-ltr" +#define FORMAT_TEXT_DIRECTION_RTL "format-text-direction-rtl" +#define FORMAT_TEXT_BOLD "format-text-bold" +#define FORMAT_TEXT_ITALIC "format-text-italic" +#define FORMAT_TEXT_UNDERLINE "format-text-underline" +#define FORMAT_TEXT_STRIKETHROUGH "format-text-strikethrough" +#define GO_BOTTOM "go-bottom" +#define GO_DOWN "go-down" +#define GO_FIRST "go-first" +#define GO_HOME "go-home" +#define GO_JUMP "go-jump" +#define GO_LAST "go-last" +#define GO_NEXT "go-next" +#define GO_PREVIOUS "go-previous" +#define GO_TOP "go-top" +#define GO_UP "go-up" +#define HELP_ABOUT "help-about" +#define HELP_CONTENTS "help-contents" +#define HELP_FAQ "help-faq" +#define INSERT_IMAGE "insert-image" +#define INSERT_LINK "insert-link" +#define INSERT_OBJECT "insert-object" +#define INSERT_TEXT "insert-text" +#define LIST_ADD "list-add" +#define LIST_REMOVE "list-remove" +#define MAIL_FORWARD "mail-forward" +#define MAIL_MARK_IMPORTANT "mail-mark-important" +#define MAIL_MARK_JUNK "mail-mark-junk" +#define MAIL_MARK_NOTJUNK "mail-mark-notjunk" +#define MAIL_MARK_READ "mail-mark-read" +#define MAIL_MARK_UNREAD "mail-mark-unread" +#define MAIL_MESSAGE_NEW "mail-message-new" +#define MAIL_REPLY_ALL "mail-reply-all" +#define MAIL_REPLY_SENDER "mail-reply-sender" +#define MAIL_SEND_RECEIVE "mail-send-receive" +#define MEDIA_EJECT "media-eject" +#define MEDIA_PLAYBACK_PAUSE "media-playback-pause" +#define MEDIA_PLAYBACK_START "media-playback-start" +#define MEDIA_PLAYBACK_STOP "media-playback-stop" +#define MEDIA_RECORD "media-record" +#define MEDIA_SEEK_BACKWARD "media-seek-backward" +#define MEDIA_SEEK_FORWARD "media-seek-forward" +#define MEDIA_SKIP_BACKWARD "media-skip-backward" +#define MEDIA_SKIP_FORWARD "media-skip-forward" +#define SYSTEM_LOCK_SCREEN "system-lock-screen" +#define SYSTEM_LOG_OUT "system-log-out" +#define SYSTEM_RUN "system-run" +#define SYSTEM_SEARCH "system-search" +#define TOOLS_CHECK_SPELLING "tools-check-spelling" +#define VIEW_FULLSCREEN "view-fullscreen" +#define VIEW_REFRESH "view-refresh" +#define VIEW_SORT_ASCENDING "view-sort-ascending" +#define VIEW_SORT_DESCENDING "view-sort-descending" +#define WINDOW_CLOSE "window-close" +#define WINDOW_NEW "window-new" +#define ZOOM_BEST_FIT "zoom-best-fit" +#define ZOOM_IN "zoom-in" +#define ZOOM_ORIGINAL "zoom-original" +#define ZOOM_OUT "zoom-out" + +#define PROCESS_WORKING "process-working" + +#define ACCESSORIES_CALCULATOR "accessories-calculator" +#define ACCESSORIES_CHARACTER_MAP "accessories-character-map" +#define ACCESSORIES_DICTIONARY "accessories-dictionary" +#define ACCESSORIES_TEXT_EDITOR "accessories-text-editor" +#define HELP_BROWSER "help-browser" +#define MULTIMEDIA_VOLUME_CONTROL "multimedia-volume-control" +#define PREFERENCES_DESKTOP_ACCESSIBILITY "preferences-desktop-accessibility" +#define PREFERENCES_DESKTOP_FONT "preferences-desktop-font" +#define PREFERENCES_DESKTOP_KEYBOARD "preferences-desktop-keyboard" +#define PREFERENCES_DESKTOP_LOCALE "preferences-desktop-locale" +#define PREFERENCES_DESKTOP_MULTIMEDIA "preferences-desktop-multimedia" +#define PREFERENCES_DESKTOP_SCREENSAVER "preferences-desktop-screensaver" +#define PREFERENCES_DESKTOP_THEME "preferences-desktop-theme" +#define PREFERENCES_DESKTOP_WALLPAPER "preferences-desktop-wallpaper" +#define SYSTEM_FILE_MANAGER "system-file-manager" +#define SYSTEM_SOFTWARE_UPDATE "system-software-update" +#define UTILITIES_TERMINAL "utilities-terminal" + +#define APPLICATIONS_ACCESSORIES "applications-accessories" +#define APPLICATIONS_DEVELOPMENT "applications-development" +#define APPLICATIONS_GAMES "applications-games" +#define APPLICATIONS_GRAPHICS "applications-graphics" +#define APPLICATIONS_INTERNET "applications-internet" +#define APPLICATIONS_MULTIMEDIA "applications-multimedia" +#define APPLICATIONS_OFFICE "applications-office" +#define APPLICATIONS_OTHER "applications-other" +#define APPLICATIONS_SYSTEM "applications-system" +#define APPLICATIONS_UTILITIES "applications-utilities" +#define PREFERENCES_DESKTOP "preferences-desktop" +#define PREFERENCES_DESKTOP_ACCESSIBILITY "preferences-desktop-accessibility" +#define PREFERENCES_DESKTOP_PERIPHERALS "preferences-desktop-peripherals" +#define PREFERENCES_DESKTOP_PERSONAL "preferences-desktop-personal" +#define PREFERENCES_OTHER "preferences-other" +#define PREFERENCES_SYSTEM "preferences-system" +#define PREFERENCES_SYSTEM_NETWORK "preferences-system-network" +#define SYSTEM_HELP "system-help" + +#define AUDIO_CARD "audio-card" +#define AUDIO_INPUT_MICROPHONE "audio-input-microphone" +#define BATTERY "battery" +#define CAMERA_PHOTO "camera-photo" +#define CAMERA_VIDEO "camera-video" +#define COMPUTER "computer" +#define DRIVE_CDROM "drive-cdrom" +#define DRIVE_HARDDISK "drive-harddisk" +#define DRIVE_REMOVABLE_MEDIA "drive-removable-media" +#define INPUT_GAMING "input-gaming" +#define INPUT_KEYBOARD "input-keyboard" +#define INPUT_MOUSE "input-mouse" +#define MEDIA_CDROM "media-cdrom" +#define MEDIA_FLOPPY "media-floppy" +#define MULTIMEDIA_PLAYER "multimedia-player" +#define NETWORK_WIRED "network-wired" +#define NETWORK_WIRELESS "network-wireless" +#define PRINTER "printer" + +#define EMBLEM_DEFAULT "emblem-default" +#define EMBLEM_DOCUMENTS "emblem-documents" +#define EMBLEM_DOWNLOADS "emblem-downloads" +#define EMBLEM_FAVORITE "emblem-favorite" +#define EMBLEM_IMPORTANT "emblem-important" +#define EMBLEM_MAIL "emblem-mail" +#define EMBLEM_PHOTOS "emblem-photos" +#define EMBLEM_READONLY "emblem-readonly" +#define EMBLEM_SHARED "emblem-shared" +#define EMBLEM_SYMBOLIC_LINK "emblem-symbolic-link" +#define EMBLEM_SYNCHRONIZED "emblem-synchronized" +#define EMBLEM_SYSTEM "emblem-system" +#define EMBLEM_UNREADABLE "emblem-unreadable" + +#define FACE_ANGEL "face-angel" +#define FACE_CRYING "face-crying" +#define FACE_DEVIL_GRIN "face-devil-grin" +#define FACE_DEVIL_SAD "face-devil-sad" +#define FACE_GLASSES "face-glasses" +#define FACE_KISS "face-kiss" +#define FACE_MONKEY "face-monkey" +#define FACE_PLAIN "face-plain" +#define FACE_SAD "face-sad" +#define FACE_SMILE "face-smile" +#define FACE_SMILE_BIG "face-smile-big" +#define FACE_SMIRK "face-smirk" +#define FACE_SURPRISE "face-surprise" +#define FACE_WINK "face-wink" + +#define APPLICATION_X_EXECUTABLE "application-x-executable" +#define AUDIO_X_GENERIC "audio-x-generic" +#define FONT_X_GENERIC "font-x-generic" +#define IMAGE_X_GENERIC "image-x-generic" +#define PACKAGE_X_GENERIC "package-x-generic" +#define TEXT_HTML "text-html" +#define TEXT_X_GENERIC "text-x-generic" +#define TEXT_X_GENERIC_TEMPLATE "text-x-generic-template" +#define TEXT_X_SCRIPT "text-x-script" +#define VIDEO_X_GENERIC "video-x-generic" +#define X_OFFICE_ADDRESS_BOOK "x-office-address-book" +#define X_OFFICE_CALENDAR "x-office-calendar" +#define X_OFFICE_DOCUMENT "x-office-document" +#define X_OFFICE_PRESENTATION "x-office-presentation" +#define X_OFFICE_SPREADSHEET "x-office-spreadsheet" + +#define FOLDER "folder" +#define FOLDER_REMOTE "folder-remote" +#define NETWORK_SERVER "network-server" +#define NETWORK_WORKGROUP "network-workgroup" +#define START_HERE "start-here" +#define USER_DESKTOP "user-desktop" +#define USER_HOME "user-home" +#define USER_TRASH "user-trash" + +#define APPOINTMENT_MISSED "appointment-missed" +#define APPOINTMENT_SOON "appointment-soon" +#define AUDIO_VOLUME_HIGH "audio-volume-high" +#define AUDIO_VOLUME_LOW "audio-volume-low" +#define AUDIO_VOLUME_MEDIUM "audio-volume-medium" +#define AUDIO_VOLUME_MUTED "audio-volume-muted" +#define BATTERY_CAUTION "battery-caution" +#define BATTERY_LOW "battery-low" +#define DIALOG_ERROR "dialog-error" +#define DIALOG_INFORMATION "dialog-information" +#define DIALOG_PASSWORD "dialog-password" +#define DIALOG_QUESTION "dialog-question" +#define DIALOG_WARNING "dialog-warning" +#define FOLDER_DRAG_ACCEPT "folder-drag-accept" +#define FOLDER_OPEN "folder-open" +#define FOLDER_VISITING "folder-visiting" +#define IMAGE_LOADING "image-loading" +#define IMAGE_MISSING "image-missing" +#define MAIL_ATTACHMENT "mail-attachment" +#define MAIL_UNREAD "mail-unread" +#define MAIL_READ "mail-read" +#define MAIL_REPLIED "mail-replied" +#define MAIL_SIGNED "mail-signed" +#define MAIL_SIGNED_VERIFIED "mail-signed-verified" +#define MEDIA_PLAYLIST_REPEAT "media-playlist-repeat" +#define MEDIA_PLAYLIST_SHUFFLE "media-playlist-shuffle" +#define NETWORK_ERROR "network-error" +#define NETWORK_IDLE "network-idle" + +#define NETWORK_OFFLINE "network-offline" +#define NETWORK_RECEIVE "network-receive" +#define NETWORK_TRANSMIT "network-transmit" +#define NETWORK_TRANSMIT_RECEIVE "network-transmit-receive" +#define PRINTER_ERROR "printer-error" +#define PRINTER_PRINTING "printer-printing" +#define SOFTWARE_UPDATE_AVAILABLE "software-update-available" +#define SOFTWARE_UPDATE_URGENT "software-update-urgent" +#define SYNC_ERROR "sync-error" +#define SYNC_SYNCHRONIZING "sync-synchronizing" +#define TASK_DUE "task-due" +#define TASK_PASSED_DUE "task-passed-due" +#define USER_AWAY "user-away" +#define USER_IDLE "user-idle" +#define USER_OFFLINE "user-offline" +#define USER_ONLINE "user-online" +#define USER_TRASH_FULL "user-trash-full" +#define WEATHER_CLEAR "weather-clear" +#define WEATHER_CLEAR_NIGHT "weather-clear-night" +#define WEATHER_FEW_CLOUDS "weather-few-clouds" +#define WEATHER_FEW_CLOUDS_NIGHT "weather-few-clouds-night" +#define WEATHER_FOG "weather-fog" +#define WEATHER_OVERCAST "weather-overcast" +#define WEATHER_SEVERE_ALERT "weather-severe-alert" +#define WEATHER_SHOWERS "weather-showers" +#define WEATHER_SHOWERS_SCATTERED "weather-showers-scattered" +#define WEATHER_SNOW "weather-snow" +#define WEATHER_STORM "weather-storm" + +const char *icons[] = { + ADDRESS_BOOK_NEW, + APPLICATION_EXIT, + APPOINTMENT_NEW, + CONTACT_NEW, + DIALOG_APPLY, + DIALOG_CANCEL, + DIALOG_CLOSE, + DIALOG_OK, + DOCUMENT_NEW, + DOCUMENT_OPEN, + DOCUMENT_OPEN_RECENT, + DOCUMENT_PAGE_SETUP, + DOCUMENT_PRINT, + DOCUMENT_PRINT_PREVIEW, + DOCUMENT_PROPERTIES, + DOCUMENT_REVERT, + DOCUMENT_SAVE, + DOCUMENT_SAVE_AS, + EDIT_COPY, + EDIT_CUT, + EDIT_DELETE, + EDIT_FIND, + EDIT_FIND_REPLACE, + EDIT_PASTE, + EDIT_REDO, + EDIT_SELECT_ALL, + EDIT_UNDO, + FORMAT_INDENT_LESS, + FORMAT_INDENT_MORE, + FORMAT_JUSTIFY_CENTER, + FORMAT_JUSTIFY_FILL, + FORMAT_JUSTIFY_LEFT, + FORMAT_JUSTIFY_RIGHT, + FORMAT_TEXT_DIRECTION_LTR, + FORMAT_TEXT_DIRECTION_RTL, + FORMAT_TEXT_BOLD, + FORMAT_TEXT_ITALIC, + FORMAT_TEXT_UNDERLINE, + FORMAT_TEXT_STRIKETHROUGH, + GO_BOTTOM, + GO_DOWN, + GO_FIRST, + GO_HOME, + GO_JUMP, + GO_LAST, + GO_NEXT, + GO_PREVIOUS, + GO_TOP, + GO_UP, + HELP_ABOUT, + HELP_CONTENTS, + HELP_FAQ, + INSERT_IMAGE, + INSERT_LINK, + INSERT_OBJECT, + INSERT_TEXT, + LIST_ADD, + LIST_REMOVE, + MAIL_FORWARD, + MAIL_MARK_IMPORTANT, + MAIL_MARK_JUNK, + MAIL_MARK_NOTJUNK, + MAIL_MARK_READ, + MAIL_MARK_UNREAD, + MAIL_MESSAGE_NEW, + MAIL_REPLY_ALL, + MAIL_REPLY_SENDER, + MAIL_SEND_RECEIVE, + MEDIA_EJECT, + MEDIA_PLAYBACK_PAUSE, + MEDIA_PLAYBACK_START, + MEDIA_PLAYBACK_STOP, + MEDIA_RECORD, + MEDIA_SEEK_BACKWARD, + MEDIA_SEEK_FORWARD, + MEDIA_SKIP_BACKWARD, + MEDIA_SKIP_FORWARD, + SYSTEM_LOCK_SCREEN, + SYSTEM_LOG_OUT, + SYSTEM_RUN, + SYSTEM_SEARCH, + TOOLS_CHECK_SPELLING, + VIEW_FULLSCREEN, + VIEW_REFRESH, + VIEW_SORT_ASCENDING, + VIEW_SORT_DESCENDING, + WINDOW_CLOSE, + WINDOW_NEW, + ZOOM_BEST_FIT, + ZOOM_IN, + ZOOM_ORIGINAL, + ZOOM_OUT, + PROCESS_WORKING, + ACCESSORIES_CALCULATOR, + ACCESSORIES_CHARACTER_MAP, + ACCESSORIES_DICTIONARY, + ACCESSORIES_TEXT_EDITOR, + HELP_BROWSER, + MULTIMEDIA_VOLUME_CONTROL, + PREFERENCES_DESKTOP_ACCESSIBILITY, + PREFERENCES_DESKTOP_FONT, + PREFERENCES_DESKTOP_KEYBOARD, + PREFERENCES_DESKTOP_LOCALE, + PREFERENCES_DESKTOP_MULTIMEDIA, + PREFERENCES_DESKTOP_SCREENSAVER, + PREFERENCES_DESKTOP_THEME, + PREFERENCES_DESKTOP_WALLPAPER, + SYSTEM_FILE_MANAGER, + SYSTEM_SOFTWARE_UPDATE, + UTILITIES_TERMINAL, + APPLICATIONS_ACCESSORIES, + APPLICATIONS_DEVELOPMENT, + APPLICATIONS_GAMES, + APPLICATIONS_GRAPHICS, + APPLICATIONS_INTERNET, + APPLICATIONS_MULTIMEDIA, + APPLICATIONS_OFFICE, + APPLICATIONS_OTHER, + APPLICATIONS_SYSTEM, + APPLICATIONS_UTILITIES, + PREFERENCES_DESKTOP, + PREFERENCES_DESKTOP_ACCESSIBILITY, + PREFERENCES_DESKTOP_PERIPHERALS, + PREFERENCES_DESKTOP_PERSONAL, + PREFERENCES_OTHER, + PREFERENCES_SYSTEM, + PREFERENCES_SYSTEM_NETWORK, + SYSTEM_HELP, + AUDIO_CARD, + AUDIO_INPUT_MICROPHONE, + BATTERY, + CAMERA_PHOTO, + CAMERA_VIDEO, + COMPUTER, + DRIVE_CDROM, + DRIVE_HARDDISK, + DRIVE_REMOVABLE_MEDIA, + INPUT_GAMING, + INPUT_KEYBOARD, + INPUT_MOUSE, + MEDIA_CDROM, + MEDIA_FLOPPY, + MULTIMEDIA_PLAYER, + NETWORK_WIRED, + NETWORK_WIRELESS, + PRINTER, + EMBLEM_DEFAULT, + EMBLEM_DOCUMENTS, + EMBLEM_DOWNLOADS, + EMBLEM_FAVORITE, + EMBLEM_IMPORTANT, + EMBLEM_MAIL, + EMBLEM_PHOTOS, + EMBLEM_READONLY, + EMBLEM_SHARED, + EMBLEM_SYMBOLIC_LINK, + EMBLEM_SYNCHRONIZED, + EMBLEM_SYSTEM, + EMBLEM_UNREADABLE, + FACE_ANGEL, + FACE_CRYING, + FACE_DEVIL_GRIN, + FACE_DEVIL_SAD, + FACE_GLASSES, + FACE_KISS, + FACE_MONKEY, + FACE_PLAIN, + FACE_SAD, + FACE_SMILE, + FACE_SMILE_BIG, + FACE_SMIRK, + FACE_SURPRISE, + FACE_WINK, + APPLICATION_X_EXECUTABLE, + AUDIO_X_GENERIC, + FONT_X_GENERIC, + IMAGE_X_GENERIC, + PACKAGE_X_GENERIC, + TEXT_HTML, + TEXT_X_GENERIC, + TEXT_X_GENERIC_TEMPLATE, + TEXT_X_SCRIPT, + VIDEO_X_GENERIC, + X_OFFICE_ADDRESS_BOOK, + X_OFFICE_CALENDAR, + X_OFFICE_DOCUMENT, + X_OFFICE_PRESENTATION, + X_OFFICE_SPREADSHEET, + FOLDER, + FOLDER_REMOTE, + NETWORK_SERVER, + NETWORK_WORKGROUP, + START_HERE, + USER_DESKTOP, + USER_HOME, + USER_TRASH, + APPOINTMENT_MISSED, + APPOINTMENT_SOON, + AUDIO_VOLUME_HIGH, + AUDIO_VOLUME_LOW, + AUDIO_VOLUME_MEDIUM, + AUDIO_VOLUME_MUTED, + BATTERY_CAUTION, + BATTERY_LOW, + DIALOG_ERROR, + DIALOG_INFORMATION, + DIALOG_PASSWORD, + DIALOG_QUESTION, + DIALOG_WARNING, + FOLDER_DRAG_ACCEPT, + FOLDER_OPEN, + FOLDER_VISITING, + IMAGE_LOADING, + IMAGE_MISSING, + MAIL_ATTACHMENT, + MAIL_UNREAD, + MAIL_READ, + MAIL_REPLIED, + MAIL_SIGNED, + MAIL_SIGNED_VERIFIED, + MEDIA_PLAYLIST_REPEAT, + MEDIA_PLAYLIST_SHUFFLE, + NETWORK_ERROR, + NETWORK_IDLE, + NETWORK_OFFLINE, + NETWORK_RECEIVE, + NETWORK_TRANSMIT, + NETWORK_TRANSMIT_RECEIVE, + PRINTER_ERROR, + PRINTER_PRINTING, + SOFTWARE_UPDATE_AVAILABLE, + SOFTWARE_UPDATE_URGENT, + SYNC_ERROR, + SYNC_SYNCHRONIZING, + TASK_DUE, + TASK_PASSED_DUE, + USER_AWAY, + USER_IDLE, + USER_OFFLINE, + USER_ONLINE, + USER_TRASH_FULL, + WEATHER_CLEAR, + WEATHER_CLEAR_NIGHT, + WEATHER_FEW_CLOUDS, + WEATHER_FEW_CLOUDS_NIGHT, + WEATHER_FOG, + WEATHER_OVERCAST, + WEATHER_SEVERE_ALERT, + WEATHER_SHOWERS, + WEATHER_SHOWERS_SCATTERED, + WEATHER_SNOW, + WEATHER_STORM, + NULL + }; + +#endif diff --git a/src/tests/compare/efreet_alloc.c b/src/tests/compare/efreet_alloc.c new file mode 100644 index 0000000..1527f77 --- /dev/null +++ b/src/tests/compare/efreet_alloc.c @@ -0,0 +1,30 @@ +#include <Efreet.h> +#include <stdio.h> +#include <stdlib.h> +#include "comp.h" + +int +main(void) +{ + int i = 0, k, errs = 0; + const char *path; + + efreet_init(); + + for (k = 0; k < LOOPS; k++) + { + for (i = 0; icons[i]; i++) + { + path = efreet_icon_path_find(THEME, icons[i], SIZE); + if (!path) + { + printf("%s: NOT FOUND\n", icons[i]); + errs++; + } + } + } + + efreet_shutdown(); + + return errs > 0; +} diff --git a/src/tests/compare/efreet_menu_alloc.c b/src/tests/compare/efreet_menu_alloc.c new file mode 100644 index 0000000..fcfb75b --- /dev/null +++ b/src/tests/compare/efreet_menu_alloc.c @@ -0,0 +1,23 @@ +#include <Efreet.h> +#include <stdio.h> +#include "comp.h" + +int +main(void) +{ + int k; + + efreet_init(); + + for (k = 0; k < LOOPS; k++) + { + Efreet_Menu *menu; + menu = efreet_menu_get(); + efreet_menu_free(menu); + } + + efreet_shutdown(); + + return 0; +} + diff --git a/src/tests/data/Makefile.am b/src/tests/data/Makefile.am new file mode 100644 index 0000000..50eef85 --- /dev/null +++ b/src/tests/data/Makefile.am @@ -0,0 +1,18 @@ +SUBDIRS = sub + +MAINTAINERCLEANFILES = Makefile.in + +testdir = $(pkgdatadir)/test +test_DATA = \ +test.ini \ +long.ini \ +test.desktop \ +test_type.desktop \ +test.menu \ +test_menu_slash_bad.menu \ +entry.png \ +entry \ +preferences.menu \ +test_garbage + +EXTRA_DIST = $(test_DATA) diff --git a/src/tests/data/Makefile.in b/src/tests/data/Makefile.in new file mode 100644 index 0000000..7bf1261 --- /dev/null +++ b/src/tests/data/Makefile.in @@ -0,0 +1,679 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/tests/data +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \ + html-recursive info-recursive install-data-recursive \ + install-dvi-recursive install-exec-recursive \ + install-html-recursive install-info-recursive \ + install-pdf-recursive install-ps-recursive install-recursive \ + installcheck-recursive installdirs-recursive pdf-recursive \ + ps-recursive uninstall-recursive +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(testdir)" +DATA = $(test_DATA) +RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ + distclean-recursive maintainer-clean-recursive +AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \ + $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \ + distdir +ETAGS = etags +CTAGS = ctags +DIST_SUBDIRS = $(SUBDIRS) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +am__relativize = \ + dir0=`pwd`; \ + sed_first='s,^\([^/]*\)/.*$$,\1,'; \ + sed_rest='s,^[^/]*/*,,'; \ + sed_last='s,^.*/\([^/]*\)$$,\1,'; \ + sed_butlast='s,/*[^/]*$$,,'; \ + while test -n "$$dir1"; do \ + first=`echo "$$dir1" | sed -e "$$sed_first"`; \ + if test "$$first" != "."; then \ + if test "$$first" = ".."; then \ + dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ + dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ + else \ + first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ + if test "$$first2" = "$$first"; then \ + dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ + else \ + dir2="../$$dir2"; \ + fi; \ + dir0="$$dir0"/"$$first"; \ + fi; \ + fi; \ + dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ + done; \ + reldir="$$dir2" +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +SUBDIRS = sub +MAINTAINERCLEANFILES = Makefile.in +testdir = $(pkgdatadir)/test +test_DATA = \ +test.ini \ +long.ini \ +test.desktop \ +test_type.desktop \ +test.menu \ +test_menu_slash_bad.menu \ +entry.png \ +entry \ +preferences.menu \ +test_garbage + +EXTRA_DIST = $(test_DATA) +all: all-recursive + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/data/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tests/data/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-testDATA: $(test_DATA) + @$(NORMAL_INSTALL) + test -z "$(testdir)" || $(MKDIR_P) "$(DESTDIR)$(testdir)" + @list='$(test_DATA)'; test -n "$(testdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(testdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(testdir)" || exit $$?; \ + done + +uninstall-testDATA: + @$(NORMAL_UNINSTALL) + @list='$(test_DATA)'; test -n "$(testdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(testdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(testdir)" && rm -f $$files + +# This directory's subdirectories are mostly independent; you can cd +# into them and run `make' without going through this Makefile. +# To change the values of `make' variables: instead of editing Makefiles, +# (1) if the variable is set in `config.status', edit `config.status' +# (which will cause the Makefiles to be regenerated when you run `make'); +# (2) otherwise, pass the desired values on the `make' command line. +$(RECURSIVE_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + target=`echo $@ | sed s/-recursive//`; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + dot_seen=yes; \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done; \ + if test "$$dot_seen" = "no"; then \ + $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ + fi; test -z "$$fail" + +$(RECURSIVE_CLEAN_TARGETS): + @fail= failcom='exit 1'; \ + for f in x $$MAKEFLAGS; do \ + case $$f in \ + *=* | --[!k]*);; \ + *k*) failcom='fail=yes';; \ + esac; \ + done; \ + dot_seen=no; \ + case "$@" in \ + distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ + *) list='$(SUBDIRS)' ;; \ + esac; \ + rev=''; for subdir in $$list; do \ + if test "$$subdir" = "."; then :; else \ + rev="$$subdir $$rev"; \ + fi; \ + done; \ + rev="$$rev ."; \ + target=`echo $@ | sed s/-recursive//`; \ + for subdir in $$rev; do \ + echo "Making $$target in $$subdir"; \ + if test "$$subdir" = "."; then \ + local_target="$$target-am"; \ + else \ + local_target="$$target"; \ + fi; \ + ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ + || eval $$failcom; \ + done && test -z "$$fail" +tags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \ + done +ctags-recursive: + list='$(SUBDIRS)'; for subdir in $$list; do \ + test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \ + done + +ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + mkid -fID $$unique +tags: TAGS + +TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + set x; \ + here=`pwd`; \ + if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ + include_option=--etags-include; \ + empty_fix=.; \ + else \ + include_option=--include; \ + empty_fix=; \ + fi; \ + list='$(SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test ! -f $$subdir/TAGS || \ + set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ + fi; \ + done; \ + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: CTAGS +CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \ + $(TAGS_FILES) $(LISP) + list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | \ + $(AWK) '{ files[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in files) print i; }; }'`; \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + test -d "$(distdir)/$$subdir" \ + || $(MKDIR_P) "$(distdir)/$$subdir" \ + || exit 1; \ + fi; \ + done + @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ + if test "$$subdir" = .; then :; else \ + dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ + $(am__relativize); \ + new_distdir=$$reldir; \ + dir1=$$subdir; dir2="$(top_distdir)"; \ + $(am__relativize); \ + new_top_distdir=$$reldir; \ + echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ + echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ + ($(am__cd) $$subdir && \ + $(MAKE) $(AM_MAKEFLAGS) \ + top_distdir="$$new_top_distdir" \ + distdir="$$new_distdir" \ + am__remove_distdir=: \ + am__skip_length_check=: \ + am__skip_mode_fix=: \ + distdir) \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-recursive +all-am: Makefile $(DATA) +installdirs: installdirs-recursive +installdirs-am: + for dir in "$(DESTDIR)$(testdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-recursive +install-exec: install-exec-recursive +install-data: install-data-recursive +uninstall: uninstall-recursive + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-recursive +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-recursive + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-recursive + -rm -f Makefile +distclean-am: clean-am distclean-generic distclean-tags + +dvi: dvi-recursive + +dvi-am: + +html: html-recursive + +html-am: + +info: info-recursive + +info-am: + +install-data-am: install-testDATA + +install-dvi: install-dvi-recursive + +install-dvi-am: + +install-exec-am: + +install-html: install-html-recursive + +install-html-am: + +install-info: install-info-recursive + +install-info-am: + +install-man: + +install-pdf: install-pdf-recursive + +install-pdf-am: + +install-ps: install-ps-recursive + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-recursive + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-recursive + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-recursive + +pdf-am: + +ps: ps-recursive + +ps-am: + +uninstall-am: uninstall-testDATA + +.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) ctags-recursive \ + install-am install-strip tags-recursive + +.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \ + all all-am check check-am clean clean-generic clean-libtool \ + ctags ctags-recursive distclean distclean-generic \ + distclean-libtool distclean-tags distdir dvi dvi-am html \ + html-am info info-am install install-am install-data \ + install-data-am install-dvi install-dvi-am install-exec \ + install-exec-am install-html install-html-am install-info \ + install-info-am install-man install-pdf install-pdf-am \ + install-ps install-ps-am install-strip install-testDATA \ + installcheck installcheck-am installdirs installdirs-am \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + tags tags-recursive uninstall uninstall-am uninstall-testDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tests/data/entry b/src/tests/data/entry Binary files differnew file mode 100644 index 0000000..503d8e5 --- /dev/null +++ b/src/tests/data/entry diff --git a/src/tests/data/entry.png b/src/tests/data/entry.png Binary files differnew file mode 100644 index 0000000..82e5cbe --- /dev/null +++ b/src/tests/data/entry.png diff --git a/src/tests/data/long.ini b/src/tests/data/long.ini new file mode 100644 index 0000000..32154dd --- /dev/null +++ b/src/tests/data/long.ini @@ -0,0 +1,3 @@ +[section] +key=averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,the last value +key2=averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,averylongvalue,the last value diff --git a/src/tests/data/preferences.menu b/src/tests/data/preferences.menu new file mode 100644 index 0000000..904dbd2 --- /dev/null +++ b/src/tests/data/preferences.menu @@ -0,0 +1,41 @@ +<!DOCTYPE Menu PUBLIC + "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd"> + +<Menu> + <Name>Preferences</Name> + <Directory>Preferences.directory</Directory> + + <AppDir>blah</AppDir> + <AppDir>/var/tmp</AppDir> + + <Move> + <Old>Blah</Old + <New>Borp</New> + </Move> + + <Menu> + <Name>House</Name> + <Directory>House.directory</Directory> + <Include> + <Category>House</Category> + <Category>Garden</Category> + </Include> + </Menu> + <Menu> + <Name>Mouse</Name> + <Directory>House.directory</Directory> + <Include> + <Category>House</Category> + <Category>Garden</Category> + </Include> + </Menu> + <Menu> + <Name>House</Name> + <Directory>House.directory</Directory> + <Include> + <Category>Cat</Category> + </Include> + </Menu> +</Menu> + diff --git a/src/tests/data/sub/Makefile.am b/src/tests/data/sub/Makefile.am new file mode 100644 index 0000000..7aaf7fc --- /dev/null +++ b/src/tests/data/sub/Makefile.am @@ -0,0 +1,8 @@ + +MAINTAINERCLEANFILES = Makefile.in + +testdir = $(pkgdatadir)/test/sub +test_DATA = \ +test.desktop + +EXTRA_DIST = $(test_DATA) diff --git a/src/tests/data/sub/Makefile.in b/src/tests/data/sub/Makefile.in new file mode 100644 index 0000000..340e1ea --- /dev/null +++ b/src/tests/data/sub/Makefile.in @@ -0,0 +1,468 @@ +# Makefile.in generated by automake 1.11.1 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002, +# 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, +# Inc. +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + +VPATH = @srcdir@ +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +subdir = src/tests/data/sub +DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ac_attribute.m4 \ + $(top_srcdir)/m4/efl_compiler_flag.m4 \ + $(top_srcdir)/m4/efl_coverage.m4 \ + $(top_srcdir)/m4/efl_doxygen.m4 \ + $(top_srcdir)/m4/efl_path_max.m4 $(top_srcdir)/m4/efl_tests.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = +CONFIG_CLEAN_VPATH_FILES = +AM_V_GEN = $(am__v_GEN_$(V)) +am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY)) +am__v_GEN_0 = @echo " GEN " $@; +AM_V_at = $(am__v_at_$(V)) +am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY)) +am__v_at_0 = @ +SOURCES = +DIST_SOURCES = +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__installdirs = "$(DESTDIR)$(testdir)" +DATA = $(test_DATA) +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +ALLOCA = @ALLOCA@ +AMTAR = @AMTAR@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AR = @AR@ +AS = @AS@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CHECK_CFLAGS = @CHECK_CFLAGS@ +CHECK_LIBS = @CHECK_LIBS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EFL_COVERAGE_CFLAGS = @EFL_COVERAGE_CFLAGS@ +EFL_COVERAGE_LIBS = @EFL_COVERAGE_LIBS@ +EFL_EFREET_BUILD = @EFL_EFREET_BUILD@ +EFL_EFREET_MIME_BUILD = @EFL_EFREET_MIME_BUILD@ +EFL_EFREET_TRASH_BUILD = @EFL_EFREET_TRASH_BUILD@ +EFREET_CFLAGS = @EFREET_CFLAGS@ +EFREET_LIBS = @EFREET_LIBS@ +EGREP = @EGREP@ +EINA_CFLAGS = @EINA_CFLAGS@ +EINA_LIBS = @EINA_LIBS@ +EVIL_CFLAGS = @EVIL_CFLAGS@ +EVIL_LIBS = @EVIL_LIBS@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LOCALE_DIR = @LOCALE_DIR@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +MAKEINFO = @MAKEINFO@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +VMAJ = @VMAJ@ +WIN32_LIBS = @WIN32_LIBS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +docdir = @docdir@ +dvidir = @dvidir@ +efl_doxygen = @efl_doxygen@ +efl_have_doxygen = @efl_have_doxygen@ +exec_prefix = @exec_prefix@ +have_lcov = @have_lcov@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +lt_ECHO = @lt_ECHO@ +lt_enable_auto_import = @lt_enable_auto_import@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +pkgconfig_requires_private = @pkgconfig_requires_private@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +release_info = @release_info@ +requirement_efreet = @requirement_efreet@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +version_info = @version_info@ +MAINTAINERCLEANFILES = Makefile.in +testdir = $(pkgdatadir)/test/sub +test_DATA = \ +test.desktop + +EXTRA_DIST = $(test_DATA) +all: all-am + +.SUFFIXES: +$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --gnu src/tests/data/sub/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --gnu src/tests/data/sub/Makefile +.PRECIOUS: Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-testDATA: $(test_DATA) + @$(NORMAL_INSTALL) + test -z "$(testdir)" || $(MKDIR_P) "$(DESTDIR)$(testdir)" + @list='$(test_DATA)'; test -n "$(testdir)" || list=; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(testdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(testdir)" || exit $$?; \ + done + +uninstall-testDATA: + @$(NORMAL_UNINSTALL) + @list='$(test_DATA)'; test -n "$(testdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + test -n "$$files" || exit 0; \ + echo " ( cd '$(DESTDIR)$(testdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(testdir)" && rm -f $$files +tags: TAGS +TAGS: + +ctags: CTAGS +CTAGS: + + +distdir: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am +check: check-am +all-am: Makefile $(DATA) +installdirs: + for dir in "$(DESTDIR)$(testdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + `test -z '$(STRIP)' || \ + echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install +mostlyclean-generic: + +clean-generic: + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES) +clean: clean-am + +clean-am: clean-generic clean-libtool mostlyclean-am + +distclean: distclean-am + -rm -f Makefile +distclean-am: clean-am distclean-generic + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-testDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-generic mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-testDATA + +.MAKE: install-am install-strip + +.PHONY: all all-am check check-am clean clean-generic clean-libtool \ + distclean distclean-generic distclean-libtool distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-data install-data-am install-dvi install-dvi-am \ + install-exec install-exec-am install-html install-html-am \ + install-info install-info-am install-man install-pdf \ + install-pdf-am install-ps install-ps-am install-strip \ + install-testDATA installcheck installcheck-am installdirs \ + maintainer-clean maintainer-clean-generic mostlyclean \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + uninstall uninstall-am uninstall-testDATA + + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/tests/data/sub/test.desktop b/src/tests/data/sub/test.desktop new file mode 100644 index 0000000..7abf2ae --- /dev/null +++ b/src/tests/data/sub/test.desktop @@ -0,0 +1,5 @@ +[Desktop Entry] +Type=Application +Name=Sub +Exec=subtest +Categories=Test diff --git a/src/tests/data/test.desktop b/src/tests/data/test.desktop new file mode 100644 index 0000000..412601f --- /dev/null +++ b/src/tests/data/test.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=Application +Name=Efreet Test Application +GenericName=Test Application +Exec=efreet_test %F %i +Categories=Test;Enlightenment; +Icon=TestIcon +X-Test=Own key diff --git a/src/tests/data/test.ini b/src/tests/data/test.ini new file mode 100644 index 0000000..7f73d81 --- /dev/null +++ b/src/tests/data/test.ini @@ -0,0 +1,21 @@ +# Comments should be ignored (and empty lines) + +[contact] +Name=Foo Bar +Name[en_US]=English Foo Bar +Email= foo@bar.com +Email[de_DE] = foo@bar.de +Age = 30 +TrueBoolean=true +FalseBoolean=false +InvalidBoolean=invalid +Escaped=line1\nline2\r\nline3\ttabbed \\ with a backslash\sand\sspaces + +[AIM] +Username=foobar + +# the next line has a single space. it should be skipped as well + +[Jabber] +Username=foobar@bar.de + diff --git a/src/tests/data/test.menu b/src/tests/data/test.menu new file mode 100644 index 0000000..7ae21ff --- /dev/null +++ b/src/tests/data/test.menu @@ -0,0 +1,52 @@ +<!DOCTYPE Menu PUBLIC + "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd"> + +<Menu> + <Name>Applications</Name> + <Directory>Applications.directory</Directory> + + <DefaultAppDirs/> + <DefaultDirectoryDirs/> + + <MergeDir>applications-merged</MergeDir> + + <LegacyDir>/usr/share/applnk</LegacyDir> + + <DefaultLayout> + <Merge type="menus"/> + <Merge type="files"/> + <Separator/> + <Menuname>More</Menuname> + </DefaultLayout> + + <Move> + <Old>Foo</Old> + <New>Bar</New> + <Old>Foo2</Old> + <New>Bar2</New> + </Move> + + <Menu> + <Name>Preferences</Name> + <Directory>Preferences.directory</Directory> + <MergeFile>preferences.menu</MergeFile> + </Menu> + + <Menu> + <Name>Office</Name> + <Directory>Office.directory</Directory> + <Include> + <Category>Office</Category> + </Include> + <Exclude> + <Filename>foo.desktop</Filename> + <And> + <Not> + <Filename>bar.desktop</Filename> + </Not> + </And> + </Exclude> + </Menu> +</Menu> + diff --git a/src/tests/data/test_garbage b/src/tests/data/test_garbage new file mode 100644 index 0000000..7d178fd --- /dev/null +++ b/src/tests/data/test_garbage @@ -0,0 +1,2341 @@ +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcdef +abcd
\ No newline at end of file diff --git a/src/tests/data/test_menu_slash_bad.menu b/src/tests/data/test_menu_slash_bad.menu new file mode 100644 index 0000000..8f7b6f0 --- /dev/null +++ b/src/tests/data/test_menu_slash_bad.menu @@ -0,0 +1,11 @@ +<!DOCTYPE Menu PUBLIC + "-//freedesktop//DTD Menu 1.0//EN" + "http://www.freedesktop.org/standards/menu-spec/menu-1.0.dtd"> + +<Menu> + <Name>Applications/Bar</Name> + + <Menu> + <Name>Preferences/Baz</Name> + </Menu> +</Menu> diff --git a/src/tests/data/test_type.desktop b/src/tests/data/test_type.desktop new file mode 100644 index 0000000..1b67ff5 --- /dev/null +++ b/src/tests/data/test_type.desktop @@ -0,0 +1,8 @@ +[Desktop Entry] +Type=My_Type +Name=Efreet Test Application +GenericName=Test Application +Exec=efreet_test %F %i +Categories=Test;Enlightenment; +Icon=TestIcon +X-Test=Own key diff --git a/src/tests/ef_cache.c b/src/tests/ef_cache.c new file mode 100644 index 0000000..3cbee9e --- /dev/null +++ b/src/tests/ef_cache.c @@ -0,0 +1,199 @@ +#include "Efreet.h" +#include <stdio.h> +#include <Ecore.h> +#include "ef_test.h" + +#if 0 +EAPI Efreet_Desktop *efreet_util_desktop_file_id_find(const char *file_id); + +EAPI Eina_List *efreet_util_desktop_generic_name_glob_list(const char *glob); +EAPI Eina_List *efreet_util_desktop_comment_glob_list(const char *glob); +#endif + +static Eina_Bool icon_cb = EINA_FALSE; +static Eina_Bool desktop_cb = EINA_FALSE; + +static void +check(void) +{ + Eina_List *list; + Efreet_Desktop *desktop, *desktop2; + double start; + const char *id; + + // EAPI char *efreet_util_path_to_file_id(const char *path); + start = ecore_time_get(); + id = efreet_util_path_to_file_id("/usr/share/applications/gnome-panel.desktop"); + if (id) + { + printf("efreet_util_path_to_file_id(/usr/share/applications/gnome-panel.desktop): %s %.6f\n", id, (ecore_time_get() - start)); + } + else + printf("efreet_util_path_to_file_id(/usr/share/applications/gnome-panel.desktop): NULL %.6f\n", (ecore_time_get() - start)); + + //EAPI Efreet_Desktop *efreet_util_desktop_name_find(const char *name); + start = ecore_time_get(); + desktop = efreet_util_desktop_name_find("Evolution"); + if (desktop) + printf("efreet_util_desktop_name_find(Evolution): %s %.6f\n", desktop->orig_path, (ecore_time_get() - start)); + else + printf("efreet_util_desktop_name_find(Evolution): NULL %.6f\n", (ecore_time_get() - start)); + efreet_desktop_free(desktop); + + //EAPI Efreet_Desktop *efreet_util_desktop_generic_name_find(const char *generic_name); + start = ecore_time_get(); + desktop = efreet_util_desktop_generic_name_find("Spreadsheet"); + if (desktop) + printf("efreet_util_desktop_generic_name_find(Spreadsheet): %s %.6f\n", desktop->orig_path, (ecore_time_get() - start)); + else + printf("efreet_util_desktop_generic_name_find(Spreadsheet): NULL %.6f\n", (ecore_time_get() - start)); + efreet_desktop_free(desktop); + + //EAPI Efreet_Desktop *efreet_util_desktop_wm_class_find(const char *wmname, const char *wmclass); + start = ecore_time_get(); + desktop = efreet_util_desktop_wm_class_find("Firefox", NULL); + if (desktop) + printf("efreet_util_desktop_wm_class_find(Firefox): %s %.6f\n", desktop->orig_path, (ecore_time_get() - start)); + else + printf("efreet_util_desktop_wm_class_find(Firefox): NULL %.6f\n", (ecore_time_get() - start)); + efreet_desktop_free(desktop); + + //EAPI Efreet_Desktop *efreet_util_desktop_exec_find(const char *exec); + start = ecore_time_get(); + desktop = efreet_util_desktop_exec_find("/usr/bin/update-manager"); + if (desktop) + printf("efreet_util_desktop_exec_find(update-manager): %s %.6f\n", desktop->orig_path, (ecore_time_get() - start)); + else + printf("efreet_util_desktop_exec_find(update-manager): NULL %.6f\n", (ecore_time_get() - start)); + efreet_desktop_free(desktop); + + //EAPI Eina_List *efreet_util_desktop_name_glob_list(const char *glob); + start = ecore_time_get(); + list = efreet_util_desktop_name_glob_list("Ubuntu*"); + if (list) + { + EINA_LIST_FREE(list, desktop) + { + printf("efreet_util_desktop_name_glob_list(Ubuntu*): %s\n", desktop->name); + efreet_desktop_free(desktop); + } + } + printf("time: %.6f\n", (ecore_time_get() - start)); + + //EAPI Eina_List *efreet_util_desktop_mime_list(const char *mime); + start = ecore_time_get(); + list = efreet_util_desktop_mime_list("application/ogg"); + if (list) + { + EINA_LIST_FREE(list, desktop) + { + printf("efreet_util_desktop_mime_list(application/ogg): %s\n", desktop->name); + efreet_desktop_free(desktop); + } + } + printf("time: %.6f\n", (ecore_time_get() - start)); + + //EAPI Eina_List *efreet_util_desktop_exec_glob_list(const char *glob); + start = ecore_time_get(); + list = efreet_util_desktop_exec_glob_list("*gnome*"); + if (list) + { + EINA_LIST_FREE(list, desktop) + { + printf("efreet_util_desktop_exec_glob_list(*gnome*): %s\n", desktop->exec); + efreet_desktop_free(desktop); + } + } + printf("time: %.6f\n", (ecore_time_get() - start)); + + //EAPI Eina_List *efreet_util_desktop_categories_list(void); + start = ecore_time_get(); + list = efreet_util_desktop_categories_list(); + if (list) + { + EINA_LIST_FREE(list, id) + { + printf("efreet_util_desktop_categories_list(): %s\n", id); + } + } + printf("time: %.6f\n", (ecore_time_get() - start)); + + //EAPI Eina_List *efreet_util_desktop_category_list(const char *category); + start = ecore_time_get(); + list = efreet_util_desktop_category_list("Graphics"); + if (list) + { + EINA_LIST_FREE(list, desktop) + { + printf("efreet_util_desktop_category_list(Graphics): %s\n", desktop->name); + efreet_desktop_free(desktop); + } + } + printf("time: %.6f\n", (ecore_time_get() - start)); + + desktop = efreet_desktop_get("/opt/google/chrome/google-chrome.desktop"); + if (desktop) + printf("%s: %d %d\n", desktop->orig_path, desktop->ref, desktop->eet); + desktop2 = efreet_desktop_new("/opt/google/chrome/google-chrome.desktop"); + if (desktop2) + { + printf("%s: %d %d\n", desktop2->orig_path, desktop2->ref, desktop2->eet); + efreet_desktop_free(desktop2); + } + if (desktop) + efreet_desktop_free(desktop); + + desktop = efreet_desktop_get("/usr/share/applications/firefox.desktop"); + if (desktop) + printf("%s: %d %d\n", desktop->orig_path, desktop->ref, desktop->eet); + desktop2 = efreet_desktop_new("/usr/share/applications/firefox.desktop"); + if (desktop2) + { + printf("%s: %d %d\n", desktop2->orig_path, desktop2->ref, desktop2->eet); + efreet_desktop_free(desktop2); + } + if (desktop) + efreet_desktop_free(desktop); + fflush(stdout); +} + +static Eina_Bool +icon_handler_cb(void *data __UNUSED__, int event_type __UNUSED__, void *event __UNUSED__) +{ + icon_cb = EINA_TRUE; + if (icon_cb && desktop_cb) + { + check(); + ecore_main_loop_quit(); + } + return ECORE_CALLBACK_PASS_ON; +} + +static Eina_Bool +desktop_handler_cb(void *data __UNUSED__, int event_type __UNUSED__, void *event __UNUSED__) +{ + desktop_cb = EINA_TRUE; + if (icon_cb && desktop_cb) + { + check(); + ecore_main_loop_quit(); + } + return ECORE_CALLBACK_PASS_ON; +} + +int +main(int argc __UNUSED__, char **argv __UNUSED__) +{ + Ecore_Event_Handler *icon_handler; + Ecore_Event_Handler *desktop_handler; + + if (!efreet_init()) return 1; + icon_handler = ecore_event_handler_add(EFREET_EVENT_ICON_CACHE_UPDATE, icon_handler_cb, NULL); + desktop_handler = ecore_event_handler_add(EFREET_EVENT_DESKTOP_CACHE_UPDATE, desktop_handler_cb, NULL); + check(); + ecore_main_loop_begin(); + ecore_event_handler_del(icon_handler); + ecore_event_handler_del(desktop_handler); + efreet_shutdown(); + return 0; +} diff --git a/src/tests/ef_data_dirs.c b/src/tests/ef_data_dirs.c new file mode 100644 index 0000000..a99b2ae --- /dev/null +++ b/src/tests/ef_data_dirs.c @@ -0,0 +1,330 @@ +#include "Efreet.h" +#include <Ecore_File.h> +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +int +ef_cb_efreet_data_home(void) +{ + const char *tmp; + int ret = 1; + + efreet_shutdown(); + setenv("XDG_DATA_HOME", "/var/tmp", 1); + efreet_init(); + + tmp = efreet_data_home_get(); + if (strcmp(tmp, "/var/tmp")) + { + printf("efreet_data_home_get() returned incorrect " + "value (%s) on XDG_DATA_HOME=/var/tmp\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_DATA_HOME"); + setenv("HOME", "/home/tmp", 1); + efreet_init(); + + tmp = efreet_data_home_get(); + if (strcmp(tmp, "/home/tmp/.local/share")) + { + printf("efreet_data_home_get() returned incorrect " + "value (%s) on blank XDG_DATA_HOME\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_DATA_HOME"); + unsetenv("HOME"); +#ifdef _WIN32 + unsetenv("USERPROFILE"); +#endif + efreet_init(); + + tmp = efreet_data_home_get(); + if (strcmp(tmp, "/tmp/.local/share")) + { + printf("efreet_data_home_get() returned incorrect " + "value (%s) on blank XDG_DATA_HOME and blank HOME\n", tmp); + ret = 0; + } + + return ret; +} + +int +ef_cb_efreet_config_home(void) +{ + const char *tmp; + int ret = 1; + + efreet_shutdown(); + setenv("XDG_CONFIG_HOME", "/var/tmp", 1); + efreet_init(); + + tmp = efreet_config_home_get(); + if (strcmp(tmp, "/var/tmp")) + { + printf("efreet_config_home_get() returned incorrect " + "value (%s) on XDG_CONFIG_HOME=/var/tmp\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_CONFIG_HOME"); + setenv("HOME", "/home/tmp", 1); + efreet_init(); + + tmp = efreet_config_home_get(); + if (strcmp(tmp, "/home/tmp/.config")) + { + printf("efreet_config_home_get() returned incorrect " + "value (%s) on blank XDG_CONFIG_HOME\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_CONFIG_HOME"); + unsetenv("HOME"); +#ifdef _WIN32 + unsetenv("USERPROFILE"); +#endif + efreet_init(); + + tmp = efreet_config_home_get(); + if (strcmp(tmp, "/tmp/.config")) + { + printf("efreet_config_home_get() returned incorrect " + "value (%s) on blank XDG_CONFIG_HOME and blank HOME\n", tmp); + ret = 0; + } + + return ret; +} + +int +ef_cb_efreet_cache_home(void) +{ + const char *tmp; + int ret = 1; + + efreet_shutdown(); + setenv("XDG_CACHE_HOME", "/var/tmp", 1); + efreet_init(); + + tmp = efreet_cache_home_get(); + if (strcmp(tmp, "/var/tmp")) + { + printf("efreet_cache_home_get() returned incorrect " + "value (%s) on XDG_CACHE_HOME=/var/tmp\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_CACHE_HOME"); + setenv("HOME", "/home/tmp", 1); + efreet_init(); + + tmp = efreet_cache_home_get(); + if (strcmp(tmp, "/home/tmp/.cache")) + { + printf("efreet_cache_home_get() returned incorrect " + "value (%s) on blank XDG_CACHE_HOME\n", tmp); + ret = 0; + } + + /* reset efreet here so we can set a new home dir */ + efreet_shutdown(); + unsetenv("XDG_CACHE_HOME"); + unsetenv("HOME"); +#ifdef _WIN32 + unsetenv("USERPROFILE"); +#endif + efreet_init(); + + tmp = efreet_cache_home_get(); + if (strcmp(tmp, "/tmp/.cache")) + { + printf("efreet_cache_home_get() returned incorrect " + "value (%s) on blank XDG_CACHE_HOME and blank HOME\n", tmp); + ret = 0; + } + + return ret; +} + +int +ef_cb_efreet_data_dirs(void) +{ + Eina_List *tmp, *l; + int ret = 1; + unsigned int i; + unsigned int ok; + char dirs[128], *val; + char *vals[] = {"/var/tmp/a", "/tmp/b", "/usr/local/share", "/etc", NULL}; + char *def_vals[] = {PACKAGE_DATA_DIR, "/usr/share", "/usr/local/share", NULL}; + + dirs[0] = '\0'; + for (i = 0; vals[i]; i++) + { + if (i > 0) strcat(dirs, ":"); + strcat(dirs, vals[i]); + } + + efreet_shutdown(); + setenv("XDG_DATA_DIRS", dirs, 1); + efreet_init(); + + ok = 0; + tmp = efreet_data_dirs_get(); + for (i = 0; vals[i]; i++) + { + char *found; + + found = eina_list_search_unsorted(tmp, EINA_COMPARE_CB(strcmp), vals[i]); + if (!ecore_file_exists(vals[i]) && found) + { + printf("efreet_data_dirs_get() includes non-existing dir (%s) when " + "%s set\n", vals[i], dirs); + ret = 0; + continue; + } + if (ecore_file_exists(vals[i]) && !found) + { + printf("efreet_data_dirs_get() is missing dir (%s) when " + "%s set\n", vals[i], dirs); + ret = 0; + continue; + } + if (ecore_file_exists(vals[i]) && found) + ok++; + } + if (eina_list_count(tmp) != ok) + { + printf("efreet_data_dirs_get() returned more values then it " + "should have given %s as input\n", dirs); + ret = 0; + } + + efreet_shutdown(); + unsetenv("XDG_DATA_DIRS"); + efreet_init(); + + i = 0; + tmp = efreet_data_dirs_get(); + if (eina_list_count(tmp) != 3) + { + printf("efreet_data_dirs_get() nodes is differnet from expected default\n"); + ret = 0; + } + + EINA_LIST_FOREACH(tmp, l, val) + { + if (!def_vals[i]) + { + printf("efreet_data_dirs_get() returned more values then it " + "should have given %s as input\n", dirs); + ret = 0; + break; + } + + if (strcmp(val, def_vals[i])) + { + printf("efreet_data_dirs_get() returned incorrect value (%s) when " + "XDG_DATA_DIRS= is set %s\n", val, def_vals[i]); + ret = 0; + } + + i++; + } + return ret; +} + +int +ef_cb_efreet_config_dirs(void) +{ + Eina_List *tmp, *l; + int ret = 1; + unsigned int i; + unsigned int ok; + char dirs[128], *val; + char *vals[] = {"/var/tmp/a", "/tmp/b", "/usr/local/share", "/etc", NULL}; + char *def_vals[] = {"/etc/xdg", NULL}; + + dirs[0] = '\0'; + + for (i = 0; vals[i]; i++) + { + if (i > 0) strcat(dirs, ":"); + strcat(dirs, vals[i]); + } + + efreet_shutdown(); + setenv("XDG_CONFIG_DIRS", dirs, 1); + efreet_init(); + + ok = 0; + tmp = efreet_config_dirs_get(); + for (i = 0; vals[i]; i++) + { + char *found; + + found = eina_list_search_unsorted(tmp, EINA_COMPARE_CB(strcmp), vals[i]); + if (!ecore_file_exists(vals[i]) && found) + { + printf("efreet_data_dirs_get() includes non-existing dir (%s) when " + "%s set\n", vals[i], dirs); + ret = 0; + continue; + } + if (ecore_file_exists(vals[i]) && !found) + { + printf("efreet_data_dirs_get() is missing dir (%s) when " + "%s set\n", vals[i], dirs); + ret = 0; + continue; + } + if (ecore_file_exists(vals[i]) && found) + ok++; + } + if (eina_list_count(tmp) != ok) + { + printf("efreet_data_dirs_get() returned more values then it " + "should have given %s as input\n", dirs); + ret = 0; + } + + efreet_shutdown(); + unsetenv("XDG_CONFIG_DIRS"); + efreet_init(); + + i = 0; + tmp = efreet_config_dirs_get(); + EINA_LIST_FOREACH(tmp, l, val) + { + if (!def_vals[i]) + { + printf("efreet_config_dirs_get() returned more values then it " + "should have given %s as input\n", dirs); + ret = 0; + break; + } + + if (strcmp(val, def_vals[i])) + { + printf("efreet_config_dirs_get() returned incorrect value (%s) when " + "XDG_CONFIG_DIRS= is set\n", val); + ret = 0; + } + + i++; + } + return ret; +} diff --git a/src/tests/ef_desktop.c b/src/tests/ef_desktop.c new file mode 100644 index 0000000..39f942a --- /dev/null +++ b/src/tests/ef_desktop.c @@ -0,0 +1,401 @@ +#include "Efreet.h" +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <limits.h> +#include "ef_test.h" + +static void *_cb_command(void *data, Efreet_Desktop *desktop, char *exec, int remaining); + + +int +ef_cb_desktop_parse(void) +{ + Efreet_Desktop *desktop; + Eina_List *l; + int ret = 1; + + desktop = efreet_desktop_get(PKG_DATA_DIR"/test/test.desktop"); + if (!desktop) + { + printf("No desktop found.\n"); + return 0; + } + + if (!desktop->name || strcmp(desktop->name, "Efreet Test Application")) + { + printf("Invalid Name\n"); + ret = 0; + } + + if (!desktop->generic_name || + strcmp(desktop->generic_name, "Test Application")) + { + printf("Incorrent GenericName\n"); + ret = 0; + } + + if (!desktop->exec || strcmp(desktop->exec, "efreet_test %F %i")) + { + printf("Incorrect Exec (%s)\n", (desktop->exec ? desktop->exec : "(null)")); + ret = 0; + } + + if (desktop->categories) + { + const char *categories[] = {"Test", "Enlightenment"}; + const char *cat; + int num_categories = 2, i = 0; + + EINA_LIST_FOREACH(desktop->categories, l, cat) + { + if (i >= num_categories) + { + printf("Too many categories found.\n"); + ret = 0; + break; + } + + if (!cat || !categories[i] || strcmp(cat, categories[i])) + { + printf("Expected category %s, found %s\n", categories[i], cat); + ret = 0; + } + i++; + } + } + else ret = 0; + + efreet_desktop_free(desktop); + + return ret; +} + +#if 0 +int +ef_cb_desktop_file_id(void) +{ + Efreet_Desktop *desktop; + int ret = 1; + + desktop = efreet_desktop_get(PKG_DATA_DIR"/test/test.desktop"); + if (desktop) + { + const char *id; + int i = 0; + + struct { + char *dir; + int legacy; + char *prefix; + char *expected; + } tests[] = { + {PKG_DATA_DIR"/test/", 0, NULL, "test.desktop"}, + {PKG_DATA_DIR"/", 0, NULL, "test-test.desktop"}, + {PKG_DATA_DIR"/", 1, NULL, "test.desktop"}, + {PKG_DATA_DIR"/", 1, "prefix", "prefix-test.desktop"}, + {NULL, 0, NULL, NULL} + }; + + for (i = 0; tests[i].dir != NULL; i++) + { + id = efreet_desktop_id_get(desktop, + tests[i].dir, + tests[i].legacy, + tests[i].prefix); + if (!id || strcmp(id, tests[i].expected)) + { + printf("Expecting id: %s, got: %s\n", tests[i].expected, id); + ret = 0; + } + if (id) eina_stringshare_del(id); + } + } + else + ret = 0; + + return ret; +} +#endif + +int +ef_cb_desktop_save(void) +{ + Efreet_Desktop *desktop; + + printf("\n"); + desktop = efreet_desktop_get(PKG_DATA_DIR"/test/test.desktop"); + if (!desktop) + { + printf("Failed to get Desktop file\n"); + return 0; + } + + printf("save data: %d\n", efreet_desktop_save(desktop)); + efreet_desktop_free(desktop); + + desktop = efreet_desktop_empty_new("/tmp/test.desktop"); + desktop->name = strdup("Efreet Test Application"); + desktop->type = EFREET_DESKTOP_TYPE_APPLICATION; + desktop->generic_name = strdup("Test Application"); + desktop->exec = strdup("efreet_test"); + desktop->categories = NULL; + desktop->categories = eina_list_append(desktop->categories, eina_stringshare_add("Test")); + desktop->categories = eina_list_append(desktop->categories, eina_stringshare_add("Enlightenment")); + printf("save test: %d\n", efreet_desktop_save(desktop)); + unlink("/tmp/test.desktop"); + efreet_desktop_free(desktop); + + return 1; +} + +typedef struct +{ + Eina_List *expected; + int error; + char type; +} Test_Info; + +int +ef_cb_desktop_command_get(void) +{ + Efreet_Desktop *desktop; + Eina_List *files, *expected; + char olddir[PATH_MAX]; + Test_Info *info; + int ret; + + if (getcwd(olddir, PATH_MAX) != 0) ret = 0; + if (chdir("/") != 0) ret = 0; + + printf("\n"); + desktop = efreet_desktop_empty_new("test.desktop"); + + desktop->name = strdup("App Name"); + desktop->icon = strdup("icon.png"); + + files = NULL; + files = eina_list_append(files, "/tmp/absolute_path"); + files = eina_list_append(files, "relative_path"); + files = eina_list_append(files, "file:///tmp/absolute_uri"); + files = eina_list_append(files, "file:relative_uri"); + + info = NEW(Test_Info, 1); + expected = NULL; + info->error = 0; + + /* test single full path */ + info->type = 'f'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %f"); + expected = eina_list_append(expected, "app '/tmp/absolute_path'"); + expected = eina_list_append(expected, "app '/relative_path'"); + expected = eina_list_append(expected, "app '/tmp/absolute_uri'"); + expected = eina_list_append(expected, "app '/relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); + + /* test single uri */ + info->type = 'u'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %u"); + expected = eina_list_append(expected, "app 'file:///tmp/absolute_path'"); + expected = eina_list_append(expected, "app 'file:///relative_path'"); + expected = eina_list_append(expected, "app 'file:///tmp/absolute_uri'"); + expected = eina_list_append(expected, "app 'file:///relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); + + /* test single dir */ +#if 0 + info->type = 'd'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %d"); + expected = eina_list_append(expected, "app '/tmp'"); + expected = eina_list_append(expected, "app '/'"); + expected = eina_list_append(expected, "app '/tmp'"); + expected = eina_list_append(expected, "app '/'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); +#endif + + + /* test single names */ +#if 0 + info->type = 'n'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %n"); + expected = eina_list_append(expected, "app 'absolute_path'"); + expected = eina_list_append(expected, "app 'relative_path'"); + expected = eina_list_append(expected, "app 'absolute_uri'"); + expected = eina_list_append(expected, "app 'relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); +#endif + + /* test multiple fullpaths */ + info->type = 'F'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %F"); + expected = eina_list_append(expected, "app '/tmp/absolute_path' '/relative_path' '/tmp/absolute_uri' '/relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); + + /* test multiple URIs */ + info->type = 'U'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %U"); + expected = eina_list_append(expected, "app 'file:///tmp/absolute_path' 'file:///relative_path' 'file:///tmp/absolute_uri' 'file:///relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); + + /* test multiple dirs */ +#if 0 + info->type = 'D'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %D"); + expected = eina_list_append(expected, "app '/tmp' '/' '/tmp' '/'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); +#endif + + /* test multiple names */ +#if 0 + info->type = 'N'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %N"); + expected = eina_list_append(expected, "app 'absolute_path' 'relative_path' 'absolute_uri' 'relative_uri'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, files, _cb_command, info); + expected = eina_list_free(expected); +#endif + + /* test icon appending */ + info->type = 'i'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %i"); + expected = eina_list_append(expected, "app --icon 'icon.png'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, NULL, _cb_command, info); + expected = eina_list_free(expected); + + /* test app name */ + info->type = 'c'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %c"); + expected = eina_list_append(expected, "app 'App Name'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, NULL, _cb_command, info); + expected = eina_list_free(expected); + + /* test desktop path */ + info->type = 'k'; + IF_FREE(desktop->exec); + desktop->exec = strdup("app %k"); + expected = eina_list_append(expected, "app 'test.desktop'"); + + info->expected = expected; + efreet_desktop_command_get(desktop, NULL, _cb_command, info); + eina_list_free(expected); + + /* clean up */ + efreet_desktop_free(desktop); + eina_list_free(files); + + if (chdir(olddir) != 0) ret = 0; + + ret = info->error > 0 ? 0 : 1; + free(info); + + return ret; +} + +static void * +_cb_command(void *data, Efreet_Desktop *desktop __UNUSED__, + char *exec, int remaining __UNUSED__) +{ + Test_Info *info = data; + char *expected; + + expected = eina_list_data_get(info->expected); + info->expected = eina_list_demote_list(info->expected, info->expected); + if (!expected) + { + printf(" ERROR: (%%%c) got \"%s\", expected nothing\n", info->type, exec); + info->error++; + } + else + { + if (strcmp(exec, expected)) + { + printf(" ERROR: (%%%c) got \"%s\", expected \"%s\"\n", info->type, exec, expected); + info->error++; + } + } + free(exec); + return NULL; +} + +static void * +cb_type_parse(Efreet_Desktop *desktop __UNUSED__, Efreet_Ini *ini) +{ + const char *val; + val = efreet_ini_string_get(ini, "X-Test"); + if (!val) return NULL; + return (void *)strdup(val); +} + +int +ef_cb_desktop_type_parse(void) +{ + Efreet_Desktop *desktop; + int my_type; + char *val; + int ret = 1; + + /* add my custom desktop type to efreet */ + my_type = efreet_desktop_type_add("My_Type", cb_type_parse, NULL, + (Efreet_Desktop_Type_Free_Cb)free); + + desktop = efreet_desktop_get(PKG_DATA_DIR"/test/test_type.desktop"); + if (!desktop) + { + printf("No desktop found.\n"); + return 0; + } + + if (desktop->type != my_type) + { + printf("Invalid type returned in desktop"); + ret = 0; + } + + val = (char *)efreet_desktop_type_data_get(desktop); + if (!val || strcmp(val, "Own key")) + { + printf("Invalid value of custom key (%s).\n", val); + ret = 0; + } + + efreet_desktop_free(desktop); + return ret; +} diff --git a/src/tests/ef_icon_theme.c b/src/tests/ef_icon_theme.c new file mode 100644 index 0000000..1a04cfa --- /dev/null +++ b/src/tests/ef_icon_theme.c @@ -0,0 +1,605 @@ +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "Efreet.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> +#include <limits.h> +#include <Ecore.h> +#include <Ecore_File.h> + +#define SIZE 128 +#define THEME "Tango" +#define FREE(x) do { free(x); x = NULL; } while (0); + +static Eina_Bool _hash_keys(Eina_Hash *hash, const char *key, void *list); +static void ef_icon_theme_themes_find(const char *search_dir, + Eina_Hash *themes); +static void ef_icons_find(Efreet_Icon_Theme *theme, Eina_Hash *icons); +static void ef_read_dir(const char *dir, Eina_Hash *icons); + +int +ef_cb_efreet_icon_theme(void) +{ + int ret = 1; + const char *tmp; + + unsetenv("XDG_DATA_HOME"); + efreet_shutdown(); + putenv("HOME=/var/tmp"); + efreet_init(); + + tmp = efreet_icon_user_dir_get(); + if (strcmp(tmp, "/var/tmp/.local/share/icons")) + { + printf("efreet_icon_user_dir_get() returned incorrect " + "value (%s) on HOME=/var/tmp\n", tmp); + ret = 0; + } + + efreet_shutdown(); + unsetenv("HOME"); +#ifdef _WIN32 + unsetenv("USERPROFILE"); +#endif + efreet_init(); + + tmp = efreet_icon_user_dir_get(); + if (strcmp(tmp, "/tmp/.local/share/icons")) + { + printf("efreet_icon_user_dir_get() returned incorrect " + "value (%s) on HOME=\n", tmp); + ret = 0; + } + + return ret; +} + +static Eina_Bool +_hash_keys(Eina_Hash *hash __UNUSED__, const char *key, void *list) +{ + Eina_List **l = list; + + *l = eina_list_append(*l, key); + return EINA_TRUE; +} + +int +ef_cb_efreet_icon_theme_list(void) +{ + int ret = 1; + Eina_List *themes; + Eina_List *icon_dirs; + Eina_List *l; + Eina_Hash *dirs; + Eina_Iterator *it; + Efreet_Icon_Theme *theme; + const char *dir; + char buf[PATH_MAX]; + + dirs = eina_hash_string_superfast_new(free); + + icon_dirs = efreet_data_dirs_get(); + + ef_icon_theme_themes_find(efreet_icon_user_dir_get(), dirs); + EINA_LIST_FOREACH(icon_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/icons", dir); + ef_icon_theme_themes_find(buf, dirs); + } + EINA_LIST_FOREACH(icon_dirs, l, dir) + { + snprintf(buf, sizeof(buf), "%s/pixmaps", dir); + ef_icon_theme_themes_find(buf, dirs); + } + ef_icon_theme_themes_find("/usr/share/pixmaps", dirs); + + themes = efreet_icon_theme_list_get(); + EINA_LIST_FOREACH(themes, l, theme) + { + if ((eina_hash_find(dirs, theme->name.internal))) + eina_hash_del(dirs, theme->name.internal, NULL); + else + { + printf("efreet_icon_theme_list_get() returned %s which we didn't " + "see when scanning the directories.\n", theme->name.internal); + ret = 0; + } + } + while (themes) + { + themes = eina_list_remove_list(themes, themes); + } + + themes = NULL; + it = eina_hash_iterator_key_new(dirs); + eina_iterator_foreach(it, EINA_EACH_CB(_hash_keys), &themes); + eina_iterator_free(it); + + if (eina_list_count(themes) > 0) + { + printf("efreet_icon_theme_list_get() missed: "); + EINA_LIST_FOREACH(themes, l, dir) + printf("%s ", dir); + printf("\n"); + + ret = 0; + } + while (themes) + { + themes = eina_list_remove_list(themes, themes); + } + eina_hash_free(dirs); + + return ret; +} + +static void +ef_icon_theme_themes_find(const char *search_dir, Eina_Hash *themes) +{ + Eina_List *dirs; + char *dir; + + if (!search_dir || !themes) return; + + dirs = ecore_file_ls(search_dir); + if (!dirs) return; + + while ((dir = eina_list_data_get(dirs))) + { + char p[PATH_MAX]; + + dirs = eina_list_remove_list(dirs, dirs); + /* if we've already added the theme we're done */ + if (eina_hash_find(themes, dir)) + { + free(dir); + continue; + } + + /* if the index.theme file exists we open it and look for the hidden + * flag. */ + snprintf(p, sizeof(p), "%s/%s/index.theme", search_dir, dir); + if (ecore_file_exists(p)) + { + Efreet_Ini *ini; + char *d; + int skip = 0; + + ini = efreet_ini_new(p); + efreet_ini_section_set(ini, "Icon Theme"); + + //if (efreet_ini_boolean_get(ini, "Hidden")) skip = 1; + if (!efreet_ini_localestring_get(ini, "Name")) skip = 1; + efreet_ini_free(ini); + + if (!skip) + { + d = strdup(dir); + eina_hash_add(themes, dir, d); + } + } + free(dir); + } +} + +const char *system_icons[] = +{ + "address-book-new", + "application-exit", + "appointment-new", + "contact-new", + "dialog-apply", + "dialog-cancel", + "dialog-close", + "dialog-ok", + "document-new", + "document-open", + "document-open-recent", + "document-page-setup", + "document-print", + "document-print-preview", + "document-properties", + "document-revert", + "document-save", + "document-save-as", + "edit-copy", + "edit-cut", + "edit-delete", + "edit-find", + "edit-find-replace", + "edit-paste", + "edit-redo", + "edit-select-all", + "edit-undo", + "format-indent-less", + "format-indent-more", + "format-justify-center", + "format-justify-fill", + "format-justify-left", + "format-justify-right", + "format-text-direction-ltr", + "format-text-direction-rtl", + "format-text-bold", + "format-text-italic", + "format-text-underline", + "format-text-strikethrough", + "go-bottom", + "go-down", + "go-first", + "go-home", + "go-jump", + "go-last", + "go-next", + "go-previous", + "go-top", + "go-up", + "help-about", + "help-contents", + "help-faq", + "insert-image", + "insert-link", + "insert-object", + "insert-text", + "list-add", + "list-remove", + "mail-forward", + "mail-mark-important", + "mail-mark-junk", + "mail-mark-notjunk", + "mail-mark-read", + "mail-mark-unread", + "mail-message-new", + "mail-reply-all", + "mail-reply-sender", + "mail-send-receive", + "media-eject", + "media-playback-pause", + "media-playback-start", + "media-playback-stop", + "media-record", + "media-seek-backward", + "media-seek-forward", + "media-skip-backward", + "media-skip-forward", + "system-lock-screen", + "system-log-out", + "system-run", + "system-search", + "system-search", + "tools-check-spelling", + "view-fullscreen", + "view-refresh", + "view-sort-ascending", + "view-sort-descending", + "window-close", + "window-new", + "zoom-best-fit", + "zoom-in", + "zoom-original", + "zoom-out", + "process-working", + "accessories-calculator", + "accessories-character-map", + "accessories-dictionary", + "accessories-text-editor", + "help-browser", + "multimedia-volume-control", +#if 0 + "preferences-desktop-accessibility", + "preferences-desktop-font", + "preferences-desktop-keyboard", + "preferences-desktop-locale", + "preferences-desktop-multimedia", + "preferences-desktop-screensaver", + "preferences-desktop-theme", + "preferences-desktop-wallpaper", + "system-file-manager", + "system-software-update", + "utilities-terminal", + "applications-accessories", + "applications-development", + "applications-games", + "applications-graphics", + "applications-internet", + "applications-multimedia", + "applications-office", + "applications-other", + "applications-system", + "applications-utilities", + "preferences-desktop", + "preferences-desktop-accessibility", + "preferences-desktop-peripherals", + "preferences-desktop-personal", + "preferences-other", + "preferences-system", + "preferences-system-network", + "system-help", + "audio-card", + "audio-input-microphone", + "battery", + "camera-photo", + "camera-video", + "computer", + "drive-cdrom", + "drive-harddisk", + "drive-removable-media", + "input-gaming", + "input-keyboard", + "input-mouse", + "media-cdrom", + "media-floppy", + "multimedia-player", + "multimedia-player", + "network-wired", + "network-wireless", + "printer", + "emblem-default", + "emblem-documents", + "emblem-downloads", + "emblem-favorite", + "emblem-important", + "emblem-mail", + "emblem-photos", + "emblem-readonly", + "emblem-shared", + "emblem-symbolic-link", + "emblem-synchronized", + "emblem-system", + "emblem-unreadable", + "face-angel", + "face-crying", + "face-devil-grin", + "face-devil-sad", + "face-glasses", + "face-kiss", + "face-monkey", + "face-plain", + "face-sad", + "face-smile", + "face-smile-big", + "face-smirk", + "face-surprise", + "face-wink", + "application-x-executable", + "audio-x-generic", + "font-x-generic", + "image-x-generic", + "package-x-generic", + "text-html", + "text-x-generic", + "text-x-generic-template", + "text-x-script", + "video-x-generic", + "x-office-address-book", + "x-office-calendar", + "x-office-document", + "x-office-presentation", + "x-office-spreadsheet", + "folder", + "folder-remote", + "network-server", + "network-workgroup", + "start-here", + "user-desktop", + "user-home", + "user-trash", + "appointment-missed", + "appointment-soon", + "audio-volume-high", + "audio-volume-low", + "audio-volume-medium", + "audio-volume-muted", + "battery-caution", + "battery-low", + "dialog-error", + "dialog-information", + "dialog-password", + "dialog-question", + "dialog-warning", + "folder-drag-accept", + "folder-open", + "folder-visiting", + "image-loading", + "image-missing", + "mail-attachment", + "mail-unread", + "mail-read", + "mail-replied", + "mail-signed", + "mail-signed-verified", + "media-playlist-repeat", + "media-playlist-shuffle", + "network-error", + "network-idle", + "network-offline", + "network-receive", + "network-transmit", + "network-transmit-receive", + "printer-error", + "printer-printing", + "software-update-available", + "software-update-urgent", + "sync-error", + "sync-synchronizing", + "task-due", + "task-passed-due", + "user-away", + "user-idle", + "user-offline", + "user-online", + "user-trash-full", + "weather-clear", + "weather-clear-night", + "weather-few-clouds", + "weather-few-clouds-night", + "weather-fog", + "weather-overcast", + "weather-severe-alert", + "weather-showers", + "weather-showers-scattered", + "weather-snow", + "weather-storm", +#endif + NULL +}; + +int +ef_cb_efreet_icon_match(void) +{ + int i, ret = 1; + Eina_Hash *icon_hash; + Efreet_Icon_Theme *theme; + + theme = efreet_icon_theme_find(THEME); + icon_hash = eina_hash_string_superfast_new(free); + + ef_icons_find(theme, icon_hash); + + double start = ecore_time_get(); + for (i = 0; system_icons[i]; i++) + { + const char *path; + char *p, *s; + + path = efreet_icon_path_find(THEME, system_icons[i], SIZE); + + if (!path) + { +#if 1 + if (eina_hash_find(icon_hash, system_icons[i])) + { + printf("NOT FOUND %s\n", system_icons[i]); + ret = 0; + } +#endif + continue; + } + else if (!eina_hash_find(icon_hash, system_icons[i])) + { + printf("Found icon not in hash: %s\n", system_icons[i]); + } + + p = strdup(path); + s = strrchr(p, '.'); + if (s) *s = '\0'; + s = strrchr(p, '/'); + if (s) s++; + + if (s && strcmp(s, system_icons[i])) + { + printf("Name mismatch name (%s) vs ef (%s)\n", system_icons[i], s); + ret = 0; + } + free(p); + } + printf("Time: %f\n", (ecore_time_get() - start)); + eina_hash_free(icon_hash); + + start = ecore_time_get(); + for (i = 0; system_icons[i]; i++) + { + const char *path; + char *p, *s; + + path = efreet_icon_path_find(THEME, system_icons[i], SIZE); + + if (!path) continue; + p = strdup(path); + + s = strrchr(p, '.'); + if (s) *s = '\0'; + s = strrchr(p, '/'); + if (s) s++; + + if (s && strcmp(s, system_icons[i])) + { + printf("Name mismatch name (%s) vs ef (%s)\n", system_icons[i], s); + ret = 0; + } + free(p); + } + printf("Time: %f\n", (ecore_time_get() - start)); + + return ret; +} + +static void +ef_icons_find(Efreet_Icon_Theme *theme, Eina_Hash *icons) +{ + Eina_List *l, *ll; + char path[PATH_MAX]; + const char *theme_path; + + if (!theme || !icons) return; + + EINA_LIST_FOREACH(theme->paths, l, theme_path) + { + Efreet_Icon_Theme_Directory *dir; + + EINA_LIST_FOREACH(theme->directories, ll, dir) + { + snprintf(path, sizeof(path), "%s/%s/", theme_path, dir->name); + ef_read_dir(path, icons); + } + } + + if (theme->inherits) + { + Efreet_Icon_Theme *parent_theme; + char *parent; + + EINA_LIST_FOREACH(theme->inherits, l, parent) + { + parent_theme = efreet_icon_theme_find(parent); + if (parent_theme) + ef_icons_find(parent_theme, icons); + } + } + else if (strcmp(theme->name.internal, "hicolor")) + { + Efreet_Icon_Theme *parent_theme; + + parent_theme = efreet_icon_theme_find("hicolor"); + if (parent_theme) + ef_icons_find(parent_theme, icons); + } + + ef_read_dir("/usr/share/pixmaps", icons); +} + +static void +ef_read_dir(const char *dir, Eina_Hash *icons) +{ + Eina_List *files; + char *file; + + if (!dir || !icons) return; + + files = ecore_file_ls(dir); + if (!files) return; + + while ((file = eina_list_data_get(files))) + { + char *p; + + files = eina_list_remove_list(files, files); + p = strrchr(file, '.'); + if (!p) + { + FREE(file); + continue; + } + + if (!strcmp(p, ".png") || !strcmp(p, ".xpm")) + { + *p = '\0'; + + eina_hash_add(icons, file, strdup(file)); + } + + FREE(file); + } +} diff --git a/src/tests/ef_ini.c b/src/tests/ef_ini.c new file mode 100644 index 0000000..00d459e --- /dev/null +++ b/src/tests/ef_ini.c @@ -0,0 +1,174 @@ +#include "Efreet.h" +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <stdlib.h> + +int +ef_cb_ini_parse(void) +{ + int ret = 1; + Efreet_Ini *ini; + + putenv("LC_ALL=en_US"); + + ini = efreet_ini_new(PKG_DATA_DIR"/test/test.ini"); + if (!ini) + { + printf("efreet_ini_parse() Failed to initialize Efreet_Ini\n"); + return 0; + } + + if (efreet_ini_section_set(ini, "contact")) + { + const char *val; + int ival; + unsigned int bval; + + val = efreet_ini_string_get(ini, "Name"); + if (!val || strcmp(val, "Foo Bar")) + { + printf("efreet_ini_string_get() Name parsed incorrectly\n"); + ret = 0; + } + + val = efreet_ini_localestring_get(ini, "Name"); + if (!val || strcmp(val, "English Foo Bar")) + { + printf("efreet_ini_localestring_get() Name parsed incorrectly\n"); + ret = 0; + } + + val = efreet_ini_string_get(ini, "Email"); + if (!val || strcmp(val, "foo@bar.com")) + { + printf("efreet_ini_string_get() Email parsed incorrectly\n"); + ret = 0; + } + + val = efreet_ini_localestring_get(ini, "Email"); + if (!val || strcmp(val, "foo@bar.com")) + { + printf("efreet_ini_localestring_get() Email parsed incorrectly\n"); + ret = 0; + } + + ival = efreet_ini_int_get(ini, "Age"); + if (ival != 30) + { + printf("efreet_ini_int_get() Age parsed incorrectly\n"); + ret = 0; + } + + bval = efreet_ini_boolean_get(ini, "TrueBoolean"); + if (!bval) + { + printf("efreet_ini_boolean_get() TrueBoolean parsed incorrectly\n"); + ret = 0; + } + + bval = efreet_ini_boolean_get(ini, "FalseBoolean"); + if (bval) + { + printf("efreet_ini_boolean_get() FalseBoolean parsed incorrectly\n"); + ret = 0; + } + + bval = efreet_ini_boolean_get(ini, "InvalidBoolean"); + if (bval) + { + printf("efreet_ini_boolean_get() InvalidBoolean parsed incorrectly\n"); + ret = 0; + } + + val = efreet_ini_string_get(ini, "Escaped"); + if (!val || strcmp(val, "line1\nline2\r\nline3\ttabbed \\ with a backslash and spaces")) + { + printf("efreet_ini_unescape() improperly unescaped value\n"); + ret = 0; + } + } + else + { + printf("efreet_ini_section_set() Failed to set 'contact' section\n"); + ret = 0; + } + + efreet_ini_free(ini); + + return ret; +} + +int +ef_cb_ini_long_line(void) +{ + Efreet_Ini *ini; + int ret = 1; + + struct + { + char *key; + int len; + } tests[] = { + {"key", 5099}, + {"key2", 5099}, + {NULL, 0} + }; + + ini = efreet_ini_new(PKG_DATA_DIR"/test/long.ini"); + if (!ini) + { + printf("Ini failed to parse.\n"); + ret = 0; + } + + if (ret) ret = efreet_ini_section_set(ini, "section"); + if (ret) + { + const char *val; + int i, len; + + for (i = 0; tests[i].key; i++) + { + val = efreet_ini_string_get(ini, tests[i].key); + if (val) + { + len = strlen(val); + if (len != tests[i].len) + { + printf("Invalid long line parsing. Value length: %d (expected %d)\n", len, tests[i].len); + ret = 0; + } + } + else + { + printf("Key missing: %s.", tests[i].key); + ret = 0; + } + } + } + else + { + printf("Section missing: 'section'."); + } + + if (ini) efreet_ini_free(ini); + return ret; +} + +int +ef_cb_ini_garbage(void) +{ + Efreet_Ini *ini; + int ret = 1; + + ini = efreet_ini_new(PKG_DATA_DIR"/test/test_garbage"); + if (!ini) + { + printf("Ini failed to parse.\n"); + return 0; + } + if (ini->data) ret = 0; + efreet_ini_free(ini); + return ret; +} diff --git a/src/tests/ef_locale.c b/src/tests/ef_locale.c new file mode 100644 index 0000000..cfc50e2 --- /dev/null +++ b/src/tests/ef_locale.c @@ -0,0 +1,85 @@ +#include "Efreet.h" +#include "efreet_private.h" +#include <stdlib.h> +#include <stdio.h> +#include <string.h> + +int +ef_cb_locale(void) +{ + int ret = 1, i; + struct + { + char *lc_message; + char *lang; + char *country; + char *modifier; + } langs[] = { + /* these are ordered such that when we move from LANG to LC_MESSAGES + * the LANG env will still be effect. Same with moving from + * LC_MESSAGES to LANG */ + {"LANG=", NULL, NULL, NULL}, + {"LANG=en", "en", NULL, NULL}, + {"LANG=en@Latn", "en", NULL, "Latn"}, + {"LANG=en_US", "en", "US", NULL}, + {"LANG=en_US@Latn", "en", "US", "Latn"}, + {"LANG=en_US.blah@Latn", "en", "US", "Latn"}, + {"LC_MESSAGES=", "en", "US", "Latn"}, /* This will fallback to LANG */ + {"LC_MESSAGES=fr", "fr", NULL, NULL}, + {"LC_MESSAGES=fr@Blah", "fr", NULL, "Blah"}, + {"LC_MESSAGES=fr_FR", "fr", "FR", NULL}, + {"LC_MESSAGES=fr_FR@Blah", "fr", "FR", "Blah"}, + {"LC_MESSAGES=fr_FR.Foo@Blah", "fr", "FR", "Blah"}, + {"LC_ALL=", "fr", "FR", "Blah"}, /* this will fallback to LC_MESSAGES */ + {"LC_ALL=sr", "sr", NULL, NULL}, + {"LC_ALL=sr@Ret", "sr", NULL, "Ret"}, + {"LC_ALL=sr_YU", "sr", "YU", NULL}, + {"LC_ALL=sr_YU@Ret", "sr", "YU", "Ret"}, + {"LC_ALL=sr_YU.ssh@Ret", "sr", "YU", "Ret"}, + {NULL, NULL, NULL, NULL} + }; + + /* reset everything to blank */ + putenv("LC_ALL="); + putenv("LC_MESSAGES="); + putenv("LANG="); + + for (i = 0; langs[i].lc_message; i++) + { + const char *tmp; + + putenv(langs[i].lc_message); + + tmp = efreet_lang_get(); + if ((langs[i].lang && (!tmp || strcmp(tmp, langs[i].lang))) + || (!langs[i].lang && tmp)) + { + printf("efreet_lang_get() is wrong (%s) with %s\n", + tmp, langs[i].lang); + ret = 0; + } + + tmp = efreet_lang_country_get(); + if ((langs[i].country && (!tmp || strcmp(tmp, langs[i].country))) + || (!langs[i].country && tmp)) + { + printf("efreet_lang_country_get() is wrong (%s) with %s\n", + tmp, langs[i].lang); + ret = 0; + } + + tmp = efreet_lang_modifier_get(); + if ((langs[i].modifier && (!tmp || strcmp(tmp, langs[i].modifier))) + || (!langs[i].modifier && tmp)) + { + printf("efreet_lang_modifier_get() is wrong with %s with %s\n", + tmp, langs[i].lang); + ret = 0; + } + + efreet_shutdown(); + efreet_init(); + } + + return ret; +} diff --git a/src/tests/ef_menu.c b/src/tests/ef_menu.c new file mode 100644 index 0000000..a7519b7 --- /dev/null +++ b/src/tests/ef_menu.c @@ -0,0 +1,150 @@ +#include "Efreet.h" +#include "config.h" +#include <stdio.h> +#include <unistd.h> + +#if 0 +static void +ef_menu_desktop_exec(Efreet_Menu *menu) +{ + Eina_List *l; + + if (menu->entries) + { + Efreet_Desktop *desktop; + + EINA_LIST_FOREACH(menu->entries, l, desktop) + efreet_desktop_exec(desktop, NULL); + } + if (menu->sub_menus) + { + Efreet_Menu *sub_menu; + + EINA_LIST_FOREACH(menu->sub_menus, l, sub_menu) + ef_menu_desktop_exec(sub_menu); + } +} +#endif + +int +ef_cb_menu_get(void) +{ + Efreet_Menu *menu; + + menu = efreet_menu_get(); +// menu = efreet_menu_parse(PKG_DATA_DIR"/test/test.menu"); + if (!menu) + { + printf("efreet_menu_get() returned NULL\n"); + return 0; + } + printf("\n"); + efreet_menu_dump(menu, ""); + efreet_menu_free(menu); + + return 1; +} + +int +ef_cb_menu_with_slashes(void) +{ + Efreet_Menu *menu; + + menu = efreet_menu_parse(PKG_DATA_DIR"/test/test_menu_slash_bad.menu"); + if (menu) + { + printf("efreet_menu_get() didn't return NULL\n"); + return 0; + } + + return 1; +} + +int +ef_cb_menu_save(void) +{ + Efreet_Menu *menu; + int ret; + +// menu = efreet_menu_get(); + menu = efreet_menu_parse(PKG_DATA_DIR"/test/test.menu"); + if (!menu) + { + printf("efreet_menu_get() returned NULL\n"); + return 0; + } + unlink("/tmp/test.menu"); + ret = efreet_menu_save(menu, "/tmp/test.menu"); + efreet_menu_free(menu); + return ret; +} + +int +ef_cb_menu_edit(void) +{ + Efreet_Menu *menu, *entry; + Efreet_Desktop *desktop; + +// menu = efreet_menu_get(); + menu = efreet_menu_parse(PKG_DATA_DIR"/test/test.menu"); + if (!menu) + { + printf("efreet_menu_get() returned NULL\n"); + return 0; + } +#if 0 + printf("\n"); + efreet_menu_dump(menu, ""); + printf("\n"); +#endif + + desktop = efreet_desktop_get(PKG_DATA_DIR"/test/test.desktop"); + if (!desktop) + { + efreet_menu_free(menu); + printf("No desktop found.\n"); + return 0; + } + + efreet_menu_desktop_insert(menu, desktop, 0); +#if 0 + printf("\n"); + efreet_menu_dump(menu, ""); + printf("\n"); +#endif + entry = eina_list_data_get(menu->entries); + if (desktop != entry->desktop) + { + efreet_menu_free(menu); + return 0; + } + + efreet_menu_desktop_insert(menu, desktop, 2); +#if 0 + printf("\n"); + efreet_menu_dump(menu, ""); + printf("\n"); +#endif + entry = eina_list_nth(menu->entries, 2); + if (desktop != entry->desktop) + { + efreet_menu_free(menu); + return 0; + } + + efreet_menu_desktop_insert(menu, desktop, -1); +#if 0 + printf("\n"); + efreet_menu_dump(menu, ""); + printf("\n"); +#endif + entry = eina_list_data_get(eina_list_last(menu->entries)); + if (desktop != entry->desktop) + { + efreet_menu_free(menu); + return 0; + } + + efreet_menu_free(menu); + return 1; +} diff --git a/src/tests/ef_mime.c b/src/tests/ef_mime.c new file mode 100644 index 0000000..2cb9e21 --- /dev/null +++ b/src/tests/ef_mime.c @@ -0,0 +1,57 @@ +#include "Efreet.h" +#include "Efreet_Mime.h" +#include "config.h" +#include <stdio.h> +#include <string.h> +#include <sys/time.h> +#include <Ecore.h> + +#define THEME "Tango" +#define SIZE 128 + +int +ef_mime_cb_get(void) +{ + const char *mime = NULL, *icon; + int misses = 0, i = 0; + struct + { + char *file; + char *mime; + } files[] = { + {PKG_DATA_DIR"/test/test_type.desktop", "application/x-desktop"}, + {PKG_DATA_DIR"/test/entry.png", "image/png"}, + {PKG_DATA_DIR"/test/entry", "image/png"}, + {PKG_DATA_DIR"/test/sub", "inode/directory"}, + {NULL, NULL} + }; + double start; + + if (!efreet_mime_init()) + { + printf("Could not init efreet\n"); + return 1; + } + + for (i = 0; files[i].file; ++i) + { + mime = efreet_mime_type_get(files[i].file); + if (!mime) + { + printf("Got %s as null instead of %s\n", files[i].file, files[i].mime); + misses ++; + } + else if (strcmp(mime, files[i].mime)) + { + printf("Got %s as %s instead of %s\n", files[i].file, mime, files[i].mime); + misses ++; + } + start = ecore_time_get(); + icon = efreet_mime_type_icon_get(files[i].mime, THEME, SIZE); + printf("mime icon: %s %s %f\n", files[i].mime, icon, ecore_time_get() - start); + } + + efreet_mime_shutdown(); + + return !misses; +} diff --git a/src/tests/ef_test.h b/src/tests/ef_test.h new file mode 100644 index 0000000..2e88c68 --- /dev/null +++ b/src/tests/ef_test.h @@ -0,0 +1,11 @@ +#ifndef EF_TEST +#define EF_TEST + +#include "config.h" + +#include <eina_types.h> + +#define IF_FREE(x) do { if (x) free(x); x = NULL; } while (0); +#define NEW(x, c) calloc(c, sizeof(x)) + +#endif diff --git a/src/tests/ef_utils.c b/src/tests/ef_utils.c new file mode 100644 index 0000000..0647ef0 --- /dev/null +++ b/src/tests/ef_utils.c @@ -0,0 +1,28 @@ +#include "Efreet.h" +#include <stdio.h> + +int +ef_cb_utils(void) +{ + Efreet_Desktop *desktop; + const char *tmp2; + + printf("\n"); + + tmp2 = efreet_util_path_to_file_id("/usr/share/applications/this/tmp/test.desktop"); + if (tmp2) printf("%s\n", tmp2); + + desktop = efreet_util_desktop_file_id_find("kde-kresources.desktop"); + printf("kde-kresources.desktop: %p\n", desktop); + efreet_desktop_free(desktop); + + desktop = efreet_util_desktop_file_id_find("mplayer.desktop"); + printf("mplayer.desktop: %p\n", desktop); + efreet_desktop_free(desktop); + + desktop = efreet_util_desktop_file_id_find("nautilus-computer.desktop"); + printf("nautilus-computer.desktop: %p\n", desktop); + efreet_desktop_free(desktop); + + return 1; +} diff --git a/src/tests/efreet_icon_cache_dump.c b/src/tests/efreet_icon_cache_dump.c new file mode 100644 index 0000000..d1cb126 --- /dev/null +++ b/src/tests/efreet_icon_cache_dump.c @@ -0,0 +1,120 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif +#include <limits.h> +#include <stdio.h> +#include <sys/stat.h> +#include <sys/mman.h> +#include <fcntl.h> +#include <unistd.h> +#include <errno.h> + +#include <Eina.h> +#include <Eet.h> +#include <Ecore.h> +#include <Ecore_File.h> + +#define EFREET_MODULE_LOG_DOM /* no logging in this file */ + +#include "Efreet.h" +#include "efreet_private.h" +#include "efreet_cache_private.h" + +int verbose = 0; + +static void +dump(Efreet_Icon_Theme *theme) +{ + Eet_File *ef; + unsigned int count = 0; + double start, avg; + char **keys; + int num, i; + + start = ecore_time_get(); + ef = eet_open(efreet_icon_cache_file(theme->name.internal), EET_FILE_MODE_READ); + printf("open: %s %f\n", theme->name.internal, ecore_time_get() - start); + + start = ecore_time_get(); + keys = eet_list(ef, "*", &num); + printf("list: %s %f\n", theme->name.internal, ecore_time_get() - start); + if (!keys) return; + + start = ecore_time_get(); + for (i = 0; i < num; i++) + { + Efreet_Cache_Icon *icon; + unsigned int j; + + icon = eet_data_read(ef, efreet_icon_edd(), keys[i]); + if (!icon) continue; + + for (j = 0; j < icon->icons_count; ++j) + count += icon->icons[j]->paths_count; + } + free(keys); + + start = ecore_time_get() - start; + avg = start / count; + printf("read: %s - %u paths (time: %f) (avg %f)\n", theme->name.internal, count, start, avg); + eet_close(ef); + eet_clearcache(); +} + +int +main(int argc, char **argv) +{ + Eet_File *theme_ef; + Eina_List *l = NULL; + Efreet_Icon_Theme *theme; + int i; + + efreet_cache_update = 0; + + if (!efreet_init()) return -1; + + theme_ef = eet_open(efreet_icon_theme_cache_file(), EET_FILE_MODE_READ); + if (!theme_ef) return -1; + + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + theme = eet_data_read(theme_ef, efreet_icon_theme_edd(EINA_FALSE), argv[i]); + if (theme) l = eina_list_append(l, theme); + } + } + else + { + char **keys; + int num; + + keys = eet_list(theme_ef, "*", &num); + if (keys) + { + for (i = 0; i < num; i++) + { + theme = eet_data_read(theme_ef, efreet_icon_theme_edd(EINA_FALSE), keys[i]); + if (theme) l = eina_list_append(l, theme); + } + free(keys); + } + } + + EINA_LIST_FREE(l, theme) + { + void *data; + + dump(theme); + + /* free theme */ + eina_list_free(theme->paths); + eina_list_free(theme->inherits); + EINA_LIST_FREE(theme->directories, data) + free(data); + free(theme); + } + + efreet_shutdown(); + return 0; +} diff --git a/src/tests/efreet_spec_test.c b/src/tests/efreet_spec_test.c new file mode 100644 index 0000000..7c414b5 --- /dev/null +++ b/src/tests/efreet_spec_test.c @@ -0,0 +1,57 @@ +#include <Efreet.h> +#include <stdio.h> +#include <limits.h> +#include "ef_test.h" + +static void dump(Efreet_Menu *menu, const char *path); + +int +main(int argc __UNUSED__, char **argv __UNUSED__) +{ + Efreet_Menu *menu; + + if (!efreet_init()) + { + fprintf(stderr, "Failed to init Efreet\n"); + return 1; + } + + menu = efreet_menu_get(); + if (!menu) + { + fprintf(stderr, "Failed to read menu\n"); + return 1; + } + + dump(menu, ""); + + efreet_menu_free(menu); + efreet_shutdown(); + return 0; +} + +static void +dump(Efreet_Menu *menu, const char *path) +{ + Efreet_Menu *entry; + Eina_List *l; + + if (!menu || !menu->entries) return; + + EINA_LIST_FOREACH(menu->entries, l, entry) + { + if (entry->type == EFREET_MENU_ENTRY_DESKTOP) + { + if (!path || !*path) path = "/"; + printf("%s\t%s\t%s\n", path, entry->id, + entry->desktop->orig_path); + } + else if (entry->type == EFREET_MENU_ENTRY_MENU) + { + char new_path[PATH_MAX]; + + snprintf(new_path, sizeof(new_path), "%s%s/", path, entry->name); + dump(entry, new_path); + } + } +} diff --git a/src/tests/efreet_suite.c b/src/tests/efreet_suite.c new file mode 100644 index 0000000..7424435 --- /dev/null +++ b/src/tests/efreet_suite.c @@ -0,0 +1,103 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdlib.h> +#include <stdio.h> + +#include <Efreet.h> + +#include "efreet_suite.h" + +typedef struct _Efreet_Test_Case Efreet_Test_Case; + +struct _Efreet_Test_Case +{ + const char *test_case; + void (*build)(TCase *tc); +}; + +static const Efreet_Test_Case etc[] = { + { "Efreet", efreet_test_efreet }, + { "Efreet Cache", efreet_test_efreet_cache }, + { NULL, NULL } +}; + +static void +_list_tests(void) +{ + const Efreet_Test_Case *itr; + + itr = etc; + fputs("Available Test Cases:\n", stderr); + for (; itr->test_case; itr++) + fprintf(stderr, "\t%s\n", itr->test_case); +} + +static Eina_Bool +_use_test(int argc, const char **argv, const char *test_case) +{ + if (argc < 1) + return 1; + + for (; argc > 0; argc--, argv++) + if (strcmp(test_case, *argv) == 0) + return 1; + return 0; +} + +static Suite * +efreet_suite_build(int argc, const char **argv) +{ + TCase *tc; + Suite *s; + int i; + + s = suite_create("Efreet"); + + for (i = 0; etc[i].test_case; ++i) + { + if (!_use_test(argc, argv, etc[i].test_case)) continue; + tc = tcase_create(etc[i].test_case); + + etc[i].build(tc); + + suite_add_tcase(s, tc); + tcase_set_timeout(tc, 0); + } + + return s; +} + +int +main(int argc, char **argv) +{ + Suite *s; + SRunner *sr; + int i, failed_count; + + for (i = 1; i < argc; i++) + if ((strcmp(argv[i], "-h") == 0) || + (strcmp(argv[i], "--help") == 0)) + { + fprintf(stderr, "Usage:\n\t%s [test_case1 .. [test_caseN]]\n", + argv[0]); + _list_tests(); + return 0; + } + else if ((strcmp(argv[i], "-l") == 0) || + (strcmp(argv[i], "--list") == 0)) + { + _list_tests(); + return 0; + } + + s = efreet_suite_build(argc - 1, (const char **)argv + 1); + sr = srunner_create(s); + + srunner_run_all(sr, CK_NORMAL); + failed_count = srunner_ntests_failed(sr); + srunner_free(sr); + + return (failed_count == 0) ? 0 : 255; +} diff --git a/src/tests/efreet_test_efreet.c b/src/tests/efreet_test_efreet.c new file mode 100644 index 0000000..d35ec9e --- /dev/null +++ b/src/tests/efreet_test_efreet.c @@ -0,0 +1,25 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Efreet.h> + +#include "efreet_suite.h" + + +START_TEST(efreet_test_efreet_init) +{ + int ret; + + ret = efreet_init(); + fail_if(ret != 1); + + ret = efreet_shutdown(); + fail_if(ret != 0); +} +END_TEST + +void efreet_test_efreet(TCase *tc) +{ + tcase_add_test(tc, efreet_test_efreet_init); +} diff --git a/src/tests/efreet_test_efreet_cache.c b/src/tests/efreet_test_efreet_cache.c new file mode 100644 index 0000000..2f8972d --- /dev/null +++ b/src/tests/efreet_test_efreet_cache.c @@ -0,0 +1,25 @@ +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <Efreet.h> + +#include "efreet_suite.h" + + +START_TEST(efreet_test_efreet_cache_init) +{ + int ret; + + ret = efreet_init(); + fail_if(ret != 1); + + ret = efreet_shutdown(); + fail_if(ret != 0); +} +END_TEST + +void efreet_test_efreet_cache(TCase *tc) +{ + tcase_add_test(tc, efreet_test_efreet_cache_init); +} diff --git a/src/tests/main.c b/src/tests/main.c new file mode 100644 index 0000000..de6cf37 --- /dev/null +++ b/src/tests/main.c @@ -0,0 +1,188 @@ +#include "Efreet.h" +/* no logging */ +#define EFREET_MODULE_LOG_DOM +#include "efreet_private.h" +#include "Efreet_Mime.h" +#include "config.h" +#include <Ecore.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +int ef_cb_efreet_data_home(void); +int ef_cb_efreet_config_home(void); +int ef_cb_efreet_cache_home(void); +int ef_cb_efreet_data_dirs(void); +int ef_cb_efreet_config_dirs(void); +int ef_cb_efreet_icon_theme(void); +int ef_cb_efreet_icon_theme_list(void); +int ef_cb_efreet_icon_match(void); +int ef_cb_ini_parse(void); +int ef_cb_ini_long_line(void); +int ef_cb_ini_garbage(void); +#if DEFAULT_VISIBILITY +int ef_cb_locale(void); +#endif +int ef_cb_desktop_parse(void); +int ef_cb_desktop_save(void); +int ef_cb_desktop_command_get(void); +int ef_cb_desktop_type_parse(void); +#if 0 +int ef_cb_desktop_file_id(void); +#endif +int ef_cb_menu_get(void); +int ef_cb_menu_with_slashes(void); +int ef_cb_menu_save(void); +#if 0 +int ef_cb_menu_edit(void); +#endif +int ef_cb_utils(void); +int ef_mime_cb_get(void); + +typedef struct Efreet_Test Efreet_Test; +struct Efreet_Test +{ + char *name; + int (*cb)(void); +}; + +static Efreet_Test tests[] = { + {"Data Home", ef_cb_efreet_data_home}, + {"Config Home", ef_cb_efreet_config_home}, + {"Cache Home", ef_cb_efreet_cache_home}, + {"Data Directories", ef_cb_efreet_data_dirs}, + {"Config Directories", ef_cb_efreet_config_dirs}, + {"Icon Theme Basic", ef_cb_efreet_icon_theme}, + {"Icon Theme List", ef_cb_efreet_icon_theme_list}, + {"Icon Matching", ef_cb_efreet_icon_match}, + {"INI Parsing", ef_cb_ini_parse}, + {"INI Long Line Parsing", ef_cb_ini_long_line}, + {"INI Garbage Parsing", ef_cb_ini_garbage}, +#if DEFAULT_VISIBILITY + {"Locale Parsing", ef_cb_locale}, +#endif + {"Desktop Parsing", ef_cb_desktop_parse}, + {"Desktop Type Parsing", ef_cb_desktop_type_parse}, + {"Desktop Save", ef_cb_desktop_save}, + {"Desktop Command", ef_cb_desktop_command_get}, +#if 0 + {"Desktop File ID", ef_cb_desktop_file_id}, +#endif + {"Menu Parsing", ef_cb_menu_get}, + {"Menu Incorrect Names", ef_cb_menu_with_slashes}, + {"Menu Save", ef_cb_menu_save}, +#if 0 + {"Menu Edit", ef_cb_menu_edit}, +#endif + {"Utils", ef_cb_utils}, + {"Mime", ef_mime_cb_get}, + {NULL, NULL} +}; + +extern char **environ; +static Eina_List *environment = NULL; + +void +environment_store(void) +{ + char *env; + char **e; +#ifdef HAVE_CLEARENV + EINA_LIST_FREE(environment, env) + free(env); + for (e = environ; *e; e++) + environment = eina_list_append(environment, strdup(*e)); +#endif +} + +void +environment_restore(void) +{ + Eina_List *l; + char *e; + if (!environment) return; +#ifdef HAVE_CLEARENV + clearenv(); + EINA_LIST_FOREACH(environment, l, e) + putenv(e); +#endif +} + +int +main(int argc, char ** argv) +{ + int i, passed = 0, num_tests = 0; + Eina_List *run = NULL; + double total; + char *env; + + eina_init(); + ecore_init(); + + total = ecore_time_get(); + if (argc > 1) + { + for (i = 1; i < argc; i++) + { + if ((!strcmp(argv[i], "-h")) || + (!strcmp(argv[i], "--help"))) + { + for (i = 0; tests[i].name; i++) + { + printf("%s\n", tests[i].name); + } + return 1; + } + run = eina_list_append(run, argv[i]); + } + } + + efreet_cache_update = 0; + environment_store(); + for (i = 0; tests[i].name; i++) + { + int ret; + double start; + + /* we've been given specific tests and it isn't in the list */ + if (run && !eina_list_search_unsorted(run, EINA_COMPARE_CB(strcasecmp), + tests[i].name)) + continue; + + if (!efreet_init()) + { + printf("Error initializing Efreet\n"); + continue; + } + + num_tests ++; + + printf("%s:\t\t", tests[i].name); + fflush(stdout); + start = ecore_time_get(); + ret = tests[i].cb(); + printf("%s in %.3f seconds\n", (ret ? "PASSED" : "FAILED"), + ecore_time_get() - start); + passed += ret; + + efreet_shutdown(); + environment_restore(); + } + + printf("\n-----------------\n"); +#ifdef HAVE_CLEARENV + clearenv(); + EINA_LIST_FREE(environment, env) + free(env); +#endif + printf("Passed %d of %d tests.\n", passed, num_tests); + + while (run) + run = eina_list_remove_list(run, run); + + printf("Total run: %.3f seconds\n", ecore_time_get() - total); + + ecore_shutdown(); + eina_shutdown(); + return 0; +} |