mirror of
https://github.com/fmang/opustags.git
synced 2025-01-15 12:43:17 +01:00
Cancel --edit when the editor closes without saving
This commit is contained in:
parent
b3b092d241
commit
ba2236facb
35
src/cli.cc
35
src/cli.cc
@ -283,25 +283,39 @@ static ot::status edit_tags_interactively(ot::opus_tags& tags, const std::option
|
||||
return {ot::st::error,
|
||||
"No editor specified in environment variable VISUAL or EDITOR."};
|
||||
|
||||
// Building the temporary tags file.
|
||||
std::string tags_path = base_path.value_or("tags") + ".XXXXXX.opustags";
|
||||
int fd = mkstemps(const_cast<char*>(tags_path.data()), 9);
|
||||
FILE* tags_file;
|
||||
if (fd == -1 || (tags_file = fdopen(fd, "w")) == nullptr)
|
||||
return {ot::st::standard_error,
|
||||
"Could not open '" + tags_path + "': " + strerror(errno)};
|
||||
|
||||
ot::print_comments(tags.comments, tags_file);
|
||||
fputs("\n"
|
||||
"# Edit these tags to your liking and close your editor to apply them.\n"
|
||||
"# If you delete all the tags however, tag edition will be cancelled.\n",
|
||||
tags_file);
|
||||
if (fclose(tags_file) != 0)
|
||||
return {ot::st::standard_error, "fclose error: "s + strerror(errno)};
|
||||
return {ot::st::standard_error, tags_path + ": fclose error: "s + strerror(errno)};
|
||||
|
||||
ot::status rc = ot::run_editor(editor, tags_path.c_str());
|
||||
if (rc != ot::st::ok)
|
||||
// Spawn the editor, and watch the modification timestamps.
|
||||
ot::status rc;
|
||||
timespec before, after;
|
||||
if ((rc = ot::get_file_timestamp(tags_path.c_str(), before)) != ot::st::ok)
|
||||
return rc;
|
||||
ot::status editor_rc = ot::run_editor(editor, tags_path.c_str());
|
||||
if ((rc = ot::get_file_timestamp(tags_path.c_str(), after)) != ot::st::ok)
|
||||
return rc; // probably because the file was deleted
|
||||
bool modified = (before.tv_sec != after.tv_sec || before.tv_nsec != after.tv_nsec);
|
||||
if (editor_rc != ot::st::ok) {
|
||||
if (modified)
|
||||
fprintf(stderr, "warning: Leaving %s on the disk.\n", tags_path.c_str());
|
||||
else
|
||||
remove(tags_path.c_str());
|
||||
return rc;
|
||||
} else if (!modified) {
|
||||
remove(tags_path.c_str());
|
||||
fputs("Cancelling edition because the tags file was not modified.\n", stderr);
|
||||
return ot::st::cancel;
|
||||
}
|
||||
|
||||
// Applying the new tags.
|
||||
tags_file = fopen(tags_path.c_str(), "r");
|
||||
if (tags_file == nullptr)
|
||||
return {ot::st::standard_error, "Error opening " + tags_path + ": " + strerror(errno)};
|
||||
@ -311,11 +325,6 @@ static ot::status edit_tags_interactively(ot::opus_tags& tags, const std::option
|
||||
}
|
||||
fclose(tags_file);
|
||||
|
||||
if (tags.comments.size() == 0) {
|
||||
remove(tags_path.c_str()); // it’s empty anyway
|
||||
return {ot::st::error, "Tag edition was cancelled because all the tags were deleted."};
|
||||
}
|
||||
|
||||
// Remove the temporary tags file only on success, because unlike the
|
||||
// partial Ogg file that is irrecoverable, the edited tags file
|
||||
// contains user data, so let’s leave users a chance to recover it.
|
||||
|
@ -27,6 +27,7 @@
|
||||
#include <iconv.h>
|
||||
#include <ogg/ogg.h>
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
|
||||
#include <functional>
|
||||
#include <list>
|
||||
@ -58,6 +59,7 @@ enum class st {
|
||||
error,
|
||||
standard_error, /**< Error raised by the C standard library. */
|
||||
int_overflow,
|
||||
cancel,
|
||||
/* System */
|
||||
badly_encoded,
|
||||
information_lost,
|
||||
@ -172,6 +174,12 @@ private:
|
||||
*/
|
||||
ot::status run_editor(const char* editor, const char* path);
|
||||
|
||||
/**
|
||||
* Return the specified path’s mtime, i.e. the last data modification
|
||||
* timestamp.
|
||||
*/
|
||||
ot::status get_file_timestamp(const char* path, timespec& mtime);
|
||||
|
||||
/** \} */
|
||||
|
||||
/***********************************************************************************************//**
|
||||
|
@ -177,3 +177,12 @@ ot::status ot::run_editor(const char* editor, const char* path)
|
||||
|
||||
return st::ok;
|
||||
}
|
||||
|
||||
ot::status ot::get_file_timestamp(const char* path, timespec& mtime)
|
||||
{
|
||||
struct stat st;
|
||||
if (stat(path, &st) == -1)
|
||||
return {st::standard_error, path + ": stat error: "s + strerror(errno)};
|
||||
mtime = st.st_mtim; // more precise than st_mtime
|
||||
return st::ok;
|
||||
}
|
||||
|
@ -14,7 +14,6 @@ add_executable(oggdump EXCLUDE_FROM_ALL oggdump.cc)
|
||||
target_link_libraries(oggdump ot)
|
||||
|
||||
configure_file(gobble.opus . COPYONLY)
|
||||
configure_file(emptier . COPYONLY)
|
||||
|
||||
add_custom_target(
|
||||
check
|
||||
|
@ -1,6 +0,0 @@
|
||||
#!/bin/sh
|
||||
cat > "$1" << EOF
|
||||
|
||||
# Here’s a file with nothing but comments and newlines.
|
||||
|
||||
EOF
|
@ -230,14 +230,12 @@ $ENV{EDITOR} = 'sed -i -e y/a/A/';
|
||||
is_deeply(opustags(qw(gobble.opus --add artist=aaah -o screaming.opus -e)), ['', '', 0], 'edit a file with EDITOR');
|
||||
is(md5('screaming.opus'), '682229df1df6b0ca147e2778737d449e', 'the tags were modified');
|
||||
|
||||
$ENV{EDITOR} = './emptier';
|
||||
is_deeply(opustags(qw(--add mystery=1 -i screaming.opus -e)), ['', "screaming.opus: error: Tag edition was cancelled because all the tags were deleted.\n", 256], 'edit a file with EDITOR');
|
||||
$ENV{EDITOR} = 'true';
|
||||
is_deeply(opustags(qw(--add mystery=1 -i screaming.opus -e)), ['', "Cancelling edition because the tags file was not modified.\n", 256], 'close -e without saving');
|
||||
is(md5('screaming.opus'), '682229df1df6b0ca147e2778737d449e', 'the tags were not modified');
|
||||
|
||||
$ENV{EDITOR} = '';
|
||||
unlink('screaming.opus');
|
||||
|
||||
|
||||
####################################################################################################
|
||||
# Test muxed streams
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user