mirror of
				https://github.com/fmang/opustags.git
				synced 2025-10-31 08:58:12 +01:00 
			
		
		
		
	Cancel --edit when the editor closes without saving
This commit is contained in:
		
							
								
								
									
										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 | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user