Hello community,

here is the log from the commit of package blogc for openSUSE:Factory checked 
in at 2019-05-03 22:47:32
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/blogc (Old)
 and      /work/SRC/openSUSE:Factory/.blogc.new.5148 (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "blogc"

Fri May  3 22:47:32 2019 rev:15 rq:700320 version:0.17.0

Changes:
--------
--- /work/SRC/openSUSE:Factory/blogc/blogc.changes      2019-04-23 
14:37:21.057523343 +0200
+++ /work/SRC/openSUSE:Factory/.blogc.new.5148/blogc.changes    2019-05-03 
22:47:33.655925465 +0200
@@ -1,0 +2,12 @@
+Fri May  3 06:55:59 UTC 2019 - [email protected]
+
+- Update to 0.17.0:
+  * blogc(1) now supports sorting source files by DATE variable,
+    by providing the FILTER_SORT=1 global variable.
+       The source files are sorted in descending order by default, and
+       can be reversed by providing the FILTER_REVERSE=1 global variable.
+       See blogc-pagination(7) for details.
+  * blogc-make(1) got a new setting to support sorting posts:
+       posts_sort. See blogcfile(5) for details.
+
+-------------------------------------------------------------------

Old:
----
  blogc-0.16.1.tar.xz

New:
----
  blogc-0.17.0.tar.xz

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ blogc.spec ++++++
--- /var/tmp/diff_new_pack.7ypLvY/_old  2019-05-03 22:47:34.179926668 +0200
+++ /var/tmp/diff_new_pack.7ypLvY/_new  2019-05-03 22:47:34.179926668 +0200
@@ -17,7 +17,7 @@
 
 
 Name:           blogc
-Version:        0.16.1
+Version:        0.17.0
 Release:        0
 Summary:        Blog compiler
 License:        BSD-3-Clause

++++++ blogc-0.16.1.tar.xz -> blogc-0.17.0.tar.xz ++++++
++++ 1632 lines of diff (skipped)
++++    retrying with extended exclude list
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/.tarball-version new/blogc-0.17.0/.tarball-version
--- old/blogc-0.16.1/.tarball-version   2019-04-21 20:03:18.000000000 +0200
+++ new/blogc-0.17.0/.tarball-version   2019-05-02 22:19:18.000000000 +0200
@@ -1 +1 @@
-0.16.1
+0.17.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/.version new/blogc-0.17.0/.version
--- old/blogc-0.16.1/.version   2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/.version   2019-05-02 22:19:18.000000000 +0200
@@ -1 +1 @@
-0.16.1
+0.17.0
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/Makefile.am new/blogc-0.17.0/Makefile.am
--- old/blogc-0.16.1/Makefile.am        2019-04-21 20:02:43.000000000 +0200
+++ new/blogc-0.17.0/Makefile.am        2019-05-02 22:18:40.000000000 +0200
@@ -69,6 +69,7 @@
        src/common/config-parser.h \
        src/common/error.h \
        src/common/file.h \
+       src/common/sort.h \
        src/common/stdin.h \
        src/common/utf8.h \
        src/common/utils.h \
@@ -151,6 +152,7 @@
        src/common/config-parser.c \
        src/common/error.c \
        src/common/file.c \
+       src/common/sort.c \
        src/common/stdin.c \
        src/common/utf8.c \
        src/common/utils.c \
@@ -472,6 +474,7 @@
        tests/blogc/check_template_parser \
        tests/common/check_config_parser \
        tests/common/check_error \
+       tests/common/check_sort \
        tests/common/check_utf8 \
        tests/common/check_utils \
        $(NULL)
@@ -745,6 +748,23 @@
        $(CMOCKA_LIBS) \
        libblogc_common.la \
        $(NULL)
+
+tests_common_check_sort_SOURCES = \
+       tests/common/check_sort.c \
+       $(NULL)
+
+tests_common_check_sort_CFLAGS = \
+       $(CMOCKA_CFLAGS) \
+       $(NULL)
+
+tests_common_check_sort_LDFLAGS = \
+       -no-install \
+       $(NULL)
+
+tests_common_check_sort_LDADD = \
+       $(CMOCKA_LIBS) \
+       libblogc_common.la \
+       $(NULL)
 
 tests_common_check_utf8_SOURCES = \
        tests/common/check_utf8.c \
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-git-receiver.1 new/blogc-0.17.0/blogc-git-receiver.1
--- old/blogc-0.16.1/blogc-git-receiver.1       2019-04-21 20:03:17.000000000 
+0200
+++ new/blogc-0.17.0/blogc-git-receiver.1       2019-05-02 22:19:18.000000000 
+0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-GIT\-RECEIVER" "1" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-GIT\-RECEIVER" "1" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-git\-receiver\fR \- a simple login shell/git hook to deploy blogc 
websites
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-make.1 new/blogc-0.17.0/blogc-make.1
--- old/blogc-0.16.1/blogc-make.1       2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogc-make.1       2019-05-02 22:19:18.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-MAKE" "1" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-MAKE" "1" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-make\fR \- a simple build tool for blogc
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-pagination.7 new/blogc-0.17.0/blogc-pagination.7
--- old/blogc-0.16.1/blogc-pagination.7 2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogc-pagination.7 2019-05-02 22:19:18.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-PAGINATION" "7" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-PAGINATION" "7" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-pagination\fR \- blogc\'s pagination support
@@ -26,7 +26,11 @@
 .
 .TP
 \fBFILTER_REVERSE\fR
-Any string, if defined, blogc(1) will list files in reverse order\. This is 
always the first filter applied to the files\. All the other filters will get 
the files already in the reverse order, and won\'t care about this\.
+Boolean (1/y/yes/true/on), if set, blogc(1) will list files in reverse order\. 
This filter is combined with \fBFILTER_SORT\fR, and all the other filters will 
get the files already in the reverse order\.
+.
+.TP
+\fBFILTER_SORT\fR
+Boolean (1/y/yes/true/on), if set, blogc(1) will sort files using the 
\fBDATE\fR variable provided in the files, instead of respecting the order of 
the source files provided to blogc(1)\. The files are sorted in descending 
order and combined with \fBFILTER_REVERSE\fR, that will result in the files 
sorted in ascending order\. All the other filters will get the files already 
sorted\.
 .
 .SH "TEMPLATE VARIABLES"
 blogc(1) will export some global blogc\-template(7) variables, that can be 
used to build links for next and previous page\.
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-runserver.1 new/blogc-0.17.0/blogc-runserver.1
--- old/blogc-0.16.1/blogc-runserver.1  2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogc-runserver.1  2019-05-02 22:19:18.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-RUNSERVER" "1" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-RUNSERVER" "1" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-runserver\fR \- a simple HTTP server to test blogc websites
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-source.7 new/blogc-0.17.0/blogc-source.7
--- old/blogc-0.16.1/blogc-source.7     2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogc-source.7     2019-05-02 22:19:17.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-SOURCE" "7" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-SOURCE" "7" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-source\fR \- blogc\'s source file format
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc-template.7 new/blogc-0.17.0/blogc-template.7
--- old/blogc-0.16.1/blogc-template.7   2019-04-21 20:03:16.000000000 +0200
+++ new/blogc-0.17.0/blogc-template.7   2019-05-02 22:19:17.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC\-TEMPLATE" "7" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC\-TEMPLATE" "7" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\-template\fR \- blogc\'s template format
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc.1 new/blogc-0.17.0/blogc.1
--- old/blogc-0.16.1/blogc.1    2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogc.1    2019-05-02 22:19:17.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGC" "1" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGC" "1" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogc\fR \- a blog compiler
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc.spec new/blogc-0.17.0/blogc.spec
--- old/blogc-0.16.1/blogc.spec 2019-04-21 20:03:16.000000000 +0200
+++ new/blogc-0.17.0/blogc.spec 2019-05-02 22:19:16.000000000 +0200
@@ -1,11 +1,11 @@
 Name: blogc
-Version: 0.16.1
+Version: 0.17.0
 Release: 1%{?dist}
 License: BSD
 Group: Applications/Text
 Summary: A blog compiler
 URL: https://blogc.rgm.io/
-Source0: 
https://github.com/blogc/blogc/releases/download/v0.16.1/blogc-0.16.1.tar.xz
+Source0: 
https://github.com/blogc/blogc/releases/download/v0.17.0/blogc-0.17.0.tar.xz
 BuildRequires: gcc, libcmocka-devel, bash, coreutils, diffutils
 %if ! 0%{?el6}
 BuildRequires: git, tar, make
@@ -43,7 +43,7 @@
 blogc-runserver is a simple HTTP server to test blogc websites.
 
 %prep
-%setup -q -n blogc-0.16.1
+%setup -q -n blogc-0.17.0
 
 %build
 %if 0%{?el6}
@@ -88,6 +88,9 @@
 %license LICENSE
 
 %changelog
+* Thu May 2 2019 Rafael G. Martins <[email protected]> 0.17.0-1
+- New release.
+
 * Sun Apr 21 2019 Rafael G. Martins <[email protected]> 0.16.1-1
 - New release.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogc.spec.in new/blogc-0.17.0/blogc.spec.in
--- old/blogc-0.16.1/blogc.spec.in      2019-04-21 20:02:43.000000000 +0200
+++ new/blogc-0.17.0/blogc.spec.in      2019-05-02 22:18:40.000000000 +0200
@@ -88,6 +88,9 @@
 %license LICENSE
 
 %changelog
+* Thu May 2 2019 Rafael G. Martins <[email protected]> 0.17.0-1
+- New release.
+
 * Sun Apr 21 2019 Rafael G. Martins <[email protected]> 0.16.1-1
 - New release.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/blogcfile.5 new/blogc-0.17.0/blogcfile.5
--- old/blogc-0.16.1/blogcfile.5        2019-04-21 20:03:17.000000000 +0200
+++ new/blogc-0.17.0/blogcfile.5        2019-05-02 22:19:18.000000000 +0200
@@ -1,7 +1,7 @@
 .\" generated with Ronn/v0.7.3
 .\" http://github.com/rtomayko/ronn/tree/0.7.3
 .
-.TH "BLOGCFILE" "5" "April 2019" "Rafael G. Martins" "blogc Manual"
+.TH "BLOGCFILE" "5" "May 2019" "Rafael G. Martins" "blogc Manual"
 .
 .SH "NAME"
 \fBblogcfile\fR \- blogc\-make\'s configuration file
@@ -92,6 +92,9 @@
 \fBposts_per_page\fR (default: \fB10\fR): Number of posts per page in the 
pagination pages\. If negative, all the posts are included\. If \fB0\fR, no 
post listing pages are generated\. Also, if negative or \fB0\fR, the 
\fBpagination\fR build rule is disabled\.
 .
 .IP "\(bu" 4
+\fBposts_sort\fR (default: \fBfalse\fR): If true, blogc(1) will sort the posts 
by date, despite the order of the posts in the \fB[posts]\fR section, in 
descending order\. This setting is compatible with \fBhtml_order\fR and 
\fBatom_order\fR settings, to control the order of the posts\.
+.
+.IP "\(bu" 4
 \fBsource_ext\fR (default: \fB\.txt\fR): The extension of the source files\.
 .
 .IP "\(bu" 4
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/man/blogc-pagination.7.ronn 
new/blogc-0.17.0/man/blogc-pagination.7.ronn
--- old/blogc-0.16.1/man/blogc-pagination.7.ronn        2019-04-21 
20:02:43.000000000 +0200
+++ new/blogc-0.17.0/man/blogc-pagination.7.ronn        2019-05-02 
22:18:40.000000000 +0200
@@ -30,9 +30,16 @@
     provided tag, instead of filtering the whole file set.
 
   * `FILTER_REVERSE`:
-    Any string, if defined, blogc(1) will list files in reverse order. This
-    is always the first filter applied to the files. All the other filters will
-    get the files already in the reverse order, and won't care about this.
+    Boolean (1/y/yes/true/on), if set, blogc(1) will list files in reverse 
order.
+    This filter is combined with `FILTER_SORT`, and all the other filters will
+    get the files already in the reverse order.
+
+  * `FILTER_SORT`:
+    Boolean (1/y/yes/true/on), if set, blogc(1) will sort files using the 
`DATE`
+    variable provided in the files, instead of respecting the order of the
+    source files provided to blogc(1). The files are sorted in descending order
+    and combined with `FILTER_REVERSE`, that will result in the files sorted in
+    ascending order. All the other filters will get the files already sorted.
 
 ## TEMPLATE VARIABLES
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/man/blogcfile.5.ronn new/blogc-0.17.0/man/blogcfile.5.ronn
--- old/blogc-0.16.1/man/blogcfile.5.ronn       2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/man/blogcfile.5.ronn       2019-05-02 22:18:40.000000000 
+0200
@@ -115,6 +115,11 @@
     are included. If `0`, no post listing pages are generated. Also, if 
negative or
     `0`, the `pagination` build rule is disabled.
 
+  * `posts_sort` (default: `false`):
+    If true, blogc(1) will sort the posts by date, despite the order of the 
posts
+    in the `[posts]` section, in descending order. This setting is compatible 
with
+    `html_order` and `atom_order` settings, to control the order of the posts.
+
   * `source_ext` (default: `.txt`):
     The extension of the source files.
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc/loader.c new/blogc-0.17.0/src/blogc/loader.c
--- old/blogc-0.16.1/src/blogc/loader.c 2019-04-21 20:02:43.000000000 +0200
+++ new/blogc-0.17.0/src/blogc/loader.c 2019-05-02 22:18:40.000000000 +0200
@@ -12,12 +12,14 @@
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
+#include "datetime-parser.h"
 #include "source-parser.h"
 #include "template-parser.h"
 #include "loader.h"
 #include "../common/error.h"
 #include "../common/file.h"
 #include "../common/utils.h"
+#include "../common/sort.h"
 
 
 char*
@@ -97,26 +99,104 @@
 }
 
 
+static int
+sort_source(const void *a, const void *b)
+{
+    const char *ca = bc_trie_lookup((bc_trie_t*) a, "c");
+    const char *cb = bc_trie_lookup((bc_trie_t*) b, "c");
+
+    if (ca == NULL || cb == NULL) {
+        return 0;  // wat
+    }
+
+    return strcmp(cb, ca);
+}
+
+
+static int
+sort_source_reverse(const void *a, const void *b)
+{
+    return sort_source(b, a);
+}
+
+
 bc_slist_t*
 blogc_source_parse_from_files(bc_trie_t *conf, bc_slist_t *l, bc_error_t **err)
 {
     if (err == NULL || *err != NULL)
         return NULL;
 
-    bool reverse = bc_trie_lookup(conf, "FILTER_REVERSE");
+    bool sort = bc_str_to_bool(bc_trie_lookup(conf, "FILTER_SORT"));
+
     bc_slist_t* sources = NULL;
+    bc_error_t *tmp_err = NULL;
+    size_t with_date = 0;
     for (bc_slist_t *tmp = l; tmp != NULL; tmp = tmp->next) {
-        if (reverse) {
-            sources = bc_slist_prepend(sources, tmp->data);
+        char *f = tmp->data;
+        bc_trie_t *s = blogc_source_parse_from_file(f, &tmp_err);
+        if (s == NULL) {
+            *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
+                "An error occurred while parsing source file: %s\n\n%s",
+                f, tmp_err->msg);
+            bc_error_free(tmp_err);
+            bc_slist_free_full(sources, (bc_free_func_t) bc_trie_free);
+            return NULL;
         }
-        else {
-            sources = bc_slist_append(sources, tmp->data);
+
+        const char *date = bc_trie_lookup(s, "DATE");
+        if (date != NULL) {
+            with_date++;
         }
+
+        if (sort) {
+            if (date == NULL) {
+                *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
+                    "'FILTER_SORT' requires that 'DATE' variable is set for "
+                    "every source file: %s", f);
+                bc_trie_free(s);
+                bc_slist_free_full(sources, (bc_free_func_t) bc_trie_free);
+                return NULL;
+            }
+
+            char *timestamp = blogc_convert_datetime(date, "%s", &tmp_err);
+            if (timestamp == NULL) {
+                *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
+                    "An error occurred while parsing 'DATE' variable: %s"
+                    "\n\n%s", f, tmp_err->msg);
+                bc_error_free(tmp_err);
+                bc_trie_free(s);
+                bc_slist_free_full(sources, (bc_free_func_t) bc_trie_free);
+                return NULL;
+            }
+
+            bc_trie_insert(s, "c", timestamp);
+        }
+
+        sources = bc_slist_append(sources, s);
     }
 
-    bc_error_t *tmp_err = NULL;
-    bc_slist_t *rv = NULL;
-    size_t with_date = 0;
+    if (with_date > 0 && with_date < bc_slist_length(l)) {
+        *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
+            "'DATE' variable provided for at least one source file, but not "
+            "for all source files. It must be provided for all files.");
+        bc_slist_free_full(sources, (bc_free_func_t) bc_trie_free);
+        return NULL;
+    }
+
+    bool reverse = bc_str_to_bool(bc_trie_lookup(conf, "FILTER_REVERSE"));
+
+    if (sort) {
+        sources = bc_slist_sort(sources, reverse ? sort_source_reverse : 
sort_source);
+    }
+    else if (reverse) {
+        bc_slist_t *tmp_sources = NULL;
+        for (bc_slist_t *tmp = sources; tmp != NULL; tmp = tmp->next) {
+            tmp_sources = bc_slist_prepend(tmp_sources, tmp->data);
+        }
+        bc_slist_t *tmp = sources;
+        sources = tmp_sources;
+        bc_slist_free(tmp);
+    }
 
     const char *filter_tag = bc_trie_lookup(conf, "FILTER_TAG");
     const char *filter_page = bc_trie_lookup(conf, "FILTER_PAGE");
@@ -146,19 +226,9 @@
     size_t end = start + per_page;
     size_t counter = 0;
 
+    bc_slist_t *rv = NULL;
     for (bc_slist_t *tmp = sources; tmp != NULL; tmp = tmp->next) {
-        char *f = tmp->data;
-        bc_trie_t *s = blogc_source_parse_from_file(f, &tmp_err);
-        if (s == NULL) {
-            *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
-                "An error occurred while parsing source file: %s\n\n%s",
-                f, tmp_err->msg);
-            bc_error_free(tmp_err);
-            tmp_err = NULL;
-            bc_slist_free_full(rv, (bc_free_func_t) bc_trie_free);
-            rv = NULL;
-            break;
-        }
+        bc_trie_t *s = tmp->data;
         if (filter_tag != NULL) {
             const char *tags_str = bc_trie_lookup(s, "TAGS");
             // if user wants to filter by tag and no tag is provided, skip it
@@ -188,21 +258,11 @@
             }
             counter++;
         }
-        if (bc_trie_lookup(s, "DATE") != NULL)
-            with_date++;
         rv = bc_slist_append(rv, s);
     }
 
     bc_slist_free(sources);
 
-    if (with_date > 0 && with_date < bc_slist_length(rv)) {
-        *err = bc_error_new_printf(BLOGC_ERROR_LOADER,
-            "'DATE' variable provided for at least one source file, but not "
-            "for all source files. It must be provided for all files.\n");
-        bc_slist_free_full(rv, (bc_free_func_t) bc_trie_free);
-        rv = NULL;
-    }
-
     bool first = true;
     for (bc_slist_t *tmp = rv; tmp != NULL; tmp = tmp->next) {
         bc_trie_t *s = tmp->data;
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/ctx.c new/blogc-0.17.0/src/blogc-make/ctx.c
--- old/blogc-0.16.1/src/blogc-make/ctx.c       2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/src/blogc-make/ctx.c       2019-05-02 22:18:40.000000000 
+0200
@@ -172,22 +172,21 @@
     if (settings_file == NULL || err == NULL || *err != NULL)
         return NULL;
 
-    char real_filename[PATH_MAX];
-    if (NULL == realpath(settings_file, real_filename)) {
-        *err = bc_error_new_printf(BLOGC_MAKE_ERROR_SETTINGS,
-            "Failed to resolve settings file (%s): %s", settings_file,
-            strerror(errno));
+    char *abs_filename = bm_abspath(settings_file, err);
+    if (*err != NULL)
         return NULL;
-    }
 
     size_t content_len;
-    char *content = bc_file_get_contents(real_filename, true, &content_len,
+    char *content = bc_file_get_contents(abs_filename, true, &content_len,
         err);
-    if (*err != NULL)
+    if (*err != NULL) {
+        free(abs_filename);
         return NULL;
+    }
 
     bm_settings_t *settings = bm_settings_parse(content, content_len, err);
     if (settings == NULL || *err != NULL) {
+        free(abs_filename);
         free(content);
         return NULL;
     }
@@ -208,6 +207,7 @@
         atom_template = bm_atom_deploy(settings, err);
         atom_template_tmp = true;
         if (*err != NULL) {
+            free(abs_filename);
             bm_settings_free(settings);
             return NULL;
         }
@@ -228,8 +228,9 @@
     }
     rv->settings = settings;
 
-    rv->settings_fctx = bm_filectx_new(rv, real_filename, NULL, NULL);
-    rv->root_dir = bc_strdup(dirname(real_filename));
+    rv->settings_fctx = bm_filectx_new(rv, abs_filename, NULL, NULL);
+    rv->root_dir = bc_strdup(dirname(abs_filename));
+    free(abs_filename);
 
     const char *output_dir = getenv("OUTPUT_DIR");
     rv->short_output_dir = bc_strdup(output_dir != NULL ? output_dir : 
"_build");
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/exec-native.c 
new/blogc-0.17.0/src/blogc-make/exec-native.c
--- old/blogc-0.16.1/src/blogc-make/exec-native.c       2019-04-21 
20:02:43.000000000 +0200
+++ new/blogc-0.17.0/src/blogc-make/exec-native.c       2019-05-02 
22:18:40.000000000 +0200
@@ -45,7 +45,7 @@
             fprintf(stderr, "blogc-make: error: failed to create output "
                 "directory (%s): %s\n", fname, strerror(errno));
             free(fname);
-            exit(2);
+            return 1;
         }
         *tmp = bkp;
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/rules.c new/blogc-0.17.0/src/blogc-make/rules.c
--- old/blogc-0.16.1/src/blogc-make/rules.c     2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/src/blogc-make/rules.c     2019-05-02 22:18:40.000000000 
+0200
@@ -31,10 +31,16 @@
         return;  // something is wrong, let's not add any variable
 
     const char *value = bm_ctx_settings_lookup_str(ctx, variable);
-    if (value != NULL && ((0 == strcmp(value, "ASC")) || (0 == strcmp(value, 
"asc"))))
-        return;  // user explicitly asked for ASC
+    bool asc = 0 == strcasecmp(value, "asc");
+    bool sort = bc_str_to_bool(bm_ctx_settings_lookup(ctx, "posts_sort"));
 
-    bc_trie_insert(variables, "FILTER_REVERSE", bc_strdup("1"));
+    if (sort) {
+        bc_trie_insert(variables, "FILTER_SORT", bc_strdup("1"));
+    }
+
+    if ((sort && asc) || (!sort && !asc)) {
+        bc_trie_insert(variables, "FILTER_REVERSE", bc_strdup("1"));
+    }
 }
 
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/settings.c 
new/blogc-0.17.0/src/blogc-make/settings.c
--- old/blogc-0.16.1/src/blogc-make/settings.c  2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/src/blogc-make/settings.c  2019-05-02 22:18:40.000000000 
+0200
@@ -28,6 +28,7 @@
     {"main_template", "main.tmpl"},
     {"source_ext", ".txt"},
     {"listing_entry", NULL},
+    {"posts_sort", NULL},
 
     // pagination
     {"pagination_prefix", "page"},
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/utils.c new/blogc-0.17.0/src/blogc-make/utils.c
--- old/blogc-0.16.1/src/blogc-make/utils.c     2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/src/blogc-make/utils.c     2019-05-02 22:18:40.000000000 
+0200
@@ -6,10 +6,18 @@
  * See the file LICENSE.
  */
 
+#include <errno.h>
+#include <limits.h>
 #include <stdbool.h>
 #include <string.h>
+#include <unistd.h>
+#include "../common/error.h"
 #include "../common/utils.h"
 
+#ifndef PATH_MAX
+#define PATH_MAX 4096
+#endif
+
 
 char*
 bm_generate_filename(const char *dir, const char *prefix, const char *fname,
@@ -59,3 +67,30 @@
 
     return bc_string_free(rv, false);
 }
+
+
+char*
+bm_abspath(const char *path, bc_error_t **err)
+{
+    if (err == NULL || *err != NULL)
+        return NULL;
+
+    if (path[0] == '/') {
+        return bc_strdup(path);
+    }
+
+    char cwd[PATH_MAX];
+    if (NULL == getcwd(cwd, sizeof(cwd))) {
+        *err = bc_error_new_printf(BLOGC_MAKE_ERROR_UTILS,
+            "Failed to detect absolute path (%s): %s", path, strerror(errno));
+        return NULL;
+    }
+
+    if (cwd[0] != '/') {
+        *err = bc_error_new_printf(BLOGC_MAKE_ERROR_UTILS,
+            "Failed to get current working directory: %s", cwd);
+        return NULL;
+    }
+
+    return bc_strdup_printf("%s/%s", cwd, path);
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/blogc-make/utils.h new/blogc-0.17.0/src/blogc-make/utils.h
--- old/blogc-0.16.1/src/blogc-make/utils.h     2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/src/blogc-make/utils.h     2019-05-02 22:18:40.000000000 
+0200
@@ -9,7 +9,10 @@
 #ifndef _MAKE_UTILS_H
 #define _MAKE_UTILS_H
 
+#include "../common/error.h"
+
 char* bm_generate_filename(const char *dir, const char *prefix, const char 
*fname,
     const char *ext);
+char* bm_abspath(const char *path, bc_error_t **err);
 
 #endif /* _MAKE_UTILS_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/common/error.c new/blogc-0.17.0/src/common/error.c
--- old/blogc-0.16.1/src/common/error.c 2019-04-21 20:02:43.000000000 +0200
+++ new/blogc-0.17.0/src/common/error.c 2019-05-02 22:18:40.000000000 +0200
@@ -136,6 +136,12 @@
         case BLOGC_MAKE_ERROR_EXEC:
             fprintf(stderr, "error: exec: %s\n", err->msg);
             break;
+        case BLOGC_MAKE_ERROR_ATOM:
+            fprintf(stderr, "error: atom: %s\n", err->msg);
+            break;
+        case BLOGC_MAKE_ERROR_UTILS:
+            fprintf(stderr, "error: utils: %s\n", err->msg);
+            break;
         default:
             fprintf(stderr, "error: %s\n", err->msg);
     }
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/common/error.h new/blogc-0.17.0/src/common/error.h
--- old/blogc-0.16.1/src/common/error.h 2019-04-21 20:02:43.000000000 +0200
+++ new/blogc-0.17.0/src/common/error.h 2019-05-02 22:18:40.000000000 +0200
@@ -28,6 +28,7 @@
     BLOGC_MAKE_ERROR_SETTINGS = 300,
     BLOGC_MAKE_ERROR_EXEC,
     BLOGC_MAKE_ERROR_ATOM,
+    BLOGC_MAKE_ERROR_UTILS,
 
 } bc_error_type_t;
 
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/common/sort.c new/blogc-0.17.0/src/common/sort.c
--- old/blogc-0.16.1/src/common/sort.c  1970-01-01 01:00:00.000000000 +0100
+++ new/blogc-0.17.0/src/common/sort.c  2019-05-02 22:18:40.000000000 +0200
@@ -0,0 +1,44 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2019 Rafael G. Martins <[email protected]>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdbool.h>
+#include "utils.h"
+#include "sort.h"
+
+
+bc_slist_t*
+bc_slist_sort(bc_slist_t *l, bc_sort_func_t cmp)
+{
+    if (l == NULL) {
+        return NULL;
+    }
+
+    bool swapped = false;
+    bc_slist_t *lptr = NULL;
+    bc_slist_t *rptr = NULL;
+
+    do {
+        swapped = false;
+        lptr = l;
+
+        while (lptr->next != rptr) {
+            if (0 < cmp(lptr->data, lptr->next->data)) {
+                void *tmp = lptr->data;
+                lptr->data = lptr->next->data;
+                lptr->next->data = tmp;
+                swapped = true;
+            }
+
+            lptr = lptr->next;
+        }
+
+        rptr = lptr;
+    } while(swapped);
+
+    return l;
+}
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/src/common/sort.h new/blogc-0.17.0/src/common/sort.h
--- old/blogc-0.16.1/src/common/sort.h  1970-01-01 01:00:00.000000000 +0100
+++ new/blogc-0.17.0/src/common/sort.h  2019-05-02 22:18:40.000000000 +0200
@@ -0,0 +1,18 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2019 Rafael G. Martins <[email protected]>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#ifndef _SORT_H
+#define _SORT_H
+
+#include "utils.h"
+
+typedef int (*bc_sort_func_t) (const void *a, const void *b);
+
+bc_slist_t* bc_slist_sort(bc_slist_t *l, bc_sort_func_t cmp);
+
+#endif /* _SORT_H */
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/tests/blogc/check_loader.c 
new/blogc-0.17.0/tests/blogc/check_loader.c
--- old/blogc-0.16.1/tests/blogc/check_loader.c 2019-04-21 20:02:43.000000000 
+0200
+++ new/blogc-0.17.0/tests/blogc/check_loader.c 2019-05-02 22:18:40.000000000 
+0200
@@ -169,21 +169,52 @@
 
 
 static void
-test_source_parse_from_files_filter_reverse(void **state)
+test_source_parse_from_files_filter_sort(void **state)
 {
-    will_return(__wrap_bc_file_get_contents, "bola3.txt");
+    will_return(__wrap_bc_file_get_contents, "bola1.txt");
     will_return(__wrap_bc_file_get_contents, bc_strdup(
-        "ASD: 789\n"
-        "DATE: 2003-02-03 04:05:06\n"
+        "ASD: 123\n"
+        "DATE: 2001-02-02 04:05:06\n"
         "--------\n"
         "bola"));
     will_return(__wrap_bc_file_get_contents, "bola2.txt");
     will_return(__wrap_bc_file_get_contents, bc_strdup(
         "ASD: 456\n"
-        "DATE: 2002-02-03 04:05:06\n"
-        "TAGS: bola, chunda\n"
+        "DATE: 2001-02-01 04:05:06\n"
         "--------\n"
         "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola3.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 789\n"
+        "DATE: 2001-02-03 04:05:06\n"
+        "--------\n"
+        "bola"));
+    bc_error_t *err = NULL;
+    bc_slist_t *s = NULL;
+    s = bc_slist_append(s, bc_strdup("bola1.txt"));
+    s = bc_slist_append(s, bc_strdup("bola2.txt"));
+    s = bc_slist_append(s, bc_strdup("bola3.txt"));
+    bc_trie_t *c = bc_trie_new(free);
+    bc_trie_insert(c, "FILTER_SORT", bc_strdup("1"));
+    bc_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+    assert_null(err);
+    assert_non_null(t);
+    assert_int_equal(bc_slist_length(t), 3);  // it is enough, no need to look 
at the items
+    assert_int_equal(bc_trie_size(c), 5);
+    assert_string_equal(bc_trie_lookup(c, "FILTER_SORT"), "1");
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_FIRST"), "bola3");
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_LAST"), "bola2");
+    assert_string_equal(bc_trie_lookup(c, "DATE_FIRST"), "2001-02-03 
04:05:06");
+    assert_string_equal(bc_trie_lookup(c, "DATE_LAST"), "2001-02-01 04:05:06");
+    bc_trie_free(c);
+    bc_slist_free_full(s, free);
+    bc_slist_free_full(t, (bc_free_func_t) bc_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_reverse(void **state)
+{
     will_return(__wrap_bc_file_get_contents, "bola1.txt");
     will_return(__wrap_bc_file_get_contents, bc_strdup(
         "ASD: 123\n"
@@ -191,13 +222,26 @@
         "TAGS: chunda\n"
         "--------\n"
         "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola2.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 456\n"
+        "DATE: 2002-02-03 04:05:06\n"
+        "TAGS: bola, chunda\n"
+        "--------\n"
+        "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola3.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 789\n"
+        "DATE: 2003-02-03 04:05:06\n"
+        "--------\n"
+        "bola"));
     bc_error_t *err = NULL;
     bc_slist_t *s = NULL;
     s = bc_slist_append(s, bc_strdup("bola1.txt"));
     s = bc_slist_append(s, bc_strdup("bola2.txt"));
     s = bc_slist_append(s, bc_strdup("bola3.txt"));
     bc_trie_t *c = bc_trie_new(free);
-    bc_trie_insert(c, "FILTER_REVERSE", bc_strdup(""));
+    bc_trie_insert(c, "FILTER_REVERSE", bc_strdup("1"));
     bc_slist_t *t = blogc_source_parse_from_files(c, s, &err);
     assert_null(err);
     assert_non_null(t);
@@ -207,7 +251,53 @@
     assert_string_equal(bc_trie_lookup(c, "FILENAME_LAST"), "bola1");
     assert_string_equal(bc_trie_lookup(c, "DATE_FIRST"), "2003-02-03 
04:05:06");
     assert_string_equal(bc_trie_lookup(c, "DATE_LAST"), "2001-02-03 04:05:06");
-    assert_string_equal(bc_trie_lookup(c, "FILTER_REVERSE"), "");
+    assert_string_equal(bc_trie_lookup(c, "FILTER_REVERSE"), "1");
+    bc_trie_free(c);
+    bc_slist_free_full(s, free);
+    bc_slist_free_full(t, (bc_free_func_t) bc_trie_free);
+}
+
+
+static void
+test_source_parse_from_files_filter_sort_reverse(void **state)
+{
+    will_return(__wrap_bc_file_get_contents, "bola1.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 123\n"
+        "DATE: 2001-02-02 04:05:06\n"
+        "--------\n"
+        "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola2.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 456\n"
+        "DATE: 2001-02-01 04:05:06\n"
+        "--------\n"
+        "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola3.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 789\n"
+        "DATE: 2001-02-03 04:05:06\n"
+        "--------\n"
+        "bola"));
+    bc_error_t *err = NULL;
+    bc_slist_t *s = NULL;
+    s = bc_slist_append(s, bc_strdup("bola1.txt"));
+    s = bc_slist_append(s, bc_strdup("bola2.txt"));
+    s = bc_slist_append(s, bc_strdup("bola3.txt"));
+    bc_trie_t *c = bc_trie_new(free);
+    bc_trie_insert(c, "FILTER_SORT", bc_strdup("1"));
+    bc_trie_insert(c, "FILTER_REVERSE", bc_strdup("1"));
+    bc_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+    assert_null(err);
+    assert_non_null(t);
+    assert_int_equal(bc_slist_length(t), 3);  // it is enough, no need to look 
at the items
+    assert_int_equal(bc_trie_size(c), 6);
+    assert_string_equal(bc_trie_lookup(c, "FILTER_SORT"), "1");
+    assert_string_equal(bc_trie_lookup(c, "FILTER_REVERSE"), "1");
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_FIRST"), "bola2");
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_LAST"), "bola3");
+    assert_string_equal(bc_trie_lookup(c, "DATE_FIRST"), "2001-02-01 
04:05:06");
+    assert_string_equal(bc_trie_lookup(c, "DATE_LAST"), "2001-02-03 04:05:06");
     bc_trie_free(c);
     bc_slist_free_full(s, free);
     bc_slist_free_full(t, (bc_free_func_t) bc_trie_free);
@@ -496,7 +586,7 @@
 
 
 static void
-test_source_parse_from_files_filter_by_page_and_tag(void **state)
+test_source_parse_from_files_filter_sort_and_by_page_and_tag(void **state)
 {
     will_return(__wrap_bc_file_get_contents, "bola1.txt");
     will_return(__wrap_bc_file_get_contents, bc_strdup(
@@ -555,6 +645,7 @@
     s = bc_slist_append(s, bc_strdup("bola6.txt"));
     s = bc_slist_append(s, bc_strdup("bola7.txt"));
     bc_trie_t *c = bc_trie_new(free);
+    bc_trie_insert(c, "FILTER_SORT", bc_strdup("1"));
     bc_trie_insert(c, "FILTER_TAG", bc_strdup("chunda"));
     bc_trie_insert(c, "FILTER_PAGE", bc_strdup("2"));
     bc_trie_insert(c, "FILTER_PER_PAGE", bc_strdup("2"));
@@ -562,11 +653,12 @@
     assert_null(err);
     assert_non_null(t);
     assert_int_equal(bc_slist_length(t), 2);  // it is enough, no need to look 
at the items
-    assert_int_equal(bc_trie_size(c), 11);
-    assert_string_equal(bc_trie_lookup(c, "FILENAME_FIRST"), "bola5");
-    assert_string_equal(bc_trie_lookup(c, "FILENAME_LAST"), "bola7");
-    assert_string_equal(bc_trie_lookup(c, "DATE_FIRST"), "2005-02-03 
04:05:06");
-    assert_string_equal(bc_trie_lookup(c, "DATE_LAST"), "2007-02-03 04:05:06");
+    assert_int_equal(bc_trie_size(c), 12);
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_FIRST"), "bola3");
+    assert_string_equal(bc_trie_lookup(c, "FILENAME_LAST"), "bola2");
+    assert_string_equal(bc_trie_lookup(c, "DATE_FIRST"), "2003-02-03 
04:05:06");
+    assert_string_equal(bc_trie_lookup(c, "DATE_LAST"), "2002-02-03 04:05:06");
+    assert_string_equal(bc_trie_lookup(c, "FILTER_SORT"), "1");
     assert_string_equal(bc_trie_lookup(c, "FILTER_TAG"), "chunda");
     assert_string_equal(bc_trie_lookup(c, "FILTER_PAGE"), "2");
     assert_string_equal(bc_trie_lookup(c, "FILTER_PER_PAGE"), "2");
@@ -755,7 +847,7 @@
     assert_int_equal(err->type, BLOGC_ERROR_LOADER);
     assert_string_equal(err->msg,
         "'DATE' variable provided for at least one source file, but not for "
-        "all source files. It must be provided for all files.\n");
+        "all source files. It must be provided for all files.");
     bc_error_free(err);
     assert_int_equal(bc_trie_size(c), 0);
     bc_trie_free(c);
@@ -764,6 +856,73 @@
 
 
 static void
+test_source_parse_from_files_filter_sort_without_all_dates(void **state)
+{
+    will_return(__wrap_bc_file_get_contents, "bola1.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 123\n"
+        "DATE: 2002-02-03 04:05:06\n"
+        "--------\n"
+        "bola"));
+    will_return(__wrap_bc_file_get_contents, "bola2.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 456\n"
+        "--------\n"
+        "bola"));
+    bc_error_t *err = NULL;
+    bc_slist_t *s = NULL;
+    s = bc_slist_append(s, bc_strdup("bola1.txt"));
+    s = bc_slist_append(s, bc_strdup("bola2.txt"));
+    s = bc_slist_append(s, bc_strdup("bola3.txt"));
+    bc_trie_t *c = bc_trie_new(free);
+    bc_trie_insert(c, "FILTER_SORT", bc_strdup("1"));
+    bc_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+    assert_null(t);
+    assert_non_null(err);
+    assert_int_equal(err->type, BLOGC_ERROR_LOADER);
+    assert_string_equal(err->msg,
+        "'FILTER_SORT' requires that 'DATE' variable is set for every source "
+        "file: bola2.txt");
+    bc_error_free(err);
+    assert_int_equal(bc_trie_size(c), 1);
+    assert_string_equal(bc_trie_lookup(c, "FILTER_SORT"), "1");
+    bc_trie_free(c);
+    bc_slist_free_full(s, free);
+}
+
+
+static void
+test_source_parse_from_files_filter_sort_with_wrong_date(void **state)
+{
+    will_return(__wrap_bc_file_get_contents, "bola1.txt");
+    will_return(__wrap_bc_file_get_contents, bc_strdup(
+        "ASD: 123\n"
+        "DATE: 2002-02-03 04:05:ab\n"
+        "--------\n"
+        "bola"));
+    bc_error_t *err = NULL;
+    bc_slist_t *s = NULL;
+    s = bc_slist_append(s, bc_strdup("bola1.txt"));
+    s = bc_slist_append(s, bc_strdup("bola2.txt"));
+    s = bc_slist_append(s, bc_strdup("bola3.txt"));
+    bc_trie_t *c = bc_trie_new(free);
+    bc_trie_insert(c, "FILTER_SORT", bc_strdup("1"));
+    bc_slist_t *t = blogc_source_parse_from_files(c, s, &err);
+    assert_null(t);
+    assert_non_null(err);
+    assert_int_equal(err->type, BLOGC_ERROR_LOADER);
+    assert_string_equal(err->msg,
+        "An error occurred while parsing 'DATE' variable: bola1.txt\n\nInvalid 
"
+        "first digit of seconds. Found 'a', must be integer >= 0 and <= 6.");
+    bc_error_free(err);
+    assert_int_equal(bc_trie_size(c), 1);
+    assert_string_equal(bc_trie_lookup(c, "FILTER_SORT"), "1");
+    bc_trie_free(c);
+    bc_slist_free_full(s, free);
+}
+
+
+static void
 test_source_parse_from_files_null(void **state)
 {
     bc_error_t *err = NULL;
@@ -790,15 +949,19 @@
         unit_test(test_source_parse_from_file),
         unit_test(test_source_parse_from_file_null),
         unit_test(test_source_parse_from_files),
+        unit_test(test_source_parse_from_files_filter_sort),
         unit_test(test_source_parse_from_files_filter_reverse),
+        unit_test(test_source_parse_from_files_filter_sort_reverse),
         unit_test(test_source_parse_from_files_filter_by_tag),
         unit_test(test_source_parse_from_files_filter_by_page),
         unit_test(test_source_parse_from_files_filter_by_page2),
         unit_test(test_source_parse_from_files_filter_by_page3),
-        unit_test(test_source_parse_from_files_filter_by_page_and_tag),
+        
unit_test(test_source_parse_from_files_filter_sort_and_by_page_and_tag),
         unit_test(test_source_parse_from_files_filter_by_page_invalid),
         unit_test(test_source_parse_from_files_filter_by_page_invalid2),
         unit_test(test_source_parse_from_files_without_all_dates),
+        unit_test(test_source_parse_from_files_filter_sort_without_all_dates),
+        unit_test(test_source_parse_from_files_filter_sort_with_wrong_date),
         unit_test(test_source_parse_from_files_null),
     };
     return run_tests(tests);
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/tests/blogc-make/check_blogc_make.sh.in 
new/blogc-0.17.0/tests/blogc-make/check_blogc_make.sh.in
--- old/blogc-0.16.1/tests/blogc-make/check_blogc_make.sh.in    2019-04-21 
20:02:43.000000000 +0200
+++ new/blogc-0.17.0/tests/blogc-make/check_blogc_make.sh.in    2019-05-02 
22:18:40.000000000 +0200
@@ -755,6 +755,226 @@
 rm -rf "${TEMP}/proj/_build"
 
 
+### default settings with some posts, order asc, posts_sort
+
+cat > "${TEMP}/proj/blogcfile" <<EOF
+[global]
+AUTHOR_NAME = Lol
+AUTHOR_EMAIL = [email protected]
+SITE_TITLE = Lol's Website
+SITE_TAGLINE = WAT?!
+BASE_DOMAIN = http://example.org
+
+[settings]
+html_order = asc
+atom_order = asc
+posts_sort = yes
+
+[posts]
+foo
+bar
+EOF
+
+${TESTS_ENVIRONMENT} @abs_top_builddir@/blogc-make -f "${TEMP}/proj/blogcfile" 
2>&1 | tee "${TEMP}/output.txt"
+grep "_build/index\\.html" "${TEMP}/output.txt"
+grep "_build/atom\\.xml" "${TEMP}/output.txt"
+grep "_build/page/1/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/foo/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/bar/index\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+cat > "${TEMP}/expected-index.html" <<EOF
+
+Listing: Bar - Sep 01, 2016, 12:00 AM GMT
+
+Listing: Foo - Oct 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/index.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_build/page/1/index.html" "${TEMP}/expected-index.html"
+
+cat > "${TEMP}/expected-atom.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom";>
+  <title type="text">Lol's Website</title>
+  <id>http://example.org/atom.xml</id>
+  <updated>2016-09-01T00:00:00Z</updated>
+  <link href="http://example.org/"; />
+  <link href="http://example.org/atom.xml"; rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>[email protected]</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Bar</title>
+    <id>http://example.org/post/bar/index.html</id>
+    <updated>2016-09-01T00:00:00Z</updated>
+    <published>2016-09-01T00:00:00Z</published>
+    <link href="http://example.org/post/bar/index.html"; />
+    <author>
+      <name>Lol</name>
+      <email>[email protected]</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is bar.</p>
+]]></content>
+  </entry>
+  
+  <entry>
+    <title type="text">Foo</title>
+    <id>http://example.org/post/foo/index.html</id>
+    <updated>2016-10-01T00:00:00Z</updated>
+    <published>2016-10-01T00:00:00Z</published>
+    <link href="http://example.org/post/foo/index.html"; />
+    <author>
+      <name>Lol</name>
+      <email>[email protected]</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is foo.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-post-foo.html" <<EOF
+
+
+Foo - Oct 01, 2016, 12:00 AM GMT
+
+<p>This is foo.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/foo/index.html" 
"${TEMP}/expected-post-foo.html"
+
+cat > "${TEMP}/expected-post-bar.html" <<EOF
+
+
+Bar - Sep 01, 2016, 12:00 AM GMT
+
+<p>This is bar.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/bar/index.html" 
"${TEMP}/expected-post-bar.html"
+
+rm -rf "${TEMP}/proj/_build"
+
+
+### default settings with some posts, order desc, posts_sort
+
+cat > "${TEMP}/proj/blogcfile" <<EOF
+[global]
+AUTHOR_NAME = Lol
+AUTHOR_EMAIL = [email protected]
+SITE_TITLE = Lol's Website
+SITE_TAGLINE = WAT?!
+BASE_DOMAIN = http://example.org
+
+[settings]
+posts_sort = yes
+
+[posts]
+foo
+bar
+EOF
+
+${TESTS_ENVIRONMENT} @abs_top_builddir@/blogc-make -f "${TEMP}/proj/blogcfile" 
2>&1 | tee "${TEMP}/output.txt"
+grep "_build/index\\.html" "${TEMP}/output.txt"
+grep "_build/atom\\.xml" "${TEMP}/output.txt"
+grep "_build/page/1/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/foo/index\\.html" "${TEMP}/output.txt"
+grep "_build/post/bar/index\\.html" "${TEMP}/output.txt"
+
+rm "${TEMP}/output.txt"
+
+cat > "${TEMP}/expected-index.html" <<EOF
+
+Listing: Foo - Oct 01, 2016, 12:00 AM GMT
+
+Listing: Bar - Sep 01, 2016, 12:00 AM GMT
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/index.html" "${TEMP}/expected-index.html"
+diff -uN "${TEMP}/proj/_build/page/1/index.html" "${TEMP}/expected-index.html"
+
+cat > "${TEMP}/expected-atom.xml" <<EOF
+<?xml version="1.0" encoding="utf-8"?>
+<feed xmlns="http://www.w3.org/2005/Atom";>
+  <title type="text">Lol's Website</title>
+  <id>http://example.org/atom.xml</id>
+  <updated>2016-10-01T00:00:00Z</updated>
+  <link href="http://example.org/"; />
+  <link href="http://example.org/atom.xml"; rel="self" />
+  <author>
+    <name>Lol</name>
+    <email>[email protected]</email>
+  </author>
+  <subtitle type="text">WAT?!</subtitle>
+  
+  <entry>
+    <title type="text">Foo</title>
+    <id>http://example.org/post/foo/index.html</id>
+    <updated>2016-10-01T00:00:00Z</updated>
+    <published>2016-10-01T00:00:00Z</published>
+    <link href="http://example.org/post/foo/index.html"; />
+    <author>
+      <name>Lol</name>
+      <email>[email protected]</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is foo.</p>
+]]></content>
+  </entry>
+  
+  <entry>
+    <title type="text">Bar</title>
+    <id>http://example.org/post/bar/index.html</id>
+    <updated>2016-09-01T00:00:00Z</updated>
+    <published>2016-09-01T00:00:00Z</published>
+    <link href="http://example.org/post/bar/index.html"; />
+    <author>
+      <name>Lol</name>
+      <email>[email protected]</email>
+    </author>
+    <content type="html"><![CDATA[<p>This is bar.</p>
+]]></content>
+  </entry>
+  
+</feed>
+EOF
+diff -uN "${TEMP}/proj/_build/atom.xml" "${TEMP}/expected-atom.xml"
+
+cat > "${TEMP}/expected-post-foo.html" <<EOF
+
+
+Foo - Oct 01, 2016, 12:00 AM GMT
+
+<p>This is foo.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/foo/index.html" 
"${TEMP}/expected-post-foo.html"
+
+cat > "${TEMP}/expected-post-bar.html" <<EOF
+
+
+Bar - Sep 01, 2016, 12:00 AM GMT
+
+<p>This is bar.</p>
+
+
+EOF
+diff -uN "${TEMP}/proj/_build/post/bar/index.html" 
"${TEMP}/expected-post-bar.html"
+
+rm -rf "${TEMP}/proj/_build"
+
+
 ### default settings with some posts, order asc, listing_entry
 
 cat > "${TEMP}/proj/content/hue.txt" <<EOF
diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' 
'--exclude=.svnignore' --exclude Makefile.in --exclude configure --exclude 
config.guess --exclude '*.pot' --exclude mkinstalldirs --exclude aclocal.m4 
--exclude config.sub --exclude depcomp --exclude install-sh --exclude ltmain.sh 
old/blogc-0.16.1/tests/common/check_sort.c 
new/blogc-0.17.0/tests/common/check_sort.c
--- old/blogc-0.16.1/tests/common/check_sort.c  1970-01-01 01:00:00.000000000 
+0100
+++ new/blogc-0.17.0/tests/common/check_sort.c  2019-05-02 22:18:40.000000000 
+0200
@@ -0,0 +1,147 @@
+/*
+ * blogc: A blog compiler.
+ * Copyright (C) 2014-2019 Rafael G. Martins <[email protected]>
+ *
+ * This program can be distributed under the terms of the BSD License.
+ * See the file LICENSE.
+ */
+
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <stdlib.h>
+#include "../../src/common/utils.h"
+#include "../../src/common/sort.h"
+
+
+static int
+sort_func(void *a, void *b)
+{
+    return strcmp((char*) a, (char*) b);
+}
+
+
+static void
+test_slist_sort_empty(void **state)
+{
+    bc_slist_t *l = NULL;
+    assert_null(bc_slist_sort(l, sort_func));
+}
+
+
+static void
+test_slist_sort_single(void **state)
+{
+    bc_slist_t *l = NULL;
+    l = bc_slist_append(l, bc_strdup("a"));
+
+    l = bc_slist_sort(l, sort_func);
+
+    assert_non_null(l);
+    assert_string_equal(l->data, "a");
+    assert_null(l->next);
+
+    bc_slist_free_full(l, free);
+}
+
+
+static void
+test_slist_sort_sorted(void **state)
+{
+    bc_slist_t *l = NULL;
+    l = bc_slist_append(l, bc_strdup("a"));
+    l = bc_slist_append(l, bc_strdup("b"));
+    l = bc_slist_append(l, bc_strdup("c"));
+
+    l = bc_slist_sort(l, sort_func);
+
+    assert_non_null(l);
+    assert_string_equal(l->data, "a");
+    assert_string_equal(l->next->data, "b");
+    assert_string_equal(l->next->next->data, "c");
+    assert_null(l->next->next->next);
+
+    bc_slist_free_full(l, free);
+}
+
+
+static void
+test_slist_sort_reverse(void **state)
+{
+    bc_slist_t *l = NULL;
+    l = bc_slist_append(l, bc_strdup("d"));
+    l = bc_slist_append(l, bc_strdup("c"));
+    l = bc_slist_append(l, bc_strdup("b"));
+    l = bc_slist_append(l, bc_strdup("a"));
+
+    l = bc_slist_sort(l, sort_func);
+
+    assert_non_null(l);
+    assert_string_equal(l->data, "a");
+    assert_string_equal(l->next->data, "b");
+    assert_string_equal(l->next->next->data, "c");
+    assert_string_equal(l->next->next->next->data, "d");
+    assert_null(l->next->next->next->next);
+
+    bc_slist_free_full(l, free);
+}
+
+
+static void
+test_slist_sort_mixed1(void **state)
+{
+    bc_slist_t *l = NULL;
+    l = bc_slist_append(l, bc_strdup("a"));
+    l = bc_slist_append(l, bc_strdup("d"));
+    l = bc_slist_append(l, bc_strdup("c"));
+    l = bc_slist_append(l, bc_strdup("b"));
+
+    l = bc_slist_sort(l, sort_func);
+
+    assert_non_null(l);
+    assert_string_equal(l->data, "a");
+    assert_string_equal(l->next->data, "b");
+    assert_string_equal(l->next->next->data, "c");
+    assert_string_equal(l->next->next->next->data, "d");
+    assert_null(l->next->next->next->next);
+
+    bc_slist_free_full(l, free);
+}
+
+
+static void
+test_slist_sort_mixed2(void **state)
+{
+    bc_slist_t *l = NULL;
+    l = bc_slist_append(l, bc_strdup("c"));
+    l = bc_slist_append(l, bc_strdup("b"));
+    l = bc_slist_append(l, bc_strdup("a"));
+    l = bc_slist_append(l, bc_strdup("d"));
+
+    l = bc_slist_sort(l, sort_func);
+
+    assert_non_null(l);
+    assert_string_equal(l->data, "a");
+    assert_string_equal(l->next->data, "b");
+    assert_string_equal(l->next->next->data, "c");
+    assert_string_equal(l->next->next->next->data, "d");
+    assert_null(l->next->next->next->next);
+
+    bc_slist_free_full(l, free);
+}
+
+
+int
+main(void)
+{
+    const UnitTest tests[] = {
+        unit_test(test_slist_sort_empty),
+        unit_test(test_slist_sort_single),
+        unit_test(test_slist_sort_sorted),
+        unit_test(test_slist_sort_reverse),
+        unit_test(test_slist_sort_mixed1),
+        unit_test(test_slist_sort_mixed2),
+    };
+    return run_tests(tests);
+}


Reply via email to