[osmium-tool] 02/06: Imported Upstream version 1.3.0

Sebastiaan Couwenberg sebastic at moszumanska.debian.org
Wed Nov 18 22:07:58 UTC 2015


This is an automated email from the git hooks/post-receive script.

sebastic pushed a commit to branch master
in repository osmium-tool.

commit c8e5ea479210ac0a76ac34e447863844e041e0c3
Author: Bas Couwenberg <sebastic at xs4all.nl>
Date:   Wed Nov 18 22:32:43 2015 +0100

    Imported Upstream version 1.3.0
---
 .gitattributes                           |   5 +
 CHANGELOG.md                             |  18 ++-
 CMakeLists.txt                           |   5 +-
 README.md                                |   1 +
 cmake/FindOsmium.cmake                   |  13 +-
 man/osmium-apply-changes.md              |   6 +
 man/osmium-cat.md                        |   6 +
 man/osmium-changeset-filter.md           | 117 ++++++++++++++++
 man/osmium-check-refs.md                 |   2 +
 man/osmium-file-formats.md               |  17 +--
 man/osmium-fileinfo.md                   |   2 +
 man/osmium-getid.md                      |   6 +
 man/osmium-merge-changes.md              |   6 +
 man/osmium-renumber.md                   |   6 +
 man/{osmium-getid.md => osmium-sort.md}  |  27 ++--
 man/osmium-time-filter.md                |   6 +
 man/osmium.md                            |  14 ++
 src/cmd.hpp                              |  13 +-
 src/command_apply_changes.cpp            |  24 ++--
 src/command_cat.cpp                      |  25 ++--
 src/command_changeset_filter.cpp         | 232 +++++++++++++++++++++++++++++++
 src/command_changeset_filter.hpp         |  60 ++++++++
 src/command_check_refs.cpp               |  12 +-
 src/command_fileinfo.cpp                 |   9 +-
 src/command_getid.cpp                    |  45 +++---
 src/command_merge_changes.cpp            |  29 ++--
 src/command_renumber.cpp                 |  30 ++--
 src/command_sort.cpp                     | 122 ++++++++++++++++
 src/command_sort.hpp                     |  48 +++++++
 src/command_time_filter.cpp              |  59 +++++---
 src/io.cpp                               |  41 +++++-
 src/main.cpp                             |   2 +-
 test/changeset-filter/CMakeLists.txt     |  70 ++++++++++
 test/changeset-filter/input-open.osm     |   7 +
 test/changeset-filter/input1.osm         |  10 ++
 test/changeset-filter/output-empty.osm   |   3 +
 test/changeset-filter/output-open.osm    |   7 +
 test/changeset-filter/output1-all.osm    |  10 ++
 test/changeset-filter/output1-first.osm  |   6 +
 test/changeset-filter/output1-second.osm |   7 +
 test/sort/CMakeLists.txt                 |  26 ++++
 test/sort/input-bounds1.osm              |  16 +++
 test/sort/input-bounds2.osm              |  11 ++
 test/sort/input-change.osc               |  19 +++
 test/sort/input-history1.osm             |  12 ++
 test/sort/input-history2.osm             |   7 +
 test/sort/input-simple1.osm              |  15 ++
 test/sort/input-simple2.osm              |  10 ++
 test/sort/output-bounds.osm              |  23 +++
 test/sort/output-change.osc              |  19 +++
 test/sort/output-history.osm             |  16 +++
 test/sort/output-simple.osm              |  22 +++
 zsh_completion/_osmium                   |  38 ++++-
 53 files changed, 1201 insertions(+), 161 deletions(-)

diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 0000000..c74cd2c
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1,5 @@
+*.osm -crlf
+*.osc -crlf
+*.opl -crlf
+*.osh -crlf
+*-result.txt -crlf
diff --git a/CHANGELOG.md b/CHANGELOG.md
index bbd700d..1e4c774 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -13,6 +13,21 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 ### Fixed
 
 
+## [1.3.0] - 2015-11-17
+
+### Added
+
+- Add new `sort` subcommand for sorting OSM data files, history files,
+  and change files.
+- Add new `changeset-filter` subcommand.
+- New option `--fsync` on all subcommands that write an OSM file. Will call
+  fsync after writing any file.
+
+### Changed
+
+- Uses new libosmium version now (use at least libosmium version 2.5.3).
+
+
 ## [1.2.1] - 2015-08-31
 
 ### Changed
@@ -90,7 +105,8 @@ This project adheres to [Semantic Versioning](http://semver.org/).
 - Minor updates to documentation and build system
 
 
-[unreleased]: https://github.com/osmcode/osmium-tool/compare/v1.2.1...HEAD
+[unreleased]: https://github.com/osmcode/osmium-tool/compare/v1.3.0...HEAD
+[1.3.0]: https://github.com/osmcode/osmium-tool/compare/v1.2.1...v1.3.0
 [1.2.1]: https://github.com/osmcode/osmium-tool/compare/v1.2.0...v1.2.1
 [1.2.0]: https://github.com/osmcode/osmium-tool/compare/v1.1.0...v1.2.0
 [1.1.1]: https://github.com/osmcode/osmium-tool/compare/v1.1.0...v1.1.1
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 175e74e..9a05968 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -26,8 +26,8 @@ set(CMAKE_CONFIGURATION_TYPES "Debug;Release;RelWithDebInfo;MinSizeRel;Dev"
 project(osmium)
 
 set(OSMIUM_VERSION_MAJOR 1)
-set(OSMIUM_VERSION_MINOR 2)
-set(OSMIUM_VERSION_PATCH 1)
+set(OSMIUM_VERSION_MINOR 3)
+set(OSMIUM_VERSION_PATCH 0)
 
 set(OSMIUM_VERSION ${OSMIUM_VERSION_MAJOR}.${OSMIUM_VERSION_MINOR}.${OSMIUM_VERSION_PATCH})
 
@@ -121,6 +121,7 @@ if(PANDOC)
     add_man_page(1 osmium-getid)
     add_man_page(1 osmium-merge-changes)
     add_man_page(1 osmium-renumber)
+    add_man_page(1 osmium-sort)
     add_man_page(1 osmium-time-filter)
     add_man_page(5 osmium-file-formats)
 
diff --git a/README.md b/README.md
index df1e7b8..7128bfd 100644
--- a/README.md
+++ b/README.md
@@ -13,6 +13,7 @@ You need a C++11 compliant compiler. GCC 4.8 and later as well as clang 3.4 and
 later are known to work. You also need the following libraries:
 
     Osmium Library
+        Need at least version 2.5.1
         http://osmcode.org/libosmium
 
     boost-program-options (for parsing command line options)
diff --git a/cmake/FindOsmium.cmake b/cmake/FindOsmium.cmake
index b3a4c95..fba8ffb 100644
--- a/cmake/FindOsmium.cmake
+++ b/cmake/FindOsmium.cmake
@@ -62,6 +62,8 @@ find_path(OSMIUM_INCLUDE_DIR osmium/osm.hpp
         /opt
 )
 
+set(OSMIUM_INCLUDE_DIRS "${OSMIUM_INCLUDE_DIR}")
+
 #----------------------------------------------------------------------
 #
 #  Check for optional components
@@ -251,20 +253,15 @@ endif()
 #  Check that all required libraries are available
 #
 #----------------------------------------------------------------------
-list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+if (OSMIUM_EXTRA_FIND_VARS)
+    list(REMOVE_DUPLICATES OSMIUM_EXTRA_FIND_VARS)
+endif()
 # Handle the QUIETLY and REQUIRED arguments and set OSMIUM_FOUND to TRUE if
 # all listed variables are TRUE.
 include(FindPackageHandleStandardArgs)
 find_package_handle_standard_args(Osmium REQUIRED_VARS OSMIUM_INCLUDE_DIR ${OSMIUM_EXTRA_FIND_VARS})
 unset(OSMIUM_EXTRA_FIND_VARS)
 
-# Copy the results to the output variables.
-if(OSMIUM_FOUND)
-    set(OSMIUM_INCLUDE_DIRS ${OSMIUM_INCLUDE_DIR} ${OSMIUM_INCLUDE_DIRS})
-else()
-    set(OSMIUM_INCLUDE_DIRS "")
-endif()
-
 #----------------------------------------------------------------------
 #
 #  Add compiler flags
diff --git a/man/osmium-apply-changes.md b/man/osmium-apply-changes.md
index 7bf6628..90db8c2 100644
--- a/man/osmium-apply-changes.md
+++ b/man/osmium-apply-changes.md
@@ -51,6 +51,10 @@ so the data has to fit in there!
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -r, --remove-deleted
 :   Remove deleted objects from the output. If this is not set, deleted objects
     will be in the output with the visible flag set to false.
@@ -69,8 +73,10 @@ so the data has to fit in there!
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-cat.md b/man/osmium-cat.md
index 5004f1f..7056a1a 100644
--- a/man/osmium-cat.md
+++ b/man/osmium-cat.md
@@ -43,6 +43,10 @@ can be used to convert OSM files from one format into another.
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 --output-header=OPTION
 :   Add output header option. This option can be given several times. See the
     *libosmium manual* for a list of allowed header options.
@@ -62,8 +66,10 @@ can be used to convert OSM files from one format into another.
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-changeset-filter.md b/man/osmium-changeset-filter.md
new file mode 100644
index 0000000..1ac1be3
--- /dev/null
+++ b/man/osmium-changeset-filter.md
@@ -0,0 +1,117 @@
+
+# NAME
+
+osmium-changeset-filter - filter changesets from OSM changeset file
+
+
+# SYNOPSIS
+
+**osmium changeset-filter** \[*OPTIONS*\] *INPUT-FILE*
+
+
+# DESCRIPTION
+
+Copy the changesets matching all the given criteria to the output. Matching
+criteria are given through command line options.
+
+
+# OPTIONS
+
+-f, --output-format=FORMAT
+:   The format of the output file. Can be used to set the output file format
+    if it can't be autodetected from the output file name.
+    **See osmium-file-formats**(5) or the libosmium manual for details.
+
+-F, --input-format=FORMAT
+:   The format of the input file. Can be used to set the input format if it
+    can't be autodetected from the file names. See **osmium-file-formats**(5)
+    or the libosmium manual for details.
+
+--generator=NAME
+:   The name and version of the program generating the output file. It will be
+    added to the header of the output file. Default is "*osmium/*" and the version
+    of osmium.
+
+-o, --output=FILE
+:   Name of the output file. Default is '-' (*stdout*).
+
+-O, --overwrite
+:   Allow an existing output file to be overwritten. Normally **osmium** will
+    refuse to write over an existing file.
+
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
+--output-header=OPTION
+:   Add output header option. This option can be given several times. See the
+    *libosmium manual* for a list of allowed header options.
+
+-v, --verbose
+:   Set verbose mode. The program will output information about what it is
+    doing to *stderr*.
+
+-d, --with-discussion
+:   Only copy changesets with discussions, ie changesets with at least one
+    comment.
+
+-D, --without-discussion
+:   Only copy changesets without discussions, ie changesets without any
+    comments.
+
+-c, --with-changes
+:   Only copy changesets with changes.
+
+-C, --without-changes
+:   Only copy changesets without changes.
+
+--open
+:   Only copy open changesets.
+
+--closed
+:   Only copy closed changesets.
+
+-u, --user=USER
+:   Only copy changesets by the given user name.
+
+-U, --uid=UID
+:   Only copy changesets by the given user ID.
+
+-a, --after=TIMESTAMP
+:   Only copy changesets closed after the given time.
+    This will always include all open changesets.
+
+-b, --before=TIMESTAMP
+:   Only copy changesets created before the given time.
+
+
+# DIAGNOSTICS
+
+**osmium changeset-filter** exits with exit code
+
+0
+  ~ if everything went alright,
+
+1
+  ~ if there was an error processing the data, or
+
+2
+  ~ if there was a problem with the command line arguments.
+
+
+# EXAMPLES
+
+To see all changesets by user "foo":
+
+    osmium changeset-filter -u foo -f debug changesets.osm.bz2
+
+To create an OPL file containing only open changesets:
+
+    osmium changeset-filter --open -o open-changesets.opl.bz2 changesets.osm.bz2
+
+
+# SEE ALSO
+
+* **osmium**(1), **osmium-file-formats**(5)
+* [Osmium website](http://osmcode.org/osmium)
+
diff --git a/man/osmium-check-refs.md b/man/osmium-check-refs.md
index bf2f529..cf9390d 100644
--- a/man/osmium-check-refs.md
+++ b/man/osmium-check-refs.md
@@ -57,9 +57,11 @@ nodes in order of ID, then ways in order of ID, then relations in order of ID.
 
 0
   ~ if all references are satisfied
+
 1
   ~ if there was an error processing the data or some references were not
     satisfied, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-file-formats.md b/man/osmium-file-formats.md
index a5f99a9..8a8c9d9 100644
--- a/man/osmium-file-formats.md
+++ b/man/osmium-file-formats.md
@@ -11,10 +11,12 @@ Osmium library. These are:
 * The classical XML format in the variants *.osm* (for data files),
   *.osh* (for data files with history) and *.osc* (for change files).
 * The PBF binary format (usually with suffix *.osm.pbf*).
-* The OPL format (usually with suffix *.osm.opl*).
+* The OPL format (usually with suffix *.osm.opl*) (writing only).
+* The O5M/O5C format (usually with suffix *.o5m* or *.o5c*) (reading only).
+* The "debug" format (usually with suffix *.osm.debug*) (writing only).
 
-In addition, XML and OPL files can be compressed using *gzip* or *bzip2*.
-(Add *.gz* or *.bz2* suffixes, respectively.)
+In addition files in all formats except PBF can be compressed using *gzip* or
+*bzip2*. (Add *.gz* or *.bz2* suffixes, respectively.)
 
 # AUTODETECTION
 
@@ -46,14 +48,10 @@ pbf_compression=true/false (*default: true*)
 :   Enable/disable compression in PBF files. Disabling this will make writing
     files a bit faster, but the resulting files are 2 to 3 times bigger.
 
-pbf_add_metadata=true/false (*default: true*)
+add_metadata=true/false (*default: true*)
 :   Enable/disable writing of object metadata such as changeset id, username,
     etc. Disabling this will make files a bit smaller.
 
-pbf_sort_stringtables=true/false (*default: true*)
-:   Specify whether the string tables in the PBF data blocks should be sorted.
-    Writing the PBF files is slightly faster without sorting.
-
 
 # EXAMPLES
 
@@ -61,10 +59,13 @@ Here are some examples:
 
 pbf
 :   PBF format.
+
 osm.bz2
 :   XML format, compressed with bzip2.
+
 osc.gz
 :   OSM change file, compressed with gzip.
+
 osm.gz,xml_change_format=true
 :   OSM change file, compressed with gzip.
 
diff --git a/man/osmium-fileinfo.md b/man/osmium-fileinfo.md
index ae1cf2c..05fc3f1 100644
--- a/man/osmium-fileinfo.md
+++ b/man/osmium-fileinfo.md
@@ -115,8 +115,10 @@ are in the format `(xmin, ymin, xmax, ymax)`.
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-getid.md b/man/osmium-getid.md
index 101ef49..b25d56d 100644
--- a/man/osmium-getid.md
+++ b/man/osmium-getid.md
@@ -43,6 +43,10 @@ Get objects with the given IDs from the input and write them to the output
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -v, --verbose
 :   Set verbose mode. The program will output information about what it is
     doing to *stderr*.
@@ -54,8 +58,10 @@ Get objects with the given IDs from the input and write them to the output
 
 0
   ~ if all IDs were found
+
 1
   ~ if there was an error processing the data or not all IDs were found, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-merge-changes.md b/man/osmium-merge-changes.md
index 833d343..0e329b0 100644
--- a/man/osmium-merge-changes.md
+++ b/man/osmium-merge-changes.md
@@ -47,6 +47,10 @@ in what order the change files are given or in what order they contain the data.
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -s, --simplify
 :   Only write the last version of any object to the output.
 
@@ -61,8 +65,10 @@ in what order the change files are given or in what order they contain the data.
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-renumber.md b/man/osmium-renumber.md
index 9a967fc..48601ca 100644
--- a/man/osmium-renumber.md
+++ b/man/osmium-renumber.md
@@ -65,6 +65,10 @@ IDs.
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -v, --verbose
 :   Set verbose mode. The program will output information about what it is
     doing to *stderr*.
@@ -76,8 +80,10 @@ IDs.
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium-getid.md b/man/osmium-sort.md
similarity index 69%
copy from man/osmium-getid.md
copy to man/osmium-sort.md
index 101ef49..e65c063 100644
--- a/man/osmium-getid.md
+++ b/man/osmium-sort.md
@@ -1,17 +1,22 @@
 
 # NAME
 
-osmium-getid - get objects from OSM file by ID
+osmium-sort - sort OSM files
 
 
 # SYNOPSIS
 
-**osmium getid** \[*OPTIONS*\] *INPUT-FILE* *ID*...
+**osmium sort** \[*OPTIONS*\] *INPUT-FILE*...
 
 
 # DESCRIPTION
 
-Get objects with the given IDs from the input and write them to the output
+Merges the content of all input files given on the command line and sort the
+result. Objects are sorted by type, ID, and version.
+
+This works with normal OSM data files, history files, and change files.
+
+**osmium sort** does its work in main memory, so all data has to fit in there!
 
 
 # OPTIONS
@@ -43,6 +48,10 @@ Get objects with the given IDs from the input and write them to the output
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -v, --verbose
 :   Set verbose mode. The program will output information about what it is
     doing to *stderr*.
@@ -50,21 +59,23 @@ Get objects with the given IDs from the input and write them to the output
 
 # DIAGNOSTICS
 
-**osmium getid** exits with exit code
+**osmium sort** exits with exit code
 
 0
-  ~ if all IDs were found
+  ~ if everything went alright,
+
 1
-  ~ if there was an error processing the data or not all IDs were found, or
+  ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
 
 # EXAMPLES
 
-Output nodes 17 and 1234, way 42, and relation 111 to *stdout* in OPL format:
+Sort *in.osm.bz2* and write out to *sorted.osm.pbf*:
 
-    osmium getid -f opl planet.osm.pbf n1234 w42 n17 r111
+    osmium sort -o sorted.osm.pbf in.osm.bz2
 
 
 # SEE ALSO
diff --git a/man/osmium-time-filter.md b/man/osmium-time-filter.md
index 9c59eb8..33bbf0e 100644
--- a/man/osmium-time-filter.md
+++ b/man/osmium-time-filter.md
@@ -54,6 +54,10 @@ The format for the timestamps is "yyyy-mm-ddThh:mm::ssZ".
 :   Allow an existing output file to be overwritten. Normally **osmium** will
     refuse to write over an existing file.
 
+--fsync
+:   Call fsync after writing the output file to force the OS to flush buffers
+    to disk.
+
 -v, --verbose
 :   Set verbose mode. The program will output information about what it is
     doing to *stderr*.
@@ -65,8 +69,10 @@ The format for the timestamps is "yyyy-mm-ddThh:mm::ssZ".
 
 0
   ~ if everything went alright,
+
 1
   ~ if there was an error processing the data, or
+
 2
   ~ if there was a problem with the command line arguments.
 
diff --git a/man/osmium.md b/man/osmium.md
index e7728b5..a3c9fda 100644
--- a/man/osmium.md
+++ b/man/osmium.md
@@ -29,20 +29,34 @@ Run **osmium help** *COMMAND* to get more information about a command.
 
 apply-changes
 :   apply OSM change file(s) to OSM data file
+
 cat
 :   concatenate OSM files and convert to different formats
+
+changeset-filter
+:   filter changesets from OSM changeset files
+
 check-refs
 :   check referential integrity of OSM file
+
 fileinfo
 :   show information about an OSM file
+
 getid
 :   get objects from OSM file by ID
+
 help
 :   show help about commands
+
 merge-changes
 :   merge several OSM change files into one
+
 renumber
 :   renumber object IDs
+
+sort
+:   sort OSM files
+
 time-filter
 :   filter OSM data by time from a history file
 
diff --git a/src/cmd.hpp b/src/cmd.hpp
index d140a22..f08c238 100644
--- a/src/cmd.hpp
+++ b/src/cmd.hpp
@@ -33,7 +33,7 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 namespace po = boost::program_options;
 
 #include <osmium/io/file.hpp>
-#include <osmium/io/overwrite.hpp>
+#include <osmium/io/writer_options.hpp>
 #include <osmium/util/minmax.hpp>
 #include <osmium/util/verbose_output.hpp>
 
@@ -90,8 +90,10 @@ public:
         }
     }
 
-    void print_arguments() {
+    void print_arguments(const std::string& command) {
         if (m_vout.verbose()) {
+            m_vout << "Started osmium " << command << "\n";
+            m_vout << "Command line options and default settings:\n";
             show_arguments();
         }
     }
@@ -112,6 +114,8 @@ public:
 
     void add_single_input_options(po::options_description& options);
 
+    void show_single_input_arguments(osmium::util::VerboseOutput& vout);
+
     const osmium::io::File& input_file() const {
         return m_input_file;
     }
@@ -132,6 +136,8 @@ public:
 
     void add_multiple_inputs_options(po::options_description& options);
 
+    void show_multiple_inputs_arguments(osmium::util::VerboseOutput& vout);
+
     const std::vector<osmium::io::File>& input_files() const {
         return m_input_files;
     }
@@ -148,6 +154,7 @@ protected:
     std::string m_output_format;
     osmium::io::File m_output_file;
     osmium::io::overwrite m_output_overwrite = osmium::io::overwrite::no;
+    osmium::io::fsync m_fsync = osmium::io::fsync::no;
 
 public:
 
@@ -159,6 +166,8 @@ public:
 
     void add_output_options(po::options_description& options);
 
+    void show_output_arguments(osmium::util::VerboseOutput& vout);
+
     const osmium::io::File& output_file() const {
         return m_output_file;
     }
diff --git a/src/command_apply_changes.cpp b/src/command_apply_changes.cpp
index 4cc3a3d..1f33bb3 100644
--- a/src/command_apply_changes.cpp
+++ b/src/command_apply_changes.cpp
@@ -79,18 +79,13 @@ bool CommandApplyChanges::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandApplyChanges::show_arguments() {
-    m_vout << "Started osmium apply-changes\n";
-
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  generator: " << m_generator << "\n";
     m_vout << "  input data file name: " << m_input_filename << "\n";
     m_vout << "  input change file names: \n";
     for (const auto& fn : m_change_filenames) {
         m_vout << "    " << fn << "\n";
     }
-    m_vout << "  output filename: " << m_output_filename << "\n";
     m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  output format: " << m_output_format << "\n";
+    show_output_arguments(m_vout);
 }
 
 /**
@@ -139,6 +134,7 @@ bool CommandApplyChanges::run() {
             osmium::apply(buffer, objects);
             changes.push_back(std::move(buffer));
         }
+        reader.close();
     }
 
     m_vout << "Opening input file...\n";
@@ -148,8 +144,10 @@ bool CommandApplyChanges::run() {
     header.set("generator", m_generator);
 
     m_vout << "Opening output file...\n";
-    osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
-    osmium::io::OutputIterator<osmium::io::Writer> out(writer);
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
+    auto out = osmium::io::make_output_iterator(writer);
+
+    auto input = osmium::io::make_input_iterator_range<osmium::OSMObject>(reader);
 
     if (m_simplify_change) {
         // If the --simplify option was given we sort with the
@@ -165,8 +163,8 @@ bool CommandApplyChanges::run() {
         m_vout << "Applying changes and writing them to output...\n";
         std::set_union(objects.begin(),
                        objects.end(),
-                       osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> {reader},
-                       osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> {},
+                       input.begin(),
+                       input.end(),
                        output_it,
                        osmium::object_order_type_id_reverse_version());
     } else {
@@ -179,13 +177,13 @@ bool CommandApplyChanges::run() {
         m_vout << "Applying changes and writing them to output...\n";
         std::set_union(objects.begin(),
                        objects.end(),
-                       osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> {reader},
-                       osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> {},
+                       input.begin(),
+                       input.end(),
                        out);
     }
 
-    out.flush();
     writer.close();
+    reader.close();
 
     m_vout << "Done.\n";
 
diff --git a/src/command_cat.cpp b/src/command_cat.cpp
index 514770f..74a87ad 100644
--- a/src/command_cat.cpp
+++ b/src/command_cat.cpp
@@ -81,22 +81,11 @@ bool CommandCat::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandCat::show_arguments() {
-    m_vout << "Started osmium cat\n";
+    show_multiple_inputs_arguments(m_vout);
+    show_output_arguments(m_vout);
 
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  generator: " << m_generator << "\n";
-    m_vout << "  input filenames: \n";
-    for (const auto& fn : m_input_filenames) {
-        m_vout << "    " << fn << "\n";
-    }
-    m_vout << "  output filename: " << m_output_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  output format: " << m_output_format << "\n";
-    m_vout << "  output header: \n";
-    for (const auto& h : m_output_headers) {
-        m_vout << "    " << h << "\n";
-    }
-    m_vout << "  object types:";
+    m_vout << "  other options:\n";
+    m_vout << "    object types:";
     if (m_osm_entity_bits & osmium::osm_entity_bits::node) {
         m_vout << " node";
     }
@@ -125,16 +114,17 @@ bool CommandCat::run() {
         osmium::io::Reader reader(m_input_files[0], m_osm_entity_bits);
         osmium::io::Header header = reader.header();
         setup_header(header);
-        osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
+        osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
 
         while (osmium::memory::Buffer buffer = reader.read()) {
             writer(std::move(buffer));
         }
         writer.close();
+        reader.close();
     } else { // multiple input files
         osmium::io::Header header;
         setup_header(header);
-        osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
+        osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
 
         for (const auto& input_file : m_input_files) {
             m_vout << "Copying input file '" << input_file.filename() << "'\n";
@@ -142,6 +132,7 @@ bool CommandCat::run() {
             while (osmium::memory::Buffer buffer = reader.read()) {
                 writer(std::move(buffer));
             }
+            reader.close();
         }
         writer.close();
     }
diff --git a/src/command_changeset_filter.cpp b/src/command_changeset_filter.cpp
new file mode 100644
index 0000000..952551b
--- /dev/null
+++ b/src/command_changeset_filter.cpp
@@ -0,0 +1,232 @@
+/*
+
+Osmium -- OpenStreetMap data manipulation command line tool
+http://osmcode.org/osmium
+
+Copyright (C) 2013-2015  Jochen Topf <jochen at topf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <stdexcept>
+
+#include <boost/program_options.hpp>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/io/any_output.hpp>
+#include <osmium/io/input_iterator.hpp>
+#include <osmium/io/output_iterator.hpp>
+
+#include "command_changeset_filter.hpp"
+#include "exception.hpp"
+
+bool CommandChangesetFilter::setup(const std::vector<std::string>& arguments) {
+    po::options_description cmdline("Allowed options");
+    cmdline.add_options()
+    ("with-discussion,d", "Changesets with discussions (comments)")
+    ("without-discussion,D", "Changesets without discussions (no comments)")
+    ("with-changes,c", "Changesets with changes")
+    ("without-changes,C", "Changesets without any changes")
+    ("open", "Open changesets")
+    ("closed", "Closed changesets")
+    ("user,u", po::value<std::string>(), "Changesets by given user")
+    ("uid,U", po::value<osmium::user_id_type>(), "Changesets by given user ID")
+    ("after,a", po::value<std::string>(), "Changesets opened after this time")
+    ("before,b", po::value<std::string>(), "Changesets closed before this time")
+    ;
+
+    add_common_options(cmdline);
+    add_single_input_options(cmdline);
+    add_output_options(cmdline);
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+    ("input-filename", po::value<std::string>(), "OSM input file")
+    ;
+
+    po::options_description desc("Allowed options");
+    desc.add(cmdline).add(hidden);
+
+    po::positional_options_description positional;
+    positional.add("input-filename", 1);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(arguments).options(desc).positional(positional).run(), vm);
+    po::notify(vm);
+
+    setup_common(vm);
+    setup_input_file(vm);
+    setup_output_file(vm);
+
+    if (vm.count("with-discussion")) {
+        m_with_discussion = true;
+    }
+
+    if (vm.count("without-discussion")) {
+        m_without_discussion = true;
+    }
+
+    if (vm.count("with-changes")) {
+        m_with_changes = true;
+    }
+
+    if (vm.count("without-changes")) {
+        m_without_changes = true;
+    }
+
+    if (vm.count("open")) {
+        m_open = true;
+    }
+
+    if (vm.count("closed")) {
+        m_closed = true;
+    }
+
+    if (vm.count("uid")) {
+        m_uid = vm["uid"].as<osmium::user_id_type>();
+    }
+
+    if (vm.count("user")) {
+        m_user = vm["user"].as<std::string>();
+    }
+
+    if (vm.count("after")) {
+        auto ts = vm["after"].as<std::string>();
+        try {
+            m_after = osmium::Timestamp(ts);
+        } catch (std::invalid_argument&) {
+            throw argument_error("Wrong format for --after/-a timestamp (use YYYY-MM-DDThh:mm:ssZ).");
+        }
+    }
+
+    if (vm.count("before")) {
+        auto ts = vm["before"].as<std::string>();
+        try {
+            m_before = osmium::Timestamp(ts);
+        } catch (std::invalid_argument&) {
+            throw argument_error("Wrong format for --before/-b timestamp (use YYYY-MM-DDThh:mm:ssZ).");
+        }
+    }
+
+    if (m_with_discussion && m_without_discussion) {
+        throw argument_error("You can not use --with-discussion/-d and --without-discussion/-D together.");
+    }
+
+    if (m_with_changes && m_without_changes) {
+        throw argument_error("You can not use --with-changes/-c and --without-changes/-C together.");
+    }
+
+    if (m_open && m_closed) {
+        throw argument_error("You can not use --open and --closed together.");
+    }
+
+    if (m_after > m_before) {
+        throw argument_error("Timestamp 'after' is after 'before'.");
+    }
+
+    return true;
+}
+
+void CommandChangesetFilter::show_arguments() {
+    show_single_input_arguments(m_vout);
+    show_output_arguments(m_vout);
+    m_vout << "  other options:\n";
+    m_vout << "    changesets must\n";
+    if (m_with_discussion) {
+        m_vout << "      - have a discussion\n";
+    }
+    if (m_without_discussion) {
+        m_vout << "      - not have a discussion\n";
+    }
+    if (m_with_changes) {
+        m_vout << "      - have at least one change\n";
+    }
+    if (m_without_changes) {
+        m_vout << "      - not have any changes\n";
+    }
+    if (m_open) {
+        m_vout << "      - be open\n";
+    }
+    if (m_closed) {
+        m_vout << "      - be closed\n";
+    }
+    if (m_uid != 0) {
+        m_vout << "      - be from uid " << m_uid << "\n";
+    }
+    if (!m_user.empty()) {
+        m_vout << "      - be from user '" << m_user << "'\n";
+    }
+    if (m_after > osmium::start_of_time()) {
+        m_vout << "      - be closed after " << m_after.to_iso() << " or still open\n";
+    }
+    if (m_before < osmium::end_of_time()) {
+        m_vout << "      - be created before " << m_before.to_iso() << "\n";
+    }
+}
+
+bool changeset_after(const osmium::Changeset& changeset, osmium::Timestamp time) {
+    return changeset.open() || changeset.closed_at() >= time;
+}
+
+bool changeset_before(const osmium::Changeset& changeset, osmium::Timestamp time) {
+    return changeset.created_at() <= time;
+}
+
+bool CommandChangesetFilter::run() {
+    m_vout << "Opening input file...\n";
+    osmium::io::Reader reader(m_input_file, osmium::osm_entity_bits::changeset);
+
+    auto input = osmium::io::make_input_iterator_range<osmium::Changeset>(reader);
+
+    osmium::io::Header header = reader.header();
+    header.set("generator", m_generator);
+
+    m_vout << "Opening output file...\n";
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
+    auto out = osmium::io::make_output_iterator(writer);
+
+    m_vout << "Filtering data...\n";
+
+    std::copy_if(input.begin(), input.end(), out,
+        [this](const osmium::Changeset& changeset) {
+            return (!m_with_discussion    || changeset.num_comments() > 0) &&
+                   (!m_without_discussion || changeset.num_comments() == 0) &&
+                   (!m_with_changes       || changeset.num_changes() > 0) &&
+                   (!m_without_changes    || changeset.num_changes() == 0) &&
+                   (!m_open               || changeset.open()) &&
+                   (!m_closed             || changeset.closed()) &&
+                   (m_uid == 0            || changeset.uid() == m_uid) &&
+                   (m_user.empty()        || m_user == changeset.user()) &&
+                   changeset_after(changeset, m_after) &&
+                   changeset_before(changeset, m_before);
+
+    });
+
+    writer.close();
+    reader.close();
+
+    m_vout << "Done.\n";
+
+    return true;
+}
+
+namespace {
+
+    const bool register_changeset_filter_command = CommandFactory::add("changeset-filter", "Filter OSM changesets by different criteria", []() {
+        return new CommandChangesetFilter();
+    });
+
+}
+
diff --git a/src/command_changeset_filter.hpp b/src/command_changeset_filter.hpp
new file mode 100644
index 0000000..9bd5096
--- /dev/null
+++ b/src/command_changeset_filter.hpp
@@ -0,0 +1,60 @@
+#ifndef COMMAND_CHANGESET_FILTER_HPP
+#define COMMAND_CHANGESET_FILTER_HPP
+
+/*
+
+Osmium -- OpenStreetMap data manipulation command line tool
+http://osmcode.org/osmium
+
+Copyright (C) 2013-2015  Jochen Topf <jochen at topf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <string>
+
+#include <osmium/osm/box.hpp>
+#include <osmium/osm/timestamp.hpp>
+#include <osmium/osm/types.hpp>
+
+#include "cmd.hpp"
+
+class CommandChangesetFilter : public Command, public with_single_osm_input, public with_osm_output {
+
+    bool m_with_discussion = false;
+    bool m_without_discussion = false;
+    bool m_with_changes = false;
+    bool m_without_changes = false;
+    bool m_open = false;
+    bool m_closed = false;
+    osmium::user_id_type m_uid = 0;
+    std::string m_user;
+    osmium::Timestamp m_after = osmium::start_of_time();
+    osmium::Timestamp m_before = osmium::end_of_time();
+
+public:
+
+    CommandChangesetFilter() = default;
+
+    bool setup(const std::vector<std::string>& arguments) override final;
+
+    void show_arguments() override final;
+
+    bool run() override final;
+
+}; // class CommandChangesetFilter
+
+
+#endif // COMMAND_CHANGESET_FILTER_HPP
diff --git a/src/command_check_refs.cpp b/src/command_check_refs.cpp
index a610bbc..3705e07 100644
--- a/src/command_check_refs.cpp
+++ b/src/command_check_refs.cpp
@@ -74,13 +74,10 @@ bool CommandCheckRefs::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandCheckRefs::show_arguments() {
-    m_vout << "Started osmium check-refs\n";
-
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  input filename: " << m_input_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  show ids: " << (m_show_ids ? "yes\n" : "no\n");
-    m_vout << "  check relations: " << (m_check_relations ? "yes\n" : "no\n");
+    show_single_input_arguments(m_vout);
+    m_vout << "  other options:\n";
+    m_vout << "    show ids: " << (m_show_ids ? "yes\n" : "no\n");
+    m_vout << "    check relations: " << (m_check_relations ? "yes\n" : "no\n");
 }
 
 class RefCheckHandler : public osmium::handler::Handler {
@@ -254,6 +251,7 @@ bool CommandCheckRefs::run() {
         handler.show_missing_relation_ids();
     }
 
+    reader.close();
     m_vout << "Done.\n";
 
     return !handler.any_errors();
diff --git a/src/command_fileinfo.cpp b/src/command_fileinfo.cpp
index a811cd0..ee0e061 100644
--- a/src/command_fileinfo.cpp
+++ b/src/command_fileinfo.cpp
@@ -571,12 +571,10 @@ bool CommandFileinfo::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandFileinfo::show_arguments() {
-    m_vout << "Started osmium fileinfo\n";
+    show_single_input_arguments(m_vout);
 
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  input filename: " << m_input_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  extended output: " << (m_extended ? "yes\n" : "no\n");
+    m_vout << "  other options:\n";
+    m_vout << "    extended output: " << (m_extended ? "yes\n" : "no\n");
 }
 
 bool CommandFileinfo::run() {
@@ -601,6 +599,7 @@ bool CommandFileinfo::run() {
         output->data(header, info_handler);
     }
 
+    reader.close();
     output->output();
 
     return true;
diff --git a/src/command_getid.cpp b/src/command_getid.cpp
index 3731774..6536363 100644
--- a/src/command_getid.cpp
+++ b/src/command_getid.cpp
@@ -103,26 +103,22 @@ bool CommandGetId::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandGetId::show_arguments() {
-    m_vout << "Started osmium apply-changes\n";
-
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  generator: " << m_generator << "\n";
-    m_vout << "  input data file name: " << m_input_filename << "\n";
-    m_vout << "  output filename: " << m_output_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  output format: " << m_output_format << "\n";
-    m_vout << "  looking for these ids:\n";
-    m_vout << "    nodes:";
+    show_single_input_arguments(m_vout);
+    show_output_arguments(m_vout);
+
+    m_vout << "  other options:\n";
+    m_vout << "    looking for these ids:\n";
+    m_vout << "      nodes:";
     for (osmium::object_id_type id : ids(osmium::item_type::node)) {
         m_vout << " " << id;
     }
     m_vout << "\n";
-    m_vout << "    ways:";
+    m_vout << "      ways:";
     for (osmium::object_id_type id : ids(osmium::item_type::way)) {
         m_vout << " " << id;
     }
     m_vout << "\n";
-    m_vout << "    relations:";
+    m_vout << "      relations:";
     for (osmium::object_id_type id : ids(osmium::item_type::relation)) {
         m_vout << " " << id;
     }
@@ -146,35 +142,36 @@ osmium::osm_entity_bits::type CommandGetId::get_needed_types() const {
 }
 
 bool CommandGetId::run() {
-    m_vout << "Reading input file...\n";
+    m_vout << "Opening input file...\n";
     osmium::io::Reader reader(m_input_file, get_needed_types());
 
+    m_vout << "Opening output file...\n";
     osmium::io::Header header;
     header.set("generator", m_generator);
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
 
-    typedef osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> object_iterator;
+    m_vout << "Reading input file...\n";
+    auto input = osmium::io::make_input_iterator_range<osmium::OSMObject>(reader);
 
-    object_iterator it(reader);
-    object_iterator end;
     osmium::memory::Buffer output_buffer(10240);
 
     size_t num_ids = ids(osmium::item_type::node).size() +
                      ids(osmium::item_type::way).size() +
                      ids(osmium::item_type::relation).size();
 
-    for (; it != end; ++it) {
-        const auto& index = ids(it->type());
-        const auto result = std::equal_range(index.begin(), index.end(), it->id());
-        if (result.first != result.second) {
-            output_buffer.add_item(*it);
+    for (const osmium::OSMObject& object : input) {
+        const auto& index = ids(object.type());
+        if (std::binary_search(index.begin(), index.end(), object.id())) {
+            output_buffer.add_item(object);
             output_buffer.commit();
             --num_ids;
         }
     }
 
     m_vout << "Writing out results...\n";
-    osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
     writer(std::move(output_buffer));
+
+    m_vout << "Closing output file...\n";
     writer.close();
 
     if (num_ids == 0) {
@@ -182,6 +179,10 @@ bool CommandGetId::run() {
     } else {
         m_vout << "Did not find " << num_ids << " objects.\n";
     }
+
+    m_vout << "Closing input file...\n";
+    reader.close();
+
     m_vout << "Done.\n";
 
     return num_ids == 0;
diff --git a/src/command_merge_changes.cpp b/src/command_merge_changes.cpp
index b49e668..43c2bbe 100644
--- a/src/command_merge_changes.cpp
+++ b/src/command_merge_changes.cpp
@@ -69,20 +69,17 @@ bool CommandMergeChanges::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandMergeChanges::show_arguments() {
-    m_vout << "Started osmium merge-changes\n";
-
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  generator: " << m_generator << "\n";
-    m_vout << "  input change file names: \n";
-    for (const auto& fn : m_input_filenames) {
-        m_vout << "    " << fn << "\n";
-    }
-    m_vout << "  output filename: " << m_output_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  output format: " << m_output_format << "\n";
+    show_multiple_inputs_arguments(m_vout);
+    show_output_arguments(m_vout);
 }
 
 bool CommandMergeChanges::run() {
+    m_vout << "Opening output file...\n";
+    osmium::io::Header header;
+    header.set("generator", m_generator);
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
+    auto out = osmium::io::make_output_iterator(writer);
+
     // this will contain all the buffers with the input data
     std::vector<osmium::memory::Buffer> changes;
 
@@ -97,15 +94,9 @@ bool CommandMergeChanges::run() {
             osmium::apply(buffer, objects);
             changes.push_back(std::move(buffer));
         }
+        reader.close();
     }
 
-    osmium::io::Header header;
-    header.set("generator", m_generator);
-
-    m_vout << "Opening output file...\n";
-    osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
-    osmium::io::OutputIterator<osmium::io::Writer> out(writer);
-
     // Now we sort all objects and write them in order into the
     // output_buffer, flushing the output_buffer whenever it is full.
     if (m_simplify_change) {
@@ -125,7 +116,7 @@ bool CommandMergeChanges::run() {
         std::copy(objects.cbegin(), objects.cend(), out);
     }
 
-    out.flush();
+    m_vout << "Closing output file...\n";
     writer.close();
 
     m_vout << "Done.\n";
diff --git a/src/command_renumber.cpp b/src/command_renumber.cpp
index 3eca5d8..fdc8fd8 100644
--- a/src/command_renumber.cpp
+++ b/src/command_renumber.cpp
@@ -80,19 +80,11 @@ bool CommandRenumber::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandRenumber::show_arguments() {
-    m_vout << "Started osmium renumber\n";
-
-    m_vout << "Command line options and default settings:\n";
-    m_vout << "  generator: " << m_generator << "\n";
-    m_vout << "  input filename: " << m_input_filename << "\n";
-    m_vout << "  output filename: " << m_output_filename << "\n";
-    m_vout << "  input format: " << m_input_format << "\n";
-    m_vout << "  output format: " << m_output_format << "\n";
-    m_vout << "  output header: \n";
-    for (const auto& h : m_output_headers) {
-        m_vout << "    " << h << "\n";
-    }
-    m_vout << "  index directory: " << m_index_directory << "\n";
+    show_single_input_arguments(m_vout);
+    show_output_arguments(m_vout);
+
+    m_vout << "  other options:\n";
+    m_vout << "    index directory: " << m_index_directory << "\n";
 }
 
 osmium::object_id_type CommandRenumber::lookup(osmium::item_type type, osmium::object_id_type id) {
@@ -207,19 +199,18 @@ bool CommandRenumber::run() {
     m_vout << "First pass through input file (reading relations)...\n";
     osmium::io::Reader reader_pass1(m_input_file, osmium::osm_entity_bits::relation);
 
+    m_vout << "Opening output file...\n";
     osmium::io::Header header = reader_pass1.header();
     header.set("generator", m_generator);
     header.set("xml_josm_upload", "false");
     for (const auto& h : m_output_headers) {
         header.set(h);
     }
-    osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
-
-    osmium::io::InputIterator<osmium::io::Reader, osmium::Relation> it { reader_pass1 };
-    osmium::io::InputIterator<osmium::io::Reader, osmium::Relation> end {};
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
 
-    for (; it != end; ++it) {
-        lookup(osmium::item_type::relation, it->id());
+    auto input = osmium::io::make_input_iterator_range<osmium::Relation>(reader_pass1);
+    for (const osmium::Relation& relation : input) {
+        lookup(osmium::item_type::relation, relation.id());
     }
 
     reader_pass1.close();
@@ -232,6 +223,7 @@ bool CommandRenumber::run() {
     }
     reader_pass2.close();
 
+    m_vout << "Closing output file...\n";
     writer.close();
 
     if (!m_index_directory.empty()) {
diff --git a/src/command_sort.cpp b/src/command_sort.cpp
new file mode 100644
index 0000000..2e1454a
--- /dev/null
+++ b/src/command_sort.cpp
@@ -0,0 +1,122 @@
+/*
+
+Osmium -- OpenStreetMap data manipulation command line tool
+http://osmcode.org/osmium
+
+Copyright (C) 2013-2015  Jochen Topf <jochen at topf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <boost/function_output_iterator.hpp>
+#include <boost/program_options.hpp>
+
+#include <osmium/io/any_input.hpp>
+#include <osmium/io/any_output.hpp>
+#include <osmium/io/output_iterator.hpp>
+#include <osmium/object_pointer_collection.hpp>
+#include <osmium/osm/object_comparisons.hpp>
+
+#include "command_sort.hpp"
+
+bool CommandSort::setup(const std::vector<std::string>& arguments) {
+    po::options_description cmdline("Allowed options");
+    cmdline.add_options()
+    ;
+
+    add_common_options(cmdline);
+    add_multiple_inputs_options(cmdline);
+    add_output_options(cmdline);
+
+    po::options_description hidden("Hidden options");
+    hidden.add_options()
+    ("input-filenames", po::value<std::vector<std::string>>(), "OSM input files")
+    ;
+
+    po::options_description desc("Allowed options");
+    desc.add(cmdline).add(hidden);
+
+    po::positional_options_description positional;
+    positional.add("input-filenames", -1);
+
+    po::variables_map vm;
+    po::store(po::command_line_parser(arguments).options(desc).positional(positional).run(), vm);
+    po::notify(vm);
+
+    setup_common(vm);
+    setup_input_files(vm);
+    setup_output_file(vm);
+
+    if (vm.count("input-filenames")) {
+        m_filenames = vm["input-filenames"].as<std::vector<std::string>>();
+    }
+
+    return true;
+}
+
+void CommandSort::show_arguments() {
+    show_multiple_inputs_arguments(m_vout);
+    show_output_arguments(m_vout);
+}
+
+bool CommandSort::run() {
+    std::vector<osmium::memory::Buffer> data;
+    osmium::ObjectPointerCollection objects;
+
+    osmium::Box bounding_box;
+
+    m_vout << "Reading contents of input files...\n";
+    for (const std::string& file_name : m_filenames) {
+        osmium::io::Reader reader(file_name, osmium::osm_entity_bits::object);
+        auto header = reader.header();
+        bounding_box.extend(header.joined_boxes());
+        while (osmium::memory::Buffer buffer = reader.read()) {
+            osmium::apply(buffer, objects);
+            data.push_back(std::move(buffer));
+        }
+        reader.close();
+    }
+
+    m_vout << "Opening output file...\n";
+    osmium::io::Header header;
+    if (bounding_box) {
+        header.add_box(bounding_box);
+    }
+    header.set("generator", m_generator);
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
+
+    m_vout << "Sorting data...\n";
+    objects.sort(osmium::object_order_type_id_version());
+
+    m_vout << "Writing out sorted data...\n";
+    auto out = osmium::io::make_output_iterator(writer);
+    std::copy(objects.begin(), objects.end(), out);
+
+    m_vout << "Closing output file...\n";
+    writer.close();
+
+    m_vout << "Done.\n";
+
+    return true;
+}
+
+namespace {
+
+    const bool register_sort_command = CommandFactory::add("sort", "Sort OSM data files", []() {
+        return new CommandSort();
+    });
+
+}
+
diff --git a/src/command_sort.hpp b/src/command_sort.hpp
new file mode 100644
index 0000000..ae07531
--- /dev/null
+++ b/src/command_sort.hpp
@@ -0,0 +1,48 @@
+#ifndef COMMAND_SORT_HPP
+#define COMMAND_SORT_HPP
+
+/*
+
+Osmium -- OpenStreetMap data manipulation command line tool
+http://osmcode.org/osmium
+
+Copyright (C) 2013-2015  Jochen Topf <jochen at topf.org>
+
+This program is free software: you can redistribute it and/or modify
+it under the terms of the GNU General Public License as published by
+the Free Software Foundation, either version 3 of the License, or
+(at your option) any later version.
+
+This program is distributed in the hope that it will be useful,
+but WITHOUT ANY WARRANTY; without even the implied warranty of
+MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+GNU General Public License for more details.
+
+You should have received a copy of the GNU General Public License
+along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+*/
+
+#include <string>
+#include <vector>
+
+#include "cmd.hpp"
+
+class CommandSort : public Command, public with_multiple_osm_inputs, public with_osm_output {
+
+    std::vector<std::string> m_filenames;
+
+public:
+
+    CommandSort() = default;
+
+    bool setup(const std::vector<std::string>& arguments) override final;
+
+    void show_arguments() override final;
+
+    bool run() override final;
+
+}; // class CommandSort
+
+
+#endif // COMMAND_SORT_HPP
diff --git a/src/command_time_filter.cpp b/src/command_time_filter.cpp
index 78cfe5d..3771fb2 100644
--- a/src/command_time_filter.cpp
+++ b/src/command_time_filter.cpp
@@ -20,6 +20,8 @@ along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 */
 
+#include <stdexcept>
+
 #include <boost/program_options.hpp>
 
 #include <osmium/io/any_input.hpp>
@@ -65,17 +67,28 @@ bool CommandTimeFilter::setup(const std::vector<std::string>& arguments) {
     m_to = m_from;
 
     if (vm.count("time-from")) {
-        m_from = osmium::Timestamp(vm["time-from"].as<std::string>().c_str());
+        auto ts = vm["time-from"].as<std::string>();
+        try {
+            m_from = osmium::Timestamp(ts);
+        } catch (std::invalid_argument&) {
+            throw argument_error("Wrong format for (first) timestamp (use YYYY-MM-DDThh:mm:ssZ).");
+        }
         m_to = m_from;
     }
 
     if (vm.count("time-to")) {
-        m_to = osmium::Timestamp(vm["time-to"].as<std::string>().c_str());
-        if (m_to < m_from) {
-            throw argument_error("Second timestamp is before first one.");
+        auto ts = vm["time-to"].as<std::string>();
+        try {
+            m_to = osmium::Timestamp(ts);
+        } catch (std::invalid_argument&) {
+            throw argument_error("Wrong format for second timestamp (use YYYY-MM-DDThh:mm:ssZ).");
         }
     }
 
+    if (m_from > m_to) {
+        throw argument_error("Second timestamp is before first one.");
+    }
+
     if (m_from == m_to) { // point in time
         if (m_output_file.has_multiple_object_versions()) {
             std::cerr << "Warning! You are writing to a file marked as having multiple object versions,\n";
@@ -92,51 +105,51 @@ bool CommandTimeFilter::setup(const std::vector<std::string>& arguments) {
 }
 
 void CommandTimeFilter::show_arguments() {
-    m_vout << "Started osmium time-filter\n";
-    m_vout << "Filtering from time " << m_from.to_iso() << " to " << m_to.to_iso() << "\n";
+    show_single_input_arguments(m_vout);
+    show_output_arguments(m_vout);
+    m_vout << "  other options:\n";
+    m_vout << "    Filtering from time " << m_from.to_iso() << " to " << m_to.to_iso() << "\n";
 }
 
 bool CommandTimeFilter::run() {
     m_vout << "Opening input file...\n";
     osmium::io::Reader reader(m_input_file, osmium::osm_entity_bits::object);
 
+    m_vout << "Opening output file...\n";
     osmium::io::Header header = reader.header();
     header.set("generator", m_generator);
+    osmium::io::Writer writer(m_output_file, header, m_output_overwrite, m_fsync);
 
-    m_vout << "Opening output file...\n";
-    osmium::io::Writer writer(m_output_file, header, m_output_overwrite);
-    osmium::io::OutputIterator<osmium::io::Writer> out(writer);
-
-    typedef osmium::io::InputIterator<osmium::io::Reader, osmium::OSMObject> object_iterator;
-
-    object_iterator object_it(reader);
-    object_iterator object_end;
-
-    typedef osmium::DiffIterator<object_iterator> diff_iterator;
-
-    m_vout << "Filtering data...\n";
+    m_vout << "Filter data while copying it from input to output...\n";
+    auto input = osmium::io::make_input_iterator_range<osmium::OSMObject>(reader);
+    auto diff_begin = osmium::make_diff_iterator(input.begin(), input.end());
+    auto diff_end   = osmium::make_diff_iterator(input.end(), input.end());
+    auto out = osmium::io::make_output_iterator(writer);
 
     if (m_from == m_to) {
         std::copy_if(
-            diff_iterator(object_it, object_end),
-            diff_iterator(object_end, object_end),
+            diff_begin,
+            diff_end,
             out,
             [this](const osmium::DiffObject& d){
                 return d.is_visible_at(m_from);
         });
     } else {
         std::copy_if(
-            diff_iterator(object_it, object_end),
-            diff_iterator(object_end, object_end),
+            diff_begin,
+            diff_end,
             out,
             [this](const osmium::DiffObject& d){
                 return d.is_between(m_from, m_to);
         });
     }
 
-    out.flush();
+    m_vout << "Closing output file...\n";
     writer.close();
 
+    m_vout << "Closing input file...\n";
+    reader.close();
+
     m_vout << "Done.\n";
 
     return true;
diff --git a/src/io.cpp b/src/io.cpp
index 89cc36d..50b0be3 100644
--- a/src/io.cpp
+++ b/src/io.cpp
@@ -33,7 +33,7 @@ void with_single_osm_input::setup_input_file(const boost::program_options::varia
     }
 
     if ((m_input_filename == "-" || m_input_filename == "") && m_input_format.empty()) {
-        throw argument_error("When reading from STDIN you need to use the --input-format,F option to declare the file format.");
+        throw argument_error("When reading from STDIN you need to use the --input-format/-F option to declare the file format.");
     }
 
     m_input_file = osmium::io::File(m_input_filename, m_input_format);
@@ -45,6 +45,12 @@ void with_single_osm_input::add_single_input_options(po::options_description& op
     ;
 }
 
+void with_single_osm_input::show_single_input_arguments(osmium::util::VerboseOutput& vout) {
+    vout << "  input options:\n";
+    vout << "    file name: " << m_input_filename << "\n";
+    vout << "    file format: " << m_input_format << "\n";
+}
+
 void with_multiple_osm_inputs::setup_input_files(const boost::program_options::variables_map& vm) {
     if (vm.count("input-filenames")) {
         m_input_filenames = vm["input-filenames"].as<std::vector<std::string>>();
@@ -64,7 +70,7 @@ void with_multiple_osm_inputs::setup_input_files(const boost::program_options::v
             }
         }
         if (uses_stdin) {
-            throw argument_error("When reading from STDIN you need to use the --input-format,F option to declare the file format.");
+            throw argument_error("When reading from STDIN you need to use the --input-format/-F option to declare the file format.");
         }
     }
 
@@ -80,6 +86,15 @@ void with_multiple_osm_inputs::add_multiple_inputs_options(po::options_descripti
     ;
 }
 
+void with_multiple_osm_inputs::show_multiple_inputs_arguments(osmium::util::VerboseOutput& vout) {
+    vout << "  input options:\n";
+    vout << "    file names: \n";
+    for (const auto& fn : m_input_filenames) {
+        vout << "      " << fn << "\n";
+    }
+    vout << "    file format: " << m_input_format << "\n";
+}
+
 void with_osm_output::setup_output_file(const po::variables_map& vm) {
     if (vm.count("generator")) {
         m_generator = vm["generator"].as<std::string>();
@@ -101,8 +116,12 @@ void with_osm_output::setup_output_file(const po::variables_map& vm) {
         m_output_overwrite = osmium::io::overwrite::allow;
     }
 
+    if (vm.count("fsync")) {
+        m_fsync = osmium::io::fsync::yes;
+    }
+
     if ((m_output_filename == "-" || m_output_filename == "") && m_output_format.empty()) {
-        throw argument_error("When writing to STDOUT you need to use the --output-format,f option to declare the file format.");
+        throw argument_error("When writing to STDOUT you need to use the --output-format/-f option to declare the file format.");
     }
 
     m_output_file = osmium::io::File(m_output_filename, m_output_format);
@@ -116,6 +135,22 @@ void with_osm_output::add_output_options(po::options_description& options) {
     ("output-format,f", po::value<std::string>(), "Format of output file")
     ("output-header", po::value<std::vector<std::string>>(), "Add output header")
     ("overwrite,O", "Allow existing output file to be overwritten")
+    ("fsync", "Call fsync after writing file")
     ;
 }
 
+void with_osm_output::show_output_arguments(osmium::util::VerboseOutput& vout) {
+    vout << "  output options:\n";
+    vout << "    file name: " << m_output_filename << "\n";
+    vout << "    file format: " << m_output_format << "\n";
+    vout << "    generator: " << m_generator << "\n";
+    vout << "    overwrite: " << (m_output_overwrite == osmium::io::overwrite::allow ? "yes" : "no") << "\n";
+    vout << "    fsync: " << (m_fsync == osmium::io::fsync::yes ? "yes" : "no") << "\n";
+    if (!m_output_headers.empty()) {
+        vout << "    output header:\n";
+        for (const auto& h : m_output_headers) {
+            vout << "      " << h << "\n";
+        }
+    }
+}
+
diff --git a/src/main.cpp b/src/main.cpp
index 3fa6eac..f732fe4 100644
--- a/src/main.cpp
+++ b/src/main.cpp
@@ -104,7 +104,7 @@ int main(int argc, char *argv[]) {
         return return_code::fatal;
     }
 
-    cmd->print_arguments();
+    cmd->print_arguments(command);
 
     try {
         if (cmd->run()) {
diff --git a/test/changeset-filter/CMakeLists.txt b/test/changeset-filter/CMakeLists.txt
new file mode 100644
index 0000000..b6564aa
--- /dev/null
+++ b/test/changeset-filter/CMakeLists.txt
@@ -0,0 +1,70 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  Osmium Tool Tests - changeset-filter
+#
+#-----------------------------------------------------------------------------
+
+function(check_changeset_filter _name _options _input _output)
+    check_output(changeset-filter ${_name} "changeset-filter --generator=test -f osm ${_options} changeset-filter/${_input}" "changeset-filter/${_output}")
+endfunction()
+
+
+#-----------------------------------------------------------------------------
+
+check_changeset_filter(cf1-no-option          ""                     input1.osm output1-all.osm)
+check_changeset_filter(cf1-with-discussion    "--with-discussion"    input1.osm output-empty.osm)
+check_changeset_filter(cf1-without-discussion "--without-discussion" input1.osm output1-all.osm)
+check_changeset_filter(cf1-with-changes       "--with-changes"       input1.osm output1-first.osm)
+check_changeset_filter(cf1-without-changes    "--without-changes"    input1.osm output1-second.osm)
+check_changeset_filter(cf1-open               "--open"               input1.osm output-empty.osm)
+check_changeset_filter(cf1-closed             "--closed"             input1.osm output1-all.osm)
+check_changeset_filter(cf1-user               "--user=Elbert"        input1.osm output1-first.osm)
+check_changeset_filter(cf1-uid                "--uid=1233268"        input1.osm output1-second.osm)
+
+check_changeset_filter(cfe-open   "--open"   input-open.osm output-open.osm)
+check_changeset_filter(cfe-closed "--closed" input-open.osm output-empty.osm)
+
+check_changeset_filter(cf1-after01 "--after=2013-03-22T02:08:50Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after02 "--after=2013-03-22T02:08:54Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after03 "--after=2013-03-22T02:08:55Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after04 "--after=2013-03-22T02:08:56Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after05 "--after=2013-03-22T02:08:57Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after06 "--after=2013-03-22T02:08:58Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-after07 "--after=2013-03-22T02:08:59Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after08 "--after=2013-03-22T02:09:00Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after09 "--after=2013-03-22T02:09:10Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after10 "--after=2013-03-22T02:09:11Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after11 "--after=2013-03-22T02:09:12Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after12 "--after=2013-03-22T03:09:10Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after13 "--after=2013-03-22T03:09:11Z" input1.osm output1-second.osm)
+check_changeset_filter(cf1-after14 "--after=2013-03-22T03:09:12Z" input1.osm output-empty.osm)
+check_changeset_filter(cf1-after15 "--after=2013-03-22T03:09:20Z" input1.osm output-empty.osm)
+
+check_changeset_filter(cfe-after01 "--after=2013-03-22T04:20:24Z" input-open.osm output-open.osm)
+check_changeset_filter(cfe-after02 "--after=2013-03-22T04:20:25Z" input-open.osm output-open.osm)
+check_changeset_filter(cfe-after03 "--after=2013-03-22T04:20:26Z" input-open.osm output-open.osm)
+
+check_changeset_filter(cf1-before01 "--before=2013-03-22T02:08:50Z" input1.osm output-empty.osm)
+check_changeset_filter(cf1-before02 "--before=2013-03-22T02:08:54Z" input1.osm output-empty.osm)
+check_changeset_filter(cf1-before03 "--before=2013-03-22T02:08:55Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before04 "--before=2013-03-22T02:08:56Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before05 "--before=2013-03-22T02:08:57Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before06 "--before=2013-03-22T02:08:58Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before07 "--before=2013-03-22T02:08:59Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before08 "--before=2013-03-22T02:09:00Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before09 "--before=2013-03-22T02:09:10Z" input1.osm output1-first.osm)
+check_changeset_filter(cf1-before10 "--before=2013-03-22T02:09:11Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-before11 "--before=2013-03-22T02:09:12Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-before12 "--before=2013-03-22T03:09:10Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-before13 "--before=2013-03-22T03:09:11Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-before14 "--before=2013-03-22T03:09:12Z" input1.osm output1-all.osm)
+check_changeset_filter(cf1-before15 "--before=2013-03-22T03:09:20Z" input1.osm output1-all.osm)
+
+check_changeset_filter(cfe-before01 "--before=2013-03-22T04:20:24Z" input-open.osm output-empty.osm)
+check_changeset_filter(cfe-before02 "--before=2013-03-22T04:20:25Z" input-open.osm output-open.osm)
+check_changeset_filter(cfe-before03 "--before=2013-03-22T04:20:26Z" input-open.osm output-open.osm)
+
+
+#-----------------------------------------------------------------------------
diff --git a/test/changeset-filter/input-open.osm b/test/changeset-filter/input-open.osm
new file mode 100644
index 0000000..9a2da93
--- /dev/null
+++ b/test/changeset-filter/input-open.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="Osmosis 0.41">
+ <changeset id="15450185" created_at="2013-03-22T04:20:25Z" num_changes="0" open="true" user="garl" uid="51196">
+  <tag k="comment" v="BBOX:40.53,43.93,40.77,44.11 ADD:18 UPD:33 DEL:0"/>
+  <tag k="created_by" v="Merkaartor 0.18.1 (ru)"/>
+ </changeset>
+</osm>
diff --git a/test/changeset-filter/input1.osm b/test/changeset-filter/input1.osm
new file mode 100644
index 0000000..cf12d24
--- /dev/null
+++ b/test/changeset-filter/input1.osm
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="Osmosis 0.41">
+ <changeset id="15449957" created_at="2013-03-22T02:08:55Z" num_changes="10" closed_at="2013-03-22T02:08:58Z" open="false" min_lon="120.2988730" min_lat="-10.0004425" max_lon="120.2991740" max_lat="-10.0002384" user="Elbert" uid="1237205">
+  <tag k="created_by" v="JOSM/1.5 (5356 en)"/>
+ </changeset>
+ <changeset id="15449958" created_at="2013-03-22T02:09:11Z" num_changes="0" closed_at="2013-03-22T03:09:11Z" open="false" user="sree dinesh" uid="1233268">
+  <tag k="comment" v="new residen road"/>
+  <tag k="created_by" v="JOSM/1.5 (5697 en)"/>
+ </changeset>
+</osm>
diff --git a/test/changeset-filter/output-empty.osm b/test/changeset-filter/output-empty.osm
new file mode 100644
index 0000000..59ff865
--- /dev/null
+++ b/test/changeset-filter/output-empty.osm
@@ -0,0 +1,3 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+</osm>
diff --git a/test/changeset-filter/output-open.osm b/test/changeset-filter/output-open.osm
new file mode 100644
index 0000000..4b0f563
--- /dev/null
+++ b/test/changeset-filter/output-open.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+ <changeset id="15450185" created_at="2013-03-22T04:20:25Z" open="true" user="garl" uid="51196" num_changes="0" comments_count="0">
+  <tag k="comment" v="BBOX:40.53,43.93,40.77,44.11 ADD:18 UPD:33 DEL:0"/>
+  <tag k="created_by" v="Merkaartor 0.18.1 (ru)"/>
+ </changeset>
+</osm>
diff --git a/test/changeset-filter/output1-all.osm b/test/changeset-filter/output1-all.osm
new file mode 100644
index 0000000..5c73046
--- /dev/null
+++ b/test/changeset-filter/output1-all.osm
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+ <changeset id="15449957" created_at="2013-03-22T02:08:55Z" closed_at="2013-03-22T02:08:58Z" open="false" user="Elbert" uid="1237205" min_lat="-10.0004425" min_lon="120.2988730" max_lat="-10.0002384" max_lon="120.2991740" num_changes="10" comments_count="0">
+  <tag k="created_by" v="JOSM/1.5 (5356 en)"/>
+ </changeset>
+ <changeset id="15449958" created_at="2013-03-22T02:09:11Z" closed_at="2013-03-22T03:09:11Z" open="false" user="sree dinesh" uid="1233268" num_changes="0" comments_count="0">
+  <tag k="comment" v="new residen road"/>
+  <tag k="created_by" v="JOSM/1.5 (5697 en)"/>
+ </changeset>
+</osm>
diff --git a/test/changeset-filter/output1-first.osm b/test/changeset-filter/output1-first.osm
new file mode 100644
index 0000000..27dca96
--- /dev/null
+++ b/test/changeset-filter/output1-first.osm
@@ -0,0 +1,6 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+ <changeset id="15449957" created_at="2013-03-22T02:08:55Z" closed_at="2013-03-22T02:08:58Z" open="false" user="Elbert" uid="1237205" min_lat="-10.0004425" min_lon="120.2988730" max_lat="-10.0002384" max_lon="120.2991740" num_changes="10" comments_count="0">
+  <tag k="created_by" v="JOSM/1.5 (5356 en)"/>
+ </changeset>
+</osm>
diff --git a/test/changeset-filter/output1-second.osm b/test/changeset-filter/output1-second.osm
new file mode 100644
index 0000000..56b1f45
--- /dev/null
+++ b/test/changeset-filter/output1-second.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+ <changeset id="15449958" created_at="2013-03-22T02:09:11Z" closed_at="2013-03-22T03:09:11Z" open="false" user="sree dinesh" uid="1233268" num_changes="0" comments_count="0">
+  <tag k="comment" v="new residen road"/>
+  <tag k="created_by" v="JOSM/1.5 (5697 en)"/>
+ </changeset>
+</osm>
diff --git a/test/sort/CMakeLists.txt b/test/sort/CMakeLists.txt
new file mode 100644
index 0000000..730f1d2
--- /dev/null
+++ b/test/sort/CMakeLists.txt
@@ -0,0 +1,26 @@
+#-----------------------------------------------------------------------------
+#
+#  CMake Config
+#
+#  Osmium Tool Tests - sort
+#
+#-----------------------------------------------------------------------------
+
+function(check_sort2 _name _in1 _in2 _output)
+    check_output(sort ${_name} "sort --generator=test -f osm sort/${_in1} sort/${_in2}" "sort/${_output}")
+endfunction()
+
+function(check_sort1 _name _input _output)
+    check_output(sort ${_name} "sort --generator=test -f osc sort/${_input}" "sort/${_output}")
+endfunction()
+
+
+#-----------------------------------------------------------------------------
+
+check_sort2(simple input-simple1.osm input-simple2.osm output-simple.osm)
+check_sort2(bounds input-bounds1.osm input-bounds2.osm output-bounds.osm)
+check_sort2(history input-history1.osm input-history2.osm output-history.osm)
+check_sort1(change input-change.osc output-change.osc)
+
+
+#-----------------------------------------------------------------------------
diff --git a/test/sort/input-bounds1.osm b/test/sort/input-bounds1.osm
new file mode 100644
index 0000000..5952a58
--- /dev/null
+++ b/test/sort/input-bounds1.osm
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <bounds minlon="0.0000000" minlat="0.0000000" maxlon="10.0000000" maxlat="10.0000000"/>
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <relation id="30" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <member type="node" ref="12" role="m1"/>
+    <member type="way" ref="20" role="m2"/>
+  </relation>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+</osm>
diff --git a/test/sort/input-bounds2.osm b/test/sort/input-bounds2.osm
new file mode 100644
index 0000000..e36adac
--- /dev/null
+++ b/test/sort/input-bounds2.osm
@@ -0,0 +1,11 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <bounds minlon="5.0000000" minlat="5.0000000" maxlon="15.0000000" maxlat="15.0000000"/>
+  <way id="20" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="10"/>
+    <nd ref="11"/>
+    <nd ref="12"/>
+    <tag k="foo" v="bar"/>
+  </way>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+</osm>
diff --git a/test/sort/input-change.osc b/test/sort/input-change.osc
new file mode 100644
index 0000000..715474a
--- /dev/null
+++ b/test/sort/input-change.osc
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osmChange version="0.6" generator="testdata">
+  <delete>
+    <node id="13" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="4" lon="1"/>
+  </delete>
+  <create>
+    <node id="14" version="1" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="5" lon="1"/>
+  </create>
+  <modify>
+    <way id="21" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2">
+      <nd ref="12"/>
+      <nd ref="14"/>
+      <tag k="xyz" v="new"/>
+    </way>
+  </modify>
+  <modify>
+    <node id="11" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="2" lon="2"/>
+  </modify>
+</osmChange>
diff --git a/test/sort/input-history1.osm b/test/sort/input-history1.osm
new file mode 100644
index 0000000..1fdefa1
--- /dev/null
+++ b/test/sort/input-history1.osm
@@ -0,0 +1,12 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="11" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="2"/>
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <node id="12" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="2"/>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+</osm>
diff --git a/test/sort/input-history2.osm b/test/sort/input-history2.osm
new file mode 100644
index 0000000..7e9c542
--- /dev/null
+++ b/test/sort/input-history2.osm
@@ -0,0 +1,7 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <node id="10" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="2"/>
+  <node id="13" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="2"/>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+</osm>
diff --git a/test/sort/input-simple1.osm b/test/sort/input-simple1.osm
new file mode 100644
index 0000000..fe9f976
--- /dev/null
+++ b/test/sort/input-simple1.osm
@@ -0,0 +1,15 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <relation id="30" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <member type="node" ref="12" role="m1"/>
+    <member type="way" ref="20" role="m2"/>
+  </relation>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+</osm>
diff --git a/test/sort/input-simple2.osm b/test/sort/input-simple2.osm
new file mode 100644
index 0000000..f0c473f
--- /dev/null
+++ b/test/sort/input-simple2.osm
@@ -0,0 +1,10 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" upload="false" generator="testdata">
+  <way id="20" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="10"/>
+    <nd ref="11"/>
+    <nd ref="12"/>
+    <tag k="foo" v="bar"/>
+  </way>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+</osm>
diff --git a/test/sort/output-bounds.osm b/test/sort/output-bounds.osm
new file mode 100644
index 0000000..6637420
--- /dev/null
+++ b/test/sort/output-bounds.osm
@@ -0,0 +1,23 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+  <bounds minlon="0.0000000" minlat="0.0000000" maxlon="15.0000000" maxlat="15.0000000"/>
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+  <way id="20" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="10"/>
+    <nd ref="11"/>
+    <nd ref="12"/>
+    <tag k="foo" v="bar"/>
+  </way>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+  <relation id="30" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <member type="node" ref="12" role="m1"/>
+    <member type="way" ref="20" role="m2"/>
+  </relation>
+</osm>
diff --git a/test/sort/output-change.osc b/test/sort/output-change.osc
new file mode 100644
index 0000000..66a34f6
--- /dev/null
+++ b/test/sort/output-change.osc
@@ -0,0 +1,19 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osmChange version="0.6" generator="test">
+  <modify>
+    <node id="11" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="2" lon="2"/>
+  </modify>
+  <delete>
+    <node id="13" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="4" lon="1"/>
+  </delete>
+  <create>
+    <node id="14" version="1" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2" lat="5" lon="1"/>
+  </create>
+  <modify>
+    <way id="21" version="2" timestamp="2015-01-01T02:00:00Z" uid="1" user="test" changeset="2">
+      <nd ref="12"/>
+      <nd ref="14"/>
+      <tag k="xyz" v="new"/>
+    </way>
+  </modify>
+</osmChange>
diff --git a/test/sort/output-history.osm b/test/sort/output-history.osm
new file mode 100644
index 0000000..935046c
--- /dev/null
+++ b/test/sort/output-history.osm
@@ -0,0 +1,16 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <node id="10" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="2"/>
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="11" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="2"/>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+  <node id="12" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="2"/>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+  <node id="13" version="2" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="2"/>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+</osm>
diff --git a/test/sort/output-simple.osm b/test/sort/output-simple.osm
new file mode 100644
index 0000000..f290c36
--- /dev/null
+++ b/test/sort/output-simple.osm
@@ -0,0 +1,22 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<osm version="0.6" generator="test">
+  <node id="10" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="1" lon="1"/>
+  <node id="11" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="2" lon="1"/>
+  <node id="12" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="3" lon="1"/>
+  <node id="13" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1" lat="4" lon="1"/>
+  <way id="20" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="10"/>
+    <nd ref="11"/>
+    <nd ref="12"/>
+    <tag k="foo" v="bar"/>
+  </way>
+  <way id="21" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <nd ref="12"/>
+    <nd ref="13"/>
+    <tag k="xyz" v="abc"/>
+  </way>
+  <relation id="30" version="1" timestamp="2015-01-01T01:00:00Z" uid="1" user="test" changeset="1">
+    <member type="node" ref="12" role="m1"/>
+    <member type="way" ref="20" role="m2"/>
+  </relation>
+</osm>
diff --git a/zsh_completion/_osmium b/zsh_completion/_osmium
index d6d4c1c..f6552d1 100644
--- a/zsh_completion/_osmium
+++ b/zsh_completion/_osmium
@@ -13,11 +13,11 @@
 #  http://zsh.sourceforge.net/Guide/zshguide06.html
 #
 
-osmium_file_glob="'*.(osm|osh|osc|pbf|osm.pbf) *.(osm|osh|osc).(bz2|gz)'"
+osmium_file_glob="'*.(osm|osh|osc|o5m|o5c|pbf|osm.pbf) *.(osm|osh|osc|o5m|o5c).(bz2|gz)'"
 
 _osmium() {
     local -a osmium_commands
-    osmium_commands=(apply-changes cat check-refs fileinfo getid help merge-changes renumber time-filter)
+    osmium_commands=(apply-changes cat changeset-filter check-refs fileinfo getid help merge-changes renumber sort time-filter)
     if (( CURRENT > 2 )); then
         # Remember the subcommand name
         local cmd=${words[2]}
@@ -80,6 +80,31 @@ _osmium-cat() {
         '*--object-type[read only object of given output types]:OSM entity type:_osmium_entity_type'
 }
 
+_osmium-changeset-filter() {
+    _arguments : \
+        ${(f)"$(_osmium-common-options)"} \
+        ${(f)"$(_osmium-single-input-options)"} \
+        ${(f)"$(_osmium-output-options)"} \
+        '(--with-discussions)-d[changesets with discussions]' \
+        '(-d)--with-discussions[changesets with discussions]' \
+        '(--without-discussions)-D[changesets without discussions]' \
+        '(-D)--without-discussions[changesets without discussions]' \
+        '(--with-changes)-c[changesets with changes]' \
+        '(-c)--with-changes[changesets with changes]' \
+        '(--without-changes)-C[changesets without changes]' \
+        '(-C)--without-changes[changesets without changes]' \
+        '--open[open changesets]' \
+        '--closed[closed changesets]' \
+        '(--user)-u[changesets by user]' \
+        '(-u)--user[changesets by user]' \
+        '(--uid)-U[changesets by user id]' \
+        '(-U)--uid[changesets by user id]' \
+        '-a[changesets closed after]:timestamp:' \
+        '--after[changesets closed after]:timestamp:' \
+        '-b[changesets opened before]:timestamp:' \
+        '--before[changesets opened before]:timestamp:'
+}
+
 _osmium-check-refs() {
     _arguments : \
         ${(f)"$(_osmium-common-options)"} \
@@ -130,6 +155,13 @@ _osmium-renumber() {
         '(-i)--index-directory[read/write index files in this directory]:directory:_path_files -/'
 }
 
+_osmium-sort() {
+    _arguments : \
+        ${(f)"$(_osmium-common-options)"} \
+        ${(f)"$(_osmium-multiple-inputs-options)"} \
+        ${(f)"$(_osmium-output-options)"}
+}
+
 _osmium-time-filter() {
     _arguments : \
         ${(f)"$(_osmium-common-options)"} \
@@ -167,7 +199,7 @@ _osmium_fileinfo_variables() {
 
 _osmium-help() {
     local -a osmium_help_topics
-    osmium_help_topics=(apply-changes cat check-refs fileinfo getid help merge-changes renumber time-filter file-formats)
+    osmium_help_topics=(apply-changes cat changeset-filter check-refs fileinfo getid help merge-changes renumber sort time-filter file-formats)
     _describe -t osmium-help-topics 'osmium help topics' osmium_help_topics
 }
 

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/pkg-grass/osmium-tool.git



More information about the Pkg-grass-devel mailing list