[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a
Maximiliano Curia
maxy at moszumanska.debian.org
Thu Jul 13 17:37:20 UTC 2017
Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=c5d91d3
The following commit has been merged in the master branch:
commit c5d91d374ac7265b508f3710afb692a132f11691
Author: Andreas Huggel <ahuggel at gmx.net>
Date: Sun Dec 11 13:41:16 2005 +0000
Added option -k to preserve file timestamps and -t/-T to set the timestamp in the rename action. Only tested on Linux. Implements feature #448.
---
src/actions.cpp | 270 ++++++++++++++++++++++++++++++++++-------------
src/exiv2.1 | 23 +++-
src/exiv2.cpp | 57 +++++++---
src/exiv2.hpp | 10 +-
test/data/exiv2-test.out | 25 +++--
5 files changed, 281 insertions(+), 104 deletions(-)
diff --git a/src/actions.cpp b/src/actions.cpp
index 61dd102..47bbe8a 100644
--- a/src/actions.cpp
+++ b/src/actions.cpp
@@ -66,11 +66,29 @@ EXIV2_RCSID("@(#) $Id$");
#ifdef EXV_HAVE_UNISTD_H
# include <unistd.h> // for stat()
#endif
+#include <utime.h>
// *****************************************************************************
// local declarations
namespace {
+ //! Helper class to set the timestamp of a file to that of another file
+ class Timestamp {
+ public:
+ //! C'tor
+ Timestamp() : actime_(0), modtime_(0) {}
+ //! Read the timestamp of a file
+ int read(const std::string& path);
+ //! Read the timestamp from a broken-down time in buffer \em tm.
+ int read(struct tm* tm);
+ //! Set the timestamp of a file
+ int touch(const std::string& path);
+
+ private:
+ time_t actime_;
+ time_t modtime_;
+ };
+
// Convert a string "YYYY:MM:DD HH:MI:SS" to a struct tm type,
// returns 0 if successful
int str2Tm(const std::string& timeStr, struct tm* tm);
@@ -94,6 +112,16 @@ namespace {
int metacopy(const std::string& source,
const std::string& target,
bool preserve);
+
+ /*!
+ @brief Rename a file according to a timestamp value.
+
+ @param path The original file path. Contains the new path on exit.
+ @param tm Pointer to a buffer with the broken-down time to rename
+ the file to.
+ @return 0 if successful, -1 if the file was skipped, 1 on error.
+ */
+ int renameFile(std::string& path, const struct tm* tm);
}
// *****************************************************************************
@@ -639,6 +667,10 @@ namespace Action {
<< ": Failed to open the file
";
return -1;
}
+ Timestamp ts;
+ if (Params::instance().preserve_) {
+ ts.read(path);
+ }
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
assert(image.get() != 0);
image->readMetadata();
@@ -661,91 +693,34 @@ namespace Action {
<< path << "
";
return 1;
}
- // Assemble the new filename from the timestamp
struct tm tm;
if (str2Tm(v, &tm) != 0) {
std::cerr << "Failed to parse timestamp `" << v
<< "' in the file " << path << "
";
return 1;
}
- const size_t max = 1024;
- char basename[max];
- memset(basename, 0x0, max);
- if (strftime(basename, max, Params::instance().format_.c_str(), &tm) == 0) {
- std::cerr << "Filename format yields empty filename for the file "
- << path << "
";
- return 1;
+ if ( Params::instance().timestamp_
+ || Params::instance().timestampOnly_) {
+ ts.read(&tm);
}
- std::string newPath
- = Util::dirname(path) + EXV_SEPERATOR_STR + basename + Util::suffix(path);
- if ( Util::dirname(newPath) == Util::dirname(path)
- && Util::basename(newPath) == Util::basename(path)) {
+ int rc = 0;
+ std::string newPath = path;
+ if (Params::instance().timestampOnly_) {
if (Params::instance().verbose_) {
- std::cout << "This file already has the correct name" << std::endl;
- }
- return 0;
- }
-
- bool go = true;
- int seq = 1;
- std::string s;
- Params::FileExistsPolicy fileExistsPolicy
- = Params::instance().fileExistsPolicy_;
- while (go) {
- if (Exiv2::fileExists(newPath)) {
- switch (fileExistsPolicy) {
- case Params::overwritePolicy:
- go = false;
- break;
- case Params::renamePolicy:
- newPath = Util::dirname(path)
- + EXV_SEPERATOR_STR + basename
- + "_" + Exiv2::toString(seq++)
- + Util::suffix(path);
- break;
- case Params::askPolicy:
- std::cout << Params::instance().progname()
- << ": File `" << newPath
- << "' exists. [O]verwrite, [r]ename or [s]kip? ";
- std::cin >> s;
- switch (s[0]) {
- case 'o':
- case 'O':
- go = false;
- break;
- case 'r':
- case 'R':
- fileExistsPolicy = Params::renamePolicy;
- newPath = Util::dirname(path)
- + EXV_SEPERATOR_STR + basename
- + "_" + Exiv2::toString(seq++)
- + Util::suffix(path);
- break;
- default: // skip
- return 0;
- break;
- }
- }
- }
- else {
- go = false;
+ std::cout << "Updating timestamp to " << v << std::endl;
}
}
-
- if (Params::instance().verbose_) {
- std::cout << "Renaming file to " << newPath << std::endl;
+ else {
+ rc = renameFile(newPath, &tm);
+ if (rc == -1) return 0; // skip
}
-
- // Workaround for MinGW rename which does not overwrite existing files
- remove(newPath.c_str());
- if (::rename(path.c_str(), newPath.c_str()) == -1) {
- std::cerr << Params::instance().progname()
- << ": Failed to rename "
- << path << " to " << newPath << ": "
- << Exiv2::strError() << "
";
- return 1;
+ if ( 0 == rc
+ && ( Params::instance().preserve_
+ || Params::instance().timestamp_
+ || Params::instance().timestampOnly_)) {
+ ts.touch(newPath);
}
- return 0;
+ return rc;
}
catch(const Exiv2::AnyError& e)
{
@@ -773,6 +748,10 @@ namespace Action {
<< ": Failed to open the file
";
return -1;
}
+ Timestamp ts;
+ if (Params::instance().preserve_) {
+ ts.read(path);
+ }
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path_);
assert(image.get() != 0);
image->readMetadata();
@@ -793,6 +772,9 @@ namespace Action {
if (0 == rc) {
image->writeMetadata();
}
+ if (Params::instance().preserve_) {
+ ts.touch(path);
+ }
return rc;
}
@@ -952,6 +934,10 @@ namespace Action {
return -1;
}
int rc = 0;
+ Timestamp ts;
+ if (Params::instance().preserve_) {
+ ts.read(path);
+ }
if (Params::instance().target_ & Params::ctThumb) {
rc = insertThumbnail(path);
}
@@ -967,6 +953,9 @@ namespace Action {
+ Util::basename(path, true) + suffix;
rc = metacopy(exvPath, path, true);
}
+ if (Params::instance().preserve_) {
+ ts.touch(path);
+ }
return rc;
}
catch(const Exiv2::AnyError& e)
@@ -1019,6 +1008,10 @@ namespace Action {
<< ": Failed to open the file
";
return -1;
}
+ Timestamp ts;
+ if (Params::instance().preserve_) {
+ ts.read(path);
+ }
image_ = Exiv2::ImageFactory::open(path);
assert(image_.get() != 0);
image_->readMetadata();
@@ -1047,6 +1040,9 @@ namespace Action {
// Save both exif and iptc metadata
image_->writeMetadata();
+ if (Params::instance().preserve_) {
+ ts.touch(path);
+ }
return 0;
}
catch(const Exiv2::AnyError& e)
@@ -1166,6 +1162,10 @@ namespace Action {
<< ": Failed to open the file
";
return -1;
}
+ Timestamp ts;
+ if (Params::instance().preserve_) {
+ ts.read(path);
+ }
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path);
assert(image.get() != 0);
image->readMetadata();
@@ -1180,6 +1180,9 @@ namespace Action {
rc += adjustDateTime(exifData, "Exif.Photo.DateTimeDigitized", path);
if (rc) return 1;
image->writeMetadata();
+ if (Params::instance().preserve_) {
+ ts.touch(path);
+ }
return rc;
}
catch(const Exiv2::AnyError& e)
@@ -1241,6 +1244,38 @@ namespace Action {
// local definitions
namespace {
+ int Timestamp::read(const std::string& path)
+ {
+ struct stat buf;
+ int rc = stat(path.c_str(), &buf);
+ if (0 == rc) {
+ actime_ = buf.st_atime;
+ modtime_ = buf.st_mtime;
+ }
+ return rc;
+ }
+
+ int Timestamp::read(struct tm* tm)
+ {
+ int rc = 1;
+ time_t t = mktime(tm);
+ if (t != (time_t)-1) {
+ rc = 0;
+ actime_ = t;
+ modtime_ = t;
+ }
+ return rc;
+ }
+
+ int Timestamp::touch(const std::string& path)
+ {
+ if (0 == actime_) return 1;
+ struct utimbuf buf;
+ buf.actime = actime_;
+ buf.modtime = modtime_;
+ return utime(path.c_str(), &buf);
+ }
+
int str2Tm(const std::string& timeStr, struct tm* tm)
{
if (timeStr.length() == 0 || timeStr[0] == ' ') return 1;
@@ -1350,4 +1385,93 @@ namespace {
return 0;
} // metacopy
+
+ int renameFile(std::string& newPath, const struct tm* tm)
+ {
+ std::string path = newPath;
+ const size_t max = 1024;
+ char basename[max];
+ memset(basename, 0x0, max);
+ if (strftime(basename, max, Params::instance().format_.c_str(), tm) == 0) {
+ std::cerr << "Filename format yields empty filename for the file "
+ << path << "
";
+ return 1;
+ }
+ newPath = Util::dirname(path) + EXV_SEPERATOR_STR
+ + basename + Util::suffix(path);
+ if ( Util::dirname(newPath) == Util::dirname(path)
+ && Util::basename(newPath) == Util::basename(path)) {
+ if (Params::instance().verbose_) {
+ std::cout << "This file already has the correct name" << std::endl;
+ }
+ return -1;
+ }
+
+ bool go = true;
+ int seq = 1;
+ std::string s;
+ Params::FileExistsPolicy fileExistsPolicy
+ = Params::instance().fileExistsPolicy_;
+ while (go) {
+ if (Exiv2::fileExists(newPath)) {
+ switch (fileExistsPolicy) {
+ case Params::overwritePolicy:
+ go = false;
+ break;
+ case Params::renamePolicy:
+ newPath = Util::dirname(path)
+ + EXV_SEPERATOR_STR + basename
+ + "_" + Exiv2::toString(seq++)
+ + Util::suffix(path);
+ break;
+ case Params::askPolicy:
+ std::cout << Params::instance().progname()
+ << ": File `" << newPath
+ << "' exists. [O]verwrite, [r]ename or [s]kip? ";
+ std::cin >> s;
+ switch (s[0]) {
+ case 'o':
+ case 'O':
+ go = false;
+ break;
+ case 'r':
+ case 'R':
+ fileExistsPolicy = Params::renamePolicy;
+ newPath = Util::dirname(path)
+ + EXV_SEPERATOR_STR + basename
+ + "_" + Exiv2::toString(seq++)
+ + Util::suffix(path);
+ break;
+ default: // skip
+ return -1;
+ break;
+ }
+ }
+ }
+ else {
+ go = false;
+ }
+ }
+
+ if (Params::instance().verbose_) {
+ std::cout << "Renaming file to " << newPath;
+ if (Params::instance().timestamp_) {
+ std::cout << ", updating timestamp";
+ }
+ std::cout << std::endl;
+ }
+
+ // Workaround for MinGW rename which does not overwrite existing files
+ remove(newPath.c_str());
+ if (std::rename(path.c_str(), newPath.c_str()) == -1) {
+ std::cerr << Params::instance().progname()
+ << ": Failed to rename "
+ << path << " to " << newPath << ": "
+ << Exiv2::strError() << "
";
+ return 1;
+ }
+
+ return 0;
+ } // renameFile
+
}
diff --git a/src/exiv2.1 b/src/exiv2.1
index 2021584..85883fd 100644
--- a/src/exiv2.1
+++ b/src/exiv2.1
@@ -57,8 +57,9 @@ Apply commands to modify (add, set, delete) the EXIF/IPTC metadata of image
files. Requires option
B\-m
P or
B\-M
P.
.TP
.B mv | rename
-Rename files according to the EXIF create timestamp. The filename format
-can be set with
B\-r
P
Ifmt
P.
+Rename files and/or set file timestamps according to the EXIF create
+timestamp. The filename format can be set with
B\-r
P
Ifmt
P,
+timestamp options are
B\-t
P and
B\-T
P.
.SH OPTIONS
.TP
.B \-h
@@ -70,11 +71,27 @@ Show the program version and exit.
.B \-v
Be verbose during the program run.
.TP
+.B \-k
+Preserve file timestamps when updating files (keep). Can be used with
+all options which update files. The flag is ignored by read-only
+options.
+.TP
+.B \-t
+Set the file timestamp according to the EXIF create timestamp in
+addition to renaming the file (overrides
B\-k
P). This option is
+only used with the 'rename' action.
+.TP
+.B \-T
+Only set the file timestamp according to the EXIF create timestamp, do
+not rename the file (overrides
B\-k
P). This option is only used
+with the 'rename' action.
+.TP
.B \-f
Do not prompt before overwriting existing files (force overwrite).
.TP
.B \-F
-Do not prompt before renaming existing files (Force rename).
+Do not prompt before renaming files (Force rename). Appends '_1'
+('_2', ...) to the name of the new file.
.TP
.B \-a
Itime
P
Time adjustment in the format [\-]HH[:MM[:SS]]. This option is only
diff --git a/src/exiv2.cpp b/src/exiv2.cpp
index 3f229dc..9b71e90 100644
--- a/src/exiv2.cpp
+++ b/src/exiv2.cpp
@@ -194,37 +194,42 @@ void Params::help(std::ostream& os) const
<< " in | insert Insert metadata from corresponding *.exv files.
"
<< " Use option -S to change the suffix of the input files.
"
<< " ex | extract Extract metadata to *.exv and thumbnail image files.
"
- << " mv | rename Rename files according to the Exif create timestamp.
"
- << " The filename format can be set with -r format.
"
+ << " mv | rename Rename files and/or set file timestamps according to the
"
+ << " Exif create timestamp. The filename format can be set with
"
+ << " -r format, timestamp options are controlled with -t and -T.
"
<< " mo | modify Apply commands to modify (add, set, delete) the Exif
"
- << " and Iptc metadata of image files. Requires option -m or -M
"
+ << " and Iptc metadata of image files. Requires option -m or -M.
"
<< "
Options:
"
<< " -h Display this help and exit.
"
<< " -V Show the program version and exit.
"
<< " -v Be verbose during the program run.
"
+ << " -k Preserve file timestamps (keep).
"
+ << " -t Also set the file timestamp in 'rename' action (overrides -k).
"
+ << " -T Only set the file timestamp in 'rename' action, do not rename
"
+ << " the file (overrides -k).
"
<< " -f Do not prompt before overwriting existing files (force).
"
- << " -F Do not prompt before renaming existing files (Force).
"
+ << " -F Do not prompt before renaming files (Force).
"
<< " -a time Time adjustment in the format [-]HH[:MM[:SS]]. This option
"
- << " is only used with the `adjust' action.
"
- << " -p mode Print mode for the `print' action. Possible modes are:
"
+ << " is only used with the 'adjust' action.
"
+ << " -p mode Print mode for the 'print' action. Possible modes are:
"
<< " s : print a summary of the Exif metadata (the default)
"
<< " t : interpreted (translated) Exif data
"
<< " v : plain Exif data values
"
<< " h : hexdump of the Exif data
"
<< " i : Iptc data values
"
<< " c : Jpeg comment
"
- << " -d tgt Delete target(s) for the `delete' action. Possible targets are:
"
+ << " -d tgt Delete target(s) for the 'delete' action. Possible targets are:
"
<< " a : all supported metadata (the default)
"
<< " e : Exif section
"
<< " t : Exif thumbnail only
"
<< " i : Iptc data
"
<< " c : Jpeg comment
"
- << " -i tgt Insert target(s) for the `insert' action. Possible targets are
"
+ << " -i tgt Insert target(s) for the 'insert' action. Possible targets are
"
<< " the same as those for the -d option. Only Jpeg thumbnails can
"
<< " be inserted, they need to be named <file>-thumb.jpg
"
- << " -e tgt Extract target(s) for the `extract' action. Possible targets
"
+ << " -e tgt Extract target(s) for the 'extract' action. Possible targets
"
<< " are the same as those for the -d option.
"
- << " -r fmt Filename format for the `rename' action. The format string
"
+ << " -r fmt Filename format for the 'rename' action. The format string
"
<< " follows strftime(3). Default filename format is "
<< format_ << ".
"
<< " -m file Command file for the modify action. The format for commands is
"
@@ -242,9 +247,12 @@ int Params::option(int opt, const std::string& optarg, int optopt)
case 'h': help_ = true; break;
case 'V': version_ = true; break;
case 'v': verbose_ = true; break;
+ case 'k': preserve_ = true; break;
case 'f': force_ = true; fileExistsPolicy_ = overwritePolicy; break;
case 'F': force_ = true; fileExistsPolicy_ = renamePolicy; break;
- case 'r': rc = evalRename(optarg); break;
+ case 'r': rc = evalRename(opt, optarg); break;
+ case 't': rc = evalRename(opt, optarg); break;
+ case 'T': rc = evalRename(opt, optarg); break;
case 'a': rc = evalAdjust(optarg); break;
case 'p': rc = evalPrint(optarg); break;
case 'd': rc = evalDelete(optarg); break;
@@ -274,21 +282,28 @@ int Params::option(int opt, const std::string& optarg, int optopt)
return rc;
} // Params::option
-int Params::evalRename(const std::string& optarg)
+int Params::evalRename(int opt, const std::string& optarg)
{
int rc = 0;
switch (action_) {
case Action::none:
action_ = Action::rename;
- format_ = optarg;
+ switch (opt) {
+ case 'r': format_ = optarg; break;
+ case 't': timestamp_ = true; break;
+ case 'T': timestampOnly_ = true; break;
+ }
break;
case Action::rename:
- std::cerr << progname()
- << ": Ignoring surplus option -r \"" << optarg << "\"
";
+ if (opt == 'r' && !format_.empty()) {
+ std::cerr << progname()
+ << ": Ignoring surplus option -r \"" << optarg << "\"
";
+ }
break;
default:
std::cerr << progname()
- << ": Option -r is not compatible with a previous option
";
+ << ": Option -" << (char)opt
+ << " is not compatible with a previous option
";
rc = 1;
break;
}
@@ -586,6 +601,16 @@ int Params::getopt(int argc, char* const argv[])
<< ": -S option can only be used with insert action
";
rc = 1;
}
+ if (timestamp_ && !(action_ == Action::rename)) {
+ std::cerr << progname()
+ << ": -t option can only be used with rename action
";
+ rc = 1;
+ }
+ if (timestampOnly_ && !(action_ == Action::rename)) {
+ std::cerr << progname()
+ << ": -T option can only be used with rename action
";
+ rc = 1;
+ }
return rc;
} // Params::getopt
diff --git a/src/exiv2.hpp b/src/exiv2.hpp
index 26d84d3..70462b0 100644
--- a/src/exiv2.hpp
+++ b/src/exiv2.hpp
@@ -134,6 +134,9 @@ public:
bool version_; //!< Version option flag.
bool verbose_; //!< Verbose (talkative) option flag.
bool force_; //!< Force overwrites flag.
+ bool preserve_; //!< Preserve timestamps flag.
+ bool timestamp_; //!< Rename also sets the file timestamp.
+ bool timestampOnly_; //!< Rename only sets the file timestamp.
FileExistsPolicy fileExistsPolicy_; //!< What to do if file to rename exists.
bool adjust_; //!< Adjustment flag.
PrintMode printMode_; //!< Print mode.
@@ -155,11 +158,14 @@ private:
@brief Default constructor. Note that optstring_ is initialized here.
The c'tor is private to force instantiation through instance().
*/
- Params() : optstring_(":hVvfFa:r:p:d:e:i:m:M:l:S:"),
+ Params() : optstring_(":hVvfktTFa:r:p:d:e:i:m:M:l:S:"),
help_(false),
version_(false),
verbose_(false),
force_(false),
+ preserve_(false),
+ timestamp_(false),
+ timestampOnly_(false),
fileExistsPolicy_(askPolicy),
adjust_(false),
printMode_(pmSummary),
@@ -174,7 +180,7 @@ private:
//! @name Helpers
//@{
- int evalRename(const std::string& optarg);
+ int evalRename(int opt, const std::string& optarg);
int evalAdjust(const std::string& optarg);
int evalPrint(const std::string& optarg);
int evalDelete(const std::string& optarg);
diff --git a/test/data/exiv2-test.out b/test/data/exiv2-test.out
index e918552..04711c9 100644
--- a/test/data/exiv2-test.out
+++ b/test/data/exiv2-test.out
@@ -21,38 +21,43 @@ Actions:
in | insert Insert metadata from corresponding *.exv files.
Use option -S to change the suffix of the input files.
ex | extract Extract metadata to *.exv and thumbnail image files.
- mv | rename Rename files according to the Exif create timestamp.
- The filename format can be set with -r format.
+ mv | rename Rename files and/or set file timestamps according to the
+ Exif create timestamp. The filename format can be set with
+ -r format, timestamp options are controlled with -t and -T.
mo | modify Apply commands to modify (add, set, delete) the Exif
- and Iptc metadata of image files. Requires option -m or -M
+ and Iptc metadata of image files. Requires option -m or -M.
Options:
-h Display this help and exit.
-V Show the program version and exit.
-v Be verbose during the program run.
+ -k Preserve file timestamps (keep).
+ -t Also set the file timestamp in 'rename' action (overrides -k).
+ -T Only set the file timestamp in 'rename' action, do not rename
+ the file (overrides -k).
-f Do not prompt before overwriting existing files (force).
- -F Do not prompt before renaming existing files (Force).
+ -F Do not prompt before renaming files (Force).
-a time Time adjustment in the format [-]HH[:MM[:SS]]. This option
- is only used with the `adjust' action.
- -p mode Print mode for the `print' action. Possible modes are:
+ is only used with the 'adjust' action.
+ -p mode Print mode for the 'print' action. Possible modes are:
s : print a summary of the Exif metadata (the default)
t : interpreted (translated) Exif data
v : plain Exif data values
h : hexdump of the Exif data
i : Iptc data values
c : Jpeg comment
- -d tgt Delete target(s) for the `delete' action. Possible targets are:
+ -d tgt Delete target(s) for the 'delete' action. Possible targets are:
a : all supported metadata (the default)
e : Exif section
t : Exif thumbnail only
i : Iptc data
c : Jpeg comment
- -i tgt Insert target(s) for the `insert' action. Possible targets are
+ -i tgt Insert target(s) for the 'insert' action. Possible targets are
the same as those for the -d option. Only Jpeg thumbnails can
be inserted, they need to be named <file>-thumb.jpg
- -e tgt Extract target(s) for the `extract' action. Possible targets
+ -e tgt Extract target(s) for the 'extract' action. Possible targets
are the same as those for the -d option.
- -r fmt Filename format for the `rename' action. The format string
+ -r fmt Filename format for the 'rename' action. The format string
follows strftime(3). Default filename format is %Y%m%d_%H%M%S.
-m file Command file for the modify action. The format for commands is
set|add|del <key> [[<type>] <value>].
--
exiv2 packaging
More information about the pkg-kde-commits
mailing list