Sign Up
Log In
Log In
or
Sign Up
Places
All Projects
Status Monitor
Collapse sidebar
GNOME:Factory
libgedit-gfls
libgedit-gfls-0.2.0.obscpio
Overview
Repositories
Revisions
Requests
Users
Attributes
Meta
File libgedit-gfls-0.2.0.obscpio of Package libgedit-gfls
07070100000000000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001D00000000libgedit-gfls-0.2.0/LICENSES07070100000001000081A400000000000000000000000166D3169B00001D07000000000000000000000000000000000000003300000000libgedit-gfls-0.2.0/LICENSES/LGPL-3.0-or-later.txtGNU LESSER GENERAL PUBLIC LICENSE Version 3, 29 June 2007 Copyright (C) 2007 Free Software Foundation, Inc. <https://fsf.org/> 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. 07070100000002000081A400000000000000000000000166D3169B00000169000000000000000000000000000000000000001900000000libgedit-gfls-0.2.0/NEWSNews 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. 07070100000003000081A400000000000000000000000166D3169B000001B4000000000000000000000000000000000000001E00000000libgedit-gfls-0.2.0/README.mdlibgedit-gfls ============= Short description ----------------- Gedit Technology - File loading and saving Longer description ------------------ libgedit-gfls is part of [Gedit Technology](https://gedit-technology.github.io/). 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) 07070100000004000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001A00000000libgedit-gfls-0.2.0/build07070100000005000081A400000000000000000000000166D3169B00000002000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/build/.gitignore* 07070100000006000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001900000000libgedit-gfls-0.2.0/docs07070100000007000081A400000000000000000000000166D3169B000003E3000000000000000000000000000000000000002F00000000libgedit-gfls-0.2.0/docs/low-level-features.mdlibgedit-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. 07070100000008000081A400000000000000000000000166D3169B000002BA000000000000000000000000000000000000002A00000000libgedit-gfls-0.2.0/docs/low-level-kit.mdlibgedit-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. 07070100000009000081A400000000000000000000000166D3169B000001E6000000000000000000000000000000000000002200000000libgedit-gfls-0.2.0/docs/names.mdlibgedit-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 (if needed). 0707010000000A000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000002300000000libgedit-gfls-0.2.0/docs/reference0707010000000B000081A400000000000000000000000166D3169B000006FE000000000000000000000000000000000000003A00000000libgedit-gfls-0.2.0/docs/reference/libgedit-gfls-docs.xml<?xml version="1.0"?> <!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.3//EN" "http://www.oasis-open.org/docbook/xml/4.3/docbookx.dtd" [ <!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'"> <!ENTITY % gtkdocentities SYSTEM "xml/gtkdocentities.ent"> %gtkdocentities; ]> <book id="index"> <bookinfo> <title>libgedit-gfls &package_api_version; Reference Manual</title> <releaseinfo>for &package_string;</releaseinfo> </bookinfo> <part id="api-reference"> <title>libgedit-gfls API Reference</title> <xi:include href="xml/gfls-init.xml"/> <xi:include href="xml/gfls-attribute-keys.xml"/> <xi:include href="xml/gfls-input-stream.xml"/> <xi:include href="xml/gfls-loader-basic.xml"/> <xi:include href="xml/gfls-loader-config.xml"/> <xi:include href="xml/gfls-loader-config-simple.xml"/> <xi:include href="xml/gfls-unsaved-document-titles.xml"/> <xi:include href="xml/gfls-utf8.xml"/> </part> <part id="annexes"> <title>Annexes</title> <chapter id="object-tree"> <title>Object Hierarchy</title> <xi:include href="xml/tree_index.sgml"/> </chapter> <xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include> <index id="api-index-full"> <title>Index of all symbols</title> <xi:include href="xml/api-index-full.xml"><xi:fallback /></xi:include> </index> <index id="api-index-0-1" role="0.1"> <title>Index of new symbols in 0.1</title> <xi:include href="xml/api-index-0.1.xml"><xi:fallback /></xi:include> </index> <index id="api-index-0-2" role="0.2"> <title>Index of new symbols in 0.2</title> <xi:include href="xml/api-index-0.2.xml"><xi:fallback /></xi:include> </index> </part> </book> 0707010000000C000081A400000000000000000000000166D3169B0000099A000000000000000000000000000000000000003E00000000libgedit-gfls-0.2.0/docs/reference/libgedit-gfls-sections.txt<INCLUDE>gfls/gfls.h</INCLUDE> <SECTION> <FILE>gfls-attribute-keys</FILE> GflsAttributeKeys gfls_attribute_keys_new gfls_attribute_keys_add gfls_attribute_keys_to_string <SUBSECTION Standard> 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 </SECTION> <SECTION> <FILE>gfls-init</FILE> gfls_init gfls_finalize <SUBSECTION Standard> GFLS_H_INSIDE </SECTION> <SECTION> <FILE>gfls-input-stream</FILE> gfls_input_stream_read_async gfls_input_stream_read_finish </SECTION> <SECTION> <FILE>gfls-loader-basic</FILE> GFLS_LOADER_ERROR GflsLoaderError gfls_loader_basic_load_async gfls_loader_basic_load_finish <SUBSECTION Standard> GFLS_TYPE_LOADER_ERROR gfls_loader_error_get_type gfls_loader_error_quark </SECTION> <SECTION> <FILE>gfls-loader-config</FILE> GflsLoaderConfig GflsLoaderConfigInterface <SUBSECTION Standard> GFLS_IS_LOADER_CONFIG GFLS_LOADER_CONFIG GFLS_LOADER_CONFIG_GET_INTERFACE GFLS_TYPE_LOADER_CONFIG gfls_loader_config_get_type </SECTION> <SECTION> <FILE>gfls-loader-config-simple</FILE> 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 <SUBSECTION Standard> 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 </SECTION> <SECTION> <FILE>gfls-unsaved-document-titles</FILE> 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 <SUBSECTION Standard> 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 </SECTION> <SECTION> <FILE>gfls-utf8</FILE> gfls_utf8_has_very_long_line </SECTION> 0707010000000D000081A400000000000000000000000166D3169B00000479000000000000000000000000000000000000002F00000000libgedit-gfls-0.2.0/docs/reference/meson.buildsubdir('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), ], install: true ) 0707010000000E000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000002700000000libgedit-gfls-0.2.0/docs/reference/xml0707010000000F000081A400000000000000000000000166D3169B00000062000000000000000000000000000000000000003D00000000libgedit-gfls-0.2.0/docs/reference/xml/gtkdocentities.ent.in<!ENTITY package_string "@PACKAGE_STRING@"> <!ENTITY package_api_version "@PACKAGE_API_VERSION@"> 07070100000010000081A400000000000000000000000166D3169B000001A0000000000000000000000000000000000000003300000000libgedit-gfls-0.2.0/docs/reference/xml/meson.buildgtkdocentities_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 ) 07070100000011000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001900000000libgedit-gfls-0.2.0/gfls07070100000012000081A400000000000000000000000166D3169B00000D91000000000000000000000000000000000000002F00000000libgedit-gfls-0.2.0/gfls/gfls-attribute-keys.c/* 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 becomes useful to do only a single query with a list of keys coming from * different parts of the program. To take an example, 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); } 07070100000013000081A400000000000000000000000166D3169B000006EC000000000000000000000000000000000000002F00000000libgedit-gfls-0.2.0/gfls/gfls-attribute-keys.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <glib-object.h> #include <gmodule.h> 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 */ 07070100000014000081A400000000000000000000000166D3169B00000532000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/gfls/gfls-init.c/* 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; } } 07070100000015000081A400000000000000000000000166D3169B000001A9000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/gfls/gfls-init.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <gmodule.h> G_BEGIN_DECLS G_MODULE_EXPORT void gfls_init (void); G_MODULE_EXPORT void gfls_finalize (void); G_END_DECLS #endif /* GFLS_INIT_H */ 07070100000016000081A400000000000000000000000166D3169B000025D2000000000000000000000000000000000000002D00000000libgedit-gfls-0.2.0/gfls/gfls-input-stream.c/* SPDX-FileCopyrightText: 2023 - 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; /* 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 TaskData * task_data_new (gsize expected_size, gsize max_size) { TaskData *task_data; gsize initial_buf_size; /* +1 to nul-terminate the buffer. */ initial_buf_size = MIN (expected_size + 1, max_size + 1); task_data = g_new (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 = max_size + 1; 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 required_buf_size = task_data->buf_pos + n_bytes_to_write + 1; if (required_buf_size <= task_data->buf_size) { return n_bytes_to_write; } /* Needs 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 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; 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; } task_data = g_task_get_task_data (task); if (g_bytes_get_size (bytes) > 0) { task_data->truncated = TRUE; } g_bytes_unref (bytes); task_data_nul_terminate_buffer (task_data); g_task_return_boolean (task, TRUE); g_object_unref (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) { task_data_nul_terminate_buffer (task_data); g_task_return_boolean (task, TRUE); g_object_unref (task); return; } task_data->buf_pos += n_bytes_read; 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: * @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. * @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. * * See the #GAsyncResult documentation to know how to use this function. * * Since: 0.1 */ void gfls_input_stream_read_async (GInputStream *input_stream, gsize expected_size, gsize max_size, gint io_priority, GCancellable *cancellable, 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); g_task_set_task_data (task, task_data, (GDestroyNotify) task_data_free); read_next_chunk (task); } /** * gfls_input_stream_read_finish: * @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. 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_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; } 07070100000017000081A400000000000000000000000166D3169B0000036C000000000000000000000000000000000000002D00000000libgedit-gfls-0.2.0/gfls/gfls-input-stream.h/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_INPUT_STREAM_H #define GFLS_INPUT_STREAM_H #if !defined (GFLS_H_INSIDE) && !defined (GFLS_COMPILATION) #error "Only <gfls/gfls.h> can be included directly." #endif #include <gio/gio.h> G_BEGIN_DECLS G_MODULE_EXPORT void gfls_input_stream_read_async (GInputStream *input_stream, gsize expected_size, gsize max_size, gint io_priority, GCancellable *cancellable, 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 #endif /* GFLS_INPUT_STREAM_H */ 07070100000018000081A400000000000000000000000166D3169B00002534000000000000000000000000000000000000002D00000000libgedit-gfls-0.2.0/gfls/gfls-loader-basic.c/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include "gfls-config.h" #include "gfls-loader-basic.h" #include <glib/gi18n-lib.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; // TODO: close explicitly the stream? to get a GError if any. // With g_input_stream_close_async/finish(). // Do it here? Or in gfls_input_stream_read_async/finish(), since it is // meant as the only read operation? GInputStream *input_stream; /* Result */ GBytes *bytes; } TaskData; 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; } 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_new_error (task, GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_NOT_UTF8, _("The file is not encoded in UTF-8.")); g_object_unref (task); return; } if (gfls_utf8_has_very_long_line (text, task_data->max_n_bytes_per_line)) { g_task_return_new_error (task, GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_HAS_VERY_LONG_LINE, _("The file contains a 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_new_error (task, GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_TOO_BIG, _("Limit on the number of bytes to read reached.")); 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), 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_new_error (task, GFLS_LOADER_ERROR, GFLS_LOADER_ERROR_TOO_BIG, _("The size of the file is too big.")); 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_has_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; } 07070100000019000081A400000000000000000000000166D3169B000005C0000000000000000000000000000000000000002D00000000libgedit-gfls-0.2.0/gfls/gfls-loader-basic.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <gio/gio.h> 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_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 */ 0707010000001A000081A400000000000000000000000166D3169B00000C05000000000000000000000000000000000000003500000000libgedit-gfls-0.2.0/gfls/gfls-loader-config-simple.c/* 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; } 0707010000001B000081A400000000000000000000000166D3169B00000806000000000000000000000000000000000000003500000000libgedit-gfls-0.2.0/gfls/gfls-loader-config-simple.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <gio/gio.h> 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 */ 0707010000001C000081A400000000000000000000000166D3169B00000255000000000000000000000000000000000000002E00000000libgedit-gfls-0.2.0/gfls/gfls-loader-config.c/* 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) { } 0707010000001D000081A400000000000000000000000166D3169B000004B7000000000000000000000000000000000000002E00000000libgedit-gfls-0.2.0/gfls/gfls-loader-config.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <glib-object.h> #include <gmodule.h> 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 */ 0707010000001E000081A400000000000000000000000166D3169B00001A1D000000000000000000000000000000000000003800000000libgedit-gfls-0.2.0/gfls/gfls-unsaved-document-titles.c/* 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 <glib/gi18n-lib.h> /** * 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 <emphasis>changes</emphasis>. */ #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; } } 0707010000001F000081A400000000000000000000000166D3169B00000B54000000000000000000000000000000000000003800000000libgedit-gfls-0.2.0/gfls/gfls-unsaved-document-titles.h/* 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 <gfls/gfls.h> can be included directly." #endif #include <glib-object.h> #include <gmodule.h> 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. * * 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 */ 07070100000020000081A400000000000000000000000166D3169B000004F9000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/gfls/gfls-utf8.c/* SPDX-FileCopyrightText: 2023 - 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_has_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). * * Returns %TRUE 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: %TRUE if @str contains a very long line, %FALSE otherwise. * Since: 0.1 */ gboolean gfls_utf8_has_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, FALSE); 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) { return TRUE; } } } return FALSE; } 07070100000021000081A400000000000000000000000166D3169B000001CA000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/gfls/gfls-utf8.h/* SPDX-FileCopyrightText: 2023 - 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 <gfls/gfls.h> can be included directly." #endif #include <gmodule.h> G_BEGIN_DECLS G_MODULE_EXPORT gboolean gfls_utf8_has_very_long_line (const gchar *str, guint max_n_bytes_per_line); G_END_DECLS #endif /* GFLS_UTF8_H */ 07070100000022000081A400000000000000000000000166D3169B00000216000000000000000000000000000000000000002000000000libgedit-gfls-0.2.0/gfls/gfls.h/* SPDX-FileCopyrightText: 2023-2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #ifndef GFLS_H #define GFLS_H #define GFLS_H_INSIDE #include <gfls/gfls-enum-types.h> #include <gfls/gfls-attribute-keys.h> #include <gfls/gfls-init.h> #include <gfls/gfls-input-stream.h> #include <gfls/gfls-loader-basic.h> #include <gfls/gfls-loader-config.h> #include <gfls/gfls-loader-config-simple.h> #include <gfls/gfls-unsaved-document-titles.h> #include <gfls/gfls-utf8.h> #undef GFLS_H_INSIDE #endif /* GFLS_H */ 07070100000023000081A400000000000000000000000166D3169B00000B3F000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/gfls/meson.buildgfls_public_headers = [ 'gfls.h', 'gfls-attribute-keys.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-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', ] 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 <gmodule.h>', sources: gfls_public_headers, install_header: true, install_dir: headers_install_dir ) gfls_static_lib = static_library( 'libgedit-gfls-static', [gfls_public_c_files, 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 07070100000024000081A400000000000000000000000166D3169B00000023000000000000000000000000000000000000002400000000libgedit-gfls-0.2.0/gfls/symbol.map{ global: gfls_*; local: *; }; 07070100000025000081A400000000000000000000000166D3169B00000498000000000000000000000000000000000000002700000000libgedit-gfls-0.2.0/libgedit-gfls.doap<?xml version="1.0" encoding="UTF-8"?> <Project xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns:rdfs="http://www.w3.org/2000/01/rdf-schema#" xmlns:foaf="http://xmlns.com/foaf/0.1/" xmlns:gnome="http://api.gnome.org/doap-extensions#" xmlns="http://usefulinc.com/ns/doap#"> <name>libgedit-gfls</name> <shortdesc xml:lang="en">Gedit Technology - File loading and saving</shortdesc> <description xml:lang="en"> 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. </description> <homepage rdf:resource="https://gitlab.gnome.org/World/gedit/libgedit-gfls" /> <download-page rdf:resource="https://download.gnome.org/sources/libgedit-gfls/" /> <bug-database rdf:resource="https://gitlab.gnome.org/World/gedit/libgedit-gfls/-/issues" /> <programming-language>C</programming-language> <maintainer> <foaf:Person> <foaf:name>Sébastien Wilmet</foaf:name> <foaf:mbox rdf:resource="mailto:swilmet@mailfence.com" /> <gnome:userid>swilmet</gnome:userid> </foaf:Person> </maintainer> </Project> 07070100000026000081A400000000000000000000000166D3169B00000CE2000000000000000000000000000000000000002000000000libgedit-gfls-0.2.0/meson.build# 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.2.0', 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()) 07070100000027000081A400000000000000000000000166D3169B00000185000000000000000000000000000000000000002600000000libgedit-gfls-0.2.0/meson_options.txtoption( '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)' ) 07070100000028000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001700000000libgedit-gfls-0.2.0/po07070100000029000081A400000000000000000000000166D3169B0000004D000000000000000000000000000000000000001F00000000libgedit-gfls-0.2.0/po/LINGUAS# Set of available languages. # Please keep this list sorted alphabetically. 0707010000002A000081A400000000000000000000000166D3169B00000106000000000000000000000000000000000000002300000000libgedit-gfls-0.2.0/po/POTFILES.in# List of source files containing translatable strings. gfls/gfls-attribute-keys.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 0707010000002B000081A400000000000000000000000166D3169B00000000000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/po/POTFILES.skip0707010000002C000081A400000000000000000000000166D3169B00000039000000000000000000000000000000000000002300000000libgedit-gfls-0.2.0/po/meson.buildI18N.gettext( GETTEXT_PACKAGE_NAME, preset: 'glib' ) 0707010000002D000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000001A00000000libgedit-gfls-0.2.0/tests0707010000002E000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000002C00000000libgedit-gfls-0.2.0/tests/interactive-tests0707010000002F000081A400000000000000000000000166D3169B00001874000000000000000000000000000000000000003700000000libgedit-gfls-0.2.0/tests/interactive-tests/gfls-gui.c/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gtk/gtk.h> #include <locale.h> #include <gfls/gfls.h> /* 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; } 07070100000030000081A400000000000000000000000166D3169B00000CA0000000000000000000000000000000000000003B00000000libgedit-gfls-0.2.0/tests/interactive-tests/gfls-program.c/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gio/gio.h> #include <locale.h> 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 <input_file>\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; } 07070100000031000081A400000000000000000000000166D3169B000015DB000000000000000000000000000000000000004A00000000libgedit-gfls-0.2.0/tests/interactive-tests/gfls-test-race-read-content.c/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gio/gio.h> #include <locale.h> /* 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 <input_file>\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; } 07070100000032000081A400000000000000000000000166D3169B00000138000000000000000000000000000000000000003800000000libgedit-gfls-0.2.0/tests/interactive-tests/meson.buildexecutable( '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 07070100000033000081A400000000000000000000000166D3169B00000031000000000000000000000000000000000000002600000000libgedit-gfls-0.2.0/tests/meson.buildsubdir('interactive-tests') subdir('unit-tests') 07070100000034000041ED00000000000000000000000266D3169B00000000000000000000000000000000000000000000002500000000libgedit-gfls-0.2.0/tests/unit-tests07070100000035000081A400000000000000000000000166D3169B00000103000000000000000000000000000000000000003100000000libgedit-gfls-0.2.0/tests/unit-tests/meson.buildunit_tests = [ 'test-attribute-keys', '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 07070100000036000081A400000000000000000000000166D3169B000003AD000000000000000000000000000000000000003B00000000libgedit-gfls-0.2.0/tests/unit-tests/test-attribute-keys.c/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gfls/gfls.h> 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; } 07070100000037000081A400000000000000000000000166D3169B00000745000000000000000000000000000000000000004400000000libgedit-gfls-0.2.0/tests/unit-tests/test-unsaved-document-titles.c/* SPDX-FileCopyrightText: 2024 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gfls/gfls.h> 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; } 07070100000038000081A400000000000000000000000166D3169B000007FA000000000000000000000000000000000000003100000000libgedit-gfls-0.2.0/tests/unit-tests/test-utf8.c/* SPDX-FileCopyrightText: 2023 - Sébastien Wilmet * SPDX-License-Identifier: LGPL-3.0-or-later */ #include <gfls/gfls.h> static void test_has_very_long_line (void) { /* Without newline chars */ g_assert_false (gfls_utf8_has_very_long_line ("", 0)); g_assert_true (gfls_utf8_has_very_long_line ("a", 0)); g_assert_false (gfls_utf8_has_very_long_line ("", 1)); g_assert_false (gfls_utf8_has_very_long_line ("a", 1)); g_assert_true (gfls_utf8_has_very_long_line ("ab", 1)); g_assert_true (gfls_utf8_has_very_long_line ("é", 1)); g_assert_false (gfls_utf8_has_very_long_line ("é", 2)); /* With \n */ g_assert_false (gfls_utf8_has_very_long_line ("\n\n\n", 0)); g_assert_true (gfls_utf8_has_very_long_line ("\na\n", 0)); g_assert_true (gfls_utf8_has_very_long_line ("\na", 0)); g_assert_false (gfls_utf8_has_very_long_line ("a\nb\nc\n", 1)); g_assert_false (gfls_utf8_has_very_long_line ("a\nb\nc", 1)); g_assert_true (gfls_utf8_has_very_long_line ("a\nbc\n", 1)); g_assert_true (gfls_utf8_has_very_long_line ("a\nbcd\n", 1)); g_assert_true (gfls_utf8_has_very_long_line ("a\nbcd\n", 2)); g_assert_true (gfls_utf8_has_very_long_line ("a\nbcd", 2)); g_assert_true (gfls_utf8_has_very_long_line ("é\nSé", 2)); g_assert_false (gfls_utf8_has_very_long_line ("é\nSé", 3)); g_assert_false (gfls_utf8_has_very_long_line ("é\nSé\n", 3)); /* Quick test with \r */ g_assert_false (gfls_utf8_has_very_long_line ("\r\r\r", 0)); g_assert_false (gfls_utf8_has_very_long_line ("\n\r\n\r\n\r", 0)); g_assert_false (gfls_utf8_has_very_long_line ("\r\n\r\n\r\n", 0)); g_assert_false (gfls_utf8_has_very_long_line ("a\rb\nc\rd", 1)); g_assert_true (gfls_utf8_has_very_long_line ("a\ré", 1)); g_assert_false (gfls_utf8_has_very_long_line ("a\ré", 2)); } int main (int argc, char **argv) { int exit_status; gfls_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ("/utf8/has_very_long_line", test_has_very_long_line); exit_status = g_test_run (); gfls_finalize (); return exit_status; } 07070100000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000B00000000TRAILER!!!199 blocks
Locations
Projects
Search
Status Monitor
Help
OpenBuildService.org
Documentation
API Documentation
Code of Conduct
Contact
Support
@OBShq
Terms
openSUSE Build Service is sponsored by
The Open Build Service is an
openSUSE project
.
Sign Up
Log In
Places
Places
All Projects
Status Monitor