+++ /dev/null
-SUBDIRS = rss seederd init
Compile-Dependencies:
-libtorrent-rasterbar-dev
-inotify-tools
+libsodium-dev
Optional Dependencies:
systemd
autoconf
automake
gcc
-g++
Testing Dependencies:
valgrind
To Build+Install:
autoreconf -vif
-./configure SEEDER_DOMAIN=[DOMAIN]
+./configure
make
make install
systemctl enable seederd
-# -*- Autoconf -*-
-# Process this file with autoconf to produce a configure script.
-
AC_PREREQ([2.69])
-AC_INIT([seeder], [1.1.1])
-
-# Store build files not in main directory
-AC_CONFIG_AUX_DIR([build-aux])
-AC_CONFIG_MACRO_DIR([m4])
-
-AM_INIT_AUTOMAKE([foreign subdir-objects nostdinc -Wall -Werror])
-
-AC_ARG_ENABLE([tests],
- [AS_HELP_STRING([--disable-tests],
- [disable tests (enabled by default)])],
- [enable_tests=$enableval],
- [enable_tests=yes])
-
-AC_ARG_ENABLE([memcheck],
- [AS_HELP_STRING([--disable-memcheck],
- [disable valgrind (enabled by default)])],
- [enable_memcheck=$enableval],
- [enable_memcheck=yes])
-
-AC_PATH_PROG([VALGRIND], [valgrind])
-AM_CONDITIONAL([HAVE_VALGRIND], [test -n "$VALGRIND"])
-AC_PATH_PROG([NGINX], [nginx])
-AM_CONDITIONAL([HAVE_NGINX], [test -n "$NGINX"])
-AC_PATH_PROG([SYSTEMD], [systemd])
-AM_CONDITIONAL([HAVE_SYSTEMD], [test -n "$SYSTEMD"])
-
-AC_PATH_PROG([INOTIFYWAIT], [inotifywait])
-if test -z "$INOTIFYWAIT"; then
- AC_MSG_ERROR("inotifywait required");
-fi
-
-AC_ARG_VAR(SEEDER_DOMAIN,[hostname from which seeder is serving])
-
-dnl disable memcheck if valgrind not found
-if test "x$enable_memcheck" != "xno"; then
- if test -z "$VALGRIND"; then
- enable_memcheck=no
- fi
-fi
-
-AC_MSG_CHECKING([if memcheck should be enabled])
-if test x$enable_memcheck != xno; then
- AC_MSG_RESULT(yes)
-else
- AC_MSG_RESULT(no)
-fi
-
-AM_CONDITIONAL([ENABLE_MEMCHECK],[test x$enable_memcheck = xyes])
-
-dnl Enable debug
-AC_ARG_ENABLE([debug],
- [AS_HELP_STRING([--enable-debug],
- [use compiler flags and macros suited for debugging (default is no)])],
- [enable_debug=$enableval],
- [enable_debug=no])
-
-AC_MSG_CHECKING([if debugging])
-if test x$enable_debug != xno; then
- AC_MSG_RESULT(yes)
- CFLAGS="-ggdb -O0"
- CXXFLAGS="-ggdb -O0"
-else
- AC_MSG_RESULT(no)
-fi
-
-AM_CONDITIONAL([ENABLE_DEBUG],[test x$enable_debug = xyes])
+AC_INIT([seeder], [0.0.0])
+AC_CONFIG_SRCDIR([src/main.c])
+AC_CONFIG_HEADERS([config.h])
# Checks for programs.
AC_PROG_CC
-AC_PROG_CXX
-AC_PROG_LN_S
# Checks for libraries.
-AC_CHECK_LIB([torrent-rasterbar], [main],,AC_MSG_ERROR(libtorrent-rasterbar required))
# Checks for header files.
-AC_CHECK_HEADERS([stddef.h stdlib.h string.h])
+AC_CHECK_HEADERS([stdlib.h])
# Checks for typedefs, structures, and compiler characteristics.
-AC_CHECK_HEADER_STDBOOL
-AC_TYPE_SIZE_T
# Checks for library functions.
-AC_CHECK_FUNCS([atexit malloc mkdir strchr strpbrk strrchr])
-
-AX_CXX_COMPILE_STDCXX([17], [noext], [mandatory])
-AC_CONFIG_FILES([Makefile
- init/Makefile
- rss/Makefile
- seederd/Makefile])
AC_OUTPUT
+++ /dev/null
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-rm /etc/ssh/ssh_host_*
-dpkg-reconfigure openssh-server
-
-service ssh start
-service nginx start
-service cron start
-
-monitor-seederd &
-
-seederd
--- /dev/null
+#ifndef __DEFAULT_H_
+#define __DEFAULT_H_
+
+int defaults();
+
+#endif
--- /dev/null
+#ifndef __LOG_H_
+#define __LOG_H_
+
+#include<stdarg.h>
+#include<stdio.h>
+
+extern int verbose_flag;
+
+enum log_level {
+ LOG_LEVEL_SILENT = 0, /* suppresses all output */
+ LOG_LEVEL_ERRORS = 1, /* only prints errors */
+ LOG_LEVEL_DEFAULT = 2, /* normal output */
+ LOG_LEVEL_VERBOSE = 3 /* logging and debugging info */
+};
+
+#define log_err(...) log_message(LOG_LEVEL_ERRORS,stderr,__VA_ARGS__)
+#define log_info(...) log_message(LOG_LEVEL_VERBOSE,stdout,__VA_ARGS__)
+#define log_msg(...) log_message(LOG_LEVEL_DEFAULT,stdout,__VA_ARGS__)
+
+void log_message(enum log_level,FILE*,const char*,...);
+
+#endif
#ifndef __MAIN_H_
#define __MAIN_H_
-#include<getopt.h>
-#include<stdio.h>
#include<stdlib.h>
-#include<add.h>
#include<default.h>
-#include<info.h>
-#include<opt.h>
+#include<log.h>
+#include<usage.h>
int main(int,char**);
--- /dev/null
+#ifndef __OPT_H_
+#define __OPT_H_
+
+#include<log.h>
+
+void opt_set_log_level(enum log_level);
+
+#endif
--- /dev/null
+#ifndef __USAGE_H_
+#define __USAGE_H_
+
+#include<log.h>
+
+void usage();
+
+#endif
+++ /dev/null
-install-exec-local:
- ./setup.sh $(bindir) $(localstatedir)/seeder $(SEEDER_DOMAIN)
-if HAVE_NGINX
- ./setup-nginx.sh $(localstatedir)/seeder
-endif
-if HAVE_SYSTEMD
- -./setup-systemd.sh $(localstatedir)/seeder
-endif
-
-uninstall-local:
- -./remove.sh $(bindir) $(localstatedir)/seeder
-if HAVE_NGINX
- -./remove-nginx.sh $(localstatedir)/seeder
-endif
-if HAVE_SYSTEMD
- -./remove-systemd.sh
-endif
+++ /dev/null
-#!/usr/bin/env bash
-
-rm -f "$1/index.html"
-
-rm -f /etc/nginx/sites-enabled/feeds
-rm -f /etc/nginx/sites-available/feeds
-
-systemctl reload nginx
+++ /dev/null
-#!/usr/bin/env bash
-
-systemctl stop seederd
-systemctl disable seederd
-rm -f /lib/systemd/system/seederd.service
-
-systemctl stop seederd-monitor
-systemctl disable seederd-monitor
-rm -f /lib/systemd/system/seederd-monitor.service
-
-systemctl daemon-reload
-systemctl reset-failed
+++ /dev/null
-#!/usr/bin/env bash
-
-rm -f "$1/update-feeds"
-
-rm -rf "$2"
+++ /dev/null
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-mkdir -p "$1"
-
-cat > "$1/index.html" << EOF
-<html>
-<p>This is the homepage of seeder.</p>
-<p><a href="feeds/">Feeds</a></p>
-<p><a href="torrents/">Torrent Files</a></p>
-</html>
-EOF
-
-# setup nginx
-rm -f /etc/nginx/sites-enabled/default
-cat > /etc/nginx/sites-available/feeds << EOF
-server {
- listen 80 default_server;
- listen [::]:80;
-
- root $1;
- index index.html;
-
- location /feeds {
- autoindex on;
- }
-
- location /torrents {
- autoindex on;
- }
-}
-EOF
-ln -sf /etc/nginx/sites-available/feeds /etc/nginx/sites-enabled/feeds
-
-set +e; systemctl reload nginx; set -e;
+++ /dev/null
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-cat > /lib/systemd/system/seederd.service << EOF
-[Unit]
-Description=Seeder daemon
-After=network.target
-
-[Service]
-ExecStartPre=mkdir -p $1
-ExecStart=seederd
-ExecReload=kill -HUP \$MAINPID
-
-Type=simple
-Restart=always
-TimeoutStopSec=60
-
-# Hardening measures
-PrivateTmp=true
-ProtectSystem=full
-ProtectHome=true
-NoNewPrivileges=true
-PrivateDevices=true
-ReadWritePaths=$1
-
-[Install]
-WantedBy=multi-user.target
-EOF
-
-cat > /lib/systemd/system/seederd-monitor.service << EOF
-[Unit]
-Description=Seeder Monitor Service
-After=seederd.service
-
-[Service]
-ExecStartPre=mkdir -p "$1/data"
-ExecStart=inotifywait -e modify,create,delete,move -r "$1/data"
-ExecStopPost=systemctl reload seederd
-Type=simple
-Restart=on-success
-RestartSec=500ms
-
-[Install]
-RequiredBy=seederd.service
-EOF
+++ /dev/null
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-mkdir -p "$1"
-mkdir -p "$2"
-
-cat > "$1/update-feeds" << EOF
-#!/usr/bin/env bash
-
-set -euo pipefail
-
-mkdir -p $2/feeds
-
-FEEDS=(\$(find $2/data -maxdepth 1 -mindepth 1 -type d))
-
-for feed in "\${FEEDS[@]}"; do
- NAME=\$(basename \$feed)
- echo "building feed: \$NAME"
- (cd \$feed; find . -mindepth 1 -maxdepth 1 -not -name ".*" -not -path "**/.*" | sed "s|./||" | sort | rss-create -o $2/feeds/\$NAME.xml -l "$3" -f "$3/torrents/" -n \$NAME -m "../.\$NAME.meta")
-done
-EOF
-
-chmod +x "$1/update-feeds"
+++ /dev/null
-# ===========================================================================
-# https://www.gnu.org/software/autoconf-archive/ax_cxx_compile_stdcxx.html
-# ===========================================================================
-#
-# SYNOPSIS
-#
-# AX_CXX_COMPILE_STDCXX(VERSION, [ext|noext], [mandatory|optional])
-#
-# DESCRIPTION
-#
-# Check for baseline language coverage in the compiler for the specified
-# version of the C++ standard. If necessary, add switches to CXX and
-# CXXCPP to enable support. VERSION may be '11' (for the C++11 standard)
-# or '14' (for the C++14 standard).
-#
-# The second argument, if specified, indicates whether you insist on an
-# extended mode (e.g. -std=gnu++11) or a strict conformance mode (e.g.
-# -std=c++11). If neither is specified, you get whatever works, with
-# preference for no added switch, and then for an extended mode.
-#
-# The third argument, if specified 'mandatory' or if left unspecified,
-# indicates that baseline support for the specified C++ standard is
-# required and that the macro should error out if no mode with that
-# support is found. If specified 'optional', then configuration proceeds
-# regardless, after defining HAVE_CXX${VERSION} if and only if a
-# supporting mode is found.
-#
-# LICENSE
-#
-# Copyright (c) 2014, 2015 Google Inc.; contributed by Alexey Sokolov <
[email protected]>
-#
-# Copying and distribution of this file, with or without modification, are
-# permitted in any medium without royalty provided the copyright notice
-# and this notice are preserved. This file is offered as-is, without any
-# warranty.
-
-#serial 12
-
-dnl This macro is based on the code from the AX_CXX_COMPILE_STDCXX_11 macro
-dnl (serial version number 13).
-
-AC_DEFUN([AX_CXX_COMPILE_STDCXX], [dnl
- m4_if([$1], [11], [ax_cxx_compile_alternatives="11 0x"],
- [$1], [14], [ax_cxx_compile_alternatives="14 1y"],
- [$1], [17], [ax_cxx_compile_alternatives="17 1z"],
- [m4_fatal([invalid first argument `$1' to AX_CXX_COMPILE_STDCXX])])dnl
- m4_if([$2], [], [],
- [$2], [ext], [],
- [$2], [noext], [],
- [m4_fatal([invalid second argument `$2' to AX_CXX_COMPILE_STDCXX])])dnl
- m4_if([$3], [], [ax_cxx_compile_cxx$1_required=true],
- [$3], [mandatory], [ax_cxx_compile_cxx$1_required=true],
- [$3], [optional], [ax_cxx_compile_cxx$1_required=false],
- [m4_fatal([invalid third argument `$3' to AX_CXX_COMPILE_STDCXX])])
- AC_LANG_PUSH([C++])dnl
- ac_success=no
-
- m4_if([$2], [], [dnl
- AC_CACHE_CHECK(whether $CXX supports C++$1 features by default,
- ax_cv_cxx_compile_cxx$1,
- [AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [ax_cv_cxx_compile_cxx$1=yes],
- [ax_cv_cxx_compile_cxx$1=no])])
- if test x$ax_cv_cxx_compile_cxx$1 = xyes; then
- ac_success=yes
- fi])
-
- m4_if([$2], [noext], [], [dnl
- if test x$ac_success = xno; then
- for alternative in ${ax_cxx_compile_alternatives}; do
- switch="-std=gnu++${alternative}"
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
- $cachevar,
- [ac_save_CXX="$CXX"
- CXX="$CXX $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXX="$ac_save_CXX"])
- if eval test x\$$cachevar = xyes; then
- CXX="$CXX $switch"
- if test -n "$CXXCPP" ; then
- CXXCPP="$CXXCPP $switch"
- fi
- ac_success=yes
- break
- fi
- done
- fi])
-
- m4_if([$2], [ext], [], [dnl
- if test x$ac_success = xno; then
- dnl HP's aCC needs +std=c++11 according to:
- dnl http://h21007.www2.hp.com/portal/download/files/unprot/aCxx/PDF_Release_Notes/769149-001.pdf
- dnl Cray's crayCC needs "-h std=c++11"
- for alternative in ${ax_cxx_compile_alternatives}; do
- for switch in -std=c++${alternative} +std=c++${alternative} "-h std=c++${alternative}"; do
- cachevar=AS_TR_SH([ax_cv_cxx_compile_cxx$1_$switch])
- AC_CACHE_CHECK(whether $CXX supports C++$1 features with $switch,
- $cachevar,
- [ac_save_CXX="$CXX"
- CXX="$CXX $switch"
- AC_COMPILE_IFELSE([AC_LANG_SOURCE([_AX_CXX_COMPILE_STDCXX_testbody_$1])],
- [eval $cachevar=yes],
- [eval $cachevar=no])
- CXX="$ac_save_CXX"])
- if eval test x\$$cachevar = xyes; then
- CXX="$CXX $switch"
- if test -n "$CXXCPP" ; then
- CXXCPP="$CXXCPP $switch"
- fi
- ac_success=yes
- break
- fi
- done
- if test x$ac_success = xyes; then
- break
- fi
- done
- fi])
- AC_LANG_POP([C++])
- if test x$ax_cxx_compile_cxx$1_required = xtrue; then
- if test x$ac_success = xno; then
- AC_MSG_ERROR([*** A compiler with support for C++$1 language features is required.])
- fi
- fi
- if test x$ac_success = xno; then
- HAVE_CXX$1=0
- AC_MSG_NOTICE([No compiler with C++$1 support was found])
- else
- HAVE_CXX$1=1
- AC_DEFINE(HAVE_CXX$1,1,
- [define if the compiler supports basic C++$1 syntax])
- fi
- AC_SUBST(HAVE_CXX$1)
-])
-
-
-dnl Test body for checking C++11 support
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_11],
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
-)
-
-
-dnl Test body for checking C++14 support
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_14],
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
-)
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_17],
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_11
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_14
- _AX_CXX_COMPILE_STDCXX_testbody_new_in_17
-)
-
-dnl Tests for new features in C++11
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_11], [[
-
-// If the compiler admits that it is not ready for C++11, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
-
-#error "This is not a C++ compiler"
-
-#elif __cplusplus < 201103L
-
-#error "This is not a C++11 compiler"
-
-#else
-
-namespace cxx11
-{
-
- namespace test_static_assert
- {
-
- template <typename T>
- struct check
- {
- static_assert(sizeof(int) <= sizeof(T), "not big enough");
- };
-
- }
-
- namespace test_final_override
- {
-
- struct Base
- {
- virtual ~Base() {}
- virtual void f() {}
- };
-
- struct Derived : public Base
- {
- virtual ~Derived() override {}
- virtual void f() override {}
- };
-
- }
-
- namespace test_double_right_angle_brackets
- {
-
- template < typename T >
- struct check {};
-
- typedef check<void> single_type;
- typedef check<check<void>> double_type;
- typedef check<check<check<void>>> triple_type;
- typedef check<check<check<check<void>>>> quadruple_type;
-
- }
-
- namespace test_decltype
- {
-
- int
- f()
- {
- int a = 1;
- decltype(a) b = 2;
- return a + b;
- }
-
- }
-
- namespace test_type_deduction
- {
-
- template < typename T1, typename T2 >
- struct is_same
- {
- static const bool value = false;
- };
-
- template < typename T >
- struct is_same<T, T>
- {
- static const bool value = true;
- };
-
- template < typename T1, typename T2 >
- auto
- add(T1 a1, T2 a2) -> decltype(a1 + a2)
- {
- return a1 + a2;
- }
-
- int
- test(const int c, volatile int v)
- {
- static_assert(is_same<int, decltype(0)>::value == true, "");
- static_assert(is_same<int, decltype(c)>::value == false, "");
- static_assert(is_same<int, decltype(v)>::value == false, "");
- auto ac = c;
- auto av = v;
- auto sumi = ac + av + 'x';
- auto sumf = ac + av + 1.0;
- static_assert(is_same<int, decltype(ac)>::value == true, "");
- static_assert(is_same<int, decltype(av)>::value == true, "");
- static_assert(is_same<int, decltype(sumi)>::value == true, "");
- static_assert(is_same<int, decltype(sumf)>::value == false, "");
- static_assert(is_same<int, decltype(add(c, v))>::value == true, "");
- return (sumf > 0.0) ? sumi : add(c, v);
- }
-
- }
-
- namespace test_noexcept
- {
-
- int f() { return 0; }
- int g() noexcept { return 0; }
-
- static_assert(noexcept(f()) == false, "");
- static_assert(noexcept(g()) == true, "");
-
- }
-
- namespace test_constexpr
- {
-
- template < typename CharT >
- unsigned long constexpr
- strlen_c_r(const CharT *const s, const unsigned long acc) noexcept
- {
- return *s ? strlen_c_r(s + 1, acc + 1) : acc;
- }
-
- template < typename CharT >
- unsigned long constexpr
- strlen_c(const CharT *const s) noexcept
- {
- return strlen_c_r(s, 0UL);
- }
-
- static_assert(strlen_c("") == 0UL, "");
- static_assert(strlen_c("1") == 1UL, "");
- static_assert(strlen_c("example") == 7UL, "");
- static_assert(strlen_c("another\0example") == 7UL, "");
-
- }
-
- namespace test_rvalue_references
- {
-
- template < int N >
- struct answer
- {
- static constexpr int value = N;
- };
-
- answer<1> f(int&) { return answer<1>(); }
- answer<2> f(const int&) { return answer<2>(); }
- answer<3> f(int&&) { return answer<3>(); }
-
- void
- test()
- {
- int i = 0;
- const int c = 0;
- static_assert(decltype(f(i))::value == 1, "");
- static_assert(decltype(f(c))::value == 2, "");
- static_assert(decltype(f(0))::value == 3, "");
- }
-
- }
-
- namespace test_uniform_initialization
- {
-
- struct test
- {
- static const int zero {};
- static const int one {1};
- };
-
- static_assert(test::zero == 0, "");
- static_assert(test::one == 1, "");
-
- }
-
- namespace test_lambdas
- {
-
- void
- test1()
- {
- auto lambda1 = [](){};
- auto lambda2 = lambda1;
- lambda1();
- lambda2();
- }
-
- int
- test2()
- {
- auto a = [](int i, int j){ return i + j; }(1, 2);
- auto b = []() -> int { return '0'; }();
- auto c = [=](){ return a + b; }();
- auto d = [&](){ return c; }();
- auto e = [a, &b](int x) mutable {
- const auto identity = [](int y){ return y; };
- for (auto i = 0; i < a; ++i)
- a += b--;
- return x + identity(a + b);
- }(0);
- return a + b + c + d + e;
- }
-
- int
- test3()
- {
- const auto nullary = [](){ return 0; };
- const auto unary = [](int x){ return x; };
- using nullary_t = decltype(nullary);
- using unary_t = decltype(unary);
- const auto higher1st = [](nullary_t f){ return f(); };
- const auto higher2nd = [unary](nullary_t f1){
- return [unary, f1](unary_t f2){ return f2(unary(f1())); };
- };
- return higher1st(nullary) + higher2nd(nullary)(unary);
- }
-
- }
-
- namespace test_variadic_templates
- {
-
- template <int...>
- struct sum;
-
- template <int N0, int... N1toN>
- struct sum<N0, N1toN...>
- {
- static constexpr auto value = N0 + sum<N1toN...>::value;
- };
-
- template <>
- struct sum<>
- {
- static constexpr auto value = 0;
- };
-
- static_assert(sum<>::value == 0, "");
- static_assert(sum<1>::value == 1, "");
- static_assert(sum<23>::value == 23, "");
- static_assert(sum<1, 2>::value == 3, "");
- static_assert(sum<5, 5, 11>::value == 21, "");
- static_assert(sum<2, 3, 5, 7, 11, 13>::value == 41, "");
-
- }
-
- // http://stackoverflow.com/questions/13728184/template-aliases-and-sfinae
- // Clang 3.1 fails with headers of libstd++ 4.8.3 when using std::function
- // because of this.
- namespace test_template_alias_sfinae
- {
-
- struct foo {};
-
- template<typename T>
- using member = typename T::member_type;
-
- template<typename T>
- void func(...) {}
-
- template<typename T>
- void func(member<T>*) {}
-
- void test();
-
- void test() { func<foo>(0); }
-
- }
-
-} // namespace cxx11
-
-#endif // __cplusplus >= 201103L
-
-]])
-
-
-dnl Tests for new features in C++14
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_14], [[
-
-// If the compiler admits that it is not ready for C++14, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
-
-#error "This is not a C++ compiler"
-
-#elif __cplusplus < 201402L
-
-#error "This is not a C++14 compiler"
-
-#else
-
-namespace cxx14
-{
-
- namespace test_polymorphic_lambdas
- {
-
- int
- test()
- {
- const auto lambda = [](auto&&... args){
- const auto istiny = [](auto x){
- return (sizeof(x) == 1UL) ? 1 : 0;
- };
- const int aretiny[] = { istiny(args)... };
- return aretiny[0];
- };
- return lambda(1, 1L, 1.0f, '1');
- }
-
- }
-
- namespace test_binary_literals
- {
-
- constexpr auto ivii = 0b0000000000101010;
- static_assert(ivii == 42, "wrong value");
-
- }
-
- namespace test_generalized_constexpr
- {
-
- template < typename CharT >
- constexpr unsigned long
- strlen_c(const CharT *const s) noexcept
- {
- auto length = 0UL;
- for (auto p = s; *p; ++p)
- ++length;
- return length;
- }
-
- static_assert(strlen_c("") == 0UL, "");
- static_assert(strlen_c("x") == 1UL, "");
- static_assert(strlen_c("test") == 4UL, "");
- static_assert(strlen_c("another\0test") == 7UL, "");
-
- }
-
- namespace test_lambda_init_capture
- {
-
- int
- test()
- {
- auto x = 0;
- const auto lambda1 = [a = x](int b){ return a + b; };
- const auto lambda2 = [a = lambda1(x)](){ return a; };
- return lambda2();
- }
-
- }
-
- namespace test_digit_separators
- {
-
- constexpr auto ten_million = 100'000'000;
- static_assert(ten_million == 100000000, "");
-
- }
-
- namespace test_return_type_deduction
- {
-
- auto f(int& x) { return x; }
- decltype(auto) g(int& x) { return x; }
-
- template < typename T1, typename T2 >
- struct is_same
- {
- static constexpr auto value = false;
- };
-
- template < typename T >
- struct is_same<T, T>
- {
- static constexpr auto value = true;
- };
-
- int
- test()
- {
- auto x = 0;
- static_assert(is_same<int, decltype(f(x))>::value, "");
- static_assert(is_same<int&, decltype(g(x))>::value, "");
- return x;
- }
-
- }
-
-} // namespace cxx14
-
-#endif // __cplusplus >= 201402L
-
-]])
-
-
-dnl Tests for new features in C++17
-
-m4_define([_AX_CXX_COMPILE_STDCXX_testbody_new_in_17], [[
-
-// If the compiler admits that it is not ready for C++17, why torture it?
-// Hopefully, this will speed up the test.
-
-#ifndef __cplusplus
-
-#error "This is not a C++ compiler"
-
-#elif __cplusplus < 201703L
-
-#error "This is not a C++17 compiler"
-
-#else
-
-#include <initializer_list>
-#include <utility>
-#include <type_traits>
-
-namespace cxx17
-{
-
- namespace test_constexpr_lambdas
- {
-
- constexpr int foo = [](){return 42;}();
-
- }
-
- namespace test::nested_namespace::definitions
- {
-
- }
-
- namespace test_fold_expression
- {
-
- template<typename... Args>
- int multiply(Args... args)
- {
- return (args * ... * 1);
- }
-
- template<typename... Args>
- bool all(Args... args)
- {
- return (args && ...);
- }
-
- }
-
- namespace test_extended_static_assert
- {
-
- static_assert (true);
-
- }
-
- namespace test_auto_brace_init_list
- {
-
- auto foo = {5};
- auto bar {5};
-
- static_assert(std::is_same<std::initializer_list<int>, decltype(foo)>::value);
- static_assert(std::is_same<int, decltype(bar)>::value);
- }
-
- namespace test_typename_in_template_template_parameter
- {
-
- template<template<typename> typename X> struct D;
-
- }
-
- namespace test_fallthrough_nodiscard_maybe_unused_attributes
- {
-
- int f1()
- {
- return 42;
- }
-
- [[nodiscard]] int f2()
- {
- [[maybe_unused]] auto unused = f1();
-
- switch (f1())
- {
- case 17:
- f1();
- [[fallthrough]];
- case 42:
- f1();
- }
- return f1();
- }
-
- }
-
- namespace test_extended_aggregate_initialization
- {
-
- struct base1
- {
- int b1, b2 = 42;
- };
-
- struct base2
- {
- base2() {
- b3 = 42;
- }
- int b3;
- };
-
- struct derived : base1, base2
- {
- int d;
- };
-
- derived d1 {{1, 2}, {}, 4}; // full initialization
- derived d2 {{}, {}, 4}; // value-initialized bases
-
- }
-
- namespace test_general_range_based_for_loop
- {
-
- struct iter
- {
- int i;
-
- int& operator* ()
- {
- return i;
- }
-
- const int& operator* () const
- {
- return i;
- }
-
- iter& operator++()
- {
- ++i;
- return *this;
- }
- };
-
- struct sentinel
- {
- int i;
- };
-
- bool operator== (const iter& i, const sentinel& s)
- {
- return i.i == s.i;
- }
-
- bool operator!= (const iter& i, const sentinel& s)
- {
- return !(i == s);
- }
-
- struct range
- {
- iter begin() const
- {
- return {0};
- }
-
- sentinel end() const
- {
- return {5};
- }
- };
-
- void f()
- {
- range r {};
-
- for (auto i : r)
- {
- [[maybe_unused]] auto v = i;
- }
- }
-
- }
-
- namespace test_lambda_capture_asterisk_this_by_value
- {
-
- struct t
- {
- int i;
- int foo()
- {
- return [*this]()
- {
- return i;
- }();
- }
- };
-
- }
-
- namespace test_enum_class_construction
- {
-
- enum class byte : unsigned char
- {};
-
- byte foo {42};
-
- }
-
- namespace test_constexpr_if
- {
-
- template <bool cond>
- int f ()
- {
- if constexpr(cond)
- {
- return 13;
- }
- else
- {
- return 42;
- }
- }
-
- }
-
- namespace test_selection_statement_with_initializer
- {
-
- int f()
- {
- return 13;
- }
-
- int f2()
- {
- if (auto i = f(); i > 0)
- {
- return 3;
- }
-
- switch (auto i = f(); i + 4)
- {
- case 17:
- return 2;
-
- default:
- return 1;
- }
- }
-
- }
-
- namespace test_template_argument_deduction_for_class_templates
- {
-
- template <typename T1, typename T2>
- struct pair
- {
- pair (T1 p1, T2 p2)
- : m1 {p1},
- m2 {p2}
- {}
-
- T1 m1;
- T2 m2;
- };
-
- void f()
- {
- [[maybe_unused]] auto p = pair{13, 42u};
- }
-
- }
-
- namespace test_non_type_auto_template_parameters
- {
-
- template <auto n>
- struct B
- {};
-
- B<5> b1;
- B<'a'> b2;
-
- }
-
- namespace test_structured_bindings
- {
-
- int arr[2] = { 1, 2 };
- std::pair<int, int> pr = { 1, 2 };
-
- auto f1() -> int(&)[2]
- {
- return arr;
- }
-
- auto f2() -> std::pair<int, int>&
- {
- return pr;
- }
-
- struct S
- {
- int x1 : 2;
- volatile double y1;
- };
-
- S f3()
- {
- return {};
- }
-
- auto [ x1, y1 ] = f1();
- auto& [ xr1, yr1 ] = f1();
- auto [ x2, y2 ] = f2();
- auto& [ xr2, yr2 ] = f2();
- const auto [ x3, y3 ] = f3();
-
- }
-
- namespace test_exception_spec_type_system
- {
-
- struct Good {};
- struct Bad {};
-
- void g1() noexcept;
- void g2();
-
- template<typename T>
- Bad
- f(T*, T*);
-
- template<typename T1, typename T2>
- Good
- f(T1*, T2*);
-
- static_assert (std::is_same_v<Good, decltype(f(g1, g2))>);
-
- }
-
- namespace test_inline_variables
- {
-
- template<class T> void f(T)
- {}
-
- template<class T> inline T g(T)
- {
- return T{};
- }
-
- template<> inline void f<>(int)
- {}
-
- template<> int g<>(int)
- {
- return 5;
- }
-
- }
-
-} // namespace cxx17
-
-#endif // __cplusplus < 201703L
-
-]])
+++ /dev/null
-AM_CPPFLAGS = \
- -I$(builddir)/inc/ \
- -I$(srcdir)/inc/
-
-bin_PROGRAMS = rss-create
-
-rss_create_SOURCES = \
- src/add.c \
- src/default.c \
- src/escape.c \
- src/info.c \
- src/log.c \
- src/main.c \
- src/meta.c \
- src/next.c \
- src/opt/desc.c \
- src/opt/feed.c \
- src/opt/link.c \
- src/opt/meta.c \
- src/opt/name.c \
- src/opt/out.c \
- src/util/now.c
-
-rss_create_SOURCES += \
- inc/add.h \
- inc/default.h \
- inc/escape.h \
- inc/info.h \
- inc/log.h \
- inc/main.h \
- inc/meta.h \
- inc/next.h \
- inc/opt.h \
- inc/util.h
-
-EXTRA_DIST = \
- test/add.tests.h \
- test/escape.tests.h \
- test/info.tests.h \
- test/meta.tests.h \
- test/next.tests.h \
- test/opt.desc.tests.h \
- test/opt.feed.tests.h \
- test/opt.link.tests.h \
- test/opt.meta.tests.h \
- test/opt.name.tests.h \
- test/opt.out.tests.h \
- test/util.now.tests.h \
- test/test_utils.h
-
-check_PROGRAMS = add_tests escape_tests info_tests meta_tests next_tests opt_description_tests opt_feed_tests opt_link_tests opt_meta_tests opt_name_tests opt_out_tests util_now_tests
-
-TESTS = $(check_PROGRAMS)
-
-if ENABLE_MEMCHECK
-LOG_COMPILER = $(VALGRIND)
-AM_LOG_FLAGS = --leak-check=full -v --track-origins=yes --error-exitcode=1
-endif
-
-common_SOURCES = \
- src/default.c \
- src/log.c \
- src/opt/out.c \
- src/util/now.c \
- test/test_utils.c
-
-add_tests_SOURCES = \
- $(common_SOURCES) \
- src/escape.c \
- src/meta.c \
- test/add.tests.c
-
-escape_tests_SOURCES = \
- $(common_SOURCES) \
- src/escape.c \
- test/escape.tests.c
-
-info_tests_SOURCES = \
- $(common_SOURCES) \
- src/info.c \
- test/info.tests.c
-
-meta_tests_SOURCES = \
- $(common_SOURCES) \
- src/escape.c \
- src/meta.c \
- test/meta.tests.c
-
-next_tests_SOURCES = \
- $(common_SOURCES) \
- test/next.tests.c
-
-opt_description_tests_SOURCES = \
- $(common_SOURCES) \
- src/opt/desc.c \
- test/opt.desc.tests.c
-
-opt_feed_tests_SOURCES = \
- $(common_SOURCES) \
- src/opt/feed.c \
- test/opt.feed.tests.c
-
-opt_link_tests_SOURCES = \
- $(common_SOURCES) \
- src/opt/link.c \
- test/opt.link.tests.c
-
-opt_meta_tests_SOURCES = \
- $(common_SOURCES) \
- src/escape.c \
- src/meta.c \
- src/opt/meta.c \
- test/opt.meta.tests.c
-
-opt_name_tests_SOURCES = \
- $(common_SOURCES) \
- src/opt/name.c \
- test/opt.name.tests.c
-
-opt_out_tests_SOURCES = \
- $(common_SOURCES) \
- test/opt.out.tests.c
-
-util_now_tests_SOURCES = \
- $(common_SOURCES) \
- test/util.now.tests.c
+++ /dev/null
-#ifndef __ADD_H_
-#define __ADD_H_
-
-#include<stdio.h>
-
-#include<log.h>
-#include<meta.h>
-#include<next.h>
-#include<opt.h>
-#include<rss.h>
-#include<util.h>
-
-#define FIELD_ADDER(x) add_field(x,FIELD_PREFIX(FIELD_STRING_LOADER(x)),FIELD_SUFFIX(FIELD_STRING_LOADER(x)))
-
-#define add_title() FIELD_ADDER(FIELD_TITLE)
-#define add_link() FIELD_ADDER(FIELD_LINK)
-#define add_pubdate() FIELD_ADDER(FIELD_PUBDATE)
-#define add_description() FIELD_ADDER(FIELD_DESCRIPTION)
-#define add_guid() FIELD_ADDER(FIELD_GUID)
-
-int add();
-int add_default(enum field);
-int add_field(enum field,const char*,const char*);
-
-#endif
+++ /dev/null
-#ifndef __DEFAULT_H_
-#define __DEFAULT_H_
-
-#include<stdlib.h>
-#include<string.h>
-
-#include<log.h>
-#include<next.h>
-#include<opt.h>
-#include<util.h>
-
-int defaults();
-
-#endif
+++ /dev/null
-#ifndef __ESCAPE_H_
-#define __ESCAPE_H_
-
-#include<stdlib.h>
-#include<string.h>
-
-#include<log.h>
-
-int escape(char*,size_t);
-
-#endif
+++ /dev/null
-#ifndef __INFO_H_
-#define __INFO_H_
-
-#include<log.h>
-#include<opt.h>
-#include<util.h>
-
-#define INFO_DEFAULT_DESCRIPTION "(no description)"
-#define INFO_DEFAULT_LANGUAGE "en-us"
-
-int info();
-
-#endif
+++ /dev/null
-#ifndef __LOG_H_
-#define __LOG_H_
-
-#include<stdarg.h>
-#include<stdio.h>
-
-extern FILE *output_stream;
-
-#define log_err(...) log_message(stderr,__VA_ARGS__)
-#define out(...) log_message(output_stream,__VA_ARGS__);
-
-void log_close();
-void log_message(FILE*,const char*,...);
-
-#endif
+++ /dev/null
-#ifndef __META_H_
-#define __META_H_
-
-#include<string.h>
-
-#include<escape.h>
-#include<log.h>
-#include<next.h>
-#include<opt.h>
-#include<rss.h>
-
-int meta(char*,char[FIELD_COUNT][BUF_SIZE]);
-int meta_filename(char*,char*,size_t);
-
-#endif
+++ /dev/null
-#ifndef __NEXT_H_
-#define __NEXT_H_
-
-#include<stdio.h>
-
-#define BUF_SIZE 4096
-
-int next(char*,size_t);
-
-#endif
+++ /dev/null
-#ifndef __OPT_H_
-#define __OPT_H_
-
-#include<stddef.h>
-#include<stdio.h>
-#include<stdlib.h>
-#include<string.h>
-
-#include<log.h>
-#include<meta.h>
-#include<rss.h>
-
-struct channel_options {
- char *title;
- char *link;
- char *description;
- char *language;
- char *last_build_date;
-};
-
-struct global_options {
- struct channel_options channel;
- char *feedurl;
-};
-
-extern struct global_options global_opts;
-
-int opt_set_and_parse_meta(char*);
-int opt_set_description(char*);
-int opt_set_feedurl(char*);
-int opt_set_link(char*);
-int opt_set_name(char*);
-int opt_set_output(char*);
-
-#endif
+++ /dev/null
-#ifndef __RSS_H_
-#define __RSS_H_
-
-enum field {
- FIELD_TITLE = 0,
- FIELD_LINK,
- FIELD_PUBDATE,
- FIELD_DESCRIPTION,
- FIELD_GUID,
- FIELD_LANGUAGE,
- FIELD_COUNT
-};
-
-#define XML_START "<"
-#define XML_CLOSE "</"
-#define XML_END ">"
-
-#define FIELD_TITLE_STRING "title"
-#define FIELD_LINK_STRING "link"
-#define FIELD_PUBDATE_STRING "pubDate"
-#define FIELD_DESCRIPTION_STRING "description"
-#define FIELD_GUID_STRING "guid"
-#define FIELD_LANGUAGE_STRING "language"
-
-#define FIELD_STRING_LOADER(x) x ## _STRING
-#define FIELD_PREFIX(x) XML_START x XML_END
-#define FIELD_SUFFIX(x) XML_CLOSE x XML_END
-
-#endif
+++ /dev/null
-#ifndef __UTIL_H_
-#define __UTIL_H_
-
-#include<stdlib.h>
-#include<time.h>
-
-int now_string(char**);
-
-#endif
+++ /dev/null
-#include<add.h>
-
-char bufs[FIELD_COUNT][BUF_SIZE] = {0};
-
-int add() {
- int i;
-
- // clear bufs
- for(i=0;i<FIELD_COUNT;i++) {
- bufs[i][0] = '\0';
- }
-
- // place next file into FIELD_TITLE buffer
- if((i = next(bufs[FIELD_TITLE],BUF_SIZE))<0) { return -1; }
- if(i==0) { return 0; }
-
- // try to get metadata
- if(meta(NULL,bufs)<0) { return -1; }
-
- out("<item>");
- if(add_title()<0) { return -1; }
- if(add_link()<0) { return -1; }
- if(add_pubdate()<0) { return -1; }
- if(add_description()<0) { return -1; }
- if(add_guid()<0) { return -1; }
- out("</item>");
- return 1;
-}
-
-int add_field(enum field field, const char *prefix, const char *suffix) {
- if(strlen(bufs[field])>0) {
- out("%s",prefix);
- out("%s",bufs[field]);
- out("%s",suffix);
- } else {
- if(add_default(field)<0) { return -1; }
- }
-
- return 1;
-}
-
-int add_default(enum field type) {
- char *timebuf;
- switch(type) {
- case FIELD_TITLE:
- case FIELD_LINK:
- log_err("missing required field...aborting...\n");
- return -1;
- case FIELD_DESCRIPTION:
- out("<description>no description</description>");
- break;
- case FIELD_GUID:
- break;
- case FIELD_PUBDATE:
- if(now_string(&timebuf)<0) { return -1; }
- out("<pubDate>%s</pubDate>",timebuf);
- free(timebuf);
- break;
- default:
- log_err("unknown field type\n");
- return -1;
- }
-
- return 1;
-}
+++ /dev/null
-#include<default.h>
-
-struct global_options global_opts = { { NULL }, NULL };
-
-int defaults() {
- struct channel_options *ch;
-
- output_stream = stdout;
- if(atexit(log_close)!=0) { return -1; }
-
- ch = &(global_opts.channel);
-
- if(now_string(&(global_opts.channel.last_build_date))<0) { return -1; }
-
- return 1;
-}
+++ /dev/null
-#include<escape.h>
-
-int escape(char *buf, size_t buf_size) {
- char *p, *p2, *tmpbuf;
- char c;
- size_t len;
- int left;
-
- if(NULL==buf) { return -1; }
- if(buf_size<=0) { return -1; }
- if(strlen(buf)>buf_size) { return -1; }
-
- tmpbuf = NULL;
-
- char to_escape[] = "<\\>&";
-
- p = strpbrk(buf,to_escape);
- p2 = buf;
- while(NULL!=p) {
- if(NULL==tmpbuf) {
- tmpbuf = malloc(buf_size);
- if(NULL==tmpbuf) {
- log_err("allocation error\n");
- return -1;
- }
- tmpbuf[0] = '\0';
- }
-
- c = p[0];
- p[0] = '\0';
- p++;
-
- strcat(tmpbuf,p2);
-
- left = buf_size - strlen(tmpbuf);
-
- switch(c) {
- case '<':
- if(left<=4) { goto panic; }
- strcat(tmpbuf,"<");
- break;
- case '\\':
- if(p[0]=='n') {
- if(left<1) { goto panic; }
- strcat(tmpbuf,"\n");
- p++;
- }
- break;
- case '>':
- if(left<=4) { goto panic; }
- strcat(tmpbuf,">");
- break;
- case '&':
- if(left<=5) { goto panic; }
- strcat(tmpbuf,"&");
- break;
- default:
- log_err("unknown escape character: %c\n",c);
- goto panic;
- }
-
- p2 = p;
- p = strpbrk(p,to_escape);
- }
-
- if(tmpbuf!=NULL) {
- strcat(tmpbuf,p2);
- len = strlen(tmpbuf);
- if(len>buf_size) {
- log_err("escaped string larger than buffer...\n");
- goto panic;
- }
-
- strcpy(buf,tmpbuf);
- free(tmpbuf);
- }
-
- return 1;
- panic:
- if(tmpbuf!=NULL) {
- free(tmpbuf);
- }
- return -1;
-}
+++ /dev/null
-#include<info.h>
-
-int info() {
- struct channel_options *ch;
-
- ch = &(global_opts.channel);
-
- if(NULL==ch->title) {
- log_err("missing channel title\n");
- return -1;
- }
-
- if(NULL==ch->link) {
- log_err("missing channel link\n");
- return -1;
- }
-
- out("<title>%s</title>",global_opts.channel.title);
- out("<link>%s</link>",global_opts.channel.link);
-
- if(NULL==ch->description) {
- out("<description>%s</description>",INFO_DEFAULT_DESCRIPTION);
- } else {
- out("<description>%s</description>",ch->description);
- }
-
- if(NULL==ch->language) {
- out("<language>%s</language>",INFO_DEFAULT_LANGUAGE);
- } else {
- out("<language>%s</language>",global_opts.channel.language);
- }
-
- out("<lastBuildDate>%s</lastBuildDate>",global_opts.channel.last_build_date);
-
- return 1;
-}
+++ /dev/null
-#include<log.h>
-
-FILE *output_stream;
-
-void log_close() {
- if(output_stream!=stdout) {
- fclose(output_stream);
- }
-}
-
-void log_message(FILE *out_stream, const char *format,...) {
- va_list args;
- va_start(args,format);
- vfprintf(out_stream,format,args);
- va_end(args);
-}
+++ /dev/null
-#include<main.h>
-
-static struct option long_options[] = {
- {"description", required_argument, 0, 'd'},
- {"feedurl", required_argument, 0, 'f'},
- {"link", required_argument, 0, 'l'},
- {"meta", required_argument, 0, 'm'},
- {"name", required_argument, 0, 'n'},
- {"output", required_argument, 0, 'o'},
- {0,0,0,0}
-};
-
-int main(int argc, char **argv) {
- int c,i;
-
- if(defaults()<0) { return EXIT_FAILURE; }
-
- while(1) {
- int option_index = 0;
-
- if((c = getopt_long(argc,argv,"d:f:l:m:n:o:",long_options,&option_index))==-1) { break; }
- switch(c) {
- case 0:
- if(long_options[option_index].flag!=0) { break; }
- log_err("option %s", long_options[option_index].name);
- if(optarg) {
- log_err(" with arg %s",optarg);
- }
- log_err("\n");
- return EXIT_FAILURE;
-
- break;
- case 'd':
- if(opt_set_description(optarg)<0) { return EXIT_FAILURE; }
- break;
- case 'f':
- if(opt_set_feedurl(optarg)<0) { return EXIT_FAILURE; }
- break;
- case 'l':
- if(opt_set_link(optarg)<0) { return EXIT_FAILURE; }
- break;
- case 'm':
- if(opt_set_and_parse_meta(optarg)<0) { return EXIT_FAILURE; }
- break;
- case 'n':
- if(opt_set_name(optarg)<0) { return EXIT_FAILURE; }
- break;
- case 'o':
- if(opt_set_output(optarg)<0) { return EXIT_FAILURE; }
- break;
- case '?':
- default:
- return EXIT_FAILURE;
- }
- }
-
- out("<rss version=\"2.0\">");
- out("<channel>");
-
- if(info()<0) { return EXIT_FAILURE; }
-
- while((i = add())>0) { }
-
- if(i<0) { return EXIT_FAILURE; }
-
- out("</channel></rss>\n");
-
- return EXIT_SUCCESS;
-}
+++ /dev/null
-#include<meta.h>
-
-int meta_filename(char *file, char *out, size_t out_len) {
- char *p;
- size_t len;
-
- p = strrchr(file,'/');
- if(NULL==p) {
- p = file;
- } else {
- p++;
- }
-
- len = p-file;
- // prefix length, "." [1], suffix length, ".meta", '\0'
- if((len+1+strlen(p)+5+1)>out_len) {
- return -1;
- }
-
- if(len>0) {
- strncpy(out,file,len);
- }
-
- out[len] = '.';
- out[len+1] = '\0';
- strcat(out,p);
- strcat(out,".meta");
-
- return 1;
-}
-
-int meta(char *meta_file, char bufs[FIELD_COUNT][BUF_SIZE]) {
- char tmp[BUF_SIZE];
- char *p,*p2;
- FILE *fp;
- int i;
-
- if(NULL==meta_file) {
- if(meta_filename(bufs[FIELD_TITLE],tmp,BUF_SIZE)<0) { return -1; }
- fp = fopen(tmp,"r");
- } else {
- fp = fopen(meta_file,"r");
- bufs[FIELD_TITLE][0] = '\0';
- }
-
- if(NULL==fp) { return 0; }
-
- // FIELD_TITLE=0
- for(i=1;i<FIELD_COUNT;i++) {
- bufs[i][0] = '\0';
- }
-
- while(fgets(tmp,BUF_SIZE,fp)!=NULL) {
- p = strchr(tmp,'=');
- if(NULL==p) { goto panic; }
-
- *p = '\0';
- p++;
-
- p2 = p;
- while(*p2!='\0') {
- if('\n'==*p2) {
- *p2 = '\0';
- break;
- }
- p2++;
- }
-
- if(escape(p,BUF_SIZE-(p-tmp))<0) { goto panic; }
-
- if(strcmp(tmp,FIELD_TITLE_STRING)==0) {
- strcpy(bufs[FIELD_TITLE],p);
- } else if(strcmp(tmp,FIELD_LINK_STRING)==0) {
- if(NULL!=global_opts.feedurl) {
- strcpy(bufs[FIELD_LINK],global_opts.feedurl);
- strcat(bufs[FIELD_LINK],p);
- } else {
- strcpy(bufs[FIELD_LINK],p);
- }
- } else if(strcmp(tmp,FIELD_PUBDATE_STRING)==0) {
- strcpy(bufs[FIELD_PUBDATE],p);
- } else if(strcmp(tmp,FIELD_DESCRIPTION_STRING)==0) {
- strcpy(bufs[FIELD_DESCRIPTION],p);
- } else if(strcmp(tmp,FIELD_GUID_STRING)==0) {
- strcpy(bufs[FIELD_GUID],p);
- } else if(strcmp(tmp,FIELD_LANGUAGE_STRING)==0) {
- strcpy(bufs[FIELD_LANGUAGE],p);
- } else {
- log_err("unknown field: %s\n",tmp);
- goto panic;
- }
- }
-
- fclose(fp);
- return 1;
- panic:
- log_err("malformed .meta file: %s\n", meta_file);
- fclose(fp);
- return -1;
-}
+++ /dev/null
-#include<next.h>
-
-int next(char *buf, size_t buf_size) {
- int i;
-
- if(NULL==buf) { return -1; }
-
- i = 0;
- while((buf[i] = getchar())!=EOF) {
- if(buf[i]=='\n') { break; }
- if(i>=buf_size) { return -1; }
- i++;
- }
-
- buf[i] = '\0';
-
- return (i>0);
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_description(char *desc) {
- char *p;
- size_t len;
-
- if(NULL==desc) { return -1; }
-
- len = strlen(desc);
- if(len==0) { return -1; }
-
- p = malloc(sizeof(char)*(len+1));
- if(NULL==p) { return -1; }
-
- strcpy(p,desc);
- global_opts.channel.description = p;
-
- return 1;
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_feedurl(char *url) {
- char *p;
- size_t len;
-
- if(NULL==url) { return -1; }
-
- len = strlen(url);
- if(len==0) { return -1; }
-
- if(url[len-1]!='/') { len++; }
-
- p = malloc(sizeof(char)*(len+1));
- if(NULL==p) { return -1; }
-
- strcpy(p,url);
-
- if(url[len-1]!='/') {
- strcat(p,"/");
- }
-
- global_opts.feedurl = p;
-
- return 1;
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_link(char *link) {
- char *p;
- size_t len;
-
- if(NULL==link) { return -1; }
-
- len = strlen(link);
- if(len==0) { return -1; }
-
- p = malloc(sizeof(char)*(len+1));
- if(NULL==p) { return -1; }
-
- strcpy(p,link);
- global_opts.channel.link = p;
-
- return 1;
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_and_parse_meta(char *filename) {
- char bufs[FIELD_COUNT][BUF_SIZE] = {0};
- char *p;
- size_t len, title_len, desc_len, link_len, guid_len, lan_len;
- struct channel_options *ch;
- int i;
-
- if(NULL==filename) { return -1; }
-
- if((i = meta(filename,bufs))<0) { return -1; }
- if(i==0) {
- log_err("missing meta file: %s\n",filename);
- return -1;
- }
-
- ch = &(global_opts.channel);
-
- title_len = strlen(bufs[FIELD_TITLE]);
- desc_len = strlen(bufs[FIELD_DESCRIPTION]);
- link_len = strlen(bufs[FIELD_LINK]);
- guid_len = strlen(bufs[FIELD_GUID]);
- lan_len = strlen(bufs[FIELD_LANGUAGE]);
- len = title_len+desc_len+link_len+guid_len+lan_len+5;
-
- if(len>0) {
- p = malloc(sizeof(char)*(len));
- if(NULL==p) { return -1; }
- }
-
- if(title_len>0) {
- ch->title = p;
- strcpy(ch->title,bufs[FIELD_TITLE]);
- p += title_len+1;
- }
-
- if(desc_len>0) {
- ch->description = p;
- strcpy(ch->description,bufs[FIELD_DESCRIPTION]);
- p += desc_len+1;
- }
-
- if(link_len>0) {
- if(NULL==ch->description) {
- ch->description = p;
- ch->description[0] = '\0';
- } else {
- strcat(ch->description,"\n");
- }
-
- strcat(ch->description,bufs[FIELD_LINK]);
- p += link_len+1;
- }
-
- if(guid_len>0) {
- if(NULL==ch->description) {
- ch->description = p;
- ch->description[0] = '\0';
- } else {
- strcat(ch->description,"\n");
- }
-
- strcat(ch->description,bufs[FIELD_GUID]);
- p += guid_len+1;
- }
-
- if(lan_len>0) {
- ch->language = p;
- strcpy(ch->language,bufs[FIELD_LANGUAGE]);
- }
-
- return 1;
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_name(char *name) {
- char *p;
- size_t len;
-
- if(NULL==name) { return -1; }
-
- len = strlen(name);
- if(len==0) { return -1; }
-
- p = malloc(sizeof(char)*(len+1));
- if(NULL==p) { return -1; }
-
- strcpy(p,name);
- global_opts.channel.title = p;
-
- return 1;
-}
+++ /dev/null
-#include<opt.h>
-
-int opt_set_output(char *target) {
- FILE *fp;
-
- if(NULL==target) { return -1; }
-
- fp = fopen(target,"w");
- if(NULL==fp) {
- log_err("unable to open %s for writing\n",target);
- return -1;
- }
-
- output_stream = fp;
- return 1;
-}
+++ /dev/null
-#include<util.h>
-
-int now_string(char **timebuf) {
- if(NULL==timebuf) { return -1; }
-
- *timebuf = malloc(sizeof(char)*70);
- if(NULL==(*timebuf)) { return -1; }
-
- struct tm now;
-
- now = *localtime(&(time_t){time(NULL)});
- if(!(strftime((*timebuf),sizeof(char)*70, "%a, %d %b %Y %H:%M:%S %z", &now))) { return -1; }
-
- return 1;
-}
+++ /dev/null
-#include "add.tests.h"
-
-int main() {
- setup_env();
-
- add_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-static int i = 0;
-
-void add_basic_tests() {
- FILE *fp;
- char buf[1024];
-
- assert(opt_set_output(DATADIR "feed.xml")==1);
-
- assert(add()==1);
- assert(add()==-1);
-
- log_close();
-
- fp = fopen(DATADIR "feed.xml","r");
- assert(NULL!=fp);
-
- assert(fread(buf,sizeof(char),1024,fp)==260);
- assert(fclose(fp)==0);
-
- assert(memcmp(buf,"<item><title>/tmp/rss-create/test/test2.txt</title><link>0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent</link><pubDate>Sat, 15 May 2021 11:01:04 +0000</pubDate><description>no description</description></item><item><title>/tmp/rss-create/test/test.txt</title>",260)==0);
-}
-
-int next_dummy(char *buf, size_t size) {
- switch(i) {
- case 0:
- snprintf(buf,size,FILE_2);
- break;
- case 1:
- snprintf(buf,size,FILE_1);
- break;
- case 2:
- snprintf(buf,size,FILE_3);
- break;
- default:
- snprintf(buf,size,"notarealfile");
- break;
- }
- i++;
- return 1;
-}
+++ /dev/null
-#ifndef __ADD_TESTS_H_
-#define __ADD_TESTS_H_
-
-#include "test_utils.h"
-
-#include<add.h>
-
-int main();
-void add_basic_tests();
-int next_dummy(char*,size_t);
-
-#define next(buf,size) next_dummy(buf,size)
-#include "../src/add.c"
-
-#endif
+++ /dev/null
-#include "escape.tests.h"
-
-int main() {
- setup_env();
-
- escape_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-#define BUF_SIZE 1024
-void escape_basic_tests() {
- char buf[BUF_SIZE];
-
- assert(escape(NULL,0)==-1);
- assert(escape(buf,0)==-1);
-
- strcpy(buf,"<");
- assert(escape(buf,BUF_SIZE)==1);
- assert(strcmp(buf,"<")==0);
-
- strcpy(buf,">");
- assert(escape(buf,BUF_SIZE)==1);
- assert(strcmp(buf,">")==0);
-
- strcpy(buf,"\\n");
- assert(escape(buf,BUF_SIZE)==1);
- assert(strcmp(buf,"\n")==0);
-
- strcpy(buf,"&");
- assert(escape(buf,BUF_SIZE)==1);
- assert(strcmp(buf,"&")==0);
-
- strcpy(buf,"this");
- assert(escape(buf,6)==1);
-
- strcpy(buf,"this&");
- assert(escape(buf,6)==-1);
-
- strcpy(buf,"this<");
- assert(escape(buf,6)==-1);
-
- strcpy(buf,"this>");
- assert(escape(buf,6)==-1);
-
- strcpy(buf,"this\\n");
- assert(escape(buf,4)==-1);
-
- strcpy(buf,"lskjdflaksjdfl<>slkdfjlsdf&lsdjkfsldfjsldkfj\\nsldkjfslkdjfk<<<<>>>>");
- assert(escape(buf,10)==-1);
- assert(escape(buf,1024)==1);
- assert(strcmp(buf,"lskjdflaksjdfl<>slkdfjlsdf&lsdjkfsldfjsldkfj\nsldkjfslkdjfk<<<<>>>>")==0);
-}
+++ /dev/null
-#ifndef __ESCAPE_TESTS_H_
-#define __ESCAPE_TESTS_H_
-
-#include "test_utils.h"
-
-#include<escape.h>
-
-int main();
-void escape_basic_tests();
-
-#endif
+++ /dev/null
-#include "info.tests.h"
-
-int main() {
- setup_env();
-
- info_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void info_basic_tests() {
- FILE *fp;
- char buf[1024];
- char buf2[1024];
-
- assert(opt_set_output(DATADIR "feed.xml")==1);
-
- assert(info()==-1);
-
- global_opts.channel.title = "test title";
- assert(info()==-1);
-
- global_opts.channel.link = "https://test.com/test/feed.xml";
- assert(now_string(&(global_opts.channel.last_build_date))==1);
-
- assert(info()==1);
-
- log_close();
-
- fp = fopen(DATADIR "feed.xml","r");
- assert(NULL!=fp);
-
- assert(fread(buf,sizeof(char),1024,fp)==199);
- assert(fclose(fp)==0);
-
- sprintf(buf2,"<title>test title</title><link>https://test.com/test/feed.xml</link><description>(no description)</description><language>en-us</language><lastBuildDate>%s</lastBuildDate>",global_opts.channel.last_build_date);
-
- assert(memcmp(buf,buf2,199)==0);
-}
+++ /dev/null
-#ifndef __INFO_TESTS_H_
-#define __INFO_TESTS_H_
-
-#include "test_utils.h"
-
-#include<info.h>
-
-int main();
-void info_basic_tests();
-
-#endif
+++ /dev/null
-#include "meta.tests.h"
-
-int main() {
- setup_env();
-
- meta_basic_tests();
- meta_feedurl_test();
- meta_filename_basic_test();
- meta_duplicate_field_test();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void meta_basic_tests() {
- char bufs[FIELD_COUNT][BUF_SIZE];
-
- assert(meta("nonexistentfile",bufs)==0);
- strcpy(bufs[FIELD_TITLE],"nonexistentfile");
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_1,bufs)==-1);
- strcpy(bufs[FIELD_TITLE],FILE_1);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_2,bufs)==-1);
- strcpy(bufs[FIELD_TITLE],FILE_2);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],FILE_2)==0);
- assert(strcmp(bufs[FIELD_LINK],"0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
- assert(strcmp(bufs[FIELD_PUBDATE],"Sat, 15 May 2021 11:01:04 +0000")==0);
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- assert(meta(FILE_3,bufs)==-1);
- strcpy(bufs[FIELD_TITLE],FILE_3);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_4,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(strcmp(bufs[FIELD_PUBDATE],"Sun, 16 May 2021 02:55:07 +0000")==0);
- assert(strcmp(bufs[FIELD_DESCRIPTION],"this a<Mactual>ly show\na new line")==0);
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
- strcpy(bufs[FIELD_TITLE],FILE_4);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_5,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(strcmp(bufs[FIELD_LINK],"0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
- assert(strcmp(bufs[FIELD_PUBDATE],"Sat, 15 May 2021 11:01:04 +0000")==0);
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
- strcpy(bufs[FIELD_TITLE],FILE_5);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_6,bufs)==-1);
- strcpy(bufs[FIELD_TITLE],FILE_6);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_7,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(strcmp(bufs[FIELD_GUID],"hello")==0);
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
- strcpy(bufs[FIELD_TITLE],FILE_7);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_8,bufs)==-1);
- strcpy(bufs[FIELD_TITLE],FILE_8);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],FILE_8)==0);
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(strcmp(bufs[FIELD_GUID],"hello")==0);
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- assert(meta(FILE_9,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(strcmp(bufs[FIELD_DESCRIPTION],"this is a test description")==0);
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
- strcpy(bufs[FIELD_TITLE],FILE_9);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(FILE_10,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(strcmp(bufs[FIELD_LANGUAGE],"en-uk")==0);
- strcpy(bufs[FIELD_TITLE],FILE_10);
- assert(meta(NULL,bufs)==0);
-
- assert(meta(DIRECTORY_1,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- assert(meta(DIRECTORY_2,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- assert(meta(DIRECTORY_3,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- assert(meta(DIRECTORY_4,bufs)==1);
- assert(bufs[FIELD_TITLE][0]=='\0');
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- strcpy(bufs[FIELD_TITLE],DIRECTORY_1);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],DIRECTORY_1)==0);
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(strcmp(bufs[FIELD_DESCRIPTION],"this is a test description")==0);
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- strcpy(bufs[FIELD_TITLE],DIRECTORY_2);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],DIRECTORY_2)==0);
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(bufs[FIELD_PUBDATE][0]=='\0');
- assert(bufs[FIELD_DESCRIPTION][0]=='\0');
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(strcmp(bufs[FIELD_LANGUAGE],"en-uk")==0);
-
- strcpy(bufs[FIELD_TITLE],DIRECTORY_3);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],DIRECTORY_3)==0);
- assert(bufs[FIELD_LINK][0]=='\0');
- assert(strcmp(bufs[FIELD_PUBDATE],"Sun, 16 May 2021 02:55:07 +0000")==0);
- assert(strcmp(bufs[FIELD_DESCRIPTION],"this a<Mactual>ly show\na new line")==0);
- assert(bufs[FIELD_GUID][0]=='\0');
- assert(bufs[FIELD_LANGUAGE][0]=='\0');
-
- strcpy(bufs[FIELD_TITLE],DIRECTORY_4);
- assert(meta(NULL,bufs)==0);
-}
-
-void meta_feedurl_test() {
- char bufs[FIELD_COUNT][BUF_SIZE];
-
- strcpy(bufs[FIELD_TITLE],FILE_2);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_LINK],"0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
-
- assert(meta(FILE_5,bufs)==1);
- assert(strcmp(bufs[FIELD_LINK],"0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
-
- // opt_set_feedurl() should make sure that feedurl has '/' at end
- char testurl[] = "https://example.com/feeds/";
- global_opts.feedurl = testurl;
-
- strcpy(bufs[FIELD_TITLE],FILE_2);
- assert(meta(NULL,bufs)==1);
- assert(strcmp(bufs[FIELD_LINK],"https://example.com/feeds/0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
-
- assert(meta(FILE_5,bufs)==1);
- assert(strcmp(bufs[FIELD_LINK],"https://example.com/feeds/0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent")==0);
-
- global_opts.feedurl = NULL;
-}
-
-void meta_filename_basic_test() {
- char tmp[BUF_SIZE];
- char tmp2[BUF_SIZE];
-
- strcpy(tmp,"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");
-
- assert(meta_filename(tmp,tmp2,10)==-1);
- assert(meta_filename(tmp,tmp2,BUF_SIZE)==1);
- assert(strcmp(tmp2,".aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.meta")==0);
-
- strcpy(tmp,"/this/is/a/test/path");
- assert(meta_filename(tmp,tmp2,10)==-1);
- assert(meta_filename(tmp,tmp2,26)==-1);
- assert(meta_filename(tmp,tmp2,27)==1);
- assert(strcmp(tmp2,"/this/is/a/test/.path.meta")==0);
-}
-
-void meta_duplicate_field_test() {
- char bufs[FIELD_COUNT][BUF_SIZE];
-
- assert(meta(FILE_11,bufs)==1);
- assert(strcmp(bufs[FIELD_TITLE],"test2")==0);
- assert(strcmp(bufs[FIELD_LINK],"link2")==0);
- assert(strcmp(bufs[FIELD_PUBDATE],"date2")==0);
- assert(strcmp(bufs[FIELD_DESCRIPTION],"desc2")==0);
- assert(strcmp(bufs[FIELD_GUID],"guid2")==0);
- assert(strcmp(bufs[FIELD_LANGUAGE],"lan2")==0);
-}
+++ /dev/null
-#ifndef __META_TESTS_H_
-#define __META_TESTS_H_
-
-#include "test_utils.h"
-
-#include<meta.h>
-
-int main();
-void meta_basic_tests();
-void meta_feedurl_test();
-void meta_filename_basic_test();
-void meta_duplicate_field_test();
-
-#endif
+++ /dev/null
-#include "next.tests.h"
-
-int main() {
- setup_env();
-
- next_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-static int i = 0;
-
-void next_basic_tests() {
- char buf[1024];
-
- assert(next(NULL,0)==-1);
- assert(next(buf,10)==-1);
- i = 0;
- assert(next(buf,1024)==1);
- assert(strcmp(buf,"aaaaaaaaaaaaaaaaaaaa")==0);
-}
-
-int getchar_dummy() {
- if(i<20) {
- i++;
- return 'a';
- } else {
- return '\n';
- }
-}
+++ /dev/null
-#ifndef __NEXT_TESTS_H_
-#define __NEXT_TESTS_H_
-
-#include "test_utils.h"
-
-#include<next.h>
-
-int main();
-void next_basic_tests();
-int getchar_dummy();
-
-#define getchar() getchar_dummy()
-#include "../src/next.c"
-
-#endif
+++ /dev/null
-#include "opt.desc.tests.h"
-
-int main() {
- setup_env();
-
- opt_desc_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_desc_basic_tests() {
- assert(opt_set_description(NULL)==-1);
- assert(opt_set_description("")==-1);
-
- assert(opt_set_description("test")==1);
- assert(strcmp(global_opts.channel.description,"test")==0);
-}
+++ /dev/null
-#ifndef __OPT_DESC_TESTS_H_
-#define __OPT_DESC_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_desc_basic_tests();
-
-#endif
+++ /dev/null
-#include "opt.feed.tests.h"
-
-int main() {
- setup_env();
-
- opt_feed_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_feed_basic_tests() {
- assert(opt_set_feedurl(NULL)==-1);
- assert(opt_set_feedurl("")==-1);
-
- assert(opt_set_feedurl("https://test.com")==1);
- assert(strcmp(global_opts.feedurl,"https://test.com/")==0);
-
- free(global_opts.feedurl);
- global_opts.feedurl = NULL;
-
- assert(opt_set_feedurl("http://test.com/")==1);
- assert(strcmp(global_opts.feedurl,"http://test.com/")==0);
-}
+++ /dev/null
-#ifndef __OPT_FEED_TESTS_H_
-#define __OPT_FEED_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_feed_basic_tests();
-
-#endif
+++ /dev/null
-#include "opt.link.tests.h"
-
-int main() {
- setup_env();
-
- opt_link_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_link_basic_tests() {
- assert(opt_set_link(NULL)==-1);
- assert(opt_set_link("")==-1);
-
- assert(opt_set_link("alksdjflasdjf")==1);
- assert(strcmp(global_opts.channel.link,"alksdjflasdjf")==0);
-}
+++ /dev/null
-#ifndef __OPT_LINK_TESTS_H_
-#define __OPT_LINK_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_link_basic_tests();
-
-#endif
+++ /dev/null
-#include "opt.meta.tests.h"
-
-int main() {
- setup_env();
-
- opt_set_and_parse_meta_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_set_and_parse_meta_basic_tests() {
- assert(opt_set_and_parse_meta(NULL)==-1);
- assert(opt_set_and_parse_meta("notarealfile")==-1);
-
- assert(opt_set_and_parse_meta(FILE_9)==1);
- assert(NULL==global_opts.channel.title);
- assert(strcmp(global_opts.channel.description,"this is a test description")==0);
- assert(NULL==global_opts.channel.language);
-}
+++ /dev/null
-#ifndef __OPT_META_TESTS_H_
-#define __OPT_META_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_set_and_parse_meta_basic_tests();
-
-#endif
+++ /dev/null
-#include "opt.name.tests.h"
-
-int main() {
- setup_env();
-
- opt_set_name_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_set_name_basic_tests() {
- assert(opt_set_name(NULL)==-1);
- assert(opt_set_name("")==-1);
-
- assert(opt_set_name("feedname")==1);
- assert(strcmp(global_opts.channel.title,"feedname")==0);
-}
+++ /dev/null
-#ifndef __OPT_NAME_TESTS_H_
-#define __OPT_NAME_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_set_name_basic_tests();
-
-#endif
+++ /dev/null
-#include "opt.out.tests.h"
-
-int main() {
- setup_env();
-
- opt_out_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void opt_out_basic_tests() {
- assert(opt_set_output(NULL)==-1);
- assert(opt_set_output("/tmp/tempoutfile")==1);
-}
+++ /dev/null
-#ifndef __OPT_OUT_TESTS_H_
-#define __OPT_OUT_TESTS_H_
-
-#include "test_utils.h"
-
-#include<opt.h>
-
-int main();
-void opt_out_basic_tests();
-
-#endif
+++ /dev/null
-#include "test_utils.h"
-
-void clean_env() {
- system("rm -rf " DATADIR);
-}
-
-void reset_env() {
- clean_env();
- setup_env();
-}
-
-void setup_env() {
- clean_env();
-
- create_test_directory(DATADIR);
- create_test_directory(DIRECTORY_1);
- create_test_directory(DIRECTORY_2);
- create_test_directory(DIRECTORY_3);
- create_test_directory(DIRECTORY_4);
- CREATE(1);
- CREATE(2);
- CREATE(3);
- CREATE(4);
- CREATE(5);
- CREATE(6);
- CREATE(7);
- CREATE(8);
- CREATE(9);
- CREATE(10);
- CREATE(11);
-}
-
-void create_test_directory(const char *directory) {
- assert(mkdir(directory,0700)==0);
-}
-
-void create_test_file(const char *filename, const char *contents) {
- FILE *fp;
-
- printf("creating %s\n",filename);
- fp = fopen(filename,"w+");
- assert(NULL!=fp);
-
- assert(strlen(contents)==fwrite(contents,sizeof(char),strlen(contents),fp));
- assert(fclose(fp)==0);
-}
+++ /dev/null
-#ifndef __TEST_UTILS_H_
-#define __TEST_UTILS_H_
-
-#include<assert.h>
-#include<stdlib.h>
-#include<stdio.h>
-#include<string.h>
-#include<sys/stat.h>
-#include<sys/types.h>
-
-#define DATADIR "/tmp/rss-create"
-
-#define DIRECTORY_1 DATADIR "/test"
-#define DIRECTORY_2 DATADIR "/test2"
-#define DIRECTORY_3 DATADIR "/test/test3"
-#define DIRECTORY_4 DATADIR "/test/.dotfiles"
-
-#define FILE_1 DATADIR "/test/test.txt"
-#define FILE_1_CONTENTS "test"
-#define FILE_2 DATADIR "/test/test2.txt"
-#define FILE_2_CONTENTS "test2"
-#define FILE_3 DATADIR "/test/test3/hello.txt"
-#define FILE_3_CONTENTS "test3"
-#define FILE_4 DATADIR "/test/.test3.meta"
-#define FILE_4_CONTENTS "description=nope\ndescription=this a<Mactual>ly show\\na new line\npubDate=Sun, 16 May 2021 02:55:07 +0000\n"
-#define FILE_5 DATADIR "/test/.test2.txt.meta"
-#define FILE_5_CONTENTS "pubDate=Sat, 15 May 2021 11:01:04 +0000\nlink=0bc6c0de1ff1d26d84187a4d42fb9a2d0bc73a1d.torrent"
-#define FILE_6 DATADIR "/test/.dotfiles/haha.txt"
-#define FILE_6_CONTENTS "hahaha"
-
-#define FILE_7 DATADIR "/test2/.nope.txt.meta"
-#define FILE_7_CONTENTS "guid=hello"
-#define FILE_8 DATADIR "/test2/nope.txt"
-#define FILE_8_CONTENTS "hahahasldkfjasldkfjaslkdfj"
-
-#define FILE_9 DATADIR "/.test.meta"
-#define FILE_9_CONTENTS "description=this is a test description"
-#define FILE_10 DATADIR "/.test2.meta"
-#define FILE_10_CONTENTS "language=en-uk"
-
-#define FILE_11 DATADIR "/test/test4.txt"
-#define FILE_11_CONTENTS "title=test\ntitle=test2\nlink=link1\nlink=link2\npubDate=date1\npubDate=date2\ndescription=desc1\ndescription=desc2\nguid=guid1\nguid=guid2\nlanguage=lan1\nlanguage=lan2"
-
-#define CREATE_FILE_NAME_LOADER(x) FILE_ ## x
-#define CREATE_FILE_CONTENTS_LOADER(x) FILE_ ## x ## _CONTENTS
-#define CREATE(x) create_test_file(CREATE_FILE_NAME_LOADER(x),CREATE_FILE_CONTENTS_LOADER(x))
-
-void clean_env();
-void reset_env();
-void setup_env();
-void create_test_directory(const char*);
-void create_test_file(const char*,const char*);
-
-#endif
+++ /dev/null
-#include "util.now.tests.h"
-
-int main() {
- setup_env();
-
- util_now_basic_tests();
-
- clean_env();
-
- return EXIT_SUCCESS;
-}
-
-void util_now_basic_tests() {
- char *p;
- assert(now_string(NULL)==-1);
-
- assert(now_string(&p)==1);
-
- free(p);
-}
+++ /dev/null
-#ifndef __UTIL_NOW_TESTS_H_
-#define __UTIL_NOW_TESTS_H_
-
-#include "test_utils.h"
-
-#include<util.h>
-
-int main();
-void util_now_basic_tests();
-
-#endif
+++ /dev/null
-AM_CXXFLAGS = \
- -DPREFIX=\"$(localstatedir)/seeder\" \
- -DTORRENT_USE_OPENSSL \
- -I$(builddir)/inc/ \
- -I$(srcdir)/inc/
-
-bin_PROGRAMS = seederd
-
-seederd_SOURCES = \
- src/feed.cpp \
- src/main.cpp \
- src/seed.cpp \
- src/torrent.cpp
-
-seederd_SOURCES += \
- inc/feed.hpp \
- inc/main.h \
- inc/seed.hpp \
- inc/torrent.hpp
-
-seederd_LDFLAGS = -ltorrent-rasterbar -lboost_system -lpthread
-seederd_LDADD = -lstdc++fs
+++ /dev/null
-#ifndef __CONSTS_H_
-#define __CONSTS_H_
-
-#define DATADIR PREFIX "/data"
-#define TORRENTDIR PREFIX "/torrents"
-
-#endif
+++ /dev/null
-#ifndef __FEED_HPP_
-#define __FEED_HPP_
-
-#include<torrent.hpp>
-
-class feed {
- public:
- feed(lt::session& session, fs::path feed_path) : m_path(feed_path) {
- for(auto &p: fs::directory_iterator(feed_path)) {
- if(torrent::file_filter(p.path().string())) {
- torrent t(session,p);
- }
- }
-
- torrent t(session,feed_path);
- }
- void save();
- private:
- fs::path m_path;
-};
-
-#endif
+++ /dev/null
-#ifndef __MAIN_H_
-#define __MAIN_H_
-
-#include<cstdlib>
-#include<filesystem>
-#include<getopt.h>
-#include<iostream>
-#include<signal.h>
-
-#include<libtorrent/alert_types.hpp>
-#include<libtorrent/session.hpp>
-
-#include<consts.h>
-#include<feed.hpp>
-#include<torrent.hpp>
-
-int main(int,char**);
-void init(lt::session&);
-void handle_alerts(lt::session&);
-void remove_missing(lt::session&);
-int setup_signal_handler();
-void signal_handler(int);
-
-#endif
+++ /dev/null
-#ifndef __SEED_HPP_
-#define __SEED_HPP_
-
-#include<filesystem>
-#include<iostream>
-
-#include<libtorrent/session.hpp>
-#include<libtorrent/torrent_info.hpp>
-
-namespace fs = std::filesystem;
-
-class seed {
- public:
- seed(lt::session& session, std::string torrent_filepath, std::string data_path) {
- lt::add_torrent_params params;
- params.save_path = data_path;
- params.ti = std::make_shared<lt::torrent_info>(torrent_filepath);
- params.flags = lt::torrent_flags::seed_mode;
-
- session.async_add_torrent(params);
- }
- void static remove();
-};
-
-#endif
+++ /dev/null
-#ifndef __TORRENT_HPP_
-#define __TORRENT_HPP_
-
-#include<filesystem>
-#include<fstream>
-#include<iostream>
-#include<string>
-
-#include<libtorrent/create_torrent.hpp>
-#include<libtorrent/magnet_uri.hpp>
-#include<libtorrent/torrent_info.hpp>
-
-#include<consts.h>
-#include<seed.hpp>
-
-namespace fs = std::filesystem;
-
-class torrent {
- public:
- torrent(lt::session &session, fs::path p) : m_path(p) {
- lt::add_files(m_fs,p,file_filter);
- if(m_fs.num_files()>0) {
- save(session);
- } else {
- std::cerr << "WARNING: no files found in " << p << "; skipping"<< std::endl;
- }
- };
- void add(fs::path);
- void add_link_to_meta(std::string,std::string);
- bool static file_filter(std::string const&);
- void save(lt::session&);
- private:
- fs::path m_path;
- lt::file_storage m_fs;
-};
-
-#endif
+++ /dev/null
-#include<feed.hpp>
-
-namespace fs = std::filesystem;
-
-void feed::save() {
- throw std::runtime_error("not implemented\n");
-}
+++ /dev/null
-#include<main.h>
-
-namespace fs = std::filesystem;
-
-int setup_signal_handler() {
- struct sigaction action;
-
- action.sa_handler = &signal_handler;
- action.sa_flags = 0;
- if(sigemptyset(&action.sa_mask)==-1) {
- perror("sigemptyset");
- return -1;
- }
-
- if(sigaddset(&action.sa_mask,SIGHUP)==-1) {
- perror("sigaddset");
- return -1;
- }
-
- if(sigaction(SIGHUP, &action, NULL)==-1) {
- perror("sigaction");
- return -1;
- }
-
- return 1;
-}
-
-static struct option long_options[] = {
- {"verbose", no_argument, 0, 'v'},
- {0,0,0,0}
-};
-
-int main(int argc, char **argv) try {
- char c;
- bool verbose_flag = false;
-
- while(1) {
- int option_index = 0;
-
- if((c = getopt_long(argc,argv,"v",long_options,&option_index))==-1) { break; }
-
- switch(c) {
- case 0:
- break;
- case 'v':
- verbose_flag = true;
- std::cerr << "verbose mode enabled" << std::endl;
-
- break;
- case '?':
- default:
- std::cerr << "invalid option" << std::endl;
- return EXIT_FAILURE;
- }
- }
-
- if(setup_signal_handler()<0) { return EXIT_FAILURE; }
-
- std::cout << "creating required directories" << std::endl;
- fs::create_directories(DATADIR);
- std::cout << "created " << DATADIR << std::endl;
- fs::create_directories(TORRENTDIR);
- std::cout << "created " << TORRENTDIR << std::endl;
-
- lt::session_params params;
- auto& settings = params.settings;
-
- settings = lt::high_performance_seed();
- settings.set_int(lt::settings_pack::active_seeds,-1);
- settings.set_int(lt::settings_pack::active_limit,-1);
- settings.set_str(lt::settings_pack::listen_interfaces,"0.0.0.0:6881");
- settings.set_bool(lt::settings_pack::listen_system_port_fallback,false);
- settings.set_str(lt::settings_pack::user_agent,PACKAGE_STRING);
-
- if(verbose_flag) {
- settings.set_int(lt::settings_pack::alert_mask, lt::alert::all_categories
- & ~(lt::alert::dht_notification
- + lt::alert::piece_progress_notification
- + lt::alert::block_progress_notification
- + lt::alert::session_log_notification
- + lt::alert::torrent_log_notification
- + lt::alert::peer_log_notification
- + lt::alert::dht_log_notification
- + lt::alert::picker_log_notification
- ));
- }
-
- lt::session session(params);
-
- init(session);
-
- handle_alerts(session);
-
- return EXIT_SUCCESS;
-}
-catch(std::exception const& e) {
- std::cerr << "ERROR: " << e.what() << std::endl;
- return EXIT_FAILURE;
-}
-
-void init(lt::session& session) {
- for(auto &p: fs::directory_iterator(DATADIR)) {
- if(p.is_directory()) {
- if(!torrent::file_filter(p.path().string())) { continue; }
-
- std::cout << "creating torrents in " << p.path() << "..." << std::endl;
-
- feed fd(session,p.path());
-
- std::cout<< "done!" << std::endl;
- }
- }
-
- remove_missing(session);
-
- system("update-feeds");
-}
-
-void remove_missing(lt::session& session) {
- // add all .torrent files
- std::unordered_map<std::string,fs::path> found;
- for(auto &p: fs::directory_iterator(TORRENTDIR)) {
- if(p.is_regular_file()) {
- fs::path path = p.path();
- found.insert({path.stem().string(),path});
- }
- }
-
- std::vector<lt::torrent_handle> current = session.get_torrents();
- for(auto t: current) {
- std::stringstream hash;
- hash << t.info_hash();
-
- // remove torrent if .torrent file no longer exists
- auto search = found.find(hash.str());
- if(search==found.end()) {
- session.remove_torrent(t);
- }
- }
-}
-
-
-bool reload = false;
-
-void handle_alerts(lt::session& session) {
- for (;;) {
- if(reload) {
- reload = false;
- std::cout << "reloading configuration..." << std::endl;
- init(session);
- std::cout << "configuration reloaded" << std::endl;
- }
-
- lt::alert const* a = session.wait_for_alert(lt::seconds(10));
- if(nullptr==a) { continue; }
-
- std::vector<lt::alert*> alerts;
- session.pop_alerts(&alerts);
-
- for (lt::alert const* a : alerts) {
- std::cout << "[" << a->type() << "]: " << a->message() << std::endl;
- if (lt::alert_cast<lt::torrent_error_alert>(a)) { break; }
- }
- }
- std::cout << "error, shutting down..." << std::endl;
-}
-
-void signal_handler(int signo) {
- reload = true;
-}
+++ /dev/null
-#include<seed.hpp>
-
-void seed::remove() {
- std::cerr << "not implemented\n";
-}
+++ /dev/null
-#include<torrent.hpp>
-
-void torrent::add(fs::path p) {
- lt::add_files(m_fs,p,file_filter);
-}
-
-void torrent::add_link_to_meta(std::string link, std::string magnet_uri) {
- std::fstream meta_file;
-
- fs::path meta_filepath = m_path.parent_path();
- meta_filepath /= "." + m_path.filename().string() + ".meta";
-
- bool hasLink = false;
- bool hasGuid = false;
-
- meta_file.open(meta_filepath.string(), std::ios_base::in);
- if(meta_file.is_open()) {
- std::string line, searchLink, searchGuid;
- searchLink = "link=" + link;
- searchGuid = "guid=" + magnet_uri;
- while(getline(meta_file,line)) {
- if(line==searchLink) { hasLink = true; }
- if(line==searchGuid) { hasGuid = true; }
- }
-
- meta_file.close();
- }
-
- meta_file.open(meta_filepath.string(), std::ios_base::out | std::ios_base::app);
- if(!meta_file.is_open()) {
- std::cerr << "something went wrong" << std::endl;
- }
-
- if(!hasLink) {
- meta_file << "link=" << link << "\n";
- }
-
- if(!hasGuid) {
- meta_file << "guid=" << magnet_uri << "\n";
- }
-
- meta_file.close();
-}
-
-bool torrent::file_filter(std::string const& f) {
- if(f.empty()) { return false; }
-
- char const *first = f.c_str();
- char const *sep = strrchr(first, '/');
-
- if(nullptr==sep) {
- sep = first;
- } else {
- sep++;
- }
-
- if(sep[0]=='.') {
- std::cerr << "skipped: " << f << std::endl;
- return false;
- }
-
- std::cerr << "added: " << f << std::endl;
- return true;
-}
-
-void torrent::save(lt::session &session) {
- fs::path temp_path = PREFIX;
- temp_path /= ".tmp.torrent";
- std::cerr << "temp path: " << temp_path << std::endl;
-
- fs::path parent_path = m_path.parent_path();
- lt::create_torrent t(m_fs);
- lt::set_piece_hashes(t, parent_path);
-
- std::ofstream out(temp_path, std::ios_base::binary);
- lt::bencode(std::ostream_iterator<char>(out), t.generate());
- out.close();
-
- lt::torrent_info info(temp_path);
-
- std::stringstream filename;
- filename << info.info_hash() << ".torrent";
- fs::path out_path(TORRENTDIR);
- out_path /= filename.str();
-
- add_link_to_meta(filename.str(),lt::make_magnet_uri(info));
-
- if(!fs::exists(out_path)) { rename(temp_path,out_path); }
- remove(temp_path);
-
- seed sd(session,out_path.string(),parent_path.string());
-}
--- /dev/null
+#include<default.h>
+
+int defaults() {
+ opt_set_log_level(LOG_LEVEL_DEFAULT);
+
+ return 1;
+}
--- /dev/null
+#include<log.h>
+
+int verbose_flag = LOG_LEVEL_DEFAULT;
+
+void log_message(enum log_level level, FILE *out_stream, const char *format,...) {
+ if(level<=verbose_flag) {
+ va_list args;
+ va_start(args,format);
+ vfprintf(out_stream,format,args);
+ va_end(args);
+ }
+}
--- /dev/null
+#include<main.h>
+
+static struct option long_options[] = {
+ {"daemon", no_argument, 0, 'd'},
+ {"help", no_argument, 0, 'h'},
+ {"quiet", no_argument, &verbose_flag, LOG_LEVEL_SILENT},
+ {"verbose", no_argument, &verbose_flag, LOG_LEVEL_VERBOSE},
+ {0,0,0,0}
+};
+
+int main(int argc, char **argv) {
+ int c;
+
+ if(defaults()<0) { return EXIT_FAILURE; }
+
+ while(1) {
+ int option_index = 0;
+
+ if((c = getopt_long(argc,argv,"dhqv",long_options,&option_index))==-1) { break; }
+
+ switch(c) {
+ case 'd':
+ log_err("not implemented\n");
+ return EXIT_FAILURE;
+ break;
+ case 'h':
+ usage();
+ return EXIT_FAILURE;
+ case 'q':
+ opt_set_log_level(LOG_LEVEL_SILENT);
+ break;
+ case 'v':
+ opt_set_log_level(LOG_LEVEL_VERBOSE);
+ break;
+ case '?':
+ default:
+ return EXIT_FAILURE;
+ }
+ }
+
+ log_msg("here?\n");
+
+ return EXIT_FAILURE;
+}
--- /dev/null
+#include<opt.h>
+
+void opt_set_log_level(enum log_level level) {
+ verbose_flag = level;
+}