summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoel Klinghed <the_jk@yahoo.com>2011-11-17 21:32:51 +0100
committerJoel Klinghed <the_jk@yahoo.com>2011-11-17 21:32:51 +0100
commit574e9ca2bc2d2893767b14e0732cbffd07d4979a (patch)
tree291523ce96b6376d85dcdac86063351e6f6552ba
parent331d327671af3969e56e8019657a91ead88643d3 (diff)
autofoo & finishing touches on VIEW torrent. Interaction next time
-rw-r--r--.gitignore17
-rw-r--r--Makefile8
-rw-r--r--Makefile.am7
-rw-r--r--config.h0
-rw-r--r--configure.ac54
-rw-r--r--configure.sh2
-rw-r--r--gui/Makefile.am3
-rw-r--r--gui/viewtorrents.glade6
-rw-r--r--m4/ax_cflags_warn_all.m4158
-rw-r--r--m4/pkg.m4158
-rw-r--r--src/.gitignore1
-rw-r--r--src/Makefile30
-rw-r--r--src/Makefile.am17
-rw-r--r--src/main.c155
-rw-r--r--test/.gitignore3
-rw-r--r--test/Makefile.am13
-rw-r--r--test/test_hashlist.c284
17 files changed, 861 insertions, 55 deletions
diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..c9f7d12
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,17 @@
+Makefile
+Makefile.in
+.deps
+*.o
+/aclocal.m4
+/autom4te.cache
+/compile
+/config.h
+/config.h.in
+/config.log
+/config.status
+/configure
+/depcomp
+/install-sh
+/missing
+/stamp-h1
+
diff --git a/Makefile b/Makefile
deleted file mode 100644
index f0e2ef0..0000000
--- a/Makefile
+++ /dev/null
@@ -1,8 +0,0 @@
-all:
- $(MAKE) -C src all
-
-check:
- $(MAKE) -C test check
-
-clean:
- $(MAKE) -C src clean
diff --git a/Makefile.am b/Makefile.am
new file mode 100644
index 0000000..18f84ae
--- /dev/null
+++ b/Makefile.am
@@ -0,0 +1,7 @@
+ACLOCAL_AMFLAGS = -I m4
+
+MAINTAINERCLEANFILES = Makefile.in aclocal.m4 config.guess config.h.in \
+ config.sub configure depcomp install-sh ltmain.sh \
+ missing config.rpath mkinstalldirs
+
+SUBDIRS = gui test src
diff --git a/config.h b/config.h
deleted file mode 100644
index e69de29..0000000
--- a/config.h
+++ /dev/null
diff --git a/configure.ac b/configure.ac
new file mode 100644
index 0000000..546e8e9
--- /dev/null
+++ b/configure.ac
@@ -0,0 +1,54 @@
+AC_INIT([viewtorrents], [0.1], [the_jk@yahoo.com])
+AC_CONFIG_MACRO_DIR([m4])
+
+AM_INIT_AUTOMAKE([dist-bzip2 foreign color-tests parallel-tests])
+
+m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
+
+AC_ISC_POSIX
+AM_PROG_CC_STDC
+AM_PROG_CC_C_O
+AC_HEADER_STDC
+AC_C_CONST
+AC_C_INLINE
+
+# Defines
+
+DEFINES=""
+AX_CFLAGS_WARN_ALL(DEFINES)
+
+AC_ARG_ENABLE([debug], AC_HELP_STRING([compile with debug options]),
+ if test "x$enableval" = "xyes"; then
+ DEFINES="$DEFINES -g -DDEBUG"
+ fi,)
+
+AC_SUBST(DEFINES)
+
+# fabs
+
+AC_SEARCH_LIBS([fabs], [m],, AC_MSG_ERROR([No fabs found]))
+
+# GTK
+
+PKG_CHECK_MODULES([GTK], [gtk+-2.0 >= 2.12 glib-2.0 >= 2.28])
+
+# xmlrpc-c
+
+AC_PATH_PROG([XMLRPC_C_CONFIG], [xmlrpc-c-config])
+
+AS_IF([test -x "$XMLRPC_C_CONFIG"],
+ [
+ XMLRPC_C_VERSION=`xmlrpc-c-config --version`
+ XMLRPC_C_CFLAGS=`xmlrpc-c-config client --cflags`
+ XMLRPC_C_LIBS=`xmlrpc-c-config client --libs`
+ AS_VERSION_COMPARE([$XMLRPC_C_VERSION],[1.05],
+ [AC_MSG_ERROR([Need xmlrpc-c >= 1.05])])
+ AC_SUBST([XMLRPC_C_CFLAGS])
+ AC_SUBST([XMLRPC_C_LIBS])
+ ],
+ [AC_MSG_ERROR([Need xmlrpc-c >= 1.05])])
+
+# End
+
+AM_CONFIG_HEADER([config.h])
+AC_OUTPUT([Makefile gui/Makefile test/Makefile src/Makefile])
diff --git a/configure.sh b/configure.sh
deleted file mode 100644
index b4dbe28..0000000
--- a/configure.sh
+++ /dev/null
@@ -1,2 +0,0 @@
-glib >= 2.28
-xmlrpc-c >= 1.05 \ No newline at end of file
diff --git a/gui/Makefile.am b/gui/Makefile.am
new file mode 100644
index 0000000..744fbcb
--- /dev/null
+++ b/gui/Makefile.am
@@ -0,0 +1,3 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+dist_pkgdata_DATA = viewtorrents.glade
diff --git a/gui/viewtorrents.glade b/gui/viewtorrents.glade
index db80a9c..0068407 100644
--- a/gui/viewtorrents.glade
+++ b/gui/viewtorrents.glade
@@ -42,7 +42,6 @@
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
- <property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
@@ -114,6 +113,7 @@ If authentication is needed, enter username and password as well.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
@@ -129,6 +129,7 @@ If authentication is needed, enter username and password as well.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
@@ -147,6 +148,7 @@ If authentication is needed, enter username and password as well.</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
@@ -436,7 +438,6 @@ If authentication is needed, enter username and password as well.</property>
<property name="visible">True</property>
<property name="can_focus">True</property>
<property name="can_default">True</property>
- <property name="has_default">True</property>
<property name="receives_default">True</property>
<property name="use_action_appearance">False</property>
<property name="use_stock">True</property>
@@ -473,6 +474,7 @@ If authentication is needed, enter username and password as well.</property>
<property name="can_focus">True</property>
<property name="visibility">False</property>
<property name="invisible_char">●</property>
+ <property name="activates_default">True</property>
<property name="primary_icon_activatable">False</property>
<property name="secondary_icon_activatable">False</property>
<property name="primary_icon_sensitive">True</property>
diff --git a/m4/ax_cflags_warn_all.m4 b/m4/ax_cflags_warn_all.m4
new file mode 100644
index 0000000..48f9eca
--- /dev/null
+++ b/m4/ax_cflags_warn_all.m4
@@ -0,0 +1,158 @@
+##### http://autoconf-archive.cryp.to/ax_cflags_warn_all.html
+#
+# SYNOPSIS
+#
+# AX_CFLAGS_WARN_ALL [(shellvar [,default, [A/NA]])]
+#
+# DESCRIPTION
+#
+# Try to find a compiler option that enables most reasonable
+# warnings. This macro is directly derived from VL_PROG_CC_WARNINGS
+# which is split up into two AX_CFLAGS_WARN_ALL and
+# AX_CFLAGS_WARN_ALL_ANSI
+#
+# For the GNU CC compiler it will be -Wall (and -ansi -pedantic) The
+# result is added to the shellvar being CFLAGS by default.
+#
+# Currently this macro knows about GCC, Solaris C compiler, Digital
+# Unix C compiler, C for AIX Compiler, HP-UX C compiler, IRIX C
+# compiler, NEC SX-5 (Super-UX 10) C compiler, and Cray J90 (Unicos
+# 10.0.0.8) C compiler.
+#
+# - $1 shell-variable-to-add-to : CFLAGS
+# - $2 add-value-if-not-found : nothing
+# - $3 action-if-found : add value to shellvariable
+# - $4 action-if-not-found : nothing
+#
+# LAST MODIFICATION
+#
+# 2006-12-12
+#
+# COPYLEFT
+#
+# Copyright (c) 2006 Guido U. Draheim <guidod@gmx.de>
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License as
+# published by the Free Software Foundation; either version 2 of the
+# License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
+# 02111-1307, USA.
+#
+# As a special exception, the respective Autoconf Macro's copyright
+# owner gives unlimited permission to copy, distribute and modify the
+# configure scripts that are the output of Autoconf when processing
+# the Macro. You need not follow the terms of the GNU General Public
+# License when using or distributing such scripts, even though
+# portions of the text of the Macro appear in them. The GNU General
+# Public License (GPL) does govern all other use of the material that
+# constitutes the Autoconf Macro.
+#
+# This special exception to the GPL applies to versions of the
+# Autoconf Macro released by the Autoconf Macro Archive. When you
+# make and distribute a modified version of the Autoconf Macro, you
+# may extend this special exception to the GPL to apply to your
+# modified version as well.
+
+AC_DEFUN([AX_CFLAGS_WARN_ALL],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cflags_warn_all])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_C
+ ac_save_[]FLAGS="$[]FLAGS"
+for ac_arg dnl
+in "-pedantic % -Wall" dnl GCC
+ "-xstrconst % -v" dnl Solaris C
+ "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
+ "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+ "-ansi -ansiE % -fullwarn" dnl IRIX
+ "+ESlit % +w1" dnl HP-UX C
+ "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
+ "-h conform % -h msglevel 2" dnl Cray C (Unicos)
+ #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+ AC_TRY_COMPILE([],[return 0;],
+ [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+ .ok|.ok,*) m4_ifvaln($3,$3) ;;
+ .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+ *) m4_ifvaln($3,$3,[
+ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+ then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+ else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+ fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+dnl the only difference - the LANG selection... and the default FLAGS
+
+AC_DEFUN([AX_CXXFLAGS_WARN_ALL],[dnl
+AS_VAR_PUSHDEF([FLAGS],[CXXFLAGS])dnl
+AS_VAR_PUSHDEF([VAR],[ac_cv_cxxflags_warn_all])dnl
+AC_CACHE_CHECK([m4_ifval($1,$1,FLAGS) for maximum warnings],
+VAR,[VAR="no, unknown"
+ AC_LANG_SAVE
+ AC_LANG_CPLUSPLUS
+ ac_save_[]FLAGS="$[]FLAGS"
+for ac_arg dnl
+in "-pedantic % -Wall" dnl GCC
+ "-xstrconst % -v" dnl Solaris C
+ "-std1 % -verbose -w0 -warnprotos" dnl Digital Unix
+ "-qlanglvl=ansi % -qsrcmsg -qinfo=all:noppt:noppc:noobs:nocnd" dnl AIX
+ "-ansi -ansiE % -fullwarn" dnl IRIX
+ "+ESlit % +w1" dnl HP-UX C
+ "-Xc % -pvctl[,]fullmsg" dnl NEC SX-5 (Super-UX 10)
+ "-h conform % -h msglevel 2" dnl Cray C (Unicos)
+ #
+do FLAGS="$ac_save_[]FLAGS "`echo $ac_arg | sed -e 's,%%.*,,' -e 's,%,,'`
+ AC_TRY_COMPILE([],[return 0;],
+ [VAR=`echo $ac_arg | sed -e 's,.*% *,,'` ; break])
+done
+ FLAGS="$ac_save_[]FLAGS"
+ AC_LANG_RESTORE
+])
+case ".$VAR" in
+ .ok|.ok,*) m4_ifvaln($3,$3) ;;
+ .|.no|.no,*) m4_ifvaln($4,$4,[m4_ifval($2,[
+ AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $2"])]) ;;
+ *) m4_ifvaln($3,$3,[
+ if echo " $[]m4_ifval($1,$1,FLAGS) " | grep " $VAR " 2>&1 >/dev/null
+ then AC_RUN_LOG([: m4_ifval($1,$1,FLAGS) does contain $VAR])
+ else AC_RUN_LOG([: m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"])
+ m4_ifval($1,$1,FLAGS)="$m4_ifval($1,$1,FLAGS) $VAR"
+ fi ]) ;;
+esac
+AS_VAR_POPDEF([VAR])dnl
+AS_VAR_POPDEF([FLAGS])dnl
+])
+
+dnl implementation tactics:
+dnl the for-argument contains a list of options. The first part of
+dnl these does only exist to detect the compiler - usually it is
+dnl a global option to enable -ansi or -extrawarnings. All other
+dnl compilers will fail about it. That was needed since a lot of
+dnl compilers will give false positives for some option-syntax
+dnl like -Woption or -Xoption as they think of it is a pass-through
+dnl to later compile stages or something. The "%" is used as a
+dnl delimimiter. A non-option comment can be given after "%%" marks
+dnl which will be shown but not added to the respective C/CXXFLAGS.
diff --git a/m4/pkg.m4 b/m4/pkg.m4
new file mode 100644
index 0000000..bfe1dd1
--- /dev/null
+++ b/m4/pkg.m4
@@ -0,0 +1,158 @@
+# pkg.m4 - Macros to locate and utilise pkg-config. -*- Autoconf -*-
+#
+# Copyright © 2004 Scott James Remnant <scott@netsplit.com>.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+#
+# As a special exception to the GNU General Public License, if you
+# distribute this file as part of a program that contains a
+# configuration script generated by Autoconf, you may include it under
+# the same distribution terms that you use for the rest of that program.
+
+# PKG_PROG_PKG_CONFIG([MIN-VERSION])
+# ----------------------------------
+AC_DEFUN([PKG_PROG_PKG_CONFIG],
+[m4_pattern_forbid([^_?PKG_[A-Z_]+$])
+m4_pattern_allow([^PKG_CONFIG(_PATH)?$])
+AC_ARG_VAR([PKG_CONFIG], [path to pkg-config utility])dnl
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+ AC_PATH_TOOL([PKG_CONFIG], [pkg-config])
+fi
+if test -n "$PKG_CONFIG"; then
+ _pkg_min_version=m4_default([$1], [0.9.0])
+ AC_MSG_CHECKING([pkg-config is at least version $_pkg_min_version])
+ if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+ AC_MSG_RESULT([yes])
+ else
+ AC_MSG_RESULT([no])
+ PKG_CONFIG=""
+ fi
+
+fi[]dnl
+])# PKG_PROG_PKG_CONFIG
+
+# PKG_CHECK_EXISTS(MODULES, [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND])
+#
+# Check to see whether a particular set of modules exists. Similar
+# to PKG_CHECK_MODULES(), but does not set variables or print errors.
+#
+#
+# Similar to PKG_CHECK_MODULES, make sure that the first instance of
+# this or PKG_CHECK_MODULES is called, or make sure to call
+# PKG_CHECK_EXISTS manually
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_EXISTS],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+if test -n "$PKG_CONFIG" && \
+ AC_RUN_LOG([$PKG_CONFIG --exists --print-errors "$1"]); then
+ m4_ifval([$2], [$2], [:])
+m4_ifvaln([$3], [else
+ $3])dnl
+fi])
+
+
+# _PKG_CONFIG([VARIABLE], [COMMAND], [MODULES])
+# ---------------------------------------------
+m4_define([_PKG_CONFIG],
+[if test -n "$PKG_CONFIG"; then
+ if test -n "$$1"; then
+ pkg_cv_[]$1="$$1"
+ else
+ PKG_CHECK_EXISTS([$3],
+ [pkg_cv_[]$1=`$PKG_CONFIG --[]$2 "$3" 2>/dev/null`],
+ [pkg_failed=yes])
+ fi
+else
+ pkg_failed=untried
+fi[]dnl
+])# _PKG_CONFIG
+
+# _PKG_SHORT_ERRORS_SUPPORTED
+# -----------------------------
+AC_DEFUN([_PKG_SHORT_ERRORS_SUPPORTED],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+ _pkg_short_errors_supported=yes
+else
+ _pkg_short_errors_supported=no
+fi[]dnl
+])# _PKG_SHORT_ERRORS_SUPPORTED
+
+
+# PKG_CHECK_MODULES(VARIABLE-PREFIX, MODULES, [ACTION-IF-FOUND],
+# [ACTION-IF-NOT-FOUND])
+#
+#
+# Note that if there is a possibility the first call to
+# PKG_CHECK_MODULES might not happen, you should be sure to include an
+# explicit call to PKG_PROG_PKG_CONFIG in your configure.ac
+#
+#
+# --------------------------------------------------------------
+AC_DEFUN([PKG_CHECK_MODULES],
+[AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl
+AC_ARG_VAR([$1][_CFLAGS], [C compiler flags for $1, overriding pkg-config])dnl
+AC_ARG_VAR([$1][_LIBS], [linker flags for $1, overriding pkg-config])dnl
+
+pkg_failed=no
+AC_MSG_CHECKING([for $2])
+
+_PKG_CONFIG([$1][_CFLAGS], [cflags], [$2])
+_PKG_CONFIG([$1][_LIBS], [libs], [$2])
+
+m4_define([_PKG_TEXT], [Alternatively, you may set the environment variables $1[]_CFLAGS
+and $1[]_LIBS to avoid the need to call pkg-config.
+See the pkg-config man page for more details.])
+
+if test $pkg_failed = yes; then
+ _PKG_SHORT_ERRORS_SUPPORTED
+ if test $_pkg_short_errors_supported = yes; then
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "$2"`
+ else
+ $1[]_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "$2"`
+ fi
+ # Put the nasty error message in config.log where it belongs
+ echo "$$1[]_PKG_ERRORS" >&AS_MESSAGE_LOG_FD
+
+ ifelse([$4], , [AC_MSG_ERROR(dnl
+[Package requirements ($2) were not met:
+
+$$1_PKG_ERRORS
+
+Consider adjusting the PKG_CONFIG_PATH environment variable if you
+installed software in a non-standard prefix.
+
+_PKG_TEXT
+])],
+ [$4])
+ AC_MSG_RESULT([no])
+elif test $pkg_failed = untried; then
+ ifelse([$4], , [AC_MSG_FAILURE(dnl
+[The pkg-config script could not be found or is too old. Make sure it
+is in your PATH or set the PKG_CONFIG environment variable to the full
+path to pkg-config.
+
+_PKG_TEXT
+
+To get pkg-config, see <http://www.freedesktop.org/software/pkgconfig>.])],
+ [$4])
+ AC_MSG_RESULT([no])
+else
+ $1[]_CFLAGS=$pkg_cv_[]$1[]_CFLAGS
+ $1[]_LIBS=$pkg_cv_[]$1[]_LIBS
+ AC_MSG_RESULT([yes])
+ ifelse([$3], , :, [$3])
+fi[]dnl
+])# PKG_CHECK_MODULES
diff --git a/src/.gitignore b/src/.gitignore
index c1753e9..0e69789 100644
--- a/src/.gitignore
+++ b/src/.gitignore
@@ -1,2 +1 @@
/viewtorrents
-*.o \ No newline at end of file
diff --git a/src/Makefile b/src/Makefile
deleted file mode 100644
index 022a873..0000000
--- a/src/Makefile
+++ /dev/null
@@ -1,30 +0,0 @@
-CC=gcc
-CFLAGS=-Wall -Wextra -DDEBUG -DHAVE_CONFIG_H -g -I.. -DDATAROOTDIR='"/sw/share/"'
-GTK_CFLAGS=`pkg-config gtk+-2.0 --cflags`
-XMLRPC_CFLAGS=`xmlrpc-c-config client --cflags`
-LDFLAGS=
-GTK_LIBS=`pkg-config gtk+-2.0 --libs`
-XMLRPC_LIBS=`xmlrpc-c-config client --libs`
-
-all: viewtorrents
-
-clean:
- rm -f *.o viewtorrents
-
-viewtorrents: main.o customcellrendererstate.o customcellrendererprogress.o customcellrendererrate.o customcellrendererleft.o
- $(CC) $(CFLAGS) $(GTK_CFLAGS) $(XMLRPC_CFLAGS) -o $@ $^ $(LDFLAGS) $(GTK_LIBS) $(XMLRPC_LIBS)
-
-main.o: main.c customcellrendererstate.h customcellrendererprogress.h customcellrendererrate.h customcellrendererleft.h common.h
- $(CC) -c $(CFLAGS) $(GTK_CFLAGS) $(XMLRPC_CFLAGS) -o $@ $<
-
-customcellrendererstate.o: customcellrendererstate.c customcellrendererstate.h common.h
- $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
-
-customcellrendererprogress.o: customcellrendererprogress.c customcellrendererprogress.h common.h
- $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
-
-customcellrendererrate.o: customcellrendererrate.c customcellrendererrate.h common.h
- $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
-
-customcellrendererleft.o: customcellrendererleft.c customcellrendererleft.h common.h
- $(CC) -c $(CFLAGS) $(GTK_CFLAGS) -o $@ $<
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..e555a0b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,17 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES = -I$(top_srcdir)
+
+AM_CFLAGS = @DEFINES@ @GTK_CFLAGS@ @XMLRPC_C_CFLAGS@ -DDATAROOTDIR='"${pkgdatadir}"'
+
+bin_PROGRAMS = viewtorrents
+
+viewtorrents_SOURCES = main.c common.h \
+ customcellrendererstate.c customcellrendererstate.h \
+ customcellrendererprogress.c \
+ customcellrendererprogress.h \
+ customcellrendererrate.c customcellrendererrate.h \
+ customcellrendererleft.c customcellrendererleft.h
+
+viewtorrents_LDADD = @GTK_LIBS@ @XMLRPC_C_LIBS@
+
diff --git a/src/main.c b/src/main.c
index b51f1db..78c98da 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,10 +1,12 @@
#include "common.h"
#include <gtk/gtk.h>
+#include <glib.h>
#include <xmlrpc-c/base.h>
#include <xmlrpc-c/client.h>
#include <string.h>
#include <errno.h>
+#include <math.h>
#include "customcellrendererstate.h"
#include "customcellrendererprogress.h"
@@ -226,13 +228,20 @@ static void status(master_t* master, const char* format, ...);
static void noop_destroy(gpointer value);
static void torrent_destroy(gpointer value);
+static void liststore_sort_column_changed(GtkTreeSortable* sortable,
+ gpointer user_data);
+static gint liststore_default_compare_func(GtkTreeModel* model,
+ GtkTreeIter* a,
+ GtkTreeIter* b,
+ gpointer user_data);
+
int main(int argc, char** argv)
{
const gchar* gladefile;
GtkBuilder* builder;
GError* error = NULL;
guint ret;
- GtkWidget* listview, * pwddlg;
+ GtkWidget* pwddlg;
GtkCellRenderer* cell;
GtkTreeViewColumn* column;
GThread* worker;
@@ -294,10 +303,15 @@ int main(int argc, char** argv)
gtk_widget_set_sensitive(master.disconnectmenuitem, FALSE);
pwddlg = GTK_WIDGET(gtk_builder_get_object(builder, "pwddlg"));
+ gtk_dialog_set_default_response(GTK_DIALOG(pwddlg), GTK_RESPONSE_OK);
- listview = GTK_WIDGET(gtk_builder_get_object(builder, "treeview"));
master.liststore = GTK_LIST_STORE(gtk_builder_get_object(builder,
"liststore"));
+ g_signal_connect(master.liststore, "sort-column-changed",
+ G_CALLBACK(liststore_sort_column_changed), &master);
+ gtk_tree_sortable_set_default_sort_func(GTK_TREE_SORTABLE(master.liststore),
+ liststore_default_compare_func,
+ &master, NULL);
cell = custom_cell_renderer_state_new();
column = GTK_TREE_VIEW_COLUMN(gtk_builder_get_object(builder, "statecolumn"));
@@ -335,9 +349,30 @@ int main(int argc, char** argv)
G_KEY_FILE_KEEP_TRANSLATIONS,
NULL);
+ {
+ gint column =
+ g_key_file_get_integer(master.config, "view", "sort_column", NULL);
+ gboolean desc =
+ g_key_file_get_boolean(master.config, "view", "sort_desc", NULL);
+ if (column > 0)
+ {
+ gtk_tree_sortable_set_sort_column_id(
+ GTK_TREE_SORTABLE(master.liststore), column,
+ desc ? GTK_SORT_DESCENDING : GTK_SORT_ASCENDING);
+ }
+ else
+ {
+ gtk_tree_sortable_set_sort_column_id(
+ GTK_TREE_SORTABLE(master.liststore),
+ GTK_TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, GTK_SORT_ASCENDING);
+ }
+ }
+
gtk_widget_show_all(master.top);
master.connectdlg = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg"));
+ gtk_dialog_set_default_response(GTK_DIALOG(master.connectdlg),
+ GTK_RESPONSE_OK);
master.connectdlg_url = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_url"));
master.connectdlg_user = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_user"));
master.connectdlg_pwd = GTK_WIDGET(gtk_builder_get_object(builder, "connectdlg_pwd"));
@@ -646,7 +681,7 @@ void do_connect(GtkMenuItem* menuitem, gpointer data)
pass = NULL;
}
- gtk_widget_set_sensitive(master->connectmenuitem, FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(menuitem), FALSE);
status(master, "Connecting to %s...", url);
g_key_file_set_string(master->config, "connect", "url", url);
if (user != NULL)
@@ -677,7 +712,7 @@ void do_disconnect(GtkMenuItem* menuitem, gpointer data)
g_source_remove(master->sync_timeout);
master->sync_timeout = 0;
}
- gtk_widget_set_sensitive(master->disconnectmenuitem, FALSE);
+ gtk_widget_set_sensitive(GTK_WIDGET(menuitem), FALSE);
status(master, "Disconnecting...");
g_hash_table_remove_all(master->torrents);
g_async_queue_push(master->queue, msg_disconnect());
@@ -718,7 +753,7 @@ void torrent_update(torrent_t* torrent, torrent_data_t* data)
COLUMN_LEFT, data->left,
COLUMN_PROGRESSSORT,
data->downloaded < 100.0f ? data->downloaded :
- data->seeded + 1000.0f,
+ 1000.0f + data->seeded,
-1);
}
@@ -1008,14 +1043,14 @@ gpointer worker_main(gpointer _data)
break;
}
done = (guint64)tmpi64;
- if (torrent_data.size > 0)
+ if (done >= torrent_data.size)
+ {
+ torrent_data.downloaded = 100.0f;
+ }
+ else if (torrent_data.size > 0)
{
torrent_data.downloaded = ((gfloat)done * 100.0f) /
(gfloat)torrent_data.size;
- if (torrent_data.downloaded > 100.0f)
- {
- torrent_data.downloaded = 100.0f;
- }
}
else
{
@@ -1380,7 +1415,7 @@ void hashlist_free(hashlist_t* hlist)
g_free(hlist->mark);
}
-gboolean hashlist_resize(hashlist_t* hlist, gsize* a, gsize* r)
+gboolean hashlist_resize(hashlist_t* hlist, G_GNUC_UNUSED gsize* a, gsize* r)
{
gsize ns = hlist->size * 2;
gchar** tmp1;
@@ -1530,7 +1565,7 @@ gboolean hashlist_sync(hashlist_t* hlist, xmlrpc_env * const env,
return TRUE;
}
-void noop_destroy(gpointer key)
+void noop_destroy(G_GNUC_UNUSED gpointer key)
{
}
@@ -1614,3 +1649,99 @@ gboolean get_bool_xmlrpc(xmlrpc_env* env, xmlrpc_value* value)
}
}
}
+
+void liststore_sort_column_changed(GtkTreeSortable* sortable,
+ gpointer user_data)
+{
+ master_t* master = user_data;
+ gint column;
+ GtkSortType order;
+ if (gtk_tree_sortable_get_sort_column_id(sortable, &column, &order))
+ {
+ g_key_file_set_integer(master->config, "view", "sort_column",
+ column + 1);
+ g_key_file_set_boolean(master->config, "view", "sort_desc",
+ order == GTK_SORT_DESCENDING);
+ }
+ else
+ {
+ if (!g_key_file_remove_key(master->config,
+ "view", "sort_column", NULL) &&
+ !g_key_file_remove_key(master->config, "view", "sort_desc", NULL))
+ {
+ return;
+ }
+ }
+ save_config(master);
+}
+
+#ifndef G_VALUE_INIT
+# define G_VALUE_INIT { 0 }
+#endif
+
+gint liststore_default_compare_func(GtkTreeModel* model,
+ GtkTreeIter* a,
+ GtkTreeIter* b,
+ G_GNUC_UNUSED gpointer user_data)
+{
+ GValue value = G_VALUE_INIT;
+ gfloat af, bf;
+ gint ai, bi;
+ const gchar* as, * bs;
+ gtk_tree_model_get_value(model, a, COLUMN_DOWN, &value);
+ af = g_value_get_float(&value);
+ g_value_unset(&value);
+ gtk_tree_model_get_value(model, b, COLUMN_DOWN, &value);
+ bf = g_value_get_float(&value);
+ g_value_unset(&value);
+ if (fabs(af - bf) > 1e-4)
+ {
+ return af > bf ? -1 : 1;
+ }
+
+ gtk_tree_model_get_value(model, a, COLUMN_UP, &value);
+ af = g_value_get_float(&value);
+ g_value_unset(&value);
+ gtk_tree_model_get_value(model, b, COLUMN_UP, &value);
+ bf = g_value_get_float(&value);
+ g_value_unset(&value);
+ if (fabs(af - bf) > 1e-4)
+ {
+ return af > bf ? -1 : 1;
+ }
+
+ gtk_tree_model_get_value(model, a, COLUMN_STATE, &value);
+ ai = g_value_get_int(&value);
+ g_value_unset(&value);
+ gtk_tree_model_get_value(model, b, COLUMN_STATE, &value);
+ bi = g_value_get_int(&value);
+ g_value_unset(&value);
+ if (ai != bi)
+ {
+ return ai > bi ? -1 : 1;
+ }
+
+ gtk_tree_model_get_value(model, a, COLUMN_PROGRESSSORT, &value);
+ af = g_value_get_float(&value);
+ g_value_unset(&value);
+ gtk_tree_model_get_value(model, b, COLUMN_PROGRESSSORT, &value);
+ bf = g_value_get_float(&value);
+ g_value_unset(&value);
+ if (fabs(af - bf) > 1e-3)
+ {
+ return af < bf ? -1 : 1;
+ }
+
+ gtk_tree_model_get_value(model, a, COLUMN_TITLE, &value);
+ as = g_value_get_string(&value);
+ {
+ GValue value2 = G_VALUE_INIT;
+ gint ret;
+ gtk_tree_model_get_value(model, b, COLUMN_TITLE, &value2);
+ bs = g_value_get_string(&value2);
+ ret = strcmp(as, bs);
+ g_value_unset(&value);
+ g_value_unset(&value2);
+ return ret;
+ }
+}
diff --git a/test/.gitignore b/test/.gitignore
new file mode 100644
index 0000000..7146b2b
--- /dev/null
+++ b/test/.gitignore
@@ -0,0 +1,3 @@
+/test-suite.log
+/test_hashlist
+/test_hashlist.log
diff --git a/test/Makefile.am b/test/Makefile.am
new file mode 100644
index 0000000..2e6b3c4
--- /dev/null
+++ b/test/Makefile.am
@@ -0,0 +1,13 @@
+MAINTAINERCLEANFILES = Makefile.in
+
+INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/src
+
+AM_CFLAGS = @DEFINES@ @GTK_CFLAGS@
+
+TESTS = test_hashlist
+
+check_PROGRAMS = $(TESTS)
+
+test_hashlist_SOURCES = test_hashlist.c
+test_hashlist_LDADD = @GTK_LIBS@
+
diff --git a/test/test_hashlist.c b/test/test_hashlist.c
new file mode 100644
index 0000000..a0dbbf0
--- /dev/null
+++ b/test/test_hashlist.c
@@ -0,0 +1,284 @@
+#include "common.h"
+
+#include <glib.h>
+#include <stdio.h>
+#include <string.h>
+
+typedef struct _hashlist_t
+{
+ gchar** data;
+ gboolean* mark;
+ gsize size, fill;
+
+ const gchar** added;
+ const gchar** removed;
+} hashlist_t;
+
+static void hashlist_init(hashlist_t* hlist);
+static void hashlist_clear(hashlist_t* hlist);
+static void hashlist_free(hashlist_t* hlist);
+static gboolean hashlist_sync(hashlist_t* hlist,
+ const gchar** list, gsize count);
+
+static gboolean check(const gchar* name, hashlist_t* hlist, ...);
+
+#define CHECK(name, args...) \
+ do { \
+ ++tot; ok += check(name, &list, args) ? 1 : 0; \
+ } while (0)
+
+int main(int argc, char** argv)
+{
+ static const gchar* data[] = { "foo", "bar", "meh", "muh" };
+ int tot = 0, ok = 0;
+ hashlist_t list;
+
+ hashlist_init(&list);
+
+ hashlist_sync(&list, data, 0);
+ CHECK("nop sync", NULL, NULL);
+
+ hashlist_sync(&list, data, 2);
+ CHECK("add foo,bar", "foo", "bar", NULL, NULL);
+
+ hashlist_sync(&list, data, 4);
+ CHECK("add meh,muh", "meh", "muh", NULL, NULL);
+
+ hashlist_sync(&list, data + 2, 2);
+ CHECK("remove foo,bar", NULL, "foo", "bar", NULL);
+
+ hashlist_sync(&list, data, 4);
+ CHECK("add foo,bar", "foo", "bar", NULL, NULL);
+
+ hashlist_sync(&list, data, 3);
+ CHECK("remove muh", NULL, "muh", NULL);
+
+ hashlist_sync(&list, data + 1, 1);
+ CHECK("remove foo,meh", NULL, "meh", "foo", NULL);
+
+ hashlist_sync(&list, data + 2, 2);
+ CHECK("remove bar, add meh,muh", "meh", "muh", NULL, "bar", NULL);
+
+ hashlist_clear(&list);
+ CHECK("clear", NULL, NULL);
+
+ hashlist_free(&list);
+
+ fprintf(stdout, "OK %d/%d\n", ok, tot);
+ return EXIT_SUCCESS;
+}
+
+void hashlist_init(hashlist_t* hlist)
+{
+ hlist->fill = 0;
+ hlist->size = 10;
+ hlist->data = g_new0(gchar*, hlist->size);
+ hlist->mark = g_new0(gboolean, hlist->size);
+ hlist->added = (const gchar**)hlist->data;
+ hlist->removed = (const gchar**)hlist->data + hlist->size - 1;
+}
+
+void hashlist_clear(hashlist_t* hlist)
+{
+ gsize i, a, r;
+ for (a = hlist->added - (const gchar**)hlist->data; hlist->data[a]; ++a);
+ r = hlist->removed - (const gchar**)hlist->data;
+ for (i = 0; i < a; ++i)
+ {
+ g_free(hlist->data[i]);
+ }
+ for (i = r; hlist->data[i]; ++i)
+ {
+ g_free(hlist->data[i]);
+ }
+ hlist->data[0] = NULL;
+ hlist->fill = 0;
+ hlist->added = (const gchar**)hlist->data;
+ hlist->removed = (const gchar**)hlist->data + hlist->size - 1;
+}
+
+void hashlist_free(hashlist_t* hlist)
+{
+ hashlist_clear(hlist);
+ g_free(hlist->data);
+ g_free(hlist->mark);
+}
+
+gboolean hashlist_resize(hashlist_t* hlist, gsize* a, gsize* r)
+{
+ gsize ns = hlist->size * 2;
+ gchar** tmp;
+ g_assert(*r == hlist->size - 1);
+ if (ns < 10) ns = 10;
+ tmp = realloc(hlist->data, ns * sizeof(gchar**));
+ if (tmp == NULL)
+ {
+ hlist->added = (const gchar**)hlist->data + hlist->fill;
+ hlist->removed = (const gchar**)hlist->data + *r;
+ return FALSE;
+ }
+ memset(tmp + hlist->size, 0, (ns - hlist->size) * sizeof(gchar*));
+ hlist->data = tmp;
+ hlist->size = ns;
+ *r = hlist->size - 1;
+ return TRUE;
+}
+
+gboolean hashlist_sync(hashlist_t* hlist, const gchar** list, gsize count)
+{
+ gsize i, j, a, r;
+ gsize found = 0;
+ g_assert((const gchar**)hlist->data + hlist->fill == hlist->added);
+ for (a = hlist->added - (const gchar**)hlist->data; hlist->data[a]; ++a);
+ hlist->fill = a;
+ hlist->added = (const gchar**)hlist->data + a;
+ for (r = hlist->removed - (const gchar**)hlist->data; hlist->data[r]; ++r)
+ {
+ g_free(hlist->data[r]);
+ }
+ g_assert(r == hlist->size - 1);
+ if (a + 5 > r)
+ {
+ gsize ns = a + 10;
+ gchar** tmp = realloc(hlist->data, ns * sizeof(gchar*));
+ if (tmp != NULL)
+ {
+ hlist->data = tmp;
+ memset(hlist->data + hlist->size, 0,
+ (ns - hlist->size) * sizeof(gchar*));
+ hlist->size = ns;
+ r = hlist->size - 1;
+ }
+ }
+ memset(hlist->mark, 0, hlist->fill * sizeof(gboolean));
+ for (i = 0; i < count; ++i)
+ {
+ const gchar* hash = list[i];
+ if (found == hlist->fill)
+ {
+ if (a + 1 == r &&
+ !hashlist_resize(hlist, &a, &r))
+ {
+ return FALSE;
+ }
+ hlist->data[a++] = g_strdup(hash);
+ continue;
+ }
+ /* Quick path */
+ if (i < hlist->fill && !hlist->mark[i] &&
+ strcmp(hlist->data[i], hash) == 0)
+ {
+ hlist->mark[i] = TRUE;
+ found++;
+ continue;
+ }
+ for (j = i + 1; j != i; ++j)
+ {
+ if (j >= hlist->fill)
+ {
+ j = 0;
+ if (i == 0)
+ {
+ break;
+ }
+ }
+ if (hlist->mark[j])
+ {
+ continue;
+ }
+ if (strcmp(hlist->data[j], hash) == 0)
+ {
+ break;
+ }
+ }
+ if (j != i)
+ {
+ hlist->mark[j] = TRUE;
+ found++;
+ }
+ else
+ {
+ /* New */
+ if (a + 1 == r &&
+ !hashlist_resize(hlist, &a, &r))
+ {
+ return FALSE;
+ }
+ hlist->data[a++] = g_strdup(hash);
+ }
+ }
+ if (found < hlist->fill)
+ {
+ gsize n = hlist->fill - found;
+ for (j = hlist->fill - 1; n > 0; --j)
+ {
+ if (!hlist->mark[j])
+ {
+ hlist->data[--r] = hlist->data[j];
+ a--;
+ hlist->fill--;
+ memmove(hlist->data + j, hlist->data + j + 1,
+ (a - j) * sizeof(gchar*));
+ hlist->data[a] = NULL;
+ n--;
+ }
+ }
+ }
+ hlist->added = (const gchar**)hlist->data + hlist->fill;
+ hlist->removed = (const gchar**)hlist->data + r;
+ return TRUE;
+}
+
+gboolean check(const gchar* name, hashlist_t* hlist, ...)
+{
+ va_list args;
+ const gchar* x, **a, **r;
+ va_start(args, hlist);
+ a = hlist->added;
+ while ((x = va_arg(args, const gchar*)) != NULL)
+ {
+ if (*a == NULL)
+ {
+ fprintf(stderr, "%s: Expected added `%s` got EOL\n",
+ name, x);
+ return FALSE;
+ }
+ if (strcmp(*a, x) != 0)
+ {
+ fprintf(stderr, "%s: Expected added `%s` got `%s`\n", name, x, *a);
+ return FALSE;
+ }
+ ++a;
+ }
+ if (*a != NULL)
+ {
+ fprintf(stderr, "%s: Expected added EOL got `%s`\n",
+ name, *a);
+ return FALSE;
+ }
+ r = hlist->removed;
+ while ((x = va_arg(args, const gchar*)) != NULL)
+ {
+ if (*r == NULL)
+ {
+ fprintf(stderr, "%s: Expected removed `%s` got EOL\n",
+ name, x);
+ return FALSE;
+ }
+ if (strcmp(*r, x) != 0)
+ {
+ fprintf(stderr, "%s: Expected removed `%s` got `%s`\n",
+ name, x, *r);
+ return FALSE;
+ }
+ ++r;
+ }
+ va_end(args);
+ if (*r != NULL)
+ {
+ fprintf(stderr, "%s: Expected removed EOL got `%s`\n",
+ name, *r);
+ return FALSE;
+ }
+ return TRUE;
+}