From f06d92b70c0eb81e0c1a2741f0009ef25f67e3d7 Mon Sep 17 00:00:00 2001 From: Kjell Ahlstedt Date: Thu, 1 Sep 2022 14:58:06 +0200 Subject: Gio::File: Add create_tmp() * gio/src/file.[ccg|hg]: Add create_tmp(). Document create_for_parse_name(). * tests/giomm_simple/main.cc: Test File::create_tmp(). --- gio/src/file.ccg | 12 ++++++++++ gio/src/file.hg | 47 +++++++++++++++++++++++++++++++------ tests/giomm_simple/main.cc | 58 ++++++++++++++++++++++++++++++++++++++++++---- 3 files changed, 106 insertions(+), 11 deletions(-) diff --git a/gio/src/file.ccg b/gio/src/file.ccg index adef931e..8e8204a9 100644 --- a/gio/src/file.ccg +++ b/gio/src/file.ccg @@ -189,6 +189,18 @@ File::create_for_commandline_arg(const std::string& arg) return Glib::wrap(G_FILE(cfile)); } +std::pair, Glib::RefPtr> +File::create_tmp(const std::string& tmpl) +{ + GError* gerror = nullptr; + GFileIOStream* ciostream = nullptr; + GFile* cfile = g_file_new_tmp(tmpl.empty() ? nullptr : tmpl.c_str(), &ciostream, &gerror); + if (gerror) + ::Glib::Error::throw_exception(gerror); + + return {Glib::wrap(cfile), Glib::wrap(ciostream)}; +} + Glib::RefPtr File::create_for_parse_name(const Glib::ustring& parse_name) { diff --git a/gio/src/file.hg b/gio/src/file.hg index 0f9997cd..0ff074f2 100644 --- a/gio/src/file.hg +++ b/gio/src/file.hg @@ -28,6 +28,7 @@ #include #include #include //Because this is thrown by some of these methods. +#include _DEFS(giomm,gio) _PINCLUDE(glibmm/private/interface_p.h) @@ -46,21 +47,21 @@ _WRAP_ENUM(FileQueryInfoFlags, GFileQueryInfoFlags, NO_GTYPE, decl_prefix GIOMM_ _WRAP_ENUM(FileMonitorFlags, GFileMonitorFlags, NO_GTYPE, decl_prefix GIOMM_API) -/** File and directory handling. - * Gio::File is a high level abstraction for manipulating files on a virtual file system. Gio::Files are lightweight, immutable objects that do no - * I/O upon creation. It is necessary to understand that a Gio::File object does not represent a file, merely a handle to a file. All file I/O is +/** %File and directory handling. + * %Gio::File is a high level abstraction for manipulating files on a virtual file system. Gio::Files are lightweight, immutable objects that do no + * I/O upon creation. It is necessary to understand that a %Gio::File object does not represent a file, merely a handle to a file. All file I/O is * implemented as streaming operations (see Gio::InputStream and Gio::OutputStream). * - * A GioFile can be constructed from a path, URI, or a command line argument. + * A %Gio::File can be constructed from a path, URI, or a command line argument. * - * You can move through the filesystem with Gio::File handles with get_parent() to get a handle to the parent directory, + * You can move through the filesystem with %Gio::File handles with get_parent() to get a handle to the parent directory, * get_child() to get a handle to a child within a directory, and resolve_relative_path() to resolve a relative path between two Gio::Files. * - * Many Gio::File operations have both synchronous and asynchronous versions to suit your application. Asynchronous versions of synchronous + * Many %Gio::File operations have both synchronous and asynchronous versions to suit your application. Asynchronous versions of synchronous * functions simply have _async() appended to their function names. The asynchronous I/O functions call a SlotAsyncReady callback slot which is * then used to finalize the operation, producing a AsyncResult which is then passed to the function's matching _finish() operation. * - * Some Gio::File operations do not have synchronous analogs, as they may take a very long time to finish, and blocking may leave an application + * Some %Gio::File operations do not have synchronous analogs, as they may take a very long time to finish, and blocking may leave an application * unusable. Notable cases include: mount_mountable() to mount a mountable file, unmount_mountable() to unmount a mountable file, * and eject_mountable() to eject a mountable file. * @@ -115,11 +116,43 @@ public: static Glib::RefPtr create_for_commandline_arg(const std::string& arg); _IGNORE(g_file_new_for_commandline_arg) + /** Constructs a file in the preferred directory for temporary files. + * + * The file is created in the directory returned by Glib::get_tmp_dir(). + * A FileIOStream pointing to the file is also created. + * + * @a tmpl should be a string in the GLib file name encoding + * containing a sequence of six 'X' characters, and containing no + * directory components. If it is an empty string, a default template is used. + * + * Unlike the other %File constructors, this will throw an exception if + * a temporary file could not be created. + * + * @newin{2,74} + * + * @param tmpl Template for the file name, as in Glib::file_open_tmp(), + * or an empty string for a default template. + * @return {file, iostream} A new %File and a FileIOStream for the created file. + * + * @throws Glib::FileError + */ + static std::pair, Glib::RefPtr> create_tmp(const std::string& tmpl = {}); + _IGNORE(g_file_new_tmp) + // parse_name is a UTF8-guaranteed "nice" string that can both // be resolved to a GFile (via create_for_parse_name) and put in // e.g. a GtkEntry. In practice, it is either a UTF8-only absolute // filename (if it starts with a /), or an IRI (i.e. a URI that allows // UTF8-encoded unicode chars instead of escaping them). + /** Constructs a %File with the given @a parse_name. + * + * The @a parse_name is something given by get_parse_name(). + * This operation never fails, but the returned object might not support any + * I/O operation if the @a parse_name cannot be parsed. + * + * @param parse_name A UTF-8 encoded file name or path to be parsed. + * @return A new %File. + */ static Glib::RefPtr create_for_parse_name(const Glib::ustring& parse_name); _IGNORE(g_file_parse_name) diff --git a/tests/giomm_simple/main.cc b/tests/giomm_simple/main.cc index 0a73cb51..7d28466a 100644 --- a/tests/giomm_simple/main.cc +++ b/tests/giomm_simple/main.cc @@ -1,6 +1,6 @@ #include #include -#include +#include // Use this line if you want debug output: // std::ostream& ostr = std::cout; @@ -37,9 +37,9 @@ main(int, char**) return EXIT_FAILURE; } - gchar buffer[1000]; // TODO: This is unpleasant. - memset(buffer, 0, sizeof buffer); - const gsize bytes_read = stream->read(buffer, sizeof buffer - 1); + char buffer[1000]; // TODO: This is unpleasant. + std::memset(buffer, 0, sizeof buffer); + const gssize bytes_read = stream->read(buffer, sizeof buffer - 1); if (bytes_read) ostr << "File contents read: " << buffer << std::endl; @@ -55,5 +55,55 @@ main(int, char**) return EXIT_FAILURE; } + // Test temporary file. + try + { + auto [file, iostream] = Gio::File::create_tmp(); + if (!file || !iostream) + { + std::cerr << "Gio::File::create_tmp() returned an empty RefPtr." << std::endl; + return EXIT_FAILURE; + } + ostr << "Tmp file parse name: " << file->get_parse_name() << std::endl; + + auto input_stream = iostream->get_input_stream(); + auto output_stream = iostream->get_output_stream(); + + // Write to the temporary file. + const std::string tmp_string = "This is a temporary file."; + const gssize bytes_written = output_stream->write(tmp_string); + if (bytes_written != static_cast(tmp_string.size())) + { + std::cerr << "Gio::OutputStream::write() wrote: " << bytes_written + << " bytes. Should write " << tmp_string.size() << " bytes." + << std::endl; + return EXIT_FAILURE; + } + output_stream->flush(); + iostream->seek(0, Glib::SeekType::SET); + + // Read what was written. + char buffer[100]; + std::memset(buffer, 0, sizeof buffer); + const gssize bytes_read = input_stream->read(buffer, sizeof buffer - 1); + ostr << "Tmp file contents read: " << buffer << std::endl; + if (bytes_read != bytes_written || buffer != tmp_string) + { + std::cerr << "Gio::InputStream::read() read: " << buffer << std::endl; + return EXIT_FAILURE; + } + file->remove(); + } + catch (const Glib::FileError& ex) + { + std::cerr << "Glib::FileError exception caught: " << ex.what() << std::endl; + return EXIT_FAILURE; + } + catch (const Glib::Error& ex) + { + std::cerr << "Glib::Error exception caught: " << ex.what() << std::endl; + return EXIT_FAILURE; + } + return EXIT_SUCCESS; } -- cgit v1.2.1