pax_global_header00006660000000000000000000000064151661342620014520gustar00rootroot0000000000000052 comment=ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87 libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/000077500000000000000000000000001516613426200224225ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/LICENSES/000077500000000000000000000000001516613426200236275ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/LICENSES/LGPL-3.0-or-later.txt000066400000000000000000000164071516613426200271570ustar00rootroot00000000000000GNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. This version of the GNU Lesser General Public License incorporates the terms and conditions of version 3 of the GNU General Public License, supplemented by the additional permissions listed below. 0. Additional Definitions. As used herein, "this License" refers to version 3 of the GNU Lesser General Public License, and the "GNU GPL" refers to version 3 of the GNU General Public License. "The Library" refers to a covered work governed by this License, other than an Application or a Combined Work as defined below. An "Application" is any work that makes use of an interface provided by the Library, but which is not otherwise based on the Library. Defining a subclass of a class defined by the Library is deemed a mode of using an interface provided by the Library. A "Combined Work" is a work produced by combining or linking an Application with the Library. The particular version of the Library with which the Combined Work was made is also called the "Linked Version". The "Minimal Corresponding Source" for a Combined Work means the Corresponding Source for the Combined Work, excluding any source code for portions of the Combined Work that, considered in isolation, are based on the Application, and not on the Linked Version. The "Corresponding Application Code" for a Combined Work means the object code and/or source code for the Application, including any data and utility programs needed for reproducing the Combined Work from the Application, but excluding the System Libraries of the Combined Work. 1. Exception to Section 3 of the GNU GPL. You may convey a covered work under sections 3 and 4 of this License without being bound by section 3 of the GNU GPL. 2. Conveying Modified Versions. If you modify a copy of the Library, and, in your modifications, a facility refers to a function or data to be supplied by an Application that uses the facility (other than as an argument passed when the facility is invoked), then you may convey a copy of the modified version: a) under this License, provided that you make a good faith effort to ensure that, in the event an Application does not supply the function or data, the facility still operates, and performs whatever part of its purpose remains meaningful, or b) under the GNU GPL, with none of the additional permissions of this License applicable to that copy. 3. Object Code Incorporating Material from Library Header Files. The object code form of an Application may incorporate material from a header file that is part of the Library. You may convey such object code under terms of your choice, provided that, if the incorporated material is not limited to numerical parameters, data structure layouts and accessors, or small macros, inline functions and templates (ten or fewer lines in length), you do both of the following: a) Give prominent notice with each copy of the object code that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the object code with a copy of the GNU GPL and this license document. 4. Combined Works. You may convey a Combined Work under terms of your choice that, taken together, effectively do not restrict modification of the portions of the Library contained in the Combined Work and reverse engineering for debugging such modifications, if you also do each of the following: a) Give prominent notice with each copy of the Combined Work that the Library is used in it and that the Library and its use are covered by this License. b) Accompany the Combined Work with a copy of the GNU GPL and this license document. c) For a Combined Work that displays copyright notices during execution, include the copyright notice for the Library among these notices, as well as a reference directing the user to the copies of the GNU GPL and this license document. d) Do one of the following: 0) Convey the Minimal Corresponding Source under the terms of this License, and the Corresponding Application Code in a form suitable for, and under terms that permit, the user to recombine or relink the Application with a modified version of the Linked Version to produce a modified Combined Work, in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source. 1) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (a) uses at run time a copy of the Library already present on the user's computer system, and (b) will operate properly with a modified version of the Library that is interface-compatible with the Linked Version. e) Provide Installation Information, but only if you would otherwise be required to provide such information under section 6 of the GNU GPL, and only to the extent that such information is necessary to install and execute a modified version of the Combined Work produced by recombining or relinking the Application with a modified version of the Linked Version. (If you use option 4d0, the Installation Information must accompany the Minimal Corresponding Source and Corresponding Application Code. If you use option 4d1, you must provide the Installation Information in the manner specified by section 6 of the GNU GPL for conveying Corresponding Source.) 5. Combined Libraries. You may place library facilities that are a work based on the Library side by side in a single library together with other library facilities that are not Applications and are not covered by this License, and convey such a combined library under terms of your choice, if you do both of the following: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities, conveyed under the terms of this License. b) Give prominent notice with the combined library that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 6. Revised Versions of the GNU Lesser General Public License. The Free Software Foundation may publish revised and/or new versions of the GNU Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library as you received it specifies that a certain numbered version of the GNU Lesser General Public License "or any later version" applies to it, you have the option of following the terms and conditions either of that published version or of any later version published by the Free Software Foundation. If the Library as you received it does not specify a version number of the GNU Lesser General Public License, you may choose any version of the GNU Lesser General Public License ever published by the Free Software Foundation. If the Library as you received it specifies that a proxy can decide whether future versions of the GNU Lesser General Public License shall apply, that proxy's public statement of acceptance of any version is permanent authorization for you to choose that version for the Library. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/NEWS000066400000000000000000000023711516613426200231240ustar00rootroot00000000000000libgedit-gfls news News in 0.4.1, 2026-04-10 ------------------------- - Fix a unit test on big-endian architectures. - Translation updates. News in 0.4.0, 2026-03-27 ------------------------- - New features: GflsBytesRegion, GflsBytesRegionBuilder and GflsEncodingConvert. - New features imported from libgedit-gtksourceview: GflsIconv. - GflsInputStream: import improved version from libgedit-gtksourceview. - Translation updates. News in 0.3.1, 2025-11-17 ------------------------- - Translation updates. News in 0.3.0, 2025-03-08 ------------------------- - Improve some parts of the library (see the reference manual for changes). - Experiment with new Encoding interfaces and classes, but the code has been removed (a simpler approach is planned). - Improve the documentation. - Write more unit tests. - Translation updates. News in 0.2.1, 2024-12-07 ------------------------- - Translation updates. News in 0.2.0, 2024-08-31 ------------------------- - New classes and interfaces: GflsAttributeKeys, GflsLoaderConfig, GflsLoaderConfigSimple. - Build: add tests option. - Do some planning, write some notes. News in 0.1.0, 2024-04-27 (stable version) ------------------------------------------ - First version. - See the API reference for what's included. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/README.md000066400000000000000000000006761516613426200237120ustar00rootroot00000000000000libgedit-gfls ============= Short description ----------------- Gedit Technology - File loading and saving Longer description ------------------ libgedit-gfls is part of [Gedit Technology](https://gedit-text-editor.org/technology.html). It is a module dedicated to file loading and saving for the needs of gedit and other similar text editors. Dependencies ------------ - GLib/GIO (required) - GTK 3 (optional, used for interactive tests) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/build/000077500000000000000000000000001516613426200235215ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/build/.gitignore000066400000000000000000000000021516613426200255010ustar00rootroot00000000000000* libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/000077500000000000000000000000001516613426200233525ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/file-loading.md000066400000000000000000000014771516613426200262370ustar00rootroot00000000000000libgedit-gfls :: file loading TODO list ======================================= File loading steps ------------------ Name: GflsLoadingDriver, or GflsLoadingManager, or GflsLoader. Steps: 1. Create a GflsLoaderConfig(Simple). 2. (Optional) If GFile as input, query the GFileInfo. 3. (Optional) Check the GFileInfo against the GflsLoaderConfig(Simple) (check the file size). 4. Load all the raw content into memory (with max size). 5. (Optional) Transform if needed the raw content into the final content suitable to be inserted into a GtkTextBuffer (encoding conversion, splitting very long lines, escaping invalid characters and maybe others, keeping the relevant information along the way in order to reverse the operation - or show an error - upon saving). 6. Insert the final content into the GtkTextBuffer. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/generic-and-extensible.md000066400000000000000000000013061516613426200302100ustar00rootroot00000000000000libgedit-gfls :: generic and extensible API =========================================== Have for Gfls a **generic** and **extensible** API. Assumptions ----------- - Assume **GIO** use, in all cases. - Assume the intention to work with **text** (but allow workarounds if there are invalid chars). Use-case -------- Tepl has a framework (so with an inversion of control), with TeplAbstractFactory that apps subclass to customize the default behavior of Tepl. For a high-level file loading and saving API, Tepl can thus call the generic Gfls functions (i.e., probably just using interfaces, not concrete classes), and call TeplAbstractFactory functions to create and configure the concrete Gfls objects. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/low-level-features.md000066400000000000000000000017431516613426200274230ustar00rootroot00000000000000libgedit-gfls :: low-level features =================================== Done ---- Loading: provide a maximum number of bytes to read, and get a GBytes as a result, knowing if it is truncated. Loading: detect if there is a very long line in a UTF-8 string. To implement ------------ Have a list of encodings. Loading: encoding auto-detection. Loading: check if the content is valid in a given encoding (useful if the user explicitly asks for a certain encoding). Loading: encoding conversion to UTF-8. Loading: detect BOM. Split a GBytes into a list of chunks. Each chunk contains: - a GBytes - a boolean to tell if the GBytes is a valid UTF-8 string. To isolate invalid chars. Further split the list of chunks to isolate very long lines (in UTF-8) into their own chunks. Transform a very-long-line chunk with the line split at a certain column, and with a certain algorithm to split the line (at chars or word-chars). Adding a boolean to tell that the very long line has been split. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/low-level-kit.md000066400000000000000000000015361516613426200263740ustar00rootroot00000000000000libgedit-gfls :: low-level kit ============================== There is some desire to create something: - Generic and extensible. - With a clear split between the backend and frontend. But where libgedit-gfls is located on the stack, it makes more sense to provide a low-level "kit" (above GIO and libICU, probably not GTK). That is, no interfaces, just concrete classes and functions (the "meat"). Providing useful utilities and building blocks. Solving specific and independent problems that anyway need to be solved ("divide and conquer"). Then in libgedit-tepl the building blocks can be assembled, creating a high-level API, something generic and extensible by the application, and so on. Integration ----------- To see the finish line, it is necessary to **integrate** the different features. Incrementally/progressively, not all at once at the end. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/names.md000066400000000000000000000016211516613426200247770ustar00rootroot00000000000000libgedit-gfls :: names brainstorming ==================================== - GflsInfo, replacing GtkSourceFile or TeplFile. In the latter implementations, there is the ambiguity between a GFile (called a "location") and a TeplFile object (called "file"). With GflsInfo, a GFile object would remain to be called a "file", simply. And GflsInfo reflect the fact that it gathers a GFileInfo (basically) for later use. - GflsFile to extend GFile with more functions. - GflsLoader interface (that takes a GflsLoaderConfig as an input), with GflsLoaderBasic for dealing with UTF-8 only. - Driver: like a compiler driver that invokes several smaller programs. Have a driver for loading, and a driver for saving, that invoke smaller utilities with phases. The utilities are just classes and functions to be called (in the same process). A bit like a "Manager" class, except that the name is shorter. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/000077500000000000000000000000001516613426200253105ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/libgedit-gfls-docs.xml000066400000000000000000000050611516613426200314760ustar00rootroot00000000000000 %gtkdocentities; ]> libgedit-gfls &package_api_version; Reference Manual For &package_string; At the current stage of development of libgedit-gfls, the API is experimental. There are no API stability guarantees. And there can be unfinished features. libgedit-gfls API Reference Annexes Object Hierarchy Index of all symbols Index of new symbols in 0.1 Index of new symbols in 0.2 Index of new symbols in 0.3 Index of new symbols in 0.4 libgedit-gfls-sections.txt000066400000000000000000000065021516613426200323360ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/referencegfls/gfls.h
gfls-attribute-keys GflsAttributeKeys gfls_attribute_keys_new gfls_attribute_keys_add gfls_attribute_keys_to_string GFLS_ATTRIBUTE_KEYS GFLS_ATTRIBUTE_KEYS_CLASS GFLS_ATTRIBUTE_KEYS_GET_CLASS GFLS_IS_ATTRIBUTE_KEYS GFLS_IS_ATTRIBUTE_KEYS_CLASS GFLS_TYPE_ATTRIBUTE_KEYS GflsAttributeKeysClass GflsAttributeKeysPrivate gfls_attribute_keys_get_type
gfls-bytes-region GflsBytesRegion GflsBytesRegionIter gfls_bytes_region_free gfls_bytes_region_match_bytes gfls_bytes_region_to_string gfls_bytes_region_get_start_iter gfls_bytes_region_iter_is_end gfls_bytes_region_iter_get_sub_region gfls_bytes_region_iter_next gfls_bytes_region_iter_free
gfls-bytes-region-builder GflsBytesRegionBuilder gfls_bytes_region_builder_new gfls_bytes_region_builder_append gfls_bytes_region_builder_get_current_size gfls_bytes_region_builder_free
gfls-encoding-convert gfls_encoding_try_convert gfls_encoding_convert
gfls-iconv GflsIconv GflsIconvResult gfls_iconv_new gfls_iconv_open gfls_iconv_feed gfls_iconv_feed_discard_output gfls_iconv_close gfls_iconv_free GFLS_TYPE_ICONV_RESULT gfls_iconv_result_get_type
gfls-init gfls_init gfls_finalize GFLS_H_INSIDE
gfls-input-stream GflsSimpleProgressCallback gfls_input_stream_read_async gfls_input_stream_read_finish
gfls-loader-basic GFLS_LOADER_ERROR GflsLoaderError gfls_loader_basic_load_async gfls_loader_basic_load_finish GFLS_TYPE_LOADER_ERROR gfls_loader_error_get_type gfls_loader_error_quark
gfls-loader-config GflsLoaderConfig GflsLoaderConfigInterface GFLS_IS_LOADER_CONFIG GFLS_LOADER_CONFIG GFLS_LOADER_CONFIG_GET_INTERFACE GFLS_TYPE_LOADER_CONFIG gfls_loader_config_get_type
gfls-loader-config-simple GflsLoaderConfigSimple gfls_loader_config_simple_new_from_file gfls_loader_config_simple_new_from_stream gfls_loader_config_simple_get_file gfls_loader_config_simple_get_stream GFLS_IS_LOADER_CONFIG_SIMPLE GFLS_IS_LOADER_CONFIG_SIMPLE_CLASS GFLS_LOADER_CONFIG_SIMPLE GFLS_LOADER_CONFIG_SIMPLE_CLASS GFLS_LOADER_CONFIG_SIMPLE_GET_CLASS GFLS_TYPE_LOADER_CONFIG_SIMPLE GflsLoaderConfigSimpleClass GflsLoaderConfigSimplePrivate gfls_loader_config_simple_get_type
gfls-unsaved-document-titles GflsUnsavedDocumentTitles GflsUnsavedDocumentTitleCallback gfls_unsaved_document_titles_new gfls_unsaved_document_titles_get_default gfls_unsaved_document_titles_allocate_number gfls_unsaved_document_titles_release_number gfls_unsaved_document_titles_get_title gfls_unsaved_document_titles_set_title_callback GFLS_IS_UNSAVED_DOCUMENT_TITLES GFLS_IS_UNSAVED_DOCUMENT_TITLES_CLASS GFLS_TYPE_UNSAVED_DOCUMENT_TITLES GFLS_UNSAVED_DOCUMENT_TITLES GFLS_UNSAVED_DOCUMENT_TITLES_CLASS GFLS_UNSAVED_DOCUMENT_TITLES_GET_CLASS GflsUnsavedDocumentTitlesClass GflsUnsavedDocumentTitlesPrivate gfls_unsaved_document_titles_get_type
gfls-utf8 gfls_utf8_find_very_long_line
libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/meson.build000066400000000000000000000022431516613426200274530ustar00rootroot00000000000000subdir('xml') FS.copyfile( 'libgedit-gfls-sections.txt', 'libgedit-gfls-@0@-sections.txt'.format(GFLS_API_VERSION) ) gtkdoc_module_name = 'libgedit-gfls-@0@'.format(GFLS_API_VERSION) html_dir = get_option('prefix') / GNOME.gtkdoc_html_dir(gtkdoc_module_name) glib_docpath = dependency('glib-2.0').get_variable(pkgconfig: 'prefix') / 'share/gtk-doc/html/glib' gobject_docpath = dependency('gobject-2.0').get_variable(pkgconfig: 'prefix') / 'share/gtk-doc/html/gobject' gio_docpath = dependency('gio-2.0').get_variable(pkgconfig: 'prefix') / 'share/gtk-doc/html/gio' #gtk_docpath = dependency('gtk+-3.0').get_variable(pkgconfig: 'prefix') / 'share/gtk-doc/html/gtk3' GNOME.gtkdoc( gtkdoc_module_name, main_xml: 'libgedit-gfls-docs.xml', src_dir: include_directories('../../gfls/'), dependencies: GFLS_LIB_DEP, scan_args: ['--rebuild-types'], gobject_typesfile: 'libgedit-gfls-@0@.types'.format(GFLS_API_VERSION), fixxref_args: [ '--html-dir=@0@'.format(html_dir), '--extra-dir=@0@'.format(glib_docpath), '--extra-dir=@0@'.format(gobject_docpath), '--extra-dir=@0@'.format(gio_docpath), ], ignore_headers: [GFLS_PRIVATE_HEADERS], install: true ) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/xml/000077500000000000000000000000001516613426200261105ustar00rootroot00000000000000gtkdocentities.ent.in000066400000000000000000000001421516613426200321630ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/xml libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/reference/xml/meson.build000066400000000000000000000006401516613426200302520ustar00rootroot00000000000000gtkdocentities_conf_data = configuration_data() gtkdocentities_conf_data.set('PACKAGE_STRING', '@0@ @1@'.format(meson.project_name(), meson.project_version())) gtkdocentities_conf_data.set('PACKAGE_API_VERSION', GFLS_API_VERSION) gtkdocentities_filename = 'gtkdocentities.ent' configure_file( input: gtkdocentities_filename + '.in', output: gtkdocentities_filename, configuration: gtkdocentities_conf_data ) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/docs/split-backend-frontend.md000066400000000000000000000017401516613426200302330ustar00rootroot00000000000000libgedit-gfls :: split backend from frontend ============================================ To allow the possibility of a GTK 3 and GTK 4 frontends, sharing the single codebase for the backend (based on GLib/GIO and libICU). First idea ---------- Have two main headers, something like that: ``` #include #include ``` Inspired by libpeas 1.x. Second idea ----------- - The Gfls lib contains only the backend, it must not depend on GTK. - Implement the GTK 3 frontend in Tepl (where TeplInfoBar is directly available, and the libgedit-gtksourceview API too). The backend still has GtkTextView and its limitations in mind. Example: - Instead of providing at the end a single UTF-8 string (which is not possible in certain cases like invalid chars that need to be escaped), provide _a list_ of a data structure containing: a GBytes, boolean infos such as whether it is valid UTF-8, whether it's a very long line that has already been split, etc. libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/000077500000000000000000000000001516613426200233555ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-attribute-keys.c000066400000000000000000000066311516613426200274340ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-attribute-keys.h" /** * SECTION:gfls-attribute-keys * @Title: GflsAttributeKeys * @Short_description: A list of #GFile attribute keys * * #GflsAttributeKeys is a small utility to build a list of #GFile attribute * keys. The result is a single string to pass as an argument to a function like * g_file_query_info(). * * It is useful for doing only a single query with a list of keys coming from * different parts of the program. To take an example, libgedit-gfls might have * its own list of keys to query, but it is desirable to ask the application for * additional keys. */ /* Rationale * ========= * * The goal is to get desired #GFileInfo attributes in one query. * * Reasons to do it in one query: * 1. To avoid unnecessary round-trips (?) (especially for remote files). * Actually I don't know how it is implemented in GIO and GVfs. In case of * doubt a single query is better since the implementation has the * *possibility* to optimize network usage. * 2. For convenience in the implementation, to just call one pair of * async()/finish() functions for that task. */ struct _GflsAttributeKeysPrivate { /* Element-type: "owned gchar *" */ GPtrArray *array; }; G_DEFINE_TYPE_WITH_PRIVATE (GflsAttributeKeys, gfls_attribute_keys, G_TYPE_OBJECT) static void gfls_attribute_keys_finalize (GObject *object) { GflsAttributeKeys *keys = GFLS_ATTRIBUTE_KEYS (object); g_clear_pointer (&keys->priv->array, g_ptr_array_unref); G_OBJECT_CLASS (gfls_attribute_keys_parent_class)->finalize (object); } static void gfls_attribute_keys_class_init (GflsAttributeKeysClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gfls_attribute_keys_finalize; } static void gfls_attribute_keys_init (GflsAttributeKeys *keys) { keys->priv = gfls_attribute_keys_get_instance_private (keys); keys->priv->array = g_ptr_array_new_null_terminated (0, g_free, TRUE); } /** * gfls_attribute_keys_new: * * Returns: (transfer full): a new #GflsAttributeKeys object. * Since: 0.2 */ GflsAttributeKeys * gfls_attribute_keys_new (void) { return g_object_new (GFLS_TYPE_ATTRIBUTE_KEYS, NULL); } /** * gfls_attribute_keys_add: * @keys: a #GflsAttributeKeys. * @str: the value to add. * * Adds @str to @keys. * * @str has the same semantics as the corresponding parameter of * g_file_query_info(). * * Since: 0.2 */ void gfls_attribute_keys_add (GflsAttributeKeys *keys, const gchar *str) { g_return_if_fail (GFLS_IS_ATTRIBUTE_KEYS (keys)); g_return_if_fail (str != NULL); g_ptr_array_add (keys->priv->array, g_strdup (str)); } /** * gfls_attribute_keys_to_string: * @keys: a #GflsAttributeKeys. * * Returns: (transfer full) (nullable): the complete string to pass to * g_file_query_info() (for example), or %NULL if the list is empty. * Since: 0.2 */ gchar * gfls_attribute_keys_to_string (GflsAttributeKeys *keys) { g_return_val_if_fail (GFLS_IS_ATTRIBUTE_KEYS (keys), NULL); if (keys->priv->array->len == 0) { return NULL; } /* The list is *not* optimized here (to remove duplicates, simplify when * there are wildcards, etc). It is already optimized in GIO, but as an * implementation detail: by g_file_attribute_matcher_new(), which is * called by g_file_query_info(). */ return g_strjoinv (",", (gchar **) keys->priv->array->pdata); } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-attribute-keys.h000066400000000000000000000033541516613426200274400ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_ATTRIBUTE_KEYS_H #define GFLS_ATTRIBUTE_KEYS_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define GFLS_TYPE_ATTRIBUTE_KEYS (gfls_attribute_keys_get_type ()) #define GFLS_ATTRIBUTE_KEYS(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GFLS_TYPE_ATTRIBUTE_KEYS, GflsAttributeKeys)) #define GFLS_ATTRIBUTE_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFLS_TYPE_ATTRIBUTE_KEYS, GflsAttributeKeysClass)) #define GFLS_IS_ATTRIBUTE_KEYS(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GFLS_TYPE_ATTRIBUTE_KEYS)) #define GFLS_IS_ATTRIBUTE_KEYS_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFLS_TYPE_ATTRIBUTE_KEYS)) #define GFLS_ATTRIBUTE_KEYS_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFLS_TYPE_ATTRIBUTE_KEYS, GflsAttributeKeysClass)) typedef struct _GflsAttributeKeys GflsAttributeKeys; typedef struct _GflsAttributeKeysClass GflsAttributeKeysClass; typedef struct _GflsAttributeKeysPrivate GflsAttributeKeysPrivate; struct _GflsAttributeKeys { GObject parent; GflsAttributeKeysPrivate *priv; }; struct _GflsAttributeKeysClass { GObjectClass parent_class; gpointer padding[12]; }; G_MODULE_EXPORT GType gfls_attribute_keys_get_type (void); G_MODULE_EXPORT GflsAttributeKeys * gfls_attribute_keys_new (void); G_MODULE_EXPORT void gfls_attribute_keys_add (GflsAttributeKeys *keys, const gchar *str); G_MODULE_EXPORT gchar * gfls_attribute_keys_to_string (GflsAttributeKeys *keys); G_END_DECLS #endif /* GFLS_ATTRIBUTE_KEYS_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-bytes-region-builder.c000066400000000000000000000075011516613426200305100ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-bytes-region-builder.h" #include "gfls-bytes-region-private.h" /** * SECTION:gfls-bytes-region-builder * @Title: GflsBytesRegionBuilder * @Short_description: Builds #GflsBytesRegion objects * * Builds #GflsBytesRegion objects. */ struct _GflsBytesRegionBuilder { GArray *sub_regions; /* (element-type GflsBytesSubRegionBounds) */ gsize current_position; }; /** * gfls_bytes_region_builder_new: (skip) * * Returns: (transfer full): a new #GflsBytesRegionBuilder. * Since: 0.4 */ GflsBytesRegionBuilder * gfls_bytes_region_builder_new (void) { GflsBytesRegionBuilder *builder; builder = g_new0 (GflsBytesRegionBuilder, 1); builder->sub_regions = g_array_new (FALSE, FALSE, sizeof (GflsBytesSubRegionBounds)); return builder; } /** * gfls_bytes_region_builder_free: (skip) * @builder: (nullable): a #GflsBytesRegionBuilder. * @free_data: if %TRUE, the data is freed as well. * * Creates a #GflsBytesRegion and frees @builder. * * Returns: (transfer full) (nullable): a #GflsBytesRegion, or %NULL if * @free_data is %TRUE. * Since: 0.4 */ GflsBytesRegion * gfls_bytes_region_builder_free (GflsBytesRegionBuilder *builder, gboolean free_data) { GflsBytesRegion *region = NULL; if (builder == NULL) { return NULL; } if (!free_data) { region = _gfls_bytes_region_new (builder->sub_regions, builder->current_position); } g_array_unref (builder->sub_regions); g_free (builder); return region; } /** * gfls_bytes_region_builder_append: * @builder: a #GflsBytesRegionBuilder. * @sub_region_length: the length of the sub-region. Must not be equal to 0. * @is_part_of_region: whether the sub-region is part of the region. * * Appends a sub-region at the end. * * If @is_part_of_region is %FALSE it creates a hole. * * Contiguous sub-regions of the same kind are merged and will thus be treated * as a single sub-region. So you can conveniently call this function several * times in a row with the same value for @is_part_of_region. * * In order to create a #GflsBytesRegion that will traverse a whole #GBytes, it * is required to call this function the right amount of times, even if it ends * with a hole. See also gfls_bytes_region_match_bytes(). * * Since: 0.4 */ void gfls_bytes_region_builder_append (GflsBytesRegionBuilder *builder, gsize sub_region_length, gboolean is_part_of_region) { gsize next_position = 0; g_return_if_fail (builder != NULL); g_return_if_fail (sub_region_length != 0); if (!g_size_checked_add (&next_position, builder->current_position, sub_region_length)) { g_warning ("Ignoring the sub-region because of an integer overflow."); return; } if (is_part_of_region) { GflsBytesSubRegionBounds *last_sub_region = NULL; if (builder->sub_regions->len != 0) { last_sub_region = &g_array_index (builder->sub_regions, GflsBytesSubRegionBounds, builder->sub_regions->len - 1); } /* Merge */ if (last_sub_region != NULL && last_sub_region->end == builder->current_position) { last_sub_region->end = next_position; } /* Insert new sub-region */ else { GflsBytesSubRegionBounds new_sub_region; new_sub_region.start = builder->current_position; new_sub_region.end = next_position; g_array_append_val (builder->sub_regions, new_sub_region); } } builder->current_position = next_position; } /** * gfls_bytes_region_builder_get_current_size: * @builder: a #GflsBytesRegionBuilder. * * Returns: the current total size, in number of bytes (holes included). * Since: 0.4 */ gsize gfls_bytes_region_builder_get_current_size (GflsBytesRegionBuilder *builder) { g_return_val_if_fail (builder != NULL, 0); return builder->current_position; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-bytes-region-builder.h000066400000000000000000000016111516613426200305110ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS typedef struct _GflsBytesRegionBuilder GflsBytesRegionBuilder; G_MODULE_EXPORT GflsBytesRegionBuilder * gfls_bytes_region_builder_new (void); G_MODULE_EXPORT GflsBytesRegion * gfls_bytes_region_builder_free (GflsBytesRegionBuilder *builder, gboolean free_data); G_MODULE_EXPORT void gfls_bytes_region_builder_append (GflsBytesRegionBuilder *builder, gsize sub_region_length, gboolean is_part_of_region); G_MODULE_EXPORT gsize gfls_bytes_region_builder_get_current_size (GflsBytesRegionBuilder *builder); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-bytes-region-private.h000066400000000000000000000005661516613426200305450ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #include #include "gfls-bytes-region.h" G_BEGIN_DECLS typedef struct { gsize start; gsize end; } GflsBytesSubRegionBounds; G_GNUC_INTERNAL GflsBytesRegion * _gfls_bytes_region_new (GArray *sub_regions, gsize total_size); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-bytes-region.c000066400000000000000000000262421516613426200270670ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-bytes-region.h" #include "gfls-bytes-region-private.h" /** * SECTION:gfls-bytes-region * @Title: GflsBytesRegion * @Short_description: A group of sub-regions of a #GBytes * * #GflsBytesRegion permits to store a group of sub-regions of a #GBytes. Use a * #GflsBytesRegionBuilder to construct a #GflsBytesRegion. * * Use-case: the region delimits valid (or invalid) bytes in a specified * character encoding, possibly after a conversion (or at least a validation). * * To iterate through the sub-regions, you need to use a #GflsBytesRegionIter: * |[ * GflsBytesRegion *region; * GflsBytesRegionIter *iter; * GBytes *bytes; * * if (!gfls_bytes_region_match_bytes (region, bytes)) * { * return; * } * * iter = gfls_bytes_region_get_start_iter (region); * * while (!gfls_bytes_region_iter_is_end (region, iter)) * { * gsize sub_region_size = 0; * gsize offset = 0; * gboolean is_part_of_region = FALSE; * gconstpointer sub_region_data; * * gfls_bytes_region_iter_get_sub_region (region, * iter, * &sub_region_size, * &offset, * &is_part_of_region); * * sub_region_data = g_bytes_get_region (bytes, * sub_region_size, * offset, * 1); * * // Do something useful with the sub-region. * * gfls_bytes_region_iter_next (region, iter); * } * * gfls_bytes_region_iter_free (region, iter); * ]| * * This traverses the #GBytes from start to end. @is_part_of_region permits to * know if the sub-region is part of the #GflsBytesRegion or if it is a "hole". * (A hole doesn't mean that there are no bytes, the meaning depends on the * use-case). */ struct _GflsBytesRegion { GArray *sub_regions; /* (element-type GflsBytesSubRegionBounds) */ gsize total_size; }; /* Example: * - GflsBytesRegion's @sub_regions is: [1, 3], [4, 5] * - GflsBytesRegion's @total_size is: 6 * * Then the GflsBytesRegionIter will go through these values: * - { 0, TRUE } : corresponds to the [0, 1] range. * - { 0, FALSE } : before=false which means *inside* the sub-region [1, 3]. * - { 1, TRUE } : between [1, 3] and [4, 5], so [3, 4]. * - { 1, FALSE } : [4, 5]. * - { 2, TRUE } : outside the sub_regions GArray, which means *after* the last * sub-region, here [5, 6]. * - { 2, FALSE } : the end iterator. * * A GflsBytesRegionIter needs to internally skip empty ranges. */ struct _GflsBytesRegionIter { guint sub_region_index; guint before : 1; }; GflsBytesRegion * _gfls_bytes_region_new (GArray *sub_regions, gsize total_size) { GflsBytesRegion *region; g_return_val_if_fail (sub_regions != NULL, NULL); region = g_new0 (GflsBytesRegion, 1); region->sub_regions = g_array_ref (sub_regions); region->total_size = total_size; return region; } /** * gfls_bytes_region_free: * @region: (nullable): a #GflsBytesRegion. * * Frees @region. * * Since: 0.4 */ void gfls_bytes_region_free (GflsBytesRegion *region) { if (region != NULL) { g_array_unref (region->sub_regions); g_free (region); } } /** * gfls_bytes_region_match_bytes: * @region: a #GflsBytesRegion. * @bytes: a #GBytes. * * Returns: whether @region can be applied to @bytes (it checks the total size). * Since: 0.4 */ gboolean gfls_bytes_region_match_bytes (GflsBytesRegion *region, GBytes *bytes) { g_return_val_if_fail (region != NULL, FALSE); g_return_val_if_fail (bytes != NULL, FALSE); return region->total_size == g_bytes_get_size (bytes); } static gboolean iter_validate (GflsBytesRegion *region, GflsBytesRegionIter *iter, gboolean treat_end_iter_as_valid) { gboolean valid; g_return_val_if_fail (region != NULL, FALSE); g_return_val_if_fail (iter != NULL, FALSE); valid = iter->sub_region_index <= region->sub_regions->len; if (treat_end_iter_as_valid) { return valid; } return (valid && !gfls_bytes_region_iter_is_end (region, iter)); } static GflsBytesSubRegionBounds iter_get_sub_region_bounds (GflsBytesRegion *region, GflsBytesRegionIter *iter) { GflsBytesSubRegionBounds prev_sub_region_bounds = { 0 }; GflsBytesSubRegionBounds next_sub_region_bounds = { 0 }; GflsBytesSubRegionBounds ret = { 0 }; g_return_val_if_fail (iter_validate (region, iter, FALSE), ret); /* _Inside_ a sub-region (the easy case) */ if (!iter->before) { return g_array_index (region->sub_regions, GflsBytesSubRegionBounds, iter->sub_region_index); } /* _Outside_ a sub-region */ // Get prev_sub_region_bounds if (iter->sub_region_index == 0) { prev_sub_region_bounds.start = 0; prev_sub_region_bounds.end = 0; } else { prev_sub_region_bounds = g_array_index (region->sub_regions, GflsBytesSubRegionBounds, iter->sub_region_index - 1); } // Get next_sub_region_bounds if (iter->sub_region_index < region->sub_regions->len) { next_sub_region_bounds = g_array_index (region->sub_regions, GflsBytesSubRegionBounds, iter->sub_region_index); } else { next_sub_region_bounds.start = region->total_size; next_sub_region_bounds.end = region->total_size; } // Return value ret.start = prev_sub_region_bounds.end; ret.end = next_sub_region_bounds.start; return ret; } static gboolean iter_sub_region_is_empty (GflsBytesRegion *region, GflsBytesRegionIter *iter) { gsize sub_region_size = 0; gsize offset = 0; gboolean is_part_of_region = FALSE; gfls_bytes_region_iter_get_sub_region (region, iter, &sub_region_size, &offset, &is_part_of_region); return sub_region_size == 0; } /* "Simple", i.e. without skipping empty sub-regions. */ static void iter_next_simple (GflsBytesRegion *region, GflsBytesRegionIter *iter) { if (gfls_bytes_region_iter_is_end (region, iter)) { /* NOP */ return; } if (iter->before) { iter->before = FALSE; } else { iter->before = TRUE; iter->sub_region_index++; } } static void iter_skip_empty_sub_regions (GflsBytesRegion *region, GflsBytesRegionIter *iter) { while (!gfls_bytes_region_iter_is_end (region, iter) && iter_sub_region_is_empty (region, iter)) { iter_next_simple (region, iter); } } /** * gfls_bytes_region_get_start_iter: (skip) * @region: a #GflsBytesRegion. * * Returns: (transfer full): a new #GflsBytesRegionIter located at the * beginning. Free with gfls_bytes_region_iter_free(). * Since: 0.4 */ GflsBytesRegionIter * gfls_bytes_region_get_start_iter (GflsBytesRegion *region) { GflsBytesRegionIter *iter; g_return_val_if_fail (region != NULL, NULL); iter = g_new0 (GflsBytesRegionIter, 1); iter->sub_region_index = 0; iter->before = TRUE; iter_skip_empty_sub_regions (region, iter); return iter; } /** * gfls_bytes_region_iter_free: * @region: a #GflsBytesRegion. * @iter: (nullable): a #GflsBytesRegionIter. * * Frees @iter. * * Since: 0.4 */ void gfls_bytes_region_iter_free (GflsBytesRegion *region, GflsBytesRegionIter *iter) { g_free (iter); } /** * gfls_bytes_region_iter_is_end: * @region: a #GflsBytesRegion. * @iter: a #GflsBytesRegionIter. * * Returns: whether @iter is the end iterator. * Since: 0.4 */ gboolean gfls_bytes_region_iter_is_end (GflsBytesRegion *region, GflsBytesRegionIter *iter) { g_return_val_if_fail (region != NULL, FALSE); g_return_val_if_fail (iter != NULL, FALSE); return (!iter->before && iter->sub_region_index == region->sub_regions->len); } /** * gfls_bytes_region_iter_get_sub_region: * @region: a #GflsBytesRegion. * @iter: a #GflsBytesRegionIter. It must not be the end iterator. * @sub_region_size: (out) (not nullable): the sub-region size. * @offset: (out) (not nullable): the offset to the start of the sub-region. * @is_part_of_region: (out) (not nullable): whether the sub-region is part of the region. * * Gets the sub-region at this iterator. * * @sub_region_size and @offset can be used as arguments to * g_bytes_get_region(). * * @is_part_of_region has the same meaning as for * gfls_bytes_region_builder_append(). #GflsBytesRegionIter iterates on both the * region and the holes, so that the corresponding #GBytes is traversed from * start to end. * * Since: 0.4 */ void gfls_bytes_region_iter_get_sub_region (GflsBytesRegion *region, GflsBytesRegionIter *iter, gsize *sub_region_size, gsize *offset, gboolean *is_part_of_region) { GflsBytesSubRegionBounds sub_region_bounds; if (sub_region_size != NULL) { *sub_region_size = 0; } if (offset != NULL) { *offset = 0; } if (is_part_of_region != NULL) { *is_part_of_region = FALSE; } g_return_if_fail (region != NULL); g_return_if_fail (iter != NULL); g_return_if_fail (iter_validate (region, iter, FALSE)); g_return_if_fail (sub_region_size != NULL); g_return_if_fail (offset != NULL); g_return_if_fail (is_part_of_region != NULL); sub_region_bounds = iter_get_sub_region_bounds (region, iter); g_return_if_fail (sub_region_bounds.end >= sub_region_bounds.start); *sub_region_size = sub_region_bounds.end - sub_region_bounds.start; *offset = sub_region_bounds.start; *is_part_of_region = !iter->before; } /** * gfls_bytes_region_iter_next: * @region: a #GflsBytesRegion. * @iter: a #GflsBytesRegionIter. The end iterator is accepted as an input * value. * * Moves @iter to the next sub-region. * * If all sub-regions have been traversed, @iter is set to the end iterator. * * Since: 0.4 */ void gfls_bytes_region_iter_next (GflsBytesRegion *region, GflsBytesRegionIter *iter) { g_return_if_fail (region != NULL); g_return_if_fail (iter != NULL); g_return_if_fail (iter_validate (region, iter, TRUE)); iter_next_simple (region, iter); iter_skip_empty_sub_regions (region, iter); } /** * gfls_bytes_region_to_string: * @region: a #GflsBytesRegion. * * The format is: * * `[offset, sub_region_size, is_part_of_region]\n` * * One line per sub-region, in order. * * Returns: (transfer full): a string representation of @region. * Since: 0.4 */ gchar * gfls_bytes_region_to_string (GflsBytesRegion *region) { GString *string; GflsBytesRegionIter *iter; g_return_val_if_fail (region != NULL, NULL); string = g_string_new (NULL); iter = gfls_bytes_region_get_start_iter (region); while (!gfls_bytes_region_iter_is_end (region, iter)) { gsize sub_region_size = 0; gsize offset = 0; gboolean is_part_of_region = FALSE; gfls_bytes_region_iter_get_sub_region (region, iter, &sub_region_size, &offset, &is_part_of_region); g_string_append_printf (string, "[%" G_GSIZE_FORMAT ", %" G_GSIZE_FORMAT ", %d]\n", offset, sub_region_size, is_part_of_region); gfls_bytes_region_iter_next (region, iter); } gfls_bytes_region_iter_free (region, iter); return g_string_free (string, FALSE); } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-bytes-region.h000066400000000000000000000025731516613426200270750ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS typedef struct _GflsBytesRegion GflsBytesRegion; typedef struct _GflsBytesRegionIter GflsBytesRegionIter; G_MODULE_EXPORT void gfls_bytes_region_free (GflsBytesRegion *region); G_MODULE_EXPORT gboolean gfls_bytes_region_match_bytes (GflsBytesRegion *region, GBytes *bytes); G_MODULE_EXPORT gchar * gfls_bytes_region_to_string (GflsBytesRegion *region); G_MODULE_EXPORT GflsBytesRegionIter * gfls_bytes_region_get_start_iter (GflsBytesRegion *region); G_MODULE_EXPORT void gfls_bytes_region_iter_free (GflsBytesRegion *region, GflsBytesRegionIter *iter); G_MODULE_EXPORT gboolean gfls_bytes_region_iter_is_end (GflsBytesRegion *region, GflsBytesRegionIter *iter); G_MODULE_EXPORT void gfls_bytes_region_iter_get_sub_region (GflsBytesRegion *region, GflsBytesRegionIter *iter, gsize *sub_region_size, gsize *offset, gboolean *is_part_of_region); G_MODULE_EXPORT void gfls_bytes_region_iter_next (GflsBytesRegion *region, GflsBytesRegionIter *iter); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-encoding-conversion.c000066400000000000000000000043221516613426200304240ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-encoding-conversion.h" #include "gfls-iconv.h" /** * gfls_encoding_try_convert: * @input_bytes: a #GBytes. * @to_codeset: destination codeset. * @from_codeset: source codeset. * * Tries a conversion on @input_bytes, discarding the output. * * @from_codeset and @to_codeset must be compatible with iconv, see * gfls_iconv_open(). * * If @input_bytes ends with an incomplete multi-byte character, that part is * ignored. So @input_bytes can be for example the first chunk of a file when * loading it. * * Returns: %TRUE if and only if @input_bytes can be converted without errors, * without invalid characters and without fallback characters. * Since: 0.4 */ gboolean gfls_encoding_try_convert (GBytes *input_bytes, const gchar *to_codeset, const gchar *from_codeset) { GflsIconv *conv; const gchar *input_buffer; gsize input_buffer_size = 0; gchar *input_buffer_pos; gsize input_buffer_n_bytes_left; GflsIconvResult conv_result; gboolean success = FALSE; g_return_val_if_fail (input_bytes != NULL, FALSE); g_return_val_if_fail (to_codeset != NULL, FALSE); g_return_val_if_fail (from_codeset != NULL, FALSE); conv = gfls_iconv_new (); if (!gfls_iconv_open (conv, to_codeset, from_codeset, NULL)) { success = FALSE; goto out; } input_buffer = g_bytes_get_data (input_bytes, &input_buffer_size); input_buffer_pos = (gchar *) input_buffer; input_buffer_n_bytes_left = input_buffer_size; conv_result = gfls_iconv_feed_discard_output (conv, &input_buffer_pos, &input_buffer_n_bytes_left, NULL); switch (conv_result) { case GFLS_ICONV_RESULT_OK: case GFLS_ICONV_RESULT_INCOMPLETE_INPUT: success = TRUE; break; case GFLS_ICONV_RESULT_ERROR: case GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE: case GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL: case GFLS_ICONV_RESULT_LOSSY_CONVERSION: default: success = FALSE; break; } /* TODO: call gfls_iconv_feed_discard_output() with @inbuf and * @inbytes_left set to NULL. (But testing it completely is more * difficult). */ out: gfls_iconv_free (conv); return success; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-encoding-conversion.h000066400000000000000000000007151516613426200304330ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS G_MODULE_EXPORT gboolean gfls_encoding_try_convert (GBytes *input_bytes, const gchar *to_codeset, const gchar *from_codeset); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-encoding-convert.c000066400000000000000000000405041516613426200277210ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-config.h" #include "gfls-encoding-convert.h" #include #include "gfls-bytes-region-builder.h" #include "gfls-iconv.h" /** * SECTION:gfls-encoding-convert * @Title: GflsEncodingConvert * @Short_description: Character encoding conversion * * Functions used for character encoding conversion. */ /* # Use-case * * The gfls_encoding_convert() function has been designed for loading a file * into a #GtkTextBuffer scenario. Regarding the performances, the insertions in * the #GtkTextBuffer are the slow part, so there must be as few insertions as * possible. * * In other words, if there are no invalid chars and the target encoding is * UTF-8, have as a result a single UTF-8 string that can be inserted at once. * * # Output format * * For the output format, a previous implementation created a list of "Chunk" * structs containing two fields: a #GBytes for the data, and a boolean for * whether it's valid/invalid. But it consumed more memory. * * A worst case scenario is when there are lots of interleavings of * valid/invalid chunks. * * The current output format with a #GBytes combined with a #GflsBytesRegion * is normally more memory efficient. * * # Implementation notes about memory allocations * * Since we don't know how big the output will be, memory reallocations are * necessary. So use g_malloc() and g_realloc() family of functions. At the end, * there is the need to realloc at the right size, to not consume more memory * than necessary. */ /* 8 KiB */ #define OUTPUT_BUFFER_STEP_SIZE (8192) /* Invariants: * - 0 <= (@position - @data) <= @size * - @n_bytes_left <= @size * - @n_bytes_left == @size - (@position - @data) * * It would be possible to remove one field because there are some redundancies. * But the code is probably easier if the redundancy is kept. */ typedef struct { /* Points to the beginning of the buffer data. * Can be owned or unowned. */ gchar *data; /* Points to the current position in @data. * Always unowned. */ gchar *position; /* The total size of the memory allocation of @data. */ gsize size; /* The number of bytes not yet written in @data, starting at @position. */ gsize n_bytes_left; } Buffer; typedef struct { GflsIconv *conv; /* The @data field is unowned. */ Buffer input_buffer; /* The @data field is owned. */ Buffer output_buffer; GflsBytesRegionBuilder *output_bytes_valid_region_builder; guint allow_invalid_characters : 1; } Converter; static gboolean check_buffer_invariants (Buffer *buffer) { gintptr n_bytes_written; n_bytes_written = buffer->position - buffer->data; g_return_val_if_fail (n_bytes_written >= 0, FALSE); g_return_val_if_fail (n_bytes_written <= (gintptr)buffer->size, FALSE); g_return_val_if_fail (buffer->n_bytes_left <= buffer->size, FALSE); g_return_val_if_fail (buffer->n_bytes_left == buffer->size - n_bytes_written, FALSE); return TRUE; } static gboolean check_class_invariants (Converter *conv) { g_return_val_if_fail (check_buffer_invariants (&conv->input_buffer), FALSE); g_return_val_if_fail (check_buffer_invariants (&conv->output_buffer), FALSE); if (conv->output_bytes_valid_region_builder == NULL) { g_return_val_if_fail (conv->output_buffer.data == NULL, FALSE); } else { gsize n_bytes_written1; gsize n_bytes_written2; gsize n_bytes_written3; g_return_val_if_fail (conv->output_buffer.data != NULL, FALSE); /* There are multiple ways to know the number of bytes written. */ n_bytes_written1 = gfls_bytes_region_builder_get_current_size (conv->output_bytes_valid_region_builder); n_bytes_written2 = conv->output_buffer.size - conv->output_buffer.n_bytes_left; n_bytes_written3 = conv->output_buffer.position - conv->output_buffer.data; g_return_val_if_fail (n_bytes_written1 == n_bytes_written2, FALSE); g_return_val_if_fail (n_bytes_written1 == n_bytes_written3, FALSE); } return TRUE; } static void converter_init (Converter *conv, GBytes *input_bytes, gboolean allow_invalid_characters) { conv->conv = gfls_iconv_new (); conv->input_buffer.data = (gchar *) g_bytes_get_data (input_bytes, NULL); conv->input_buffer.position = conv->input_buffer.data; conv->input_buffer.size = g_bytes_get_size (input_bytes); conv->input_buffer.n_bytes_left = conv->input_buffer.size; conv->allow_invalid_characters = allow_invalid_characters != FALSE; g_return_if_fail (check_class_invariants (conv)); /* The output is lazily initialized, see init_output(). */ } static void init_output (Converter *conv) { if (conv->output_bytes_valid_region_builder != NULL) { return; } conv->output_bytes_valid_region_builder = gfls_bytes_region_builder_new (); /* Allocate the same size as the input + some margin, to hopefully * reduce the number of re-allocations. */ if (!g_size_checked_add (&conv->output_buffer.size, conv->input_buffer.size, OUTPUT_BUFFER_STEP_SIZE)) { g_assert_not_reached (); } /* Use g_malloc0(), more secure than g_malloc(). */ conv->output_buffer.data = g_malloc0 (conv->output_buffer.size); conv->output_buffer.position = conv->output_buffer.data; conv->output_buffer.n_bytes_left = conv->output_buffer.size; } static void enlarge_output_buffer (Converter *conv, gsize n_additional_bytes_needed) { gsize n_additional_bytes; gsize new_size; gsize n_bytes_written; g_return_if_fail (conv->output_buffer.data != NULL); n_additional_bytes = MAX (n_additional_bytes_needed, OUTPUT_BUFFER_STEP_SIZE); if (!g_size_checked_add (&new_size, conv->output_buffer.size, n_additional_bytes)) { g_assert_not_reached (); } n_bytes_written = conv->output_buffer.position - conv->output_buffer.data; conv->output_buffer.data = g_realloc (conv->output_buffer.data, new_size); conv->output_buffer.position = conv->output_buffer.data + n_bytes_written; conv->output_buffer.size = new_size; conv->output_buffer.n_bytes_left += n_additional_bytes; /* Fill the new chunk with 0's. */ memset (conv->output_buffer.data + new_size - n_additional_bytes, 0, n_additional_bytes); } static void free_output (Converter *conv) { g_free (conv->output_buffer.data); conv->output_buffer.data = NULL; conv->output_buffer.position = NULL; conv->output_buffer.size = 0; conv->output_buffer.n_bytes_left = 0; gfls_bytes_region_builder_free (conv->output_bytes_valid_region_builder, TRUE); conv->output_bytes_valid_region_builder = NULL; } static void converter_finalize (Converter *conv) { gfls_iconv_free (conv->conv); free_output (conv); } static void append_valid_sub_region (Converter *conv) { gsize n_bytes_written_before; gsize n_bytes_written_after; gsize sub_region_length; n_bytes_written_before = gfls_bytes_region_builder_get_current_size (conv->output_bytes_valid_region_builder); n_bytes_written_after = conv->output_buffer.position - conv->output_buffer.data; g_return_if_fail (n_bytes_written_before <= n_bytes_written_after); sub_region_length = n_bytes_written_after - n_bytes_written_before; if (sub_region_length != 0) { gfls_bytes_region_builder_append (conv->output_bytes_valid_region_builder, sub_region_length, TRUE); } } static void handle_iconv_result_ok (Converter *conv) { g_warn_if_fail (conv->input_buffer.n_bytes_left == 0); append_valid_sub_region (conv); } static void handle_iconv_result_error (Converter *conv) { free_output (conv); } static void handle_iconv_result_illegal_sequence (Converter *conv) { g_return_if_fail (conv->input_buffer.n_bytes_left > 0); g_return_if_fail (conv->allow_invalid_characters); /* First chunk: what has been converted successfully. */ append_valid_sub_region (conv); /* Second chunk: the invalid byte from the input buffer. */ if (conv->output_buffer.n_bytes_left == 0) { enlarge_output_buffer (conv, 1); } *conv->output_buffer.position = *conv->input_buffer.position; conv->input_buffer.position++; conv->input_buffer.n_bytes_left--; conv->output_buffer.position++; conv->output_buffer.n_bytes_left--; gfls_bytes_region_builder_append (conv->output_bytes_valid_region_builder, 1, FALSE); } static void handle_iconv_result_incomplete_input (Converter *conv) { g_return_if_fail (conv->input_buffer.n_bytes_left > 0); g_return_if_fail (conv->allow_invalid_characters); /* First chunk: what has been converted successfully. */ append_valid_sub_region (conv); /* Second chunk: the remained bytes from the input buffer. */ if (conv->output_buffer.n_bytes_left < conv->input_buffer.n_bytes_left) { enlarge_output_buffer (conv, conv->input_buffer.n_bytes_left - conv->output_buffer.n_bytes_left); } memcpy (conv->output_buffer.position, conv->input_buffer.position, conv->input_buffer.n_bytes_left); gfls_bytes_region_builder_append (conv->output_bytes_valid_region_builder, conv->input_buffer.n_bytes_left, FALSE); conv->input_buffer.position += conv->input_buffer.n_bytes_left; conv->output_buffer.position += conv->input_buffer.n_bytes_left; conv->output_buffer.n_bytes_left -= conv->input_buffer.n_bytes_left; conv->input_buffer.n_bytes_left = 0; } static void handle_iconv_result_output_buffer_full (Converter *conv) { append_valid_sub_region (conv); enlarge_output_buffer (conv, OUTPUT_BUFFER_STEP_SIZE); } static void handle_iconv_result_lossy_conversion (Converter *conv, GError **error) { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("A number of nonreversible conversions have been performed.")); handle_iconv_result_error (conv); } static void handle_invalid_character_encountered (Converter *conv, GError **error) { g_return_if_fail (!conv->allow_invalid_characters); g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("An invalid character has been encountered.")); handle_iconv_result_error (conv); } static gboolean convert (Converter *conv, GError **error) { gboolean success = TRUE; init_output (conv); while (conv->input_buffer.n_bytes_left > 0) { GflsIconvResult conv_result; g_return_val_if_fail (check_class_invariants (conv), FALSE); conv_result = gfls_iconv_feed (conv->conv, &conv->input_buffer.position, &conv->input_buffer.n_bytes_left, &conv->output_buffer.position, &conv->output_buffer.n_bytes_left, error); if (conv_result == GFLS_ICONV_RESULT_OK) { handle_iconv_result_ok (conv); break; } else if (conv_result == GFLS_ICONV_RESULT_ERROR) { handle_iconv_result_error (conv); success = FALSE; break; } else if (conv_result == GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE) { if (conv->allow_invalid_characters) { handle_iconv_result_illegal_sequence (conv); continue; } else { handle_invalid_character_encountered (conv, error); success = FALSE; break; } } else if (conv_result == GFLS_ICONV_RESULT_INCOMPLETE_INPUT) { if (conv->allow_invalid_characters) { handle_iconv_result_incomplete_input (conv); break; } else { handle_invalid_character_encountered (conv, error); success = FALSE; break; } } else if (conv_result == GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL) { handle_iconv_result_output_buffer_full (conv); continue; } else if (conv_result == GFLS_ICONV_RESULT_LOSSY_CONVERSION) { handle_iconv_result_lossy_conversion (conv, error); success = FALSE; break; } } g_return_val_if_fail (check_class_invariants (conv), FALSE); return success; } static gboolean finish_convert (Converter *conv, GError **error) { GflsIconvResult conv_result; gboolean success = TRUE; conv->input_buffer.data = NULL; conv->input_buffer.position = NULL; conv->input_buffer.size = 0; conv->input_buffer.n_bytes_left = 0; if (conv->output_buffer.n_bytes_left < OUTPUT_BUFFER_STEP_SIZE) { enlarge_output_buffer (conv, OUTPUT_BUFFER_STEP_SIZE - conv->output_buffer.n_bytes_left); } g_return_val_if_fail (check_class_invariants (conv), FALSE); /* Do not call it in a loop because the output_buffer should be big * enough. */ conv_result = gfls_iconv_feed (conv->conv, NULL, NULL, &conv->output_buffer.position, &conv->output_buffer.n_bytes_left, error); if (conv_result == GFLS_ICONV_RESULT_OK) { handle_iconv_result_ok (conv); } else if (conv_result == GFLS_ICONV_RESULT_ERROR) { handle_iconv_result_error (conv); success = FALSE; } else if (conv_result == GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE || conv_result == GFLS_ICONV_RESULT_INCOMPLETE_INPUT || conv_result == GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL) { /* Unexpected */ g_warn_if_reached (); handle_iconv_result_error (conv); success = FALSE; } else if (conv_result == GFLS_ICONV_RESULT_LOSSY_CONVERSION) { handle_iconv_result_lossy_conversion (conv, error); success = FALSE; } g_return_val_if_fail (check_class_invariants (conv), FALSE); return success; } /** * gfls_encoding_convert: * @input_bytes: the input #GBytes to convert. * @to_codeset: destination codeset. * @from_codeset: source codeset. * @allow_invalid_characters: whether invalid characters are allowed. * @output_bytes: (out) (transfer full): the output #GBytes. It must initially * point to a %NULL #GBytes value. * @output_bytes_valid_region: (out) (transfer full): the output * #GflsBytesRegion that represents the valid characters. It must initially * point to a %NULL #GflsBytesRegion value. * @error: location to a %NULL #GError, or %NULL. * * This function converts @input_bytes from a codeset to another. * * @from_codeset and @to_codeset must be compatible with iconv, see * gfls_iconv_open(). * * Note that @from_codeset and @to_codeset can be equal. It is useful to * identify the valid characters from the invalid ones. * * The output is the combination of @output_bytes and * @output_bytes_valid_region. Output bytes that are part of * @output_bytes_valid_region are the valid characters (successfully converted). * The other output bytes are invalid characters (copied as is from * @input_bytes). * * If @allow_invalid_characters is %FALSE: * - As soon as an invalid character is encountered, %FALSE is returned by this * function and @output_bytes and @output_bytes_valid_region will return * %NULL. * - Otherwise, if everything goes well, %TRUE is returned alongside the * @output_bytes and @output_bytes_valid_region (the latter contains in this * case only one, valid sub-region). * * Returns: %TRUE on success, %FALSE otherwise. * Since: 0.4 */ gboolean gfls_encoding_convert (GBytes *input_bytes, const gchar *to_codeset, const gchar *from_codeset, gboolean allow_invalid_characters, GBytes **output_bytes, GflsBytesRegion **output_bytes_valid_region, GError **error) { Converter *conv; gboolean success = FALSE; g_return_val_if_fail (input_bytes != NULL, FALSE); g_return_val_if_fail (to_codeset != NULL, FALSE); g_return_val_if_fail (from_codeset != NULL, FALSE); g_return_val_if_fail (output_bytes != NULL && *output_bytes == NULL, FALSE); g_return_val_if_fail (output_bytes_valid_region != NULL && *output_bytes_valid_region == NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); conv = g_alloca0 (sizeof (Converter)); converter_init (conv, input_bytes, allow_invalid_characters); if (!gfls_iconv_open (conv->conv, to_codeset, from_codeset, error)) { goto out; } if (!convert (conv, error)) { goto out; } if (!finish_convert (conv, error)) { goto out; } if (!gfls_iconv_close (conv->conv, error)) { goto out; } if (!check_class_invariants (conv)) { goto out; } /* Success */ if (conv->output_bytes_valid_region_builder != NULL) { gsize final_size; gchar *output_data; final_size = gfls_bytes_region_builder_get_current_size (conv->output_bytes_valid_region_builder); output_data = g_realloc (conv->output_buffer.data, final_size); conv->output_buffer.data = NULL; conv->output_buffer.position = NULL; conv->output_buffer.size = 0; conv->output_buffer.n_bytes_left = 0; *output_bytes = g_bytes_new_take (output_data, final_size); output_data = NULL; *output_bytes_valid_region = gfls_bytes_region_builder_free (conv->output_bytes_valid_region_builder, FALSE); conv->output_bytes_valid_region_builder = NULL; success = TRUE; } out: converter_finalize (conv); return success; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-encoding-convert.h000066400000000000000000000011741516613426200277260ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS G_MODULE_EXPORT gboolean gfls_encoding_convert (GBytes *input_bytes, const gchar *to_codeset, const gchar *from_codeset, gboolean allow_invalid_characters, GBytes **output_bytes, GflsBytesRegion **output_bytes_valid_region, GError **error); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-error.c000066400000000000000000000021711516613426200256040ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024-2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-config.h" #include "gfls-error.h" #include GQuark gfls_loader_error_quark (void) { static GQuark quark = 0; if (G_UNLIKELY (quark == 0)) { quark = g_quark_from_static_string ("gfls-loader-error"); } return quark; } GError * _gfls_loader_error_too_big_file_size (void) { return g_error_new_literal (GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_TOO_BIG, _("The size of the file is too big.")); } GError * _gfls_loader_error_too_big_read (void) { return g_error_new_literal (GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_TOO_BIG, _("Limit on the number of bytes to read reached.")); } GError * _gfls_loader_error_not_utf8 (void) { return g_error_new_literal (GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_NOT_UTF8, _("The content is not encoded in UTF-8.")); } GError * _gfls_loader_error_has_very_long_line (void) { return g_error_new_literal (GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_HAS_VERY_LONG_LINE, _("The content contains a very long line.")); } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-error.h000066400000000000000000000024021516613426200256060ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024-2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_ERROR_H #define GFLS_ERROR_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define GFLS_LOADER_ERROR gfls_loader_error_quark () /** * GflsLoaderError: * @GFLS_LOADER_ERROR_TOO_BIG: The content is too big. * @GFLS_LOADER_ERROR_NOT_UTF8: The content is not a valid UTF-8 string. Used by * basic loaders that don't support charset conversion. * @GFLS_LOADER_ERROR_HAS_VERY_LONG_LINE: The content contains a very long line. * * An error code used with the %GFLS_LOADER_ERROR domain. * * Since: 0.1 */ typedef enum _GflsLoaderError { GFLS_LOADER_ERROR_TOO_BIG, GFLS_LOADER_ERROR_NOT_UTF8, GFLS_LOADER_ERROR_HAS_VERY_LONG_LINE, } GflsLoaderError; G_MODULE_EXPORT GQuark gfls_loader_error_quark (void); G_GNUC_INTERNAL GError * _gfls_loader_error_too_big_file_size (void); G_GNUC_INTERNAL GError * _gfls_loader_error_too_big_read (void); G_GNUC_INTERNAL GError * _gfls_loader_error_not_utf8 (void); G_GNUC_INTERNAL GError * _gfls_loader_error_has_very_long_line (void); G_END_DECLS #endif /* GFLS_ERROR_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-iconv.c000066400000000000000000000222651516613426200255770ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019, 2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-config.h" #include "gfls-iconv.h" #include #include /** * SECTION:gfls-iconv * @Title: GflsIconv * @Short_description: To use iconv more comfortably * * #GflsIconv is a small wrapper for the g_iconv() family of functions, to * use iconv more comfortably. #GflsIconv returns #GError's and enum values * for the different situations. * * Call the functions in this order: * - gfls_iconv_new() * - gfls_iconv_open() * - gfls_iconv_feed() in a loop. * - gfls_iconv_feed() with @inbuf and @inbytes_left set to %NULL (in a * loop too if the output buffer is full). * - gfls_iconv_close() * - gfls_iconv_free() * * Note that GLib provides the g_convert() family of functions. As the * g_convert() documentation explains, it is necessary to use g_iconv() (or * #GflsIconv) for streaming conversions. One other use-case is to have * more control over invalid characters: in the case of the * libgedit-gtksourceview library, it is desirable to apply a #GtkTextTag to * them. * * # Avoid iconv if possible * * However, if you have the choice, don't use iconv! It's a crappy API and has * several design flaws (and #GflsIconv cannot fix them): * - When `iconv()` returns `(size_t)-1` (e.g., when the output buffer is full), * we don't know if it has performed lossy conversions. In a normal situation, * the number of lossy conversions performed is returned by `iconv()` as its * return value. * * To fix this flaw, an `iconv2()` function could return the number of lossy * conversions performed as an output parameter. And also an * `iconv_open2` `()` function could take a flags parameter to configure * whether lossy conversions are allowed. * * - The `EILSEQ` error returned by `iconv()` can mean two different things: * there is either an invalid character in the input buffer (so invalid wrt. * the *origin* codeset), or there is a valid character in the input buffer * that cannot be represented in the *target* codeset. * * To fix this flaw, an `iconv2()` function could simply return two different * error codes. * * - When the `EILSEQ` error is returned by `iconv()`, “`*inbuf` is left * pointing to the beginning of the invalid multibyte sequence”, however we * don't know the length of the multibyte sequence! So in practice we assume * only one invalid byte, and call `iconv()` again with `inbuf` pointing to * the next byte, which may fail again, and so on. * * An `iconv2()` function would need a more elaborate API to return this kind * of information. For example by returning/filling a struct as an optional * output parameter. * * Additionally, `iconv()` has different implementations (so working code on * Linux can behave differently on a BSD or Solaris). */ #define CLOSED_CONV_DESCRIPTOR ((GIConv) -1) struct _GflsIconv { GIConv conv_descriptor; }; static gboolean is_opened (GflsIconv *conv) { return conv->conv_descriptor != CLOSED_CONV_DESCRIPTOR; } /** * gfls_iconv_new: (skip) * * Returns: (transfer full): a new #GflsIconv. * Since: 0.4 */ GflsIconv * gfls_iconv_new (void) { GflsIconv *conv; conv = g_new0 (GflsIconv, 1); conv->conv_descriptor = CLOSED_CONV_DESCRIPTOR; return conv; } /** * gfls_iconv_open: (skip) * @conv: a #GflsIconv. * @to_codeset: destination codeset. * @from_codeset: source codeset. * @error: location to a #GError, or %NULL to ignore errors. * * Similar to g_iconv_open(). The difference is that it returns a #GError * instead of `errno`. * * Returns: %TRUE on success, %FALSE on error. * Since: 0.4 */ gboolean gfls_iconv_open (GflsIconv *conv, const gchar *to_codeset, const gchar *from_codeset, GError **error) { g_return_val_if_fail (conv != NULL, FALSE); g_return_val_if_fail (to_codeset != NULL, FALSE); g_return_val_if_fail (from_codeset != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); g_return_val_if_fail (!is_opened (conv), FALSE); conv->conv_descriptor = g_iconv_open (to_codeset, from_codeset); if (conv->conv_descriptor == CLOSED_CONV_DESCRIPTOR) { gint saved_errno = errno; errno = 0; if (saved_errno == EINVAL) { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_NO_CONVERSION, _("Conversion from character set “%s” to “%s” is not supported."), from_codeset, to_codeset); } else { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("Failed to open a character set converter from “%s” to “%s”: %s"), from_codeset, to_codeset, g_strerror (saved_errno)); } return FALSE; } return TRUE; } /** * gfls_iconv_feed: (skip) * @conv: a #GflsIconv. * @inbuf: (nullable): bytes to convert. * @inbytes_left: (nullable) (inout): bytes remaining to convert in @inbuf. * @outbuf: (not nullable): converted output bytes. * @outbytes_left: (not nullable) (inout): bytes available to fill in @outbuf. * @error: location to a #GError, or %NULL to ignore errors. * * Similar to g_iconv(). This function reads the `errno` value and converts it * either to a #GError, or to a #GflsIconvResult enumeration value. * * @error is set only when %GFLS_ICONV_RESULT_ERROR is returned. * * Returns: a #GflsIconvResult enumeration value. * Since: 0.4 */ GflsIconvResult gfls_iconv_feed (GflsIconv *conv, gchar **inbuf, gsize *inbytes_left, gchar **outbuf, gsize *outbytes_left, GError **error) { gsize iconv_ret; g_return_val_if_fail (conv != NULL, FALSE); g_return_val_if_fail (outbuf != NULL, FALSE); g_return_val_if_fail (outbytes_left != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); iconv_ret = g_iconv (conv->conv_descriptor, inbuf, inbytes_left, outbuf, outbytes_left); if (iconv_ret == (gsize)-1) { gint saved_errno = errno; errno = 0; if (saved_errno == EILSEQ) { return GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE; } else if (saved_errno == EINVAL) { return GFLS_ICONV_RESULT_INCOMPLETE_INPUT; } else if (saved_errno == E2BIG) { return GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL; } else { g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("Error during character set conversion: %s"), g_strerror (saved_errno)); return GFLS_ICONV_RESULT_ERROR; } } else if (iconv_ret > 0) { /* Note: in the other cases above (e.g., buffer full), how to * know if iconv() has performed lossy conversions before * encountering the error condition? So the outbuf might contain * lossy conversions without a way to know it! */ return GFLS_ICONV_RESULT_LOSSY_CONVERSION; } return GFLS_ICONV_RESULT_OK; } /** * gfls_iconv_feed_discard_output: (skip) * @conv: a #GflsIconv. * @inbuf: (nullable): bytes to convert. * @inbytes_left: (nullable) (inout): bytes remaining to convert in @inbuf. * @error: location to a #GError, or %NULL to ignore errors. * * Similar to gfls_iconv_feed() but without the output buffer parameters. * * Returns: a #GflsIconvResult enumeration value. * %GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL is never returned by this * function. * Since: 0.4 */ GflsIconvResult gfls_iconv_feed_discard_output (GflsIconv *conv, gchar **inbuf, gsize *inbytes_left, GError **error) { #define OUTPUT_BUFFER_SIZE (1024) gchar output_buffer[OUTPUT_BUFFER_SIZE]; GflsIconvResult result; g_return_val_if_fail (conv != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); do { gchar *output_buffer_pos = output_buffer; gsize output_buffer_n_bytes_left = OUTPUT_BUFFER_SIZE; result = gfls_iconv_feed (conv, inbuf, inbytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, error); } while (result == GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL); return result; #undef OUTPUT_BUFFER_SIZE } /** * gfls_iconv_close: (skip) * @conv: a #GflsIconv. * @error: location to a #GError, or %NULL to ignore errors. * * Similar to g_iconv_close(). The difference is that it returns a #GError * instead of `errno`. * * Returns: %TRUE on success, %FALSE on error. * Since: 0.4 */ gboolean gfls_iconv_close (GflsIconv *conv, GError **error) { g_return_val_if_fail (conv != NULL, FALSE); g_return_val_if_fail (error == NULL || *error == NULL, FALSE); if (is_opened (conv)) { gint close_ret = g_iconv_close (conv->conv_descriptor); if (close_ret == -1) { gint saved_errno = errno; errno = 0; g_set_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED, _("Failed to close the character set converter: %s"), g_strerror (saved_errno)); return FALSE; } conv->conv_descriptor = CLOSED_CONV_DESCRIPTOR; } return TRUE; } /** * gfls_iconv_free: (skip) * @conv: (nullable): a #GflsIconv, or %NULL. * * Closes and frees @conv. * * If you need to know if closing @conv returns an error, call * gfls_iconv_close() explicitly beforehand. * * Since: 0.4 */ void gfls_iconv_free (GflsIconv *conv) { if (conv != NULL) { gfls_iconv_close (conv, NULL); g_free (conv); } } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-iconv.h000066400000000000000000000042761516613426200256060ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2019, 2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS typedef struct _GflsIconv GflsIconv; /** * GflsIconvResult: * @GFLS_ICONV_RESULT_OK: Everything OK. * @GFLS_ICONV_RESULT_ERROR: An error occurred. * @GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE: Stopped at an invalid character in * the @inbuf; or the character could not be represented in the target * character set. `*inbuf` is left pointing to the beginning of the invalid or * unconvertible sequence. * @GFLS_ICONV_RESULT_INCOMPLETE_INPUT: The input byte sequence ends with * an incomplete multi-byte character. `*inbuf` is left pointing to the * beginning of the incomplete multi-byte character. * @GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL: The output buffer has no more * room for the next converted character. * @GFLS_ICONV_RESULT_LOSSY_CONVERSION: A number of nonreversible * conversions have been performed. * * Used as the result value of gfls_iconv_feed(). * * Since: 0.4 */ typedef enum { GFLS_ICONV_RESULT_OK, GFLS_ICONV_RESULT_ERROR, GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE, GFLS_ICONV_RESULT_INCOMPLETE_INPUT, GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL, GFLS_ICONV_RESULT_LOSSY_CONVERSION, } GflsIconvResult; G_MODULE_EXPORT GflsIconv * gfls_iconv_new (void); G_MODULE_EXPORT gboolean gfls_iconv_open (GflsIconv *conv, const gchar *to_codeset, const gchar *from_codeset, GError **error); G_MODULE_EXPORT GflsIconvResult gfls_iconv_feed (GflsIconv *conv, gchar **inbuf, gsize *inbytes_left, gchar **outbuf, gsize *outbytes_left, GError **error); G_MODULE_EXPORT GflsIconvResult gfls_iconv_feed_discard_output (GflsIconv *conv, gchar **inbuf, gsize *inbytes_left, GError **error); G_MODULE_EXPORT gboolean gfls_iconv_close (GflsIconv *conv, GError **error); G_MODULE_EXPORT void gfls_iconv_free (GflsIconv *conv); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-init.c000066400000000000000000000024621516613426200254210ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-init.h" #include "gfls-unsaved-document-titles.h" /** * SECTION:gfls-init * @Title: Gfls Initialization and Finalization */ /** * gfls_init: * * Initializes the Gfls library (e.g. for the internationalization). * * This function can be called several times, but is meant to be called at the * beginning of main(), before any other Gfls function call. * * Since: 0.1 */ void gfls_init (void) { } /** * gfls_finalize: * * Free the resources allocated by Gfls. For example it unrefs the singleton * objects. * * It is not mandatory to call this function, it's just to be friendlier to * memory debugging tools. This function is meant to be called at the end of * main(). It can be called several times. * * Since: 0.1 */ void gfls_finalize (void) { static gboolean done = FALSE; /* Unref the singleton only once, even if this function is called * multiple times, to see if a reference is not released correctly. * Normally the singleton have a ref count of 1. If for some reason the * ref count is increased somewhere, it needs to be decreased * accordingly, at the right place. */ if (!done) { _gfls_unsaved_document_titles_unref_default_instance (); done = TRUE; } } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-init.h000066400000000000000000000006511516613426200254240ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_INIT_H #define GFLS_INIT_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS G_MODULE_EXPORT void gfls_init (void); G_MODULE_EXPORT void gfls_finalize (void); G_END_DECLS #endif /* GFLS_INIT_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-input-stream.c000066400000000000000000000271671516613426200271170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-input-stream.h" /** * SECTION:gfls-input-stream * @Title: GflsInputStream * @Short_description: Additional functions for #GInputStream * * Additional functions for #GInputStream. */ /* Problem with g_file_load_partial_contents_async/finish(): * * From an API point of view, the maximum number of bytes to read is not * provided *initially*, the GFileReadMoreCallback is called at least once. For * example if I try to load a 100MB file with that function, nothing tells me * that I'll be able to restrict it to 20MB (the API doesn't guarantee it). * * gfls_input_stream_read_async/finish() solves this (and works on any * GInputStream, which we need for stdin support). */ typedef struct { /* Buffer to store the bytes read. It needs to contain one more byte at * the end to nul-terminate the string. Note that it can contain nul * bytes inside the content too (whatever is read from the input * stream). */ guint8 *buf; /* The number of bytes currently allocated to @buf. */ gsize buf_size; /* The current position inside @buf where to write the next bytes. * Invariant: buf_pos < buf_size */ gsize buf_pos; /* Max value for @buf_size. */ gsize buf_max_size; /* Can be NULL. */ GflsSimpleProgressCallback progress_callback; gpointer progress_callback_data; /* Boolean to know if the content from the input stream needed to be * truncated because the maximum number of bytes to read has been * reached (and there *is* more content to read). */ guint truncated : 1; } TaskData; /* 8 KiB, a value recommended by g_input_stream_read_bytes(). */ #define CHUNK_SIZE (8192) static void read_next_chunk (GTask *task); static gsize size_safe_add (gsize a, gsize b) { gsize ret; if (g_size_checked_add (&ret, a, b)) { return ret; } return G_MAXSIZE; } static TaskData * task_data_new (gsize expected_size, gsize max_size) { TaskData *task_data; gsize full_expected_size; gsize full_max_size; gsize initial_buf_size; /* +1 to nul-terminate the buffer. */ full_expected_size = size_safe_add (expected_size, 1); full_max_size = size_safe_add (max_size, 1); initial_buf_size = MIN (full_expected_size, full_max_size); task_data = g_new0 (TaskData, 1); task_data->buf = g_malloc (initial_buf_size); task_data->buf_size = initial_buf_size; task_data->buf_pos = 0; task_data->buf_max_size = full_max_size; task_data->truncated = FALSE; return task_data; } static void task_data_free (TaskData *task_data) { if (task_data != NULL) { g_free (task_data->buf); g_free (task_data); } } static gboolean task_data_max_reached (TaskData *task_data) { g_assert (task_data->buf_pos < task_data->buf_max_size); /* When this is true, it's still possible to nul-terminate the buffer. */ return task_data->buf_pos == task_data->buf_max_size - 1; } /* Returns: the new value for @n_bytes_to_write. */ static gsize task_data_prepare_buffer (TaskData *task_data, gsize n_bytes_to_write) { gsize full_n_bytes_to_write; gsize required_buf_size; g_assert (task_data->buf_pos < task_data->buf_size); g_assert (task_data->buf_pos < task_data->buf_max_size); g_assert (task_data->buf_size <= task_data->buf_max_size); /* To be able to add 1 to n_bytes_to_write without the need to check for * integer overflows. */ g_assert (n_bytes_to_write < G_MAXSIZE); full_n_bytes_to_write = n_bytes_to_write + 1; if (!g_size_checked_add (&required_buf_size, task_data->buf_pos, full_n_bytes_to_write)) { g_assert_not_reached (); } if (required_buf_size <= task_data->buf_size) { return n_bytes_to_write; } /* Need to realloc the buffer */ if (required_buf_size <= task_data->buf_max_size) { task_data->buf = g_realloc (task_data->buf, required_buf_size); task_data->buf_size = required_buf_size; return n_bytes_to_write; } task_data->buf = g_realloc (task_data->buf, task_data->buf_max_size); task_data->buf_size = task_data->buf_max_size; return task_data->buf_size - task_data->buf_pos - 1; } static void task_data_nul_terminate_buffer (TaskData *task_data) { task_data->buf[task_data->buf_pos] = '\0'; } static GBytes * task_data_buffer_to_gbytes (TaskData *task_data) { GBytes *bytes; bytes = g_bytes_new_take (task_data->buf, task_data->buf_pos); task_data->buf = NULL; return bytes; } static void finish_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *input_stream = G_INPUT_STREAM (source_object); GTask *task = G_TASK (user_data); TaskData *task_data = g_task_get_task_data (task); GError *error = NULL; g_input_stream_close_finish (input_stream, result, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); return; } task_data_nul_terminate_buffer (task_data); g_task_return_boolean (task, TRUE); g_object_unref (task); } static void finish (GTask *task) { GInputStream *input_stream = G_INPUT_STREAM (g_task_get_source_object (task)); g_input_stream_close_async (input_stream, g_task_get_priority (task), g_task_get_cancellable (task), finish_cb, task); } static void read_past_max_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *input_stream = G_INPUT_STREAM (source_object); GTask *task = user_data; TaskData *task_data = g_task_get_task_data (task); GBytes *bytes; GError *error = NULL; bytes = g_input_stream_read_bytes_finish (input_stream, result, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); return; } if (g_bytes_get_size (bytes) > 0) { task_data->truncated = TRUE; } g_bytes_unref (bytes); finish (task); } static void read_past_max (GTask *task) { GInputStream *input_stream; input_stream = g_task_get_source_object (task); g_input_stream_read_bytes_async (input_stream, 1, g_task_get_priority (task), g_task_get_cancellable (task), read_past_max_cb, task); } static void read_next_chunk_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *input_stream = G_INPUT_STREAM (source_object); GTask *task = user_data; GError *error = NULL; gssize n_bytes_read; TaskData *task_data; n_bytes_read = g_input_stream_read_finish (input_stream, result, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); return; } if (n_bytes_read < 0) { /* Should not happen, already handled with error != NULL, but * have robust code. */ g_task_return_boolean (task, FALSE); g_object_unref (task); return; } task_data = g_task_get_task_data (task); if (n_bytes_read == 0) { finish (task); return; } task_data->buf_pos += n_bytes_read; if (task_data->progress_callback != NULL) { task_data->progress_callback (task_data->buf_pos, task_data->progress_callback_data); } read_next_chunk (task); } static void read_next_chunk (GTask *task) { GInputStream *input_stream; TaskData *task_data; gsize actual_size_to_read; input_stream = g_task_get_source_object (task); task_data = g_task_get_task_data (task); if (task_data_max_reached (task_data)) { read_past_max (task); return; } actual_size_to_read = task_data_prepare_buffer (task_data, CHUNK_SIZE); g_input_stream_read_async (input_stream, task_data->buf + task_data->buf_pos, actual_size_to_read, g_task_get_priority (task), g_task_get_cancellable (task), read_next_chunk_cb, task); } /** * gfls_input_stream_read_async: (skip) * @input_stream: a #GInputStream. * @expected_size: the expected number of bytes contained in @input_stream. * @max_size: the maximum number of bytes to read. * @io_priority: the I/O priority of the request. E.g. %G_PRIORITY_LOW, * %G_PRIORITY_DEFAULT or %G_PRIORITY_HIGH. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. * @progress_callback: (nullable): function to call back with progress * information, or %NULL if progress information is not needed. * @progress_callback_data: user data to pass to @progress_callback. * @callback: (scope async): a #GAsyncReadyCallback to call when the operation * is finished. * @user_data: user data to pass to @callback. * * This function starts a read operation on @input_stream. It is meant to be * used as the only read operation on @input_stream, to get a #GBytes as a * result, with @max_size as the provided maximum number of bytes to read. * * @expected_size is typically a #GFile size as returned by * g_file_info_get_size(). But note that in that case, the returned #GBytes may * contain a different number of bytes than what was expected (the * TOC/TOU problem: time of check to time of use). @expected_size is used as an * indication to how much memory to allocate initially. * * This function also closes @input_stream after reading the content. * * See the #GAsyncResult documentation to know how to use this function. * * Since: 0.4 */ void gfls_input_stream_read_async (GInputStream *input_stream, gsize expected_size, gsize max_size, gint io_priority, GCancellable *cancellable, GflsSimpleProgressCallback progress_callback, gpointer progress_callback_data, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; TaskData *task_data; g_return_if_fail (G_IS_INPUT_STREAM (input_stream)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (input_stream, cancellable, callback, user_data); g_task_set_priority (task, io_priority); task_data = task_data_new (expected_size, max_size); task_data->progress_callback = progress_callback; task_data->progress_callback_data = progress_callback_data; g_task_set_task_data (task, task_data, (GDestroyNotify) task_data_free); read_next_chunk (task); } /** * gfls_input_stream_read_finish: (skip) * @input_stream: a #GInputStream. * @result: a #GAsyncResult. * @is_truncated: will be set to %TRUE if the @input_stream contains more data * to be read, but the maximum number of bytes to read has been reached. * @error: a #GError, or %NULL. * * Finishes an operation started with gfls_input_stream_read_async(). * * If @is_truncated is set to %TRUE, it is not an error (@error is not set), and * a #GBytes is returned. However, since gfls_input_stream_read_async() is * meant to be used as the only read operation on @input_stream, it is an * undefined behavior if you try to read more content from @input_stream. * * The data contained in the resulting #GBytes is always zero-terminated, but * this is not included in the #GBytes length. * * Returns: (transfer full) (nullable): a #GBytes, or %NULL on error. Free with * g_bytes_unref(). * Since: 0.4 */ GBytes * gfls_input_stream_read_finish (GInputStream *input_stream, GAsyncResult *result, gboolean *is_truncated, GError **error) { gboolean ok; g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL); g_return_val_if_fail (g_task_is_valid (result, input_stream), NULL); g_return_val_if_fail (is_truncated != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ok = g_task_propagate_boolean (G_TASK (result), error); if (ok) { TaskData *task_data; task_data = g_task_get_task_data (G_TASK (result)); *is_truncated = task_data->truncated; return task_data_buffer_to_gbytes (task_data); } *is_truncated = FALSE; return NULL; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-input-stream.h000066400000000000000000000023051516613426200271070ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #pragma once #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS /** * GflsSimpleProgressCallback: * @number: the number. * @user_data: user data. * * Like #GFileProgressCallback but without the total. * * Since: 0.4 */ typedef void (*GflsSimpleProgressCallback) (gsize number, gpointer user_data); G_MODULE_EXPORT void gfls_input_stream_read_async (GInputStream *input_stream, gsize expected_size, gsize max_size, gint io_priority, GCancellable *cancellable, GflsSimpleProgressCallback progress_callback, gpointer progress_callback_data, GAsyncReadyCallback callback, gpointer user_data); G_MODULE_EXPORT GBytes * gfls_input_stream_read_finish (GInputStream *input_stream, GAsyncResult *result, gboolean *is_truncated, GError **error); G_END_DECLS libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-basic.c000066400000000000000000000211651516613426200270040ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-loader-basic.h" #include "gfls-error.h" #include "gfls-input-stream.h" #include "gfls-utf8.h" /** * SECTION:gfls-loader-basic * @Title: GflsLoaderBasic * @Short_description: Basic file loader * * Basic file loader that validates input for GtkTextView purposes: * - Must not exceed a certain size (because all the content of a GtkTextBuffer * is stored in memory). * - Must be valid UTF-8 already (GTK in general accepts only UTF-8 only * strings). * - Must not contain very long lines (not well supported by the GtkTextView * widget, there can be performance problems and freezes). * * So: * - No character encoding auto-detection and/or conversion. * - No workarounds for problems found, just return an error without the * possibility to re-configure the loading. * * But this basic file loader offers a convenient API for the above: #GFile * loading with the intention to put its content into a GtkTextBuffer. */ /* When the file size is unknown, start with 8 KiB. */ #define DEFAULT_FILE_SIZE (8192) typedef struct { /* Config */ gsize max_size; guint max_n_bytes_per_line; /* Intermediate data */ gsize expected_file_size; GInputStream *input_stream; /* Result */ GBytes *bytes; } TaskData; static TaskData * task_data_new (gsize max_size, guint max_n_bytes_per_line) { TaskData *task_data; task_data = g_new0 (TaskData, 1); task_data->max_size = max_size; task_data->max_n_bytes_per_line = max_n_bytes_per_line; return task_data; } static void task_data_free (TaskData *task_data) { if (task_data != NULL) { g_clear_object (&task_data->input_stream); g_clear_pointer (&task_data->bytes, g_bytes_unref); g_free (task_data); } } static void check_bytes (GTask *task) { TaskData *task_data; const gchar *text; gsize n_bytes; task_data = g_task_get_task_data (task); text = g_bytes_get_data (task_data->bytes, &n_bytes); if (!g_utf8_validate_len (text, n_bytes, NULL)) { g_task_return_error (task, _gfls_loader_error_not_utf8 ()); g_object_unref (task); return; } if (gfls_utf8_find_very_long_line (text, task_data->max_n_bytes_per_line) != NULL) { g_task_return_error (task, _gfls_loader_error_has_very_long_line ()); g_object_unref (task); return; } /* Everything OK, finally done. */ g_task_return_boolean (task, TRUE); g_object_unref (task); } static void read_input_stream_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *input_stream = G_INPUT_STREAM (source_object); GTask *task = G_TASK (user_data); TaskData *task_data; gboolean is_truncated = FALSE; GError *error = NULL; task_data = g_task_get_task_data (task); g_clear_pointer (&task_data->bytes, g_bytes_unref); task_data->bytes = gfls_input_stream_read_finish (input_stream, result, &is_truncated, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); return; } if (is_truncated) { /* Free memory as early as possible, especially because it * reached the maximum. */ g_clear_pointer (&task_data->bytes, g_bytes_unref); g_task_return_error (task, _gfls_loader_error_too_big_read ()); g_object_unref (task); return; } check_bytes (task); } static void read_input_stream (GTask *task) { TaskData *task_data = g_task_get_task_data (task); gfls_input_stream_read_async (task_data->input_stream, task_data->expected_file_size, task_data->max_size, g_task_get_priority (task), g_task_get_cancellable (task), NULL, NULL, read_input_stream_cb, task); } static void open_file_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); GTask *task = G_TASK (user_data); GFileInputStream *file_input_stream; TaskData *task_data; GError *error = NULL; file_input_stream = g_file_read_finish (file, result, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); g_clear_object (&file_input_stream); return; } task_data = g_task_get_task_data (task); g_clear_object (&task_data->input_stream); task_data->input_stream = G_INPUT_STREAM (file_input_stream); read_input_stream (task); } static void open_file (GTask *task) { GFile *file = g_task_get_source_object (task); g_file_read_async (file, g_task_get_priority (task), g_task_get_cancellable (task), open_file_cb, task); } static void query_file_info_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); GTask *task = G_TASK (user_data); TaskData *task_data; GFileInfo *info; GError *error = NULL; info = g_file_query_info_finish (file, result, &error); if (error != NULL) { g_task_return_error (task, error); g_object_unref (task); g_clear_object (&info); return; } task_data = g_task_get_task_data (task); if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) { task_data->expected_file_size = g_file_info_get_size (info); if (task_data->expected_file_size > task_data->max_size) { g_task_return_error (task, _gfls_loader_error_too_big_file_size ()); g_object_unref (task); g_clear_object (&info); return; } } else { task_data->expected_file_size = DEFAULT_FILE_SIZE; } open_file (task); g_clear_object (&info); } static void query_file_info (GTask *task) { GFile *file = g_task_get_source_object (task); g_file_query_info_async (file, G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, g_task_get_priority (task), g_task_get_cancellable (task), query_file_info_cb, task); } /** * gfls_loader_basic_load_async: * @file: a #GFile. * @max_size: the maximum allowed number of bytes in total. * @max_n_bytes_per_line: the maximum allowed number of bytes per line, as per * gfls_utf8_find_very_long_line(). * @io_priority: the I/O priority of the request. E.g. %G_PRIORITY_LOW, * %G_PRIORITY_DEFAULT or %G_PRIORITY_HIGH. * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. * @callback: (scope async): a #GAsyncReadyCallback to call when the operation * is finished. * @user_data: user data to pass to @callback. * * Starts a basic file loading operation. * * If the @file content is not a valid UTF-8 string, or if the @max_size or * @max_n_bytes_per_line conditions are not satisfied, an error will be returned * without the file content. * * See the #GAsyncResult documentation to know how to use this function. * * Since: 0.1 */ void gfls_loader_basic_load_async (GFile *file, gsize max_size, guint max_n_bytes_per_line, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GTask *task; TaskData *task_data; g_return_if_fail (G_IS_FILE (file)); g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable)); task = g_task_new (file, cancellable, callback, user_data); g_task_set_priority (task, io_priority); task_data = task_data_new (max_size, max_n_bytes_per_line); g_task_set_task_data (task, task_data, (GDestroyNotify) task_data_free); query_file_info (task); } /** * gfls_loader_basic_load_finish: * @file: a #GFile. * @result: a #GAsyncResult. * @error: a #GError, or %NULL. * * Finishes an operation started with gfls_loader_basic_load_async(). * * If everything went well, a #GBytes with the #GFile content (unmodified) is * returned. It is guaranteed to be a valid UTF-8 string. * * Otherwise an error is returned. The %GFLS_LOADER_ERROR domain is used, among * others. * * The data contained in the resulting #GBytes is always zero-terminated, but * this is not included in the #GBytes length. The resulting #GBytes should be * freed with g_bytes_unref() when no longer in use. * * Returns: a #GBytes, or %NULL on error. * Since: 0.1 */ GBytes * gfls_loader_basic_load_finish (GFile *file, GAsyncResult *result, GError **error) { gboolean ok; g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (g_task_is_valid (result, file), NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); ok = g_task_propagate_boolean (G_TASK (result), error); if (ok) { TaskData *task_data; GBytes *bytes; task_data = g_task_get_task_data (G_TASK (result)); bytes = task_data->bytes; task_data->bytes = NULL; return bytes; } return NULL; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-basic.h000066400000000000000000000014771516613426200270150ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_LOADER_BASIC_H #define GFLS_LOADER_BASIC_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS G_MODULE_EXPORT void gfls_loader_basic_load_async (GFile *file, gsize max_size, guint max_n_bytes_per_line, gint io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); G_MODULE_EXPORT GBytes * gfls_loader_basic_load_finish (GFile *file, GAsyncResult *result, GError **error); G_END_DECLS #endif /* GFLS_LOADER_BASIC_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-config-simple.c000066400000000000000000000060051516613426200304530ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-loader-config-simple.h" /** * SECTION:gfls-loader-config-simple * @Title: GflsLoaderConfigSimple * @Short_description: Loader configuration */ struct _GflsLoaderConfigSimplePrivate { GFile *file; GInputStream *input_stream; }; G_DEFINE_TYPE_WITH_PRIVATE (GflsLoaderConfigSimple, gfls_loader_config_simple, G_TYPE_OBJECT) static void gfls_loader_config_simple_dispose (GObject *object) { GflsLoaderConfigSimple *config = GFLS_LOADER_CONFIG_SIMPLE (object); g_clear_object (&config->priv->file); g_clear_object (&config->priv->input_stream); G_OBJECT_CLASS (gfls_loader_config_simple_parent_class)->dispose (object); } static void gfls_loader_config_simple_class_init (GflsLoaderConfigSimpleClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->dispose = gfls_loader_config_simple_dispose; } static void gfls_loader_config_simple_init (GflsLoaderConfigSimple *config) { config->priv = gfls_loader_config_simple_get_instance_private (config); } /** * gfls_loader_config_simple_new_from_file: * @file: a #GFile. * * Creates a new #GflsLoaderConfigSimple object with @file for the input * content. * * Returns: (transfer full): a new #GflsLoaderConfigSimple object. * Since: 0.2 */ GflsLoaderConfigSimple * gfls_loader_config_simple_new_from_file (GFile *file) { GflsLoaderConfigSimple *config; g_return_val_if_fail (G_IS_FILE (file), NULL); config = g_object_new (GFLS_TYPE_LOADER_CONFIG_SIMPLE, NULL); config->priv->file = g_object_ref (file); return config; } /** * gfls_loader_config_simple_new_from_stream: * @input_stream: a #GInputStream. * * Creates a new #GflsLoaderConfigSimple object with @input_stream for the input * content. * * To load from stdin, a useful function is * g_application_command_line_get_stdin(). * * Returns: (transfer full): a new #GflsLoaderConfigSimple object. * Since: 0.2 */ GflsLoaderConfigSimple * gfls_loader_config_simple_new_from_stream (GInputStream *input_stream) { GflsLoaderConfigSimple *config; g_return_val_if_fail (G_IS_INPUT_STREAM (input_stream), NULL); config = g_object_new (GFLS_TYPE_LOADER_CONFIG_SIMPLE, NULL); config->priv->input_stream = g_object_ref (input_stream); return config; } /** * gfls_loader_config_simple_get_file: * @config: a #GflsLoaderConfigSimple. * * Returns: (transfer none) (nullable): the #GFile of @config, or %NULL. * Since: 0.2 */ GFile * gfls_loader_config_simple_get_file (GflsLoaderConfigSimple *config) { g_return_val_if_fail (GFLS_IS_LOADER_CONFIG_SIMPLE (config), NULL); return config->priv->file; } /** * gfls_loader_config_simple_get_stream: * @config: a #GflsLoaderConfigSimple. * * Returns: (transfer none) (nullable): the #GInputStream of @config, or %NULL. * Since: 0.2 */ GInputStream * gfls_loader_config_simple_get_stream (GflsLoaderConfigSimple *config) { g_return_val_if_fail (GFLS_IS_LOADER_CONFIG_SIMPLE (config), NULL); return config->priv->input_stream; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-config-simple.h000066400000000000000000000040061516613426200304570ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_LOADER_CONFIG_SIMPLE_H #define GFLS_LOADER_CONFIG_SIMPLE_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS #define GFLS_TYPE_LOADER_CONFIG_SIMPLE (gfls_loader_config_simple_get_type ()) #define GFLS_LOADER_CONFIG_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GFLS_TYPE_LOADER_CONFIG_SIMPLE, GflsLoaderConfigSimple)) #define GFLS_LOADER_CONFIG_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFLS_TYPE_LOADER_CONFIG_SIMPLE, GflsLoaderConfigSimpleClass)) #define GFLS_IS_LOADER_CONFIG_SIMPLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GFLS_TYPE_LOADER_CONFIG_SIMPLE)) #define GFLS_IS_LOADER_CONFIG_SIMPLE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFLS_TYPE_LOADER_CONFIG_SIMPLE)) #define GFLS_LOADER_CONFIG_SIMPLE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFLS_TYPE_LOADER_CONFIG_SIMPLE, GflsLoaderConfigSimpleClass)) typedef struct _GflsLoaderConfigSimple GflsLoaderConfigSimple; typedef struct _GflsLoaderConfigSimpleClass GflsLoaderConfigSimpleClass; typedef struct _GflsLoaderConfigSimplePrivate GflsLoaderConfigSimplePrivate; struct _GflsLoaderConfigSimple { GObject parent; GflsLoaderConfigSimplePrivate *priv; }; struct _GflsLoaderConfigSimpleClass { GObjectClass parent_class; gpointer padding[12]; }; G_MODULE_EXPORT GType gfls_loader_config_simple_get_type (void); G_MODULE_EXPORT GflsLoaderConfigSimple *gfls_loader_config_simple_new_from_file (GFile *file); G_MODULE_EXPORT GflsLoaderConfigSimple *gfls_loader_config_simple_new_from_stream (GInputStream *input_stream); G_MODULE_EXPORT GFile * gfls_loader_config_simple_get_file (GflsLoaderConfigSimple *config); G_MODULE_EXPORT GInputStream * gfls_loader_config_simple_get_stream (GflsLoaderConfigSimple *config); G_END_DECLS #endif /* GFLS_LOADER_CONFIG_SIMPLE_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-config.c000066400000000000000000000011251516613426200271620ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-loader-config.h" /** * SECTION:gfls-loader-config * @Title: GflsLoaderConfig * @Short_description: Loader configuration interface * * #GflsLoaderConfig is an interface that classes implement to store a loader * configuration. * * Currently it is an empty interface, also called a “marker interface”. */ G_DEFINE_INTERFACE (GflsLoaderConfig, gfls_loader_config, G_TYPE_OBJECT) static void gfls_loader_config_default_init (GflsLoaderConfigInterface *interface) { } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-loader-config.h000066400000000000000000000022671516613426200271770ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_LOADER_CONFIG_H #define GFLS_LOADER_CONFIG_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define GFLS_TYPE_LOADER_CONFIG (gfls_loader_config_get_type ()) #define GFLS_LOADER_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GFLS_TYPE_LOADER_CONFIG, GflsLoaderConfig)) #define GFLS_IS_LOADER_CONFIG(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GFLS_TYPE_LOADER_CONFIG)) #define GFLS_LOADER_CONFIG_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), GFLS_TYPE_LOADER_CONFIG, GflsLoaderConfigInterface)) typedef struct _GflsLoaderConfig GflsLoaderConfig; typedef struct _GflsLoaderConfigInterface GflsLoaderConfigInterface; /** * GflsLoaderConfigInterface: * @parent_interface: The parent interface. * * Since: 0.2 */ struct _GflsLoaderConfigInterface { GTypeInterface parent_interface; }; G_MODULE_EXPORT GType gfls_loader_config_get_type (void); G_END_DECLS #endif /* GFLS_LOADER_CONFIG_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-unsaved-document-titles.c000066400000000000000000000150351516613426200312410ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-config.h" #include "gfls-unsaved-document-titles.h" #include /** * SECTION:gfls-unsaved-document-titles * @Title: GflsUnsavedDocumentTitles * @Short_description: To give titles to unsaved documents * * #GflsUnsavedDocumentTitles is used to give titles to unsaved documents, such * as "Unsaved Document N" with 'N' replaced by a number. * * This is for new documents that have never been saved before and reside in * memory only. These documents have not yet an associated #GFile. * * Do not confuse it with documents with unsaved changes. */ #define FIRST_NUMBER (1) struct _GflsUnsavedDocumentTitlesPrivate { /* Sorted list of owned 'gint*'. */ GList *allocated_numbers; GflsUnsavedDocumentTitleCallback title_callback; }; static GflsUnsavedDocumentTitles *default_instance; G_DEFINE_TYPE_WITH_PRIVATE (GflsUnsavedDocumentTitles, gfls_unsaved_document_titles, G_TYPE_OBJECT) static gint compare_numbers (gconstpointer a, gconstpointer b) { const gint *ptr_num_a; const gint *ptr_num_b; gint num_a; gint num_b; g_return_val_if_fail (a != NULL, 0); g_return_val_if_fail (b != NULL, 0); ptr_num_a = a; ptr_num_b = b; num_a = *ptr_num_a; num_b = *ptr_num_b; return num_a - num_b; } static gchar * default_title_cb (gint num) { return g_strdup_printf (_("Unsaved Document %d"), num); } static void gfls_unsaved_document_titles_finalize (GObject *object) { GflsUnsavedDocumentTitles *titles = GFLS_UNSAVED_DOCUMENT_TITLES (object); if (default_instance == titles) { default_instance = NULL; } g_list_free_full (titles->priv->allocated_numbers, g_free); G_OBJECT_CLASS (gfls_unsaved_document_titles_parent_class)->finalize (object); } static void gfls_unsaved_document_titles_class_init (GflsUnsavedDocumentTitlesClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->finalize = gfls_unsaved_document_titles_finalize; } static void gfls_unsaved_document_titles_init (GflsUnsavedDocumentTitles *titles) { titles->priv = gfls_unsaved_document_titles_get_instance_private (titles); titles->priv->title_callback = default_title_cb; } /** * gfls_unsaved_document_titles_new: * * Returns: (transfer full): a new #GflsUnsavedDocumentTitles object. * Since: 0.1 */ GflsUnsavedDocumentTitles * gfls_unsaved_document_titles_new (void) { return g_object_new (GFLS_TYPE_UNSAVED_DOCUMENT_TITLES, NULL); } /** * gfls_unsaved_document_titles_get_default: * * Returns: (transfer none): the default instance of #GflsUnsavedDocumentTitles. * Since: 0.1 */ GflsUnsavedDocumentTitles * gfls_unsaved_document_titles_get_default (void) { if (default_instance == NULL) { default_instance = gfls_unsaved_document_titles_new (); } return default_instance; } void _gfls_unsaved_document_titles_unref_default_instance (void) { if (default_instance != NULL) { g_object_unref (default_instance); } /* default_instance is not set to NULL here, it is set to NULL in * gfls_unsaved_document_titles_finalize() (i.e. when we are sure that * the ref count reaches 0). */ } /** * gfls_unsaved_document_titles_allocate_number: * @titles: a #GflsUnsavedDocumentTitles. * * Allocates a number for an unsaved document. When the document is saved on * disk, you need to give back the number with * gfls_unsaved_document_titles_release_number(). * * The returned number is the lowest available value, starting at 1. * * Returns: the allocated number. * Since: 0.1 */ gint gfls_unsaved_document_titles_allocate_number (GflsUnsavedDocumentTitles *titles) { gint num = FIRST_NUMBER; GList *node; gint *num_data; g_return_val_if_fail (GFLS_IS_UNSAVED_DOCUMENT_TITLES (titles), 0); node = titles->priv->allocated_numbers; while (node != NULL) { const gint *node_data = node->data; const gint allocated_num = *node_data; if (num != allocated_num) { break; } num++; node = node->next; } num_data = g_new (gint, 1); *num_data = num; titles->priv->allocated_numbers = g_list_insert_sorted (titles->priv->allocated_numbers, num_data, compare_numbers); return num; } /** * gfls_unsaved_document_titles_release_number: * @titles: a #GflsUnsavedDocumentTitles. * @number: the number to release. * * Call this function to give back @number to @titles, so that it becomes * available for a next unsaved document. This is usually done when the document * is saved on disk. * * Since: 0.1 */ void gfls_unsaved_document_titles_release_number (GflsUnsavedDocumentTitles *titles, gint number) { GList *node; g_return_if_fail (GFLS_IS_UNSAVED_DOCUMENT_TITLES (titles)); for (node = titles->priv->allocated_numbers; node != NULL; node = node->next) { const gint *node_data = node->data; const gint allocated_num = *node_data; if (allocated_num == number) { break; } } if (node != NULL) { titles->priv->allocated_numbers = g_list_remove_link (titles->priv->allocated_numbers, node); g_list_free_full (node, g_free); } } /** * gfls_unsaved_document_titles_get_title: * @titles: a #GflsUnsavedDocumentTitles. * @number: a number. * * Generates the title of an unsaved document. To customize the returned string, * you can use gfls_unsaved_document_titles_set_title_callback(). * * Returns: (transfer full): a suitable title for the unsaved document with the * given @number. * Since: 0.1 */ gchar * gfls_unsaved_document_titles_get_title (GflsUnsavedDocumentTitles *titles, gint number) { g_return_val_if_fail (GFLS_IS_UNSAVED_DOCUMENT_TITLES (titles), NULL); return titles->priv->title_callback (number); } /** * gfls_unsaved_document_titles_set_title_callback: (skip) * @titles: a #GflsUnsavedDocumentTitles. * @title_callback: (nullable): a #GflsUnsavedDocumentTitleCallback. * * Sets a #GflsUnsavedDocumentTitleCallback function. To reset to the default * setting, pass %NULL to @title_callback. * * The callback will be used by gfls_unsaved_document_titles_get_title(). * * Examples: * - "Unsaved Document N" * - "Unsaved File N" * - "Untitled Document N" * - "New Document N" * - Etc. * * Since: 0.1 */ void gfls_unsaved_document_titles_set_title_callback (GflsUnsavedDocumentTitles *titles, GflsUnsavedDocumentTitleCallback title_callback) { g_return_if_fail (GFLS_IS_UNSAVED_DOCUMENT_TITLES (titles)); if (title_callback != NULL) { titles->priv->title_callback = title_callback; } else { titles->priv->title_callback = default_title_cb; } } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-unsaved-document-titles.h000066400000000000000000000056041516613426200312470ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_UNSAVED_DOCUMENT_TITLES_H #define GFLS_UNSAVED_DOCUMENT_TITLES_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include #include G_BEGIN_DECLS #define GFLS_TYPE_UNSAVED_DOCUMENT_TITLES (gfls_unsaved_document_titles_get_type ()) #define GFLS_UNSAVED_DOCUMENT_TITLES(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GFLS_TYPE_UNSAVED_DOCUMENT_TITLES, GflsUnsavedDocumentTitles)) #define GFLS_UNSAVED_DOCUMENT_TITLES_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GFLS_TYPE_UNSAVED_DOCUMENT_TITLES, GflsUnsavedDocumentTitlesClass)) #define GFLS_IS_UNSAVED_DOCUMENT_TITLES(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GFLS_TYPE_UNSAVED_DOCUMENT_TITLES)) #define GFLS_IS_UNSAVED_DOCUMENT_TITLES_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GFLS_TYPE_UNSAVED_DOCUMENT_TITLES)) #define GFLS_UNSAVED_DOCUMENT_TITLES_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GFLS_TYPE_UNSAVED_DOCUMENT_TITLES, GflsUnsavedDocumentTitlesClass)) typedef struct _GflsUnsavedDocumentTitles GflsUnsavedDocumentTitles; typedef struct _GflsUnsavedDocumentTitlesClass GflsUnsavedDocumentTitlesClass; typedef struct _GflsUnsavedDocumentTitlesPrivate GflsUnsavedDocumentTitlesPrivate; struct _GflsUnsavedDocumentTitles { GObject parent; GflsUnsavedDocumentTitlesPrivate *priv; }; struct _GflsUnsavedDocumentTitlesClass { GObjectClass parent_class; gpointer padding[12]; }; /** * GflsUnsavedDocumentTitleCallback: * @num: the number. * * Type definition for a function that will be called to create a string * containing @num, to give a name to a document not yet present on disk. * * Returns: (transfer full): the created title. * Since: 0.1 */ typedef gchar *(*GflsUnsavedDocumentTitleCallback) (gint num); G_MODULE_EXPORT GType gfls_unsaved_document_titles_get_type (void); G_MODULE_EXPORT GflsUnsavedDocumentTitles * gfls_unsaved_document_titles_new (void); G_MODULE_EXPORT GflsUnsavedDocumentTitles * gfls_unsaved_document_titles_get_default (void); G_MODULE_EXPORT gint gfls_unsaved_document_titles_allocate_number (GflsUnsavedDocumentTitles *titles); G_MODULE_EXPORT void gfls_unsaved_document_titles_release_number (GflsUnsavedDocumentTitles *titles, gint number); G_MODULE_EXPORT gchar * gfls_unsaved_document_titles_get_title (GflsUnsavedDocumentTitles *titles, gint number); G_MODULE_EXPORT void gfls_unsaved_document_titles_set_title_callback (GflsUnsavedDocumentTitles *titles, GflsUnsavedDocumentTitleCallback title_callback); G_GNUC_INTERNAL void _gfls_unsaved_document_titles_unref_default_instance (void); G_END_DECLS #endif /* GFLS_UNSAVED_DOCUMENT_TITLES_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-utf8.c000066400000000000000000000025411516613426200253420ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-utf8.h" /** * SECTION:gfls-utf8 * @Title: GflsUtf8 * @Short_description: Functions for UTF-8 strings * * Additional functions for UTF-8 strings, to complement what is provided by * GLib. */ /** * gfls_utf8_find_very_long_line: * @str: a UTF-8 nul-terminated string. * @max_n_bytes_per_line: the maximum number of bytes per line, without counting * the newline character(s). * * Finds if a line in @str exceeds @max_n_bytes_per_line. * * For performance reasons, @str is not checked whether it is a valid UTF-8 * string. So you must call for example g_utf8_validate() beforehand. * * Returns: a pointer to the beginning of the first very long line found, or * %NULL if not found. * Since: 0.3 */ const gchar * gfls_utf8_find_very_long_line (const gchar *str, guint max_n_bytes_per_line) { guint cur_pos; guint line_length = 0; g_return_val_if_fail (str != NULL, NULL); for (cur_pos = 0; str[cur_pos] != '\0'; cur_pos++) { gchar ch = str[cur_pos]; if (ch == '\n' || ch == '\r') { line_length = 0; } else { line_length++; if (line_length > max_n_bytes_per_line) { guint line_start_pos = cur_pos - line_length + 1; return str + line_start_pos; } } } return NULL; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls-utf8.h000066400000000000000000000007251516613426200253510ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_UTF8_H #define GFLS_UTF8_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only can be included directly." #endif #include G_BEGIN_DECLS G_MODULE_EXPORT const gchar * gfls_utf8_find_very_long_line (const gchar *str, guint max_n_bytes_per_line); G_END_DECLS #endif /* GFLS_UTF8_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/gfls.h000066400000000000000000000013631516613426200244640ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_H #define GFLS_H #define GFLS_H_INSIDE #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef GFLS_H_INSIDE #endif /* GFLS_H */ libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/meson.build000066400000000000000000000063431516613426200255250ustar00rootroot00000000000000gfls_public_headers = [ 'gfls.h', 'gfls-attribute-keys.h', 'gfls-bytes-region-builder.h', 'gfls-bytes-region.h', 'gfls-encoding-conversion.h', 'gfls-encoding-convert.h', 'gfls-error.h', 'gfls-iconv.h', 'gfls-init.h', 'gfls-input-stream.h', 'gfls-loader-basic.h', 'gfls-loader-config.h', 'gfls-loader-config-simple.h', 'gfls-unsaved-document-titles.h', 'gfls-utf8.h', ] gfls_public_c_files = [ 'gfls-attribute-keys.c', 'gfls-bytes-region-builder.c', 'gfls-bytes-region.c', 'gfls-encoding-conversion.c', 'gfls-encoding-convert.c', 'gfls-error.c', 'gfls-iconv.c', 'gfls-init.c', 'gfls-input-stream.c', 'gfls-loader-basic.c', 'gfls-loader-config.c', 'gfls-loader-config-simple.c', 'gfls-unsaved-document-titles.c', 'gfls-utf8.c', ] GFLS_PRIVATE_HEADERS = [ 'gfls-bytes-region-private.h', ] headers_install_dir = get_option('includedir') / '@0@-@1@/gfls/'.format(meson.project_name(), GFLS_API_VERSION) install_headers( gfls_public_headers, install_dir: headers_install_dir ) gfls_enum_types = GNOME.mkenums_simple( 'gfls-enum-types', decorator: 'G_MODULE_EXPORT', header_prefix: '#include ', sources: gfls_public_headers, install_header: true, install_dir: headers_install_dir ) gfls_static_lib = static_library( 'libgedit-gfls-static', [gfls_public_headers, gfls_public_c_files, GFLS_PRIVATE_HEADERS, gfls_enum_types], pic: true, # gfls_static_lib is potentially linked in a shared library. include_directories: ROOT_INCLUDE_DIR, dependencies: GFLS_DEPS, c_args: '-DGFLS_COMPILATION' ) # For unit tests, to be able to test private functions. GFLS_STATIC_DEP = declare_dependency( include_directories: ROOT_INCLUDE_DIR, link_with: gfls_static_lib, sources: gfls_enum_types[1], dependencies: GFLS_DEPS ) symbol_map = 'symbol.map' gfls_lib_link_args = c_compiler.get_supported_link_arguments([ '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), symbol_map), ]) gfls_lib = library( 'gedit-gfls-@0@'.format(GFLS_API_VERSION), dependencies: GFLS_DEPS, link_args: gfls_lib_link_args, link_depends: symbol_map, # link_whole is not supported with MSVC, so we use extract_all_objects(). objects: gfls_static_lib.extract_all_objects(recursive: false), soversion: 0, install: true ) GFLS_LIB_DEP = declare_dependency( include_directories: ROOT_INCLUDE_DIR, link_with: gfls_lib, sources: gfls_enum_types[1], dependencies: GFLS_DEPS ) PKG_CONFIG.generate(gfls_lib, filebase: '@0@-@1@'.format(meson.project_name(), GFLS_API_VERSION), name: meson.project_name(), description: 'File loading and saving', subdirs: '@0@-@1@'.format(meson.project_name(), GFLS_API_VERSION), libraries: GFLS_DEPS, ) if get_option('gobject_introspection') GNOME.generate_gir( gfls_lib, export_packages: '@0@-@1@'.format(meson.project_name(), GFLS_API_VERSION), header: 'gfls/gfls.h', identifier_prefix: 'Gfls', include_directories: ROOT_INCLUDE_DIR, includes: ['Gtk-3.0'], install: true, namespace: 'Gfls', nsversion: GFLS_API_VERSION, sources: [ gfls_public_headers, gfls_public_c_files, gfls_enum_types, ], # Support for deps being built as subprojects: dependencies: GFLS_DEPS, ) endif libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/gfls/symbol.map000066400000000000000000000000431516613426200253560ustar00rootroot00000000000000{ global: gfls_*; local: *; }; libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/libgedit-gfls.doap000066400000000000000000000021031516613426200257770ustar00rootroot00000000000000 libgedit-gfls Gedit Technology - File loading and saving libgedit-gfls is part of Gedit Technology. It is a module dedicated to file loading and saving for the needs of gedit and other similar text editors. C Sébastien Wilmet swilmet libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/meson.build000066400000000000000000000063421516613426200245710ustar00rootroot00000000000000# Convention: # - Local variables in lower_case. # - Global variables in UPPER_CASE. # See: https://github.com/mesonbuild/meson/issues/2607 project( 'libgedit-gfls', 'c', meson_version: '>= 0.64', version: '0.4.1', default_options: ['warning_level=2'] ) GNOME = import('gnome') PKG_CONFIG = import('pkgconfig') I18N = import('i18n') FS = import('fs') # API version, used for parallel installability. GFLS_API_VERSION = '1' GFLS_DEPS = [ dependency('gio-2.0', version: '>= 2.78'), ] GTK3_DEP = dependency('gtk+-3.0', version: '>= 3.22', required: false) # gfls-config.h config_data = configuration_data() GETTEXT_PACKAGE_NAME = '@0@-@1@'.format(meson.project_name(), GFLS_API_VERSION) config_data.set_quoted('GETTEXT_PACKAGE', GETTEXT_PACKAGE_NAME) config_data.set_quoted('GFLS_LOCALEDIR', get_option('prefix') / get_option('localedir')) configure_file( output: 'gfls-config.h', configuration: config_data ) # Misc ROOT_INCLUDE_DIR = include_directories('.') add_project_arguments( '-DG_LOG_DOMAIN="@0@"'.format(meson.project_name()), language: 'c' ) ##### # CFLAGS # Some flags are missing when using only the builtin warning_level meson option, # even at the maximum level. # The following warning_cflags suppose that warning_level=2. c_compiler = meson.get_compiler('c') warning_cflags = [] if c_compiler.get_id() == 'msvc' # Use GLib's msvc_recommended_pragmas.h to filter out # the warnings we don't really need to worry about, # but do make the ones we want to be wary stand out warning_cflags += [ '-FImsvc_recommended_pragmas.h', ] else # Try to mimic the AX_COMPILER_FLAGS Autotools macro. warning_cflags += [ '-fno-strict-aliasing', '-Wundef', '-Wnested-externs', '-Wwrite-strings', '-Wpointer-arith', '-Wmissing-declarations', '-Wmissing-prototypes', '-Wstrict-prototypes', '-Wredundant-decls', '-Wno-unused-parameter', '-Wno-missing-field-initializers', '-Wdeclaration-after-statement', '-Wformat=2', '-Wold-style-definition', '-Wcast-align', '-Wformat-nonliteral', '-Wformat-security', '-Wsign-compare', '-Wstrict-aliasing', '-Wshadow', '-Winline', '-Wpacked', '-Wmissing-format-attribute', '-Wmissing-noreturn', '-Winit-self', '-Wredundant-decls', '-Wmissing-include-dirs', '-Wunused-but-set-variable', '-Warray-bounds', '-Wimplicit-function-declaration', '-Wreturn-type', '-Wswitch-enum', '-Wswitch-default', '-Wduplicated-cond', '-Wduplicated-branches', '-Wlogical-op', '-Wrestrict', '-Wnull-dereference', '-Wjump-misses-init', '-Wdouble-promotion' ] endif supported_warning_cflags = c_compiler.get_supported_arguments(warning_cflags) add_project_arguments(supported_warning_cflags, language: 'c') ##### end CFLAGS subdir('po') subdir('gfls') if get_option('tests') subdir('tests') endif if get_option('gtk_doc') subdir('docs/reference') endif summary('API version', GFLS_API_VERSION) summary('Prefix', get_option('prefix')) summary('GObject Introspection', get_option('gobject_introspection')) summary('API documentation', get_option('gtk_doc')) summary('Build tests', get_option('tests')) summary('Build GTK 3 tests', get_option('tests') and GTK3_DEP.found()) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/meson_options.txt000066400000000000000000000006051516613426200260600ustar00rootroot00000000000000option( 'gobject_introspection', type: 'boolean', value: true, description: 'Build GObject Introspection data (requires gobject-introspection)' ) option( 'gtk_doc', type: 'boolean', value: true, description: 'Build API reference (requires gtk-doc)' ) option( 'tests', type: 'boolean', value: true, description: 'Build tests (requires gtk3 for interactive GUI tests)' ) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/000077500000000000000000000000001516613426200230405ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/LINGUAS000066400000000000000000000002221516613426200240610ustar00rootroot00000000000000# Set of available languages. # Please keep this list sorted alphabetically. be bg cs da de el eu hu ka kk kw lt pl pt_BR ru sl sr sv tr uk zh_CN libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/POTFILES.in000066400000000000000000000006411516613426200246160ustar00rootroot00000000000000# List of source files containing translatable strings. gfls/gfls-attribute-keys.c gfls/gfls-bytes-region-builder.c gfls/gfls-bytes-region.c gfls/gfls-encoding-conversion.c gfls/gfls-encoding-convert.c gfls/gfls-error.c gfls/gfls-iconv.c gfls/gfls-init.c gfls/gfls-input-stream.c gfls/gfls-loader-basic.c gfls/gfls-loader-config.c gfls/gfls-loader-config-simple.c gfls/gfls-unsaved-document-titles.c gfls/gfls-utf8.c libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/POTFILES.skip000066400000000000000000000000001516613426200251430ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/be.po000066400000000000000000000030501516613426200237640ustar00rootroot00000000000000# Belarusian translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Yuras Shumovich \n" "Language-Team: Belarusian \n" "Language: be\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.6\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Памер файла занадта вялікі." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Дасягнута абмежаванне на колькасць байт для чытання." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Змесціва закадавана не ў UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Змесціва ўтрымлівае занадта доўгі радок." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Незахаваны дакумент %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/bg.po000066400000000000000000000030111516613426200237630ustar00rootroot00000000000000# Bulgarian translation for libgedit-gfls. # Copyright (C) 2025 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # twlvnn kraftwerk , 2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-08-10 21:54+0000\n" "PO-Revision-Date: 2025-08-23 16:07+0200\n" "Last-Translator: twlvnn kraftwerk \n" "Language-Team: Bulgarian \n" "Language: bg\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1)\n" "X-Generator: Gtranslator 48.0\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Размерът на файла е прекалено голям." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Достигнато е ограничението на броя байтове за четене." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Съдържанието не е кодирано в UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Съдържанието съдържа много дълъг ред." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Незапазен документ %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/cs.po000066400000000000000000000025001516613426200240020ustar00rootroot00000000000000# Czech translation for libgedit-gfls. # Copyright (C) 2025 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Dagobert Janota , 2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-07-20 08:53+0000\n" "PO-Revision-Date: 2025-07-27 22:02+0200\n" "Last-Translator: Dagobert Janota \n" "Language-Team: Czech\n" "Language: cs\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1) ? 0 : (n>=2 && n<=4) ? 1 : 2;\n" "X-Generator: Gtranslator 48.0\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Soubor je příliš velký." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Dosažen limit bajtů ke čtení." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Obsah není kódován v UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Soubor obsahuje velmi dlouhý řádek." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Neuložený dokument %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/da.po000066400000000000000000000041011516613426200237600ustar00rootroot00000000000000# Danish translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Alan Mortensen , 2024-26. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-09 14:04+0000\n" "PO-Revision-Date: 2026-03-14 13:21+0100\n" "Last-Translator: Alan Mortensen \n" "Language-Team: Danish \n" "Language: da\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.2\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Filen er for stor." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Grænsen for, hvor mange byte der skal læses, er nået." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Indholdet er ikke kodet i UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Der findes en meget lang linje i indholdet." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "Konvertering fra tegnsæt “%s” til “%s” understøttes ikke." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "" "Kunne ikke åbne et program til konvertering af tegnsæt fra “%s” til “%s”: " "%s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Der opstod en fejl under konvertering af tegnsæt: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Kunne ikke lukke programmet til konvertering af tegnsæt: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Dokumentet %d ikke gemt" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/de.po000066400000000000000000000025631516613426200237760ustar00rootroot00000000000000# German translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Jürgen Benvenuti , 2024, 2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-02-03 13:57+0000\n" "PO-Revision-Date: 2025-02-04 15:19+0100\n" "Last-Translator: Jürgen Benvenuti \n" "Language-Team: German \n" "Language: de\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.4.4\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Die Größe der Datei ist zu groß." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Grenze der Anzahl der zu lesenden Bytes wurde erreicht." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Der Inhalt ist nicht in UTF-8 codiert." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Der Inhalt enthält eine sehr lange Zeile." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Ungespeichertes Dokument %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/el.po000066400000000000000000000030171516613426200240010ustar00rootroot00000000000000# Greek translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Giannis Antypas , 2024. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2024-11-01 18:13+0000\n" "PO-Revision-Date: 2024-11-01 18:13+0000\n" "Last-Translator: Giannis Antypas \n" "Language-Team: Greek \n" "Language: el\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" #: gfls/gfls-loader-basic.c:108 msgid "The file is not encoded in UTF-8." msgstr "Το αρχείο δεν είναι κωδικοποιημένο σε UTF-8." #: gfls/gfls-loader-basic.c:118 msgid "The file contains a very long line." msgstr "Το αρχείο περιέχει μια πολύ μακριά γραμμή." #: gfls/gfls-loader-basic.c:164 msgid "Limit on the number of bytes to read reached." msgstr "Συμπληρώθηκε το όριο στον αριθμό των byte προς ανάγνωση." #: gfls/gfls-loader-basic.c:259 msgid "The size of the file is too big." msgstr "Το μέγεθος του αρχείου είναι πολύ μεγάλο." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Μη αποθηκευμένο έγγραφο %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/eu.po000066400000000000000000000023711516613426200240140ustar00rootroot00000000000000# Basque translation for libgedit-gfls. # Copyright (C) 2025 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # FIRST AUTHOR , YEAR. # msgid "" msgstr "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/issues\n" "POT-Creation-Date: 2025-05-10 20:14+0000\n" "PO-Revision-Date: 2025-05-10 20:14+0000\n" "Last-Translator: Asier Saratsua Garmendia \n" "Language-Team: Basque \n" "Language: eu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Fitxategiaren tamaina handiegia da." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Irakurri daitekeen byte kopuruaren mugara iritsi da." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Edukia ez dago UTF-8 kodeketan kodetuta." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Edukiak lerro oso luzea du." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Gorde gabeko %d dokumentua" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/hu.po000066400000000000000000000041501516613426200240140ustar00rootroot00000000000000# Hungarian translation for libgedit-gfls. # Copyright (C) 2025, 2026 Free Software Foundation, Inc. # This file is distributed under the same license as the libgedit-gfls package. # # Balázs Úr , 2025, 2026. msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/iss" "ues\n" "POT-Creation-Date: 2026-03-09 14:04+0000\n" "PO-Revision-Date: 2026-03-11 00:09+0100\n" "Last-Translator: Balázs Úr \n" "Language-Team: Hungarian \n" "Language: hu\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Lokalize 25.08.1\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "A fájl mérete túl nagy." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "A beolvasandó bájtok számának korlátja elérve." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "A tartalom nem UTF-8 kódolású." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "A tartalom egy nagyon hosszú sort tartalmaz." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "" "A(z) „%s” és a(z) „%s” karakterkészletek közötti átalakítás nem támogatott." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "" "Nem sikerült megnyitni a(z) „%s” és a(z) „%s” karakterkészletek közötti " "átalakítót: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Hiba a karakterkészlet-átalakítás során: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Nem sikerült bezárni a karakterkészlet-átalakítót: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Mentetlen dokumentum %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/ka.po000066400000000000000000000132341516613426200237760ustar00rootroot00000000000000# Georgian translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's authors # This file is distributed under the same license as the libgedit-gfls package. # Ekaterine Papava , 2024-2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-01-13 02:09+0000\n" "PO-Revision-Date: 2025-01-21 04:42+0100\n" "Last-Translator: Ekaterine Papava \n" "Language-Team: Georgian \n" "Language: ka\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.5\n" #. Translators: the first %s is a category, the second %s is the #. * name. #. #: gfls/gfls-encoding.c:203 #, c-format msgid "%s (%s)" msgstr "%s (%s)" #. UTF-8 first, so that it's the first encoding returned by #. * tepl_encoding_iconv_get_all(). #. #: gfls/gfls-encoding-manager-iconv.c:44 gfls/gfls-encoding-manager-iconv.c:61 #: gfls/gfls-encoding-manager-iconv.c:62 gfls/gfls-encoding-manager-iconv.c:63 #: gfls/gfls-encoding-manager-iconv.c:64 gfls/gfls-encoding-manager-iconv.c:65 #: gfls/gfls-encoding-manager-iconv.c:66 gfls/gfls-encoding-manager-iconv.c:67 msgid "Unicode" msgstr "უნიკოდი" #. FIXME GEOSTD8 ? #: gfls/gfls-encoding-manager-iconv.c:46 gfls/gfls-encoding-manager-iconv.c:58 #: gfls/gfls-encoding-manager-iconv.c:86 gfls/gfls-encoding-manager-iconv.c:109 msgid "Western" msgstr "დასავლური" #: gfls/gfls-encoding-manager-iconv.c:47 gfls/gfls-encoding-manager-iconv.c:87 #: gfls/gfls-encoding-manager-iconv.c:107 msgid "Central European" msgstr "ცენტრალურ ევროპული" #: gfls/gfls-encoding-manager-iconv.c:48 msgid "South European" msgstr "სამხრეთ ევროპული" #: gfls/gfls-encoding-manager-iconv.c:49 gfls/gfls-encoding-manager-iconv.c:56 #: gfls/gfls-encoding-manager-iconv.c:114 msgid "Baltic" msgstr "ბალტიური" #: gfls/gfls-encoding-manager-iconv.c:50 gfls/gfls-encoding-manager-iconv.c:88 #: gfls/gfls-encoding-manager-iconv.c:95 gfls/gfls-encoding-manager-iconv.c:97 #: gfls/gfls-encoding-manager-iconv.c:98 gfls/gfls-encoding-manager-iconv.c:108 msgid "Cyrillic" msgstr "კირილიცა" #: gfls/gfls-encoding-manager-iconv.c:51 gfls/gfls-encoding-manager-iconv.c:91 #: gfls/gfls-encoding-manager-iconv.c:113 msgid "Arabic" msgstr "არაბული" #: gfls/gfls-encoding-manager-iconv.c:52 gfls/gfls-encoding-manager-iconv.c:110 msgid "Greek" msgstr "ბერძნული" #: gfls/gfls-encoding-manager-iconv.c:53 msgid "Hebrew Visual" msgstr "ივრითი ვიზუალი" #: gfls/gfls-encoding-manager-iconv.c:54 gfls/gfls-encoding-manager-iconv.c:89 #: gfls/gfls-encoding-manager-iconv.c:111 msgid "Turkish" msgstr "თურქული" #: gfls/gfls-encoding-manager-iconv.c:55 msgid "Nordic" msgstr "სკანდინავიური" #: gfls/gfls-encoding-manager-iconv.c:57 msgid "Celtic" msgstr "კელტური" #: gfls/gfls-encoding-manager-iconv.c:59 msgid "Romanian" msgstr "რუმინული" #: gfls/gfls-encoding-manager-iconv.c:69 msgid "Armenian" msgstr "სომხური" #: gfls/gfls-encoding-manager-iconv.c:70 gfls/gfls-encoding-manager-iconv.c:71 #: gfls/gfls-encoding-manager-iconv.c:79 msgid "Chinese Traditional" msgstr "ჩინური ტრადიციული" #: gfls/gfls-encoding-manager-iconv.c:72 msgid "Cyrillic/Russian" msgstr "კირილიცა/რუსული" #: gfls/gfls-encoding-manager-iconv.c:74 gfls/gfls-encoding-manager-iconv.c:75 #: gfls/gfls-encoding-manager-iconv.c:76 gfls/gfls-encoding-manager-iconv.c:93 #: gfls/gfls-encoding-manager-iconv.c:101 msgid "Japanese" msgstr "იაპონური" #: gfls/gfls-encoding-manager-iconv.c:78 gfls/gfls-encoding-manager-iconv.c:94 #: gfls/gfls-encoding-manager-iconv.c:96 gfls/gfls-encoding-manager-iconv.c:104 msgid "Korean" msgstr "კორეული" #: gfls/gfls-encoding-manager-iconv.c:81 gfls/gfls-encoding-manager-iconv.c:82 #: gfls/gfls-encoding-manager-iconv.c:83 msgid "Chinese Simplified" msgstr "ჩინური გამარტივებული" #: gfls/gfls-encoding-manager-iconv.c:84 msgid "Georgian" msgstr "ქართული" #: gfls/gfls-encoding-manager-iconv.c:90 gfls/gfls-encoding-manager-iconv.c:112 msgid "Hebrew" msgstr "ივრითი" #: gfls/gfls-encoding-manager-iconv.c:99 msgid "Cyrillic/Ukrainian" msgstr "კირილიცა/უკრაინული" #: gfls/gfls-encoding-manager-iconv.c:102 #: gfls/gfls-encoding-manager-iconv.c:105 #: gfls/gfls-encoding-manager-iconv.c:115 msgid "Vietnamese" msgstr "ვიეტნამური" #: gfls/gfls-encoding-manager-iconv.c:103 msgid "Thai" msgstr "ტაილანდური" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "ფაილის ზომა ძალიან დიდია." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "შეზღუდეთ ბაიტების რაოდენობა, რომ წაიკითხოთ." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "შემცველობა არ არის კოდირებული UTF-8- ში." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "შემცველობა შეიცავს ძალიან გრძელი ხაზს." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "შეუნახავი დოკუმენტი %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/kk.po000066400000000000000000000052371516613426200240140ustar00rootroot00000000000000# Kazakh translation for libgedit-gfls. # Copyright (C) 2026 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Baurzhan Muftakhidinov , 2026. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-03-26 22:25+0500\n" "Last-Translator: Baurzhan Muftakhidinov \n" "Language-Team: Kazakh \n" "Language: kk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.9\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Бірнеше қайтарылмайтын түрлендіру жұмыстары жүргізілді." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Жарамсыз таңба кездестірілді." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Файл өлшемі тым үлкен." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Оқуға болатын байттар санының шегіне жетті." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Мазмұны UTF-8 кодында кодталмаған." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Мазмұнда тым ұзын жол бар." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "«%s» таңбалар жиынынан «%s» жиынына түрлендіруге қолдау көрсетілмейді." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "" "«%s» жиынынан «%s» жиынына таңбалар жиынын түрлендіргішті ашу сәтсіз " "аяқталды: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Таңбалар жиынын түрлендіру кезіндегі қате: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Таңбалар жиынын түрлендіргішті жабу сәтсіз аяқталды: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Сақталмаған құжат %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/kw.po000066400000000000000000000027761516613426200240350ustar00rootroot00000000000000# Cornish translation for libgedit-gfls. # Copyright (C) 2026 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # FIRST AUTHOR , YEAR. # Flynn Peck , 2026. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-02-02 20:05+0000\n" "PO-Revision-Date: 2026-01-28 23:04+0000\n" "Last-Translator: Flynn Peck \n" "Language-Team: kw\n" "Language: kw\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-DL-VCS-Web: https://gitlab.gnome.org/World/gedit/libgedit-gfls\n" "X-DL-Lang: kw\n" "X-DL-Module: libgedit-gfls\n" "X-DL-Branch: main\n" "X-DL-Domain: po\n" "X-DL-State: Translating\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Gtranslator 49.0\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "An braster a'n restren yw re bras." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Finweth war'n niver baytys rag redya hedhys." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "An dalgh na kodennys yn UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "An dalgh kontaynya unn linen pur hir." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Skrif Ansawys %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/lt.po000066400000000000000000000026211516613426200240200ustar00rootroot00000000000000# Lithuanian translation for libgedit-gfls. # Copyright (C) 2026 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Aurimas Aurimas Černius , 2026. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-12-10 20:34+0000\n" "PO-Revision-Date: 2026-01-10 18:03+0200\n" "Last-Translator: Aurimas Černius \n" "Language-Team: Lithuanian \n" "Language: lt\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "(n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.8\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Failas yra per didelis." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Pasiekta skaitomų baitų skaičiaus riba." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Turinys nėra koduotas UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Turinyje yra labai ilgai eilutė." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Neįrašytas dokumentas %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/meson.build000066400000000000000000000000711516613426200252000ustar00rootroot00000000000000I18N.gettext( GETTEXT_PACKAGE_NAME, preset: 'glib' ) libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/pl.po000066400000000000000000000026331516613426200240170ustar00rootroot00000000000000# Polish translation for libgedit-gfls. # Copyright © 2025 the libgedit-gfls authors. # This file is distributed under the same license as the libgedit-gfls package. # Piotr Drąg , 2025. # Aviary.pl , 2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-02-24 17:44+0000\n" "PO-Revision-Date: 2025-03-02 15:18+0100\n" "Last-Translator: Piotr Drąg \n" "Language-Team: Polish \n" "Language: pl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n==1 ? 0 : n%10>=2 && n%10<=4 && (n%100<10 " "|| n%100>=20) ? 1 : 2);\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Rozmiar pliku jest za duży." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Osiągnięto ograniczenie liczby bajtów do odczytu." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Treść nie jest zakodowana jako UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Treść zawiera bardzo długi wiersz." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Niezapisany dokument %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/pt_BR.po000066400000000000000000000120511516613426200244050ustar00rootroot00000000000000# Brazilian Portuguese translation for libgedit-gfls. # Copyright (C) 2025 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Rafael Fontenelle , 2024-2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-01-13 02:09+0000\n" "PO-Revision-Date: 2025-01-15 00:23-0300\n" "Last-Translator: Rafael Fontenelle \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n > 1)\n" "X-Generator: Gtranslator 47.1\n" #. Translators: the first %s is a category, the second %s is the #. * name. #. #: gfls/gfls-encoding.c:203 #, c-format msgid "%s (%s)" msgstr "%s (%s)" #. UTF-8 first, so that it's the first encoding returned by #. * tepl_encoding_iconv_get_all(). #. #: gfls/gfls-encoding-manager-iconv.c:44 gfls/gfls-encoding-manager-iconv.c:61 #: gfls/gfls-encoding-manager-iconv.c:62 gfls/gfls-encoding-manager-iconv.c:63 #: gfls/gfls-encoding-manager-iconv.c:64 gfls/gfls-encoding-manager-iconv.c:65 #: gfls/gfls-encoding-manager-iconv.c:66 gfls/gfls-encoding-manager-iconv.c:67 msgid "Unicode" msgstr "Unicode" #. FIXME GEOSTD8 ? #: gfls/gfls-encoding-manager-iconv.c:46 gfls/gfls-encoding-manager-iconv.c:58 #: gfls/gfls-encoding-manager-iconv.c:86 gfls/gfls-encoding-manager-iconv.c:109 msgid "Western" msgstr "Ocidental" #: gfls/gfls-encoding-manager-iconv.c:47 gfls/gfls-encoding-manager-iconv.c:87 #: gfls/gfls-encoding-manager-iconv.c:107 msgid "Central European" msgstr "Centro europeu" #: gfls/gfls-encoding-manager-iconv.c:48 msgid "South European" msgstr "Europa sulista" #: gfls/gfls-encoding-manager-iconv.c:49 gfls/gfls-encoding-manager-iconv.c:56 #: gfls/gfls-encoding-manager-iconv.c:114 msgid "Baltic" msgstr "Báltico" #: gfls/gfls-encoding-manager-iconv.c:50 gfls/gfls-encoding-manager-iconv.c:88 #: gfls/gfls-encoding-manager-iconv.c:95 gfls/gfls-encoding-manager-iconv.c:97 #: gfls/gfls-encoding-manager-iconv.c:98 gfls/gfls-encoding-manager-iconv.c:108 msgid "Cyrillic" msgstr "Cirílico" #: gfls/gfls-encoding-manager-iconv.c:51 gfls/gfls-encoding-manager-iconv.c:91 #: gfls/gfls-encoding-manager-iconv.c:113 msgid "Arabic" msgstr "Árabe" #: gfls/gfls-encoding-manager-iconv.c:52 gfls/gfls-encoding-manager-iconv.c:110 msgid "Greek" msgstr "Grego" #: gfls/gfls-encoding-manager-iconv.c:53 msgid "Hebrew Visual" msgstr "Hebraico visual" #: gfls/gfls-encoding-manager-iconv.c:54 gfls/gfls-encoding-manager-iconv.c:89 #: gfls/gfls-encoding-manager-iconv.c:111 msgid "Turkish" msgstr "Turco" #: gfls/gfls-encoding-manager-iconv.c:55 msgid "Nordic" msgstr "Nórdico" #: gfls/gfls-encoding-manager-iconv.c:57 msgid "Celtic" msgstr "Céltico" #: gfls/gfls-encoding-manager-iconv.c:59 msgid "Romanian" msgstr "Romeno" #: gfls/gfls-encoding-manager-iconv.c:69 msgid "Armenian" msgstr "Armênio" #: gfls/gfls-encoding-manager-iconv.c:70 gfls/gfls-encoding-manager-iconv.c:71 #: gfls/gfls-encoding-manager-iconv.c:79 msgid "Chinese Traditional" msgstr "Chinês tradicional" #: gfls/gfls-encoding-manager-iconv.c:72 msgid "Cyrillic/Russian" msgstr "Cirílico/Russo" #: gfls/gfls-encoding-manager-iconv.c:74 gfls/gfls-encoding-manager-iconv.c:75 #: gfls/gfls-encoding-manager-iconv.c:76 gfls/gfls-encoding-manager-iconv.c:93 #: gfls/gfls-encoding-manager-iconv.c:101 msgid "Japanese" msgstr "Japonês" #: gfls/gfls-encoding-manager-iconv.c:78 gfls/gfls-encoding-manager-iconv.c:94 #: gfls/gfls-encoding-manager-iconv.c:96 gfls/gfls-encoding-manager-iconv.c:104 msgid "Korean" msgstr "Coreano" #: gfls/gfls-encoding-manager-iconv.c:81 gfls/gfls-encoding-manager-iconv.c:82 #: gfls/gfls-encoding-manager-iconv.c:83 msgid "Chinese Simplified" msgstr "Chinês simplificado" #: gfls/gfls-encoding-manager-iconv.c:84 msgid "Georgian" msgstr "Georgiano" #: gfls/gfls-encoding-manager-iconv.c:90 gfls/gfls-encoding-manager-iconv.c:112 msgid "Hebrew" msgstr "Hebraico" #: gfls/gfls-encoding-manager-iconv.c:99 msgid "Cyrillic/Ukrainian" msgstr "Cirílico/Ucraniano" #: gfls/gfls-encoding-manager-iconv.c:102 #: gfls/gfls-encoding-manager-iconv.c:105 #: gfls/gfls-encoding-manager-iconv.c:115 msgid "Vietnamese" msgstr "Vietinamita" #: gfls/gfls-encoding-manager-iconv.c:103 msgid "Thai" msgstr "Tailandês" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "O tamanho do arquivo é grande demais." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Foi alcançado o limite de número de bytes para leitura." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "O conteúdo não está codificado em UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "O conteúdo contém uma linha muito longa." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Documento não salvo %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/ru.po000066400000000000000000000103371516613426200240320ustar00rootroot00000000000000# Russian translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Sergej A. , 2024. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-04-04 23:47+1000\n" "Last-Translator: Ser82-png \n" "Language-Team: Russian \n" "Language: ru\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" "X-Generator: Poedit 3.0.1\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Количество выполненных необратимых преобразований." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Выявлен недопустимый символ." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Размер файла слишком большой." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Превышено ограничение на количество байт для чтения." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Содержимое этого файла не в кодировке UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Содержимое имеет слишком длинную строку." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "Преобразование из кодировки символов «%s» в «%s» не поддерживается." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "Не удалось открыть конвертер кодировки символов из «%s» в «%s»: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Ошибка при преобразовании кодировки символов: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Не удалось закрыть конвертер кодировки символов: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Несохранённый документ %d" #, c-format #~ msgid "%s (%s)" #~ msgstr "%s (%s)" #~ msgid "Unicode" #~ msgstr "Юникод" #~ msgid "Western" #~ msgstr "Западная" #~ msgid "Central European" #~ msgstr "Центральноевропейская" #~ msgid "South European" #~ msgstr "Южноевропейская" #~ msgid "Baltic" #~ msgstr "Балтийская" #~ msgid "Cyrillic" #~ msgstr "Кириллица" #~ msgid "Arabic" #~ msgstr "Арабская" #~ msgid "Greek" #~ msgstr "Греческая" #~ msgid "Hebrew Visual" #~ msgstr "Еврейская отображаемая" #~ msgid "Turkish" #~ msgstr "Турецкая" #~ msgid "Nordic" #~ msgstr "Северная" #~ msgid "Celtic" #~ msgstr "Кельтская" #~ msgid "Romanian" #~ msgstr "Румынская" #~ msgid "Armenian" #~ msgstr "Армянская" #~ msgid "Chinese Traditional" #~ msgstr "Китайская традиционная" #~ msgid "Cyrillic/Russian" #~ msgstr "Кириллица/Русская" #~ msgid "Japanese" #~ msgstr "Японская" #~ msgid "Korean" #~ msgstr "Корейская" #~ msgid "Chinese Simplified" #~ msgstr "Китайская упрощённая" #~ msgid "Georgian" #~ msgstr "Грузинская" #~ msgid "Hebrew" #~ msgstr "Еврейская" #~ msgid "Cyrillic/Ukrainian" #~ msgstr "Кириллица/Украинская" #~ msgid "Vietnamese" #~ msgstr "Вьетнамская" #~ msgid "Thai" #~ msgstr "Тайская" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/sl.po000066400000000000000000000044721516613426200240250ustar00rootroot00000000000000# Slovenian translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Martin , 2024,2025. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-03-26 18:15+0100\n" "Last-Translator: Martin Srebotnjak \n" "Language-Team: Slovenian \n" "Language: sl\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=(n%100==1 ? 1 : n%100==2 ? 2 : n%100==3 || " "n%100==4 ? 3 : 0) ;\n" "X-Generator: Poedit 3.8\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Opravljenih je bilo več nepovratnih pretvorb." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Zaznan je bil neveljaven znak." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Datoteka je prevelika." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Dosežena je omejitev števila bajtov za branje." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Vsebina ni kodirana v UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Vsebina vsebuje zelo dolgo vrstico." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "Pretvorba iz nabora znakov »%s« v »%s« ni podprta." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "Pretvornika nabora znakov iz »%s« v »%s« ni mogoče odpreti: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Napaka med pretvorbo nabora znakov: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Pretvornika nabora znakov ni bilo mogoče zapreti: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Neshranjeni dokument %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/sr.po000066400000000000000000000077311516613426200240340ustar00rootroot00000000000000# Serbian translation of libgedit-gfls. # This file is distributed under the same license as the libgedit-gfls package. # Мирослав Николић # Марко Костић , 2026. # msgid "" msgstr "" "Project-Id-Version: \n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2025-01-26 08:23+0100\n" "Last-Translator: Мирослав Николић \n" "Language-Team: \n" "Language: sr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "X-Generator: Poedit 3.5\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Извршен је одређени број неповратних претварања." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Наишао сам на неисправан знак." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Датотека је превелика." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Достигнуто је ограничење броја бајтова за читање." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Садржај није кодиран у УТФ-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Садржај садржи врло дуг ред." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "Претварање из скупа знакова „%s“ у „%s“ није подржано." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "Нисам успео да отворим претварач скупа знакова из „%s“ у „%s“: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Грешка приликом претварања скупа знакова: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Нисам успео да затворим претварач скупа знакова: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Несачувани документ %d" #, c-format #~ msgid "%s (%s)" #~ msgstr "%s (%s)" #~ msgid "Unicode" #~ msgstr "Јуникод" #~ msgid "Western" #~ msgstr "Западни" #~ msgid "Central European" #~ msgstr "Средње-европски" #~ msgid "South European" #~ msgstr "Јужно-европски" #~ msgid "Baltic" #~ msgstr "Балтички" #~ msgid "Cyrillic" #~ msgstr "Ћирилица" #~ msgid "Arabic" #~ msgstr "Арапски" #~ msgid "Greek" #~ msgstr "Грчки" #~ msgid "Hebrew Visual" #~ msgstr "Јеврејски визуелни" #~ msgid "Turkish" #~ msgstr "Турски" #~ msgid "Nordic" #~ msgstr "Нордијски" #~ msgid "Celtic" #~ msgstr "Келтски" #~ msgid "Romanian" #~ msgstr "Румунски" #~ msgid "Armenian" #~ msgstr "Јерменски" #~ msgid "Chinese Traditional" #~ msgstr "Кинески традиционални" #~ msgid "Cyrillic/Russian" #~ msgstr "Ћирилица/руски" #~ msgid "Japanese" #~ msgstr "Јапански" #~ msgid "Korean" #~ msgstr "Корејски" #~ msgid "Chinese Simplified" #~ msgstr "Кинески поједностављен" #~ msgid "Georgian" #~ msgstr "Грузијски" #~ msgid "Hebrew" #~ msgstr "Јеврејски" #~ msgid "Cyrillic/Ukrainian" #~ msgstr "Ћирилица/украјински" #~ msgid "Vietnamese" #~ msgstr "Вијетнамски" #~ msgid "Thai" #~ msgstr "Тајландски" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/sv.po000066400000000000000000000070421516613426200240330ustar00rootroot00000000000000# Swedish translation for libgedit-gfls. # Copyright © 2024-2026 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # Anders Jonsson , 2024, 2025, 2026. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-03-22 16:59+0100\n" "Last-Translator: Anders Jonsson \n" "Language-Team: Swedish \n" "Language: sv\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" "X-Generator: Poedit 3.8\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Ett antal irreversibla konverteringar har utförts." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Ett ogiltigt tecken har påträffats." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Filen är för stor." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Gräns för antal byte att läsa uppnådd." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Innehållet är inte kodat i UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Innehållet innehåller en väldigt lång rad." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "Konvertering från teckenuppsättningen ”%s” till ”%s” stöds inte." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "" "Misslyckades med att öppna en teckenuppsättningskonverterare från ”%s” till " "”%s”: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Fel under konvertering av teckenuppsättning: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Misslyckades med att stänga teckenuppsättningskonverteraren: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Osparat dokument %d" #, c-format #~ msgid "%s (%s)" #~ msgstr "%s (%s)" #~ msgid "Unicode" #~ msgstr "Unicode" #~ msgid "Western" #~ msgstr "Västerländsk" #~ msgid "Central European" #~ msgstr "Centraleuropeisk" #~ msgid "South European" #~ msgstr "Sydeuropeisk" #~ msgid "Baltic" #~ msgstr "Baltisk" #~ msgid "Cyrillic" #~ msgstr "Kyrillisk" #~ msgid "Arabic" #~ msgstr "Arabisk" #~ msgid "Greek" #~ msgstr "Grekisk" #~ msgid "Hebrew Visual" #~ msgstr "Hebreisk visuell" #~ msgid "Turkish" #~ msgstr "Turkisk" #~ msgid "Nordic" #~ msgstr "Nordisk" #~ msgid "Celtic" #~ msgstr "Keltisk" #~ msgid "Romanian" #~ msgstr "Rumänsk" #~ msgid "Armenian" #~ msgstr "Armenisk" #~ msgid "Chinese Traditional" #~ msgstr "Traditionell kinesisk" #~ msgid "Cyrillic/Russian" #~ msgstr "Kyrillisk/rysk" #~ msgid "Japanese" #~ msgstr "Japansk" #~ msgid "Korean" #~ msgstr "Koreansk" #~ msgid "Chinese Simplified" #~ msgstr "Förenklad kinesisk" #~ msgid "Georgian" #~ msgstr "Georgisk" #~ msgid "Hebrew" #~ msgstr "Hebreisk" #~ msgid "Cyrillic/Ukrainian" #~ msgstr "Kyrillisk/ukrainsk" #~ msgid "Vietnamese" #~ msgstr "Vietnamesisk" #~ msgid "Thai" #~ msgstr "Thailändsk" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/tr.po000066400000000000000000000025041516613426200240260ustar00rootroot00000000000000# Turkish translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # # Sabri Ünal , 2024. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2025-02-03 13:57+0000\n" "PO-Revision-Date: 2025-02-03 19:24+0300\n" "Last-Translator: Sabri Ünal \n" "Language-Team: Turkish \n" "Language: tr\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Poedit 3.5\n" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Dosyanın boyutu çok büyük." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Okunacak bayt sayısı sınırına ulaşıldı." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "İçerik UTF-8 olarak kodlanmamış." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "İçerik çok uzun bir satır içeriyor." #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Kaydedilmemiş Belge %d" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/uk.po000066400000000000000000000104521516613426200240210ustar00rootroot00000000000000# Ukrainian translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # # Yuri Chornoivan , 2024, 2025, 2026. msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/is" "sues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-03-26 21:37+0200\n" "Last-Translator: Yuri Chornoivan \n" "Language-Team: Ukrainian \n" "Language: uk\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=4; plural=n==1 ? 3 : n%10==1 && n%100!=11 ? 0 : n" "%10>=2 && n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2;\n" "X-Generator: Lokalize 23.04.3\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "Кількість виконаних незворотних перетворень." #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "Виявлено некоректний символ." #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "Розмір файла є надто великим." #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "Перевищено обмеження кількості байтів для читання." #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "Дані у цьому файлі не записано у кодуванні UTF-8." #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "Файл містить надто довгий рядок." #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "" "Підтримки перетворення з кодування «%s» на кодування «%s» не передбачено." #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "" "Не вдалося відкрити засіб перетворення кодувань символів з «%s» на «%s»: %s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "Помилка під час перетворення кодувань символів: %s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "Не вдалося закрити засіб перетворення кодувань символів: %s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "Незбережений документ %d" #, c-format #~ msgid "%s (%s)" #~ msgstr "%s (%s)" #~ msgid "Unicode" #~ msgstr "Юнікод" #~ msgid "Western" #~ msgstr "західноєвропейське" #~ msgid "Central European" #~ msgstr "центральноєвропейське" #~ msgid "South European" #~ msgstr "південноєвропейське" #~ msgid "Baltic" #~ msgstr "балтійське" #~ msgid "Cyrillic" #~ msgstr "кирилиця" #~ msgid "Arabic" #~ msgstr "арабське" #~ msgid "Greek" #~ msgstr "грецьке" #~ msgid "Hebrew Visual" #~ msgstr "іврит (візуальне)" #~ msgid "Turkish" #~ msgstr "турецьке" #~ msgid "Nordic" #~ msgstr "нордичне" #~ msgid "Celtic" #~ msgstr "кельтське" #~ msgid "Romanian" #~ msgstr "румунське" #~ msgid "Armenian" #~ msgstr "вірменське" #~ msgid "Chinese Traditional" #~ msgstr "традиційне китайське" #~ msgid "Cyrillic/Russian" #~ msgstr "кирилиця/російське" #~ msgid "Japanese" #~ msgstr "японське" #~ msgid "Korean" #~ msgstr "корейське" #~ msgid "Chinese Simplified" #~ msgstr "спрощене китайське" #~ msgid "Georgian" #~ msgstr "грузинське" #~ msgid "Hebrew" #~ msgstr "іврит" #~ msgid "Cyrillic/Ukrainian" #~ msgstr "кирилиця/українське" #~ msgid "Vietnamese" #~ msgstr "в'єтнамське" #~ msgid "Thai" #~ msgstr "тайське" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/po/zh_CN.po000066400000000000000000000065751516613426200244160ustar00rootroot00000000000000# Chinese (China) translation for libgedit-gfls. # Copyright (C) 2024 libgedit-gfls's COPYRIGHT HOLDER # This file is distributed under the same license as the libgedit-gfls package. # lumingzh , 2024-2026. # msgid "" msgstr "" "Project-Id-Version: libgedit-gfls main\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/" "issues\n" "POT-Creation-Date: 2026-03-26 11:38+0000\n" "PO-Revision-Date: 2026-04-03 09:28+0800\n" "Last-Translator: lumingzh \n" "Language-Team: Chinese (China) \n" "Language: zh_CN\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" "X-Generator: Gtranslator 50.0\n" #: gfls/gfls-encoding-convert.c:344 #, c-format msgid "A number of nonreversible conversions have been performed." msgstr "已执行一些不可逆的转换。" #: gfls/gfls-encoding-convert.c:358 #, c-format msgid "An invalid character has been encountered." msgstr "遇到了无效的字符。" #: gfls/gfls-error.c:27 msgid "The size of the file is too big." msgstr "该文件太大了。" #: gfls/gfls-error.c:35 msgid "Limit on the number of bytes to read reached." msgstr "已达到字节数读取限制。" #: gfls/gfls-error.c:43 msgid "The content is not encoded in UTF-8." msgstr "该内容不是 UTF-8 编码。" #: gfls/gfls-error.c:51 msgid "The content contains a very long line." msgstr "该内容包含一个非常长的文本行。" #: gfls/gfls-iconv.c:138 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported." msgstr "不支持从字符集“%s”转换到“%s”。" #: gfls/gfls-iconv.c:147 #, c-format msgid "Failed to open a character set converter from “%s” to “%s”: %s" msgstr "打开从“%s”向“%s”的字符集转换器失败:%s" #: gfls/gfls-iconv.c:217 #, c-format msgid "Error during character set conversion: %s" msgstr "字符集转换时出错:%s" #: gfls/gfls-iconv.c:309 #, c-format msgid "Failed to close the character set converter: %s" msgstr "关闭字符集转换器失败:%s" #: gfls/gfls-unsaved-document-titles.c:61 #, c-format msgid "Unsaved Document %d" msgstr "未保存文档 %d" #, c-format #~ msgid "%s (%s)" #~ msgstr "%s(%s)" #~ msgid "Unicode" #~ msgstr "万国码" #~ msgid "Western" #~ msgstr "西文" #~ msgid "Central European" #~ msgstr "中欧" #~ msgid "South European" #~ msgstr "南欧" #~ msgid "Baltic" #~ msgstr "波罗的海语" #~ msgid "Cyrillic" #~ msgstr "西里尔语" #~ msgid "Arabic" #~ msgstr "阿拉伯语" #~ msgid "Greek" #~ msgstr "希腊语" #~ msgid "Hebrew Visual" #~ msgstr "可视希伯来语" #~ msgid "Turkish" #~ msgstr "土耳其语" #~ msgid "Nordic" #~ msgstr "北欧" #~ msgid "Celtic" #~ msgstr "凯尔特语" #~ msgid "Romanian" #~ msgstr "罗马尼亚语" #~ msgid "Armenian" #~ msgstr "亚美尼亚语" #~ msgid "Chinese Traditional" #~ msgstr "繁体中文" #~ msgid "Cyrillic/Russian" #~ msgstr "西里尔文/俄语" #~ msgid "Japanese" #~ msgstr "日语" #~ msgid "Korean" #~ msgstr "朝鲜语" #~ msgid "Chinese Simplified" #~ msgstr "简体中文" #~ msgid "Georgian" #~ msgstr "格鲁吉亚语" #~ msgid "Hebrew" #~ msgstr "希伯来语" #~ msgid "Cyrillic/Ukrainian" #~ msgstr "西里尔文/乌克兰语" #~ msgid "Vietnamese" #~ msgstr "越南语" #~ msgid "Thai" #~ msgstr "泰语" libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/000077500000000000000000000000001516613426200235645ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/interactive-tests/000077500000000000000000000000001516613426200272415ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/interactive-tests/gfls-gui.c000066400000000000000000000141641516613426200311300ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include #include #include /* 100 MiB */ #define FILE_SIZE_HARD_LIMIT (100 * 1024 * 1024) /* Number of bytes per line. 80 is for testing purposes ;-) */ #define VERY_LONG_LINE_LIMIT (80) typedef struct { GtkApplicationWindow *window; GtkTextView *view; GtkSpinButton *file_size_limit_spin_button; GFile *file; } ProgramData; static ProgramData * program_data_new (void) { return g_new0 (ProgramData, 1); } static void program_data_free (ProgramData *program_data) { if (program_data != NULL) { g_clear_object (&program_data->file); g_free (program_data); } } static GtkWidget * create_file_size_limit_spin_button (ProgramData *program_data) { GtkGrid *hgrid; GtkWidget *label; g_assert (program_data->file_size_limit_spin_button == NULL); hgrid = GTK_GRID (gtk_grid_new ()); gtk_grid_set_column_spacing (hgrid, 6); label = gtk_label_new ("File size limit:"); gtk_container_add (GTK_CONTAINER (hgrid), label); program_data->file_size_limit_spin_button = GTK_SPIN_BUTTON (gtk_spin_button_new_with_range (0.0, FILE_SIZE_HARD_LIMIT, 1.0)); gtk_container_add (GTK_CONTAINER (hgrid), GTK_WIDGET (program_data->file_size_limit_spin_button)); return GTK_WIDGET (hgrid); } static gsize get_file_size_limit (ProgramData *program_data) { gint value; value = gtk_spin_button_get_value_as_int (program_data->file_size_limit_spin_button); g_return_val_if_fail (value >= 0, 0); return value; } static void set_text_buffer_content (ProgramData *program_data, GBytes *bytes) { const gchar *text; gsize n_bytes; GtkTextBuffer *buffer; text = g_bytes_get_data (bytes, &n_bytes); buffer = gtk_text_view_get_buffer (program_data->view); gtk_text_buffer_set_text (buffer, text, n_bytes); } static void load_file_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); ProgramData *program_data = user_data; GBytes *bytes; GError *error = NULL; bytes = gfls_loader_basic_load_finish (file, result, &error); if (error != NULL) { g_printerr ("%s\n", error->message); g_clear_error (&error); g_bytes_unref (bytes); return; } set_text_buffer_content (program_data, bytes); g_bytes_unref (bytes); } static void load_file (ProgramData *program_data) { gfls_loader_basic_load_async (program_data->file, get_file_size_limit (program_data), VERY_LONG_LINE_LIMIT, G_PRIORITY_DEFAULT, NULL, load_file_cb, program_data); } static void open_file_chooser_response_cb (GtkFileChooserNative *open_file_chooser, gint response_id, ProgramData *program_data) { if (response_id == GTK_RESPONSE_ACCEPT) { gchar *parse_name; g_clear_object (&program_data->file); program_data->file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (open_file_chooser)); parse_name = g_file_get_parse_name (program_data->file); g_print ("Open file: %s\n", parse_name); g_free (parse_name); load_file (program_data); } g_object_unref (open_file_chooser); } static void open_file_button_clicked_cb (GtkButton *open_file_button, ProgramData *program_data) { GtkFileChooserNative *file_chooser; file_chooser = gtk_file_chooser_native_new ("Open File", GTK_WINDOW (program_data->window), GTK_FILE_CHOOSER_ACTION_OPEN, NULL, NULL); g_signal_connect (file_chooser, "response", G_CALLBACK (open_file_chooser_response_cb), program_data); gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (file_chooser), TRUE); gtk_native_dialog_show (GTK_NATIVE_DIALOG (file_chooser)); } static GtkWidget * create_open_file_button (ProgramData *program_data) { GtkButton *open_file_button; open_file_button = GTK_BUTTON (gtk_button_new_with_label ("Open File")); g_signal_connect (open_file_button, "clicked", G_CALLBACK (open_file_button_clicked_cb), program_data); return GTK_WIDGET (open_file_button); } static GtkWidget * create_side_panel (ProgramData *program_data) { GtkGrid *vgrid; vgrid = GTK_GRID (gtk_grid_new ()); gtk_orientable_set_orientation (GTK_ORIENTABLE (vgrid), GTK_ORIENTATION_VERTICAL); gtk_grid_set_row_spacing (vgrid, 6); gtk_container_add (GTK_CONTAINER (vgrid), create_file_size_limit_spin_button (program_data)); gtk_container_add (GTK_CONTAINER (vgrid), create_open_file_button (program_data)); return GTK_WIDGET (vgrid); } static GtkWidget * create_view (ProgramData *program_data) { GtkWidget *scrolled_window; g_assert (program_data->view == NULL); program_data->view = GTK_TEXT_VIEW (gtk_text_view_new ()); gtk_text_view_set_monospace (program_data->view, TRUE); g_object_set (program_data->view, "expand", TRUE, NULL); scrolled_window = gtk_scrolled_window_new (NULL, NULL); gtk_container_add (GTK_CONTAINER (scrolled_window), GTK_WIDGET (program_data->view)); return scrolled_window; } static void activate_cb (GApplication *g_app, ProgramData *program_data) { GtkGrid *hgrid; g_assert (program_data->window == NULL); program_data->window = GTK_APPLICATION_WINDOW (gtk_application_window_new (GTK_APPLICATION (g_app))); gtk_window_set_default_size (GTK_WINDOW (program_data->window), 800, 600); hgrid = GTK_GRID (gtk_grid_new ()); gtk_container_add (GTK_CONTAINER (hgrid), create_side_panel (program_data)); gtk_container_add (GTK_CONTAINER (hgrid), create_view (program_data)); gtk_container_add (GTK_CONTAINER (program_data->window), GTK_WIDGET (hgrid)); gtk_widget_show_all (GTK_WIDGET (program_data->window)); } int main (int argc, char **argv) { GtkApplication *app; ProgramData *program_data; int exit_status; setlocale (LC_ALL, ""); gfls_init (); app = gtk_application_new (NULL, G_APPLICATION_DEFAULT_FLAGS); program_data = program_data_new (); g_signal_connect (app, "activate", G_CALLBACK (activate_cb), program_data); exit_status = g_application_run (G_APPLICATION (app), argc, argv); g_object_unref (app); program_data_free (program_data); gfls_finalize (); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/interactive-tests/gfls-program.c000066400000000000000000000062401516613426200320070ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include #include typedef struct { GFile *file; } ProgramData; static ProgramData * program_data_new (void) { return g_new0 (ProgramData, 1); } static void program_data_free (ProgramData *program_data) { if (program_data != NULL) { g_clear_object (&program_data->file); g_free (program_data); } } static void quit_program (void) { g_application_release (g_application_get_default ()); } static void query_info_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); GFileInfo *info; GError *error = NULL; info = g_file_query_info_finish (file, result, &error); if (error != NULL) { g_printerr ("Failed to query file informations: %s\n", error->message); g_clear_error (&error); goto out; } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_TYPE)) { GFileType type; type = g_file_info_get_file_type (info); if (type == G_FILE_TYPE_REGULAR) { g_print ("Regular file.\n"); } else { g_print ("The file is not a regular file.\n"); } } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME)) { const gchar *display_name; display_name = g_file_info_get_display_name (info); g_print ("Display name: %s\n", display_name); } if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) { goffset n_bytes; n_bytes = g_file_info_get_size (info); g_print ("File size in bytes: %" G_GOFFSET_FORMAT "\n", n_bytes); } out: g_clear_object (&info); quit_program (); } static void launch_program (ProgramData *program_data) { g_application_hold (g_application_get_default ()); g_file_query_info_async (program_data->file, G_FILE_ATTRIBUTE_STANDARD_TYPE "," G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME "," G_FILE_ATTRIBUTE_STANDARD_SIZE, G_FILE_QUERY_INFO_NONE, G_PRIORITY_DEFAULT, NULL, query_info_cb, NULL); } static gint app_command_line_cb (GApplication *app, GApplicationCommandLine *command_line, gpointer user_data) { ProgramData *program_data = user_data; gchar **argv; gint argc; gint exit_status = EXIT_SUCCESS; argv = g_application_command_line_get_arguments (command_line, &argc); if (argc != 2) { g_application_command_line_printerr (command_line, "Usage: %s \n", argv[0]); exit_status = EXIT_FAILURE; goto out; } program_data->file = g_application_command_line_create_file_for_arg (command_line, argv[1]); launch_program (program_data); out: g_strfreev (argv); return exit_status; } int main (int argc, char **argv) { GApplication *app; ProgramData *program_data; int exit_status; setlocale (LC_ALL, ""); app = g_application_new (NULL, G_APPLICATION_HANDLES_COMMAND_LINE); program_data = program_data_new (); g_signal_connect (app, "command-line", G_CALLBACK (app_command_line_cb), program_data); exit_status = g_application_run (app, argc, argv); g_object_unref (app); program_data_free (program_data); return exit_status; } gfls-test-race-read-content.c000066400000000000000000000127331516613426200345350ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/interactive-tests/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include #include /* Purpose of this test program * ============================ * * To test the following race condition: * (1) Read a first block of bytes from a file (with GIO). * (2) Launch a timeout function (long enough to manually alter the file). * (3) With another program, alter the content of the file. E.g. with: * $ echo foobar > file * (4) When the timeout callback function is called, continue to read the file. * * And see what happens, how the programs behave, if errors are reported, etc. * * Result * ------ * * Absolutely no errors are reported. Even when closing the GFileInputStream. * * Solution * -------- * * Rely on the etag values provided by GIO to know if the file has been * externally modified. Worst case this is detected upon saving the file (show * an infobar at that moment). * * It can be desired to be able to open a file that is continuously modified by * another program, e.g. a log file. */ /* Read a string of 80 chars and nul-terminate it. * This is for testing purposes, so a short value is chosen. */ #define BUFFER_SIZE (81) typedef struct { GFile *file; GFileInputStream *input_stream; guint8 buffer[BUFFER_SIZE]; } ProgramData; static void read_next_chunk (ProgramData *program_data); static ProgramData * program_data_new (void) { ProgramData *program_data; program_data = g_new (ProgramData, 1); program_data->file = NULL; program_data->input_stream = NULL; /* Don't zero the buffer, it will anyway be nul-terminated manually. */ return program_data; } static void program_data_free (ProgramData *program_data) { if (program_data != NULL) { g_clear_object (&program_data->file); g_clear_object (&program_data->input_stream); g_free (program_data); } } static void quit_program (void) { g_application_release (g_application_get_default ()); } static void close_file_input_stream (ProgramData *program_data) { GError *error = NULL; g_print ("Closing file input stream.\n"); g_input_stream_close (G_INPUT_STREAM (program_data->input_stream), NULL, &error); if (error != NULL) { g_printerr ("Failed to close the file input stream: %s\n", error->message); g_clear_error (&error); } } static gboolean timeout_cb (gpointer user_data) { ProgramData *program_data = user_data; read_next_chunk (program_data); return G_SOURCE_REMOVE; } static void read_next_chunk_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { ProgramData *program_data = user_data; GError *error = NULL; gssize n_bytes_read; n_bytes_read = g_input_stream_read_finish (G_INPUT_STREAM (program_data->input_stream), result, &error); if (error != NULL) { g_printerr ("Failed to read the next chunk of content: %s\n", error->message); g_clear_error (&error); quit_program (); return; } if (n_bytes_read == 0) { g_print ("Finished reading.\n"); close_file_input_stream (program_data); quit_program (); return; } g_assert (n_bytes_read > 0); g_assert (n_bytes_read < BUFFER_SIZE); program_data->buffer[n_bytes_read] = '\0'; g_print ("Next chunk read:\n%s\n", program_data->buffer); g_timeout_add_seconds (15, timeout_cb, program_data); } static void read_next_chunk (ProgramData *program_data) { g_input_stream_read_async (G_INPUT_STREAM (program_data->input_stream), program_data->buffer, BUFFER_SIZE - 1, /* -1 to keep one byte to nul-terminate the string. */ G_PRIORITY_DEFAULT, NULL, read_next_chunk_cb, program_data); } static void file_read_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GFile *file = G_FILE (source_object); ProgramData *program_data = user_data; GError *error = NULL; g_assert (program_data->input_stream == NULL); program_data->input_stream = g_file_read_finish (file, result, &error); if (error != NULL) { g_printerr ("Failed to open file for reading: %s\n", error->message); g_clear_error (&error); quit_program (); return; } read_next_chunk (program_data); } static void launch_program (ProgramData *program_data) { g_application_hold (g_application_get_default ()); g_file_read_async (program_data->file, G_PRIORITY_DEFAULT, NULL, file_read_cb, program_data); } static gint app_command_line_cb (GApplication *app, GApplicationCommandLine *command_line, gpointer user_data) { ProgramData *program_data = user_data; gchar **argv; gint argc; gint exit_status = EXIT_SUCCESS; argv = g_application_command_line_get_arguments (command_line, &argc); if (argc != 2) { g_application_command_line_printerr (command_line, "Usage: %s \n", argv[0]); exit_status = EXIT_FAILURE; goto out; } program_data->file = g_application_command_line_create_file_for_arg (command_line, argv[1]); launch_program (program_data); out: g_strfreev (argv); return exit_status; } int main (int argc, char **argv) { GApplication *app; ProgramData *program_data; int exit_status; setlocale (LC_ALL, ""); app = g_application_new (NULL, G_APPLICATION_HANDLES_COMMAND_LINE); program_data = program_data_new (); g_signal_connect (app, "command-line", G_CALLBACK (app_command_line_cb), program_data); exit_status = g_application_run (app, argc, argv); g_object_unref (app); program_data_free (program_data); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/interactive-tests/meson.build000066400000000000000000000004701516613426200314040ustar00rootroot00000000000000executable( 'gfls-program', 'gfls-program.c', dependencies: GFLS_DEPS, ) executable( 'gfls-test-race-read-content', 'gfls-test-race-read-content.c', dependencies: GFLS_DEPS, ) if GTK3_DEP.found() executable( 'gfls-gui', 'gfls-gui.c', dependencies: [GFLS_LIB_DEP, GTK3_DEP], ) endif libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/meson.build000066400000000000000000000000611516613426200257230ustar00rootroot00000000000000subdir('interactive-tests') subdir('unit-tests') libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/000077500000000000000000000000001516613426200257035ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/meson.build000066400000000000000000000005721516613426200300510ustar00rootroot00000000000000unit_tests = [ 'test-attribute-keys', 'test-bytes-region', 'test-encoding-conversion', 'test-encoding-convert', 'test-iconv', 'test-input-stream', 'test-unsaved-document-titles', 'test-utf8', ] foreach test_name : unit_tests test_exe = executable( test_name, test_name + '.c', dependencies: GFLS_LIB_DEP ) test(test_name, test_exe) endforeach libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/test-attribute-keys.c000066400000000000000000000016551516613426200320070ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_basics (void) { GflsAttributeKeys *keys = gfls_attribute_keys_new (); gchar *result; result = gfls_attribute_keys_to_string (keys); g_assert_null (result); gfls_attribute_keys_add (keys, "standard::display-name"); result = gfls_attribute_keys_to_string (keys); g_assert_cmpstr (result, ==, "standard::display-name"); g_free (result); gfls_attribute_keys_add (keys, "access::*"); result = gfls_attribute_keys_to_string (keys); g_assert_cmpstr (result, ==, "standard::display-name,access::*"); g_free (result); g_object_unref (keys); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/AttributeKeys/basics", test_basics); exit_status = g_test_run (); gfls_finalize (); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/test-bytes-region.c000066400000000000000000000073731516613426200314450ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_empty (void) { GflsBytesRegionBuilder *builder; GflsBytesRegion *region; gsize total_size; gchar *str; builder = gfls_bytes_region_builder_new (); total_size = gfls_bytes_region_builder_get_current_size (builder); g_assert_cmpuint (total_size, ==, 0); region = gfls_bytes_region_builder_free (builder, FALSE); builder = NULL; str = gfls_bytes_region_to_string (region); g_assert_nonnull (str); g_assert_cmpstr (str, ==, ""); g_free (str); gfls_bytes_region_free (region); } static void test_single_sub_region_part_of_region (void) { GflsBytesRegionBuilder *builder; GflsBytesRegion *region; gsize total_size; gchar *str; builder = gfls_bytes_region_builder_new (); gfls_bytes_region_builder_append (builder, 3, TRUE); total_size = gfls_bytes_region_builder_get_current_size (builder); g_assert_cmpuint (total_size, ==, 3); region = gfls_bytes_region_builder_free (builder, FALSE); builder = NULL; str = gfls_bytes_region_to_string (region); g_assert_nonnull (str); g_assert_cmpstr (str, ==, "[0, 3, 1]\n"); g_free (str); gfls_bytes_region_free (region); } static void test_single_sub_region_not_part_of_region (void) { GflsBytesRegionBuilder *builder; GflsBytesRegion *region; gsize total_size; gchar *str; builder = gfls_bytes_region_builder_new (); gfls_bytes_region_builder_append (builder, 4, FALSE); total_size = gfls_bytes_region_builder_get_current_size (builder); g_assert_cmpuint (total_size, ==, 4); region = gfls_bytes_region_builder_free (builder, FALSE); builder = NULL; str = gfls_bytes_region_to_string (region); g_assert_nonnull (str); g_assert_cmpstr (str, ==, "[0, 4, 0]\n"); g_free (str); gfls_bytes_region_free (region); } static void test_merge (void) { GflsBytesRegionBuilder *builder; GflsBytesRegion *region; gsize total_size; gchar *str; builder = gfls_bytes_region_builder_new (); gfls_bytes_region_builder_append (builder, 5, TRUE); gfls_bytes_region_builder_append (builder, 5, TRUE); gfls_bytes_region_builder_append (builder, 2, FALSE); gfls_bytes_region_builder_append (builder, 2, FALSE); total_size = gfls_bytes_region_builder_get_current_size (builder); g_assert_cmpuint (total_size, ==, 14); region = gfls_bytes_region_builder_free (builder, FALSE); builder = NULL; str = gfls_bytes_region_to_string (region); g_assert_nonnull (str); g_assert_cmpstr (str, ==, "[0, 10, 1]\n" "[10, 4, 0]\n"); g_free (str); gfls_bytes_region_free (region); } static void test_match_bytes (void) { GflsBytesRegionBuilder *builder; GflsBytesRegion *region; GBytes *bytes; builder = gfls_bytes_region_builder_new (); gfls_bytes_region_builder_append (builder, 2, TRUE); gfls_bytes_region_builder_append (builder, 1, FALSE); region = gfls_bytes_region_builder_free (builder, FALSE); builder = NULL; bytes = g_bytes_new_static ("abc", 3); g_assert_true (gfls_bytes_region_match_bytes (region, bytes)); g_bytes_unref (bytes); bytes = g_bytes_new_static ("a", 1); g_assert_false (gfls_bytes_region_match_bytes (region, bytes)); g_bytes_unref (bytes); gfls_bytes_region_free (region); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/BytesRegion/empty", test_empty); g_test_add_func ("/BytesRegion/single_sub_region_part_of_region", test_single_sub_region_part_of_region); g_test_add_func ("/BytesRegion/single_sub_region_not_part_of_region", test_single_sub_region_not_part_of_region); g_test_add_func ("/BytesRegion/merge", test_merge); g_test_add_func ("/BytesRegion/match_bytes", test_match_bytes); exit_status = g_test_run (); gfls_finalize (); return exit_status; } test-encoding-conversion.c000066400000000000000000000023051516613426200327160ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/* SPDX-FileCopyrightText: 2025-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_try_convert_success (void) { GBytes *input_bytes; gboolean ret; input_bytes = g_bytes_new_static ("a", 1); ret = gfls_encoding_try_convert (input_bytes, "UTF-8", "UTF-8"); g_assert_true (ret); g_bytes_unref (input_bytes); } static void test_try_convert_illegal_sequence (void) { guint8 input_buffer[1]; GBytes *input_bytes; gboolean ret; // 255, aka "1111 1111" in binary and 0xFF in hexadecimal. // In UTF-8, this is an invalid byte. // See https://en.wikipedia.org/wiki/UTF-8 input_buffer[0] = 255; input_bytes = g_bytes_new (input_buffer, 1); ret = gfls_encoding_try_convert (input_bytes, "UTF-8", "UTF-8"); g_assert_false (ret); g_bytes_unref (input_bytes); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/EncodingConversion/try_convert_success", test_try_convert_success); g_test_add_func ("/EncodingConversion/try_convert_illegal_sequence", test_try_convert_illegal_sequence); exit_status = g_test_run (); gfls_finalize (); return exit_status; } test-encoding-convert.c000066400000000000000000000137161516613426200322210ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/* SPDX-FileCopyrightText: 2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_iconv_open_failure (void) { GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; GError *error = NULL; input_bytes = g_bytes_new_static ("a", 1); success = gfls_encoding_convert (input_bytes, "UTF-8", "CANNOT_POSSIBLY_WORK", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_false (success); g_assert_nonnull (error); g_bytes_unref (input_bytes); g_bytes_unref (output_bytes); gfls_bytes_region_free (output_bytes_valid_region); g_clear_error (&error); } static void test_basic (void) { GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; gchar *region_str; GError *error = NULL; input_bytes = g_bytes_new_static ("oh", 2); success = gfls_encoding_convert (input_bytes, "UTF-8", "ISO-8859-15", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_true (success); g_assert_no_error (error); g_assert_true (g_bytes_equal (input_bytes, output_bytes)); region_str = gfls_bytes_region_to_string (output_bytes_valid_region); g_assert_cmpstr ("[0, 2, 1]\n", ==, region_str); g_bytes_unref (input_bytes); g_bytes_unref (output_bytes); gfls_bytes_region_free (output_bytes_valid_region); g_free (region_str); } static void test_illegal_sequence (void) { guint8 input_buffer[1] = { 255 }; // See also test-iconv.c GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; gchar *region_str; GError *error = NULL; input_bytes = g_bytes_new_static (input_buffer, 1); success = gfls_encoding_convert (input_bytes, "UTF-8", "UTF-8", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_true (success); g_assert_no_error (error); g_assert_true (g_bytes_equal (input_bytes, output_bytes)); region_str = gfls_bytes_region_to_string (output_bytes_valid_region); g_assert_cmpstr ("[0, 1, 0]\n", ==, region_str); g_bytes_unref (input_bytes); g_bytes_unref (output_bytes); gfls_bytes_region_free (output_bytes_valid_region); g_free (region_str); } static void test_incomplete_input (void) { guint8 input_buffer[1] = { 195 }; // See also test-iconv.c GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; gchar *region_str; GError *error = NULL; input_bytes = g_bytes_new_static (input_buffer, 1); success = gfls_encoding_convert (input_bytes, "UTF-8", "UTF-8", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_true (success); g_assert_no_error (error); g_assert_true (g_bytes_equal (input_bytes, output_bytes)); region_str = gfls_bytes_region_to_string (output_bytes_valid_region); g_assert_cmpstr ("[0, 1, 0]\n", ==, region_str); g_bytes_unref (input_bytes); g_bytes_unref (output_bytes); gfls_bytes_region_free (output_bytes_valid_region); g_free (region_str); } static void test_buffer_full (void) { gsize input_size = 32 * 1024; gchar *input_str; GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; gchar *region_str; GError *error = NULL; input_str = g_strnfill (input_size, 'a'); input_bytes = g_bytes_new_take (input_str, input_size); input_str = NULL; success = gfls_encoding_convert (input_bytes, "UTF-16LE", "UTF-8", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_true (success); g_assert_no_error (error); { const guint8 *output_data; gsize output_size = 0; output_data = g_bytes_get_data (output_bytes, &output_size); g_assert_cmpuint (output_size, ==, input_size * 2); g_assert_cmpuint (output_data[0], ==, 97); g_assert_cmpuint (output_data[1], ==, 0); g_assert_cmpuint (output_data[2], ==, 97); g_assert_cmpuint (output_data[3], ==, 0); g_assert_cmpuint (output_data[4], ==, 97); g_assert_cmpuint (output_data[5], ==, 0); // Etc. } region_str = gfls_bytes_region_to_string (output_bytes_valid_region); g_assert_cmpstr ("[0, 65536, 1]\n", ==, region_str); g_bytes_unref (input_bytes); g_bytes_unref (output_bytes); gfls_bytes_region_free (output_bytes_valid_region); g_free (region_str); } static void test_lossy_conversion (void) { // See also test-iconv.c. // "é": Latin Small Letter E With Acute (U+00E9) guint8 input_buffer[2] = { 195, 169 }; GBytes *input_bytes; GBytes *output_bytes = NULL; GflsBytesRegion *output_bytes_valid_region = NULL; gboolean success; GError *error = NULL; input_bytes = g_bytes_new_static (input_buffer, 2); success = gfls_encoding_convert (input_bytes, "ASCII//TRANSLIT", "UTF-8", TRUE, &output_bytes, &output_bytes_valid_region, &error); g_assert_false (success); g_assert_null (output_bytes); g_assert_null (output_bytes_valid_region); g_assert_error (error, G_CONVERT_ERROR, G_CONVERT_ERROR_FAILED); g_bytes_unref (input_bytes); g_clear_error (&error); // For better code coverage (output_bytes_valid_region is NULL). gfls_bytes_region_free (output_bytes_valid_region); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/EncodingConvert/iconv_open_failure", test_iconv_open_failure); g_test_add_func ("/EncodingConvert/basic", test_basic); g_test_add_func ("/EncodingConvert/illegal_sequence", test_illegal_sequence); g_test_add_func ("/EncodingConvert/incomplete_input", test_incomplete_input); g_test_add_func ("/EncodingConvert/buffer_full", test_buffer_full); g_test_add_func ("/EncodingConvert/lossy_conversion", test_lossy_conversion); exit_status = g_test_run (); gfls_finalize (); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/test-iconv.c000066400000000000000000000244531516613426200301520ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2025 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_new_and_free (void) { GflsIconv *conv; conv = gfls_iconv_new (); gfls_iconv_free (conv); gfls_iconv_free (NULL); } static void test_open_and_close (void) { GflsIconv *conv; gboolean ok; GError *error = NULL; /* All OK */ conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", &error); g_assert_true (ok); g_assert_no_error (error); ok = gfls_iconv_close (conv, &error); g_assert_true (ok); g_assert_no_error (error); gfls_iconv_free (conv); /* Open not OK */ conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "CANNOT_POSSIBLY_WORK", &error); g_assert_false (ok); g_assert_nonnull (error); g_clear_error (&error); ok = gfls_iconv_close (conv, &error); g_assert_true (ok); g_assert_no_error (error); gfls_iconv_free (conv); } static void test_feed_ok (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gsize output_buffer_size; gchar *input_buffer; gchar *output_buffer; gchar *input_buffer_pos; gchar *output_buffer_pos; gsize input_buffer_n_bytes_left; gsize output_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", NULL); g_assert_true (ok); input_buffer_size = 1; input_buffer = g_malloc (input_buffer_size); input_buffer[0] = 'a'; output_buffer_size = 32; output_buffer = g_malloc (output_buffer_size); input_buffer_pos = input_buffer; output_buffer_pos = output_buffer; input_buffer_n_bytes_left = input_buffer_size; output_buffer_n_bytes_left = output_buffer_size; result = gfls_iconv_feed (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_OK); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 0); g_assert_cmpuint (output_buffer_n_bytes_left, ==, 31); g_assert_true (input_buffer_pos == input_buffer + 1); g_assert_true (output_buffer_pos == output_buffer + 1); gfls_iconv_free (conv); g_free (input_buffer); g_free (output_buffer); } static void test_feed_output_buffer_full (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gsize output_buffer_size; gchar *input_buffer; gchar *output_buffer; gchar *input_buffer_pos; gchar *output_buffer_pos; gsize input_buffer_n_bytes_left; gsize output_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", NULL); g_assert_true (ok); input_buffer_size = 20; input_buffer = g_malloc (input_buffer_size); memset (input_buffer, 'a', input_buffer_size); output_buffer_size = 16; output_buffer = g_malloc (output_buffer_size); input_buffer_pos = input_buffer; output_buffer_pos = output_buffer; input_buffer_n_bytes_left = input_buffer_size; output_buffer_n_bytes_left = output_buffer_size; result = gfls_iconv_feed (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_OUTPUT_BUFFER_FULL); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 4); g_assert_cmpuint (output_buffer_n_bytes_left, ==, 0); g_assert_true (input_buffer_pos == input_buffer + 16); g_assert_true (output_buffer_pos == output_buffer + 16); gfls_iconv_free (conv); g_free (input_buffer); g_free (output_buffer); } static void test_feed_incomplete_input (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gsize output_buffer_size; guint8 *input_buffer_raw; gchar *input_buffer; gchar *output_buffer; gchar *input_buffer_pos; gchar *output_buffer_pos; gsize input_buffer_n_bytes_left; gsize output_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", NULL); g_assert_true (ok); input_buffer_size = 1; input_buffer_raw = g_malloc (input_buffer_size); input_buffer = (gchar *) input_buffer_raw; // 195, aka "1100 0011" in binary and 0xC3 in hexadecimal. // In UTF-8, this is a first (valid) byte of a two-bytes encoded // character. // // For example this is the first byte of "é" // Latin Small Letter E With Acute (U+00E9) // which is encoded in UTF-8 as 0xC3 0xA9. // // For a two-bytes UTF-8 character, refer to Wikipedia: // First code point: U+0080 // Last code point: U+07FF // Byte 1: 110xxxyy // Byte 2: 10yyzzzz // See https://en.wikipedia.org/wiki/UTF-8 input_buffer_raw[0] = 195; output_buffer_size = 32; output_buffer = g_malloc (output_buffer_size); input_buffer_pos = input_buffer; output_buffer_pos = output_buffer; input_buffer_n_bytes_left = input_buffer_size; output_buffer_n_bytes_left = output_buffer_size; result = gfls_iconv_feed (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_INCOMPLETE_INPUT); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 1); g_assert_cmpuint (output_buffer_n_bytes_left, ==, 32); g_assert_true (input_buffer_pos == input_buffer); g_assert_true (output_buffer_pos == output_buffer); gfls_iconv_free (conv); g_free (input_buffer_raw); g_free (output_buffer); } static void test_feed_illegal_sequence (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gsize output_buffer_size; guint8 *input_buffer_raw; gchar *input_buffer; gchar *output_buffer; gchar *input_buffer_pos; gchar *output_buffer_pos; gsize input_buffer_n_bytes_left; gsize output_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", NULL); g_assert_true (ok); input_buffer_size = 1; input_buffer_raw = g_malloc (input_buffer_size); input_buffer = (gchar *) input_buffer_raw; // 255, aka "1111 1111" in binary and 0xFF in hexadecimal. // In UTF-8, this is an invalid byte. // See https://en.wikipedia.org/wiki/UTF-8 input_buffer_raw[0] = 255; output_buffer_size = 32; output_buffer = g_malloc (output_buffer_size); input_buffer_pos = input_buffer; output_buffer_pos = output_buffer; input_buffer_n_bytes_left = input_buffer_size; output_buffer_n_bytes_left = output_buffer_size; result = gfls_iconv_feed (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_ILLEGAL_SEQUENCE); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 1); g_assert_cmpuint (output_buffer_n_bytes_left, ==, 32); g_assert_true (input_buffer_pos == input_buffer); g_assert_true (output_buffer_pos == output_buffer); gfls_iconv_free (conv); g_free (input_buffer_raw); g_free (output_buffer); } static void test_feed_discard_output (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gchar *input_buffer; gchar *input_buffer_pos; gsize input_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "UTF-8", "UTF-8", NULL); g_assert_true (ok); // The internal output buffer of gfls_iconv_feed_discard_output() // has a size of 1024. So to trigger the loop condition, have something // greater than that. input_buffer_size = 2000; input_buffer = g_malloc (input_buffer_size); memset (input_buffer, 'a', input_buffer_size); input_buffer_pos = input_buffer; input_buffer_n_bytes_left = input_buffer_size; result = gfls_iconv_feed_discard_output (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_OK); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 0); g_assert_true (input_buffer_pos == input_buffer + 2000); gfls_iconv_free (conv); g_free (input_buffer); } static void test_feed_lossy_conversion (void) { GflsIconv *conv; gboolean ok; gsize input_buffer_size; gsize output_buffer_size; guint8 *input_buffer_raw; gchar *input_buffer; gchar *output_buffer; gchar *input_buffer_pos; gchar *output_buffer_pos; gsize input_buffer_n_bytes_left; gsize output_buffer_n_bytes_left; GflsIconvResult result; GError *error = NULL; conv = gfls_iconv_new (); ok = gfls_iconv_open (conv, "ASCII//TRANSLIT", "UTF-8", NULL); g_assert_true (ok); input_buffer_size = 2; input_buffer_raw = g_malloc (input_buffer_size); input_buffer = (gchar *) input_buffer_raw; // "é": Latin Small Letter E With Acute (U+00E9) // which is encoded in UTF-8 as 0xC3 0xA9. input_buffer_raw[0] = 195; input_buffer_raw[1] = 169; output_buffer_size = 32; output_buffer = g_malloc (output_buffer_size); input_buffer_pos = input_buffer; output_buffer_pos = output_buffer; input_buffer_n_bytes_left = input_buffer_size; output_buffer_n_bytes_left = output_buffer_size; result = gfls_iconv_feed (conv, &input_buffer_pos, &input_buffer_n_bytes_left, &output_buffer_pos, &output_buffer_n_bytes_left, &error); g_assert_true (result == GFLS_ICONV_RESULT_LOSSY_CONVERSION); g_assert_no_error (error); g_assert_cmpuint (input_buffer_n_bytes_left, ==, 0); g_assert_cmpuint (output_buffer_n_bytes_left, ==, 31); g_assert_true (input_buffer_pos == input_buffer + 2); g_assert_true (output_buffer_pos == output_buffer + 1); g_assert_cmpuint (output_buffer[0], ==, '?'); // Depends on the implementation. gfls_iconv_free (conv); g_free (input_buffer_raw); g_free (output_buffer); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/iconv/new_and_free", test_new_and_free); g_test_add_func ("/iconv/open_and_close", test_open_and_close); g_test_add_func ("/iconv/feed_ok", test_feed_ok); g_test_add_func ("/iconv/feed_output_buffer_full", test_feed_output_buffer_full); g_test_add_func ("/iconv/feed_incomplete_input", test_feed_incomplete_input); g_test_add_func ("/iconv/feed_illegal_sequence", test_feed_illegal_sequence); g_test_add_func ("/iconv/feed_discard_output", test_feed_discard_output); g_test_add_func ("/iconv/feed_lossy_conversion", test_feed_lossy_conversion); exit_status = g_test_run (); gfls_finalize (); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/test-input-stream.c000066400000000000000000000050111516613426200314510ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2024-2026 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include typedef struct { /* To run the async operation. */ GMainLoop *main_loop; /* To check against the result of gfls_input_stream_read_finish(): */ gsize result_size; guint result_is_truncated : 1; } TestData; static GInputStream * create_input_stream (gsize size) { gchar *str; GBytes *bytes; GInputStream *input_stream; str = g_strnfill (size, 'A'); bytes = g_bytes_new_take (str, size); input_stream = g_memory_input_stream_new_from_bytes (bytes); g_bytes_unref (bytes); return input_stream; } static void read_cb (GObject *source_object, GAsyncResult *result, gpointer user_data) { GInputStream *input_stream = G_INPUT_STREAM (source_object); TestData *data = user_data; GBytes *bytes; gboolean is_truncated = FALSE; GError *error = NULL; bytes = gfls_input_stream_read_finish (input_stream, result, &is_truncated, &error); g_assert_no_error (error); g_assert_cmpint (is_truncated, ==, data->result_is_truncated); g_assert_nonnull (bytes); g_assert_cmpint (g_bytes_get_size (bytes), ==, data->result_size); g_bytes_unref (bytes); g_main_loop_quit (data->main_loop); } static void check_read (gsize input_stream_real_size, gsize input_stream_expected_size, gsize max_size, gsize result_size, gboolean result_is_truncated) { GInputStream *input_stream; TestData data; input_stream = create_input_stream (input_stream_real_size); data.main_loop = g_main_loop_new (NULL, FALSE); data.result_size = result_size; data.result_is_truncated = result_is_truncated != FALSE; gfls_input_stream_read_async (input_stream, input_stream_expected_size, max_size, G_PRIORITY_DEFAULT, NULL, NULL, NULL, read_cb, &data); g_main_loop_run (data.main_loop); g_object_unref (input_stream); } static void test_read (void) { check_read (0, 0, 0, 0, FALSE); check_read (0, 1, 0, 0, FALSE); check_read (1, 0, 100, 1, FALSE); check_read (100, 50, 200, 100, FALSE); check_read (100, 100, 200, 100, FALSE); check_read (100, 100, 100, 100, FALSE); /* Truncated */ check_read (1, 0, 0, 0, TRUE); check_read (2, 2, 0, 0, TRUE); check_read (100, 50, 99, 99, TRUE); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/InputStream/read", test_read); exit_status = g_test_run (); gfls_finalize (); return exit_status; } test-unsaved-document-titles.c000066400000000000000000000035051516613426200335330ustar00rootroot00000000000000libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void test_allocate_and_release_numbers (void) { GflsUnsavedDocumentTitles *titles; gint num_a; gint num_b; gint num_c; titles = gfls_unsaved_document_titles_get_default (); num_a = gfls_unsaved_document_titles_allocate_number (titles); num_b = gfls_unsaved_document_titles_allocate_number (titles); g_assert_cmpint (num_a, ==, 1); g_assert_cmpint (num_b, ==, 2); gfls_unsaved_document_titles_release_number (titles, num_a); num_a = 0; num_c = gfls_unsaved_document_titles_allocate_number (titles); g_assert_cmpint (num_c, ==, 1); } static gchar * my_title_cb (gint num) { return g_strdup_printf ("My Dear New Document %d", num); } static void test_title (void) { GflsUnsavedDocumentTitles *titles; gchar *title_a; gchar *title_b; gchar *my_title; titles = gfls_unsaved_document_titles_new (); title_a = gfls_unsaved_document_titles_get_title (titles, 1); gfls_unsaved_document_titles_set_title_callback (titles, my_title_cb); title_b = gfls_unsaved_document_titles_get_title (titles, 1); my_title = my_title_cb (1); g_assert_cmpstr (title_b, ==, my_title); g_free (title_b); g_free (my_title); gfls_unsaved_document_titles_set_title_callback (titles, NULL); title_b = gfls_unsaved_document_titles_get_title (titles, 1); g_assert_cmpstr (title_a, ==, title_b); g_free (title_a); g_free (title_b); g_object_unref (titles); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/UnsavedDocumentTitles/allocate_and_release_numbers", test_allocate_and_release_numbers); g_test_add_func ("/UnsavedDocumentTitles/title", test_title); exit_status = g_test_run (); gfls_finalize (); return exit_status; } libgedit-gfls-0.4.1-ce4b836dfda4ea3f594b9ded7b60c5cb51ccbc87/tests/unit-tests/test-utf8.c000066400000000000000000000040741516613426200277170ustar00rootroot00000000000000/* SPDX-FileCopyrightText: 2023-2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include static void check_find_very_long_line (const gchar *str, guint max_n_bytes_per_line, gint expected_found_at_pos) { const gchar *result; result = gfls_utf8_find_very_long_line (str, max_n_bytes_per_line); if (expected_found_at_pos < 0) { g_assert_null (result); } else { gint found_at_pos; g_assert_nonnull (result); found_at_pos = result - str; g_assert_cmpint (found_at_pos, ==, expected_found_at_pos); } } static void test_find_very_long_line (void) { /* Without newline chars */ check_find_very_long_line ("", 0, -1); check_find_very_long_line ("a", 0, 0); check_find_very_long_line ("", 1, -1); check_find_very_long_line ("a", 1, -1); check_find_very_long_line ("ab", 1, 0); check_find_very_long_line ("é", 1, 0); check_find_very_long_line ("é", 2, -1); /* With \n */ check_find_very_long_line ("\n\n\n", 0, -1); check_find_very_long_line ("\na\n", 0, 1); check_find_very_long_line ("\na", 0, 1); check_find_very_long_line ("a\nb\nc\n", 1, -1); check_find_very_long_line ("a\nb\nc", 1, -1); check_find_very_long_line ("a\nbc\n", 1, 2); check_find_very_long_line ("a\nbcd\n", 1, 2); check_find_very_long_line ("a\nbcd\n", 2, 2); check_find_very_long_line ("a\nbcd", 2, 2); check_find_very_long_line ("é\nSé", 2, 3); check_find_very_long_line ("é\nSé", 3, -1); check_find_very_long_line ("é\nSé\n", 3, -1); /* Quick test with \r */ check_find_very_long_line ("\r\r\r", 0, -1); check_find_very_long_line ("\n\r\n\r\n\r", 0, -1); check_find_very_long_line ("\r\n\r\n\r\n", 0, -1); check_find_very_long_line ("a\rb\nc\rd", 1, -1); check_find_very_long_line ("a\ré", 1, 2); check_find_very_long_line ("a\ré", 2, -1); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/utf8/find_very_long_line", test_find_very_long_line); exit_status = g_test_run (); gfls_finalize (); return exit_status; }