From 52511d42630b62ba3d304cd18c0b5ab67ab8544f Mon Sep 17 00:00:00 2001 From: Karol Lewandowski Date: Tue, 3 Sep 2024 09:34:57 +0200 Subject: [PATCH] Imported Upstream version 2.79.0 --- .gitlab-ci.yml | 196 +- .gitlab-ci/alpine.Dockerfile | 38 + .gitlab-ci/check-missing-install-tag.py | 6 + .gitlab-ci/debian-stable.Dockerfile | 13 +- .gitlab-ci/fedora.Dockerfile | 14 +- .gitlab-ci/mingw.Dockerfile | 63 +- .gitlab-ci/run-style-check-diff.sh | 8 +- .gitlab-ci/test-msvc.bat | 2 +- .gitlab-ci/test-msys2.sh | 12 +- .reuse/dep5 | 7 + LICENSES/LGPL-2.1-only.txt | 175 + LICENSES/MPL-1.1.txt | 143 + NEWS | 313 +- README.md | 7 +- SECURITY.md | 15 +- docs/CODEOWNERS | 3 + docs/reference/gio/concat-files-helper.py | 36 - docs/reference/gio/dbus-error.md | 79 + docs/reference/gio/dbus-introspection.md | 23 + docs/reference/gio/dbus-name-owning.md | 14 + docs/reference/gio/dbus-name-watching.md | 14 + docs/reference/gio/dbus-utils.md | 28 + docs/reference/gio/error.md | 12 + docs/reference/gio/file-attributes.md | 111 + docs/reference/gio/gapplication.rst | 195 + docs/reference/gio/gapplication.xml | 352 -- docs/reference/gio/gdbus-codegen.rst | 805 ++++ docs/reference/gio/gdbus-codegen.xml | 1193 ----- .../gio/gdbus-object-manager-example/.gitignore | 1 - .../gdbus-object-manager-example-docs.xml | 19 - .../gdbus-object-manager-example-sections.txt | 161 - .../gio/gdbus-object-manager-example/meson.build | 11 - docs/reference/gio/gdbus.rst | 278 ++ docs/reference/gio/gdbus.xml | 429 -- docs/reference/gio/gio-docs-unix.xml | 3 - docs/reference/gio/gio-docs-win32.xml | 6 - docs/reference/gio/gio-docs.xml | 418 -- docs/reference/gio/gio-querymodules.rst | 31 + docs/reference/gio/gio-querymodules.xml | 45 - docs/reference/gio/gio-sections-common.txt | 4808 -------------------- docs/reference/gio/gio-sections-win32.txt | 122 - docs/reference/gio/gio.rst | 528 +++ docs/reference/gio/gio.toml.in | 72 + docs/reference/gio/gio.xml | 809 ---- docs/reference/gio/glib-compile-resources.rst | 181 + docs/reference/gio/glib-compile-resources.xml | 254 -- docs/reference/gio/glib-compile-schemas.rst | 83 + docs/reference/gio/glib-compile-schemas.xml | 118 - docs/reference/gio/gresource.rst | 66 + docs/reference/gio/gresource.xml | 127 - docs/reference/gio/gsettings.rst | 125 + docs/reference/gio/gsettings.xml | 248 - docs/reference/gio/io-scheduler.md | 20 + docs/reference/gio/menu-exporter.md | 15 + docs/reference/gio/meson.build | 283 +- docs/reference/gio/migrating-gconf.md | 466 ++ docs/reference/gio/migrating-gconf.xml | 515 --- docs/reference/gio/migrating-gdbus.md | 633 +++ docs/reference/gio/migrating-gdbus.xml | 310 -- docs/reference/gio/migrating-gnome-vfs.md | 109 + docs/reference/gio/migrating-gnome-vfs.xml | 133 - docs/reference/gio/migrating-posix.md | 17 + docs/reference/gio/migrating-posix.xml | 27 - docs/reference/gio/networking.md | 29 + docs/reference/gio/overview.md | 406 ++ docs/reference/gio/overview.xml | 745 --- docs/reference/gio/pollable-utils.md | 15 + docs/reference/gio/tls-overview.md | 37 + docs/reference/gio/unix-mounts.md | 35 + docs/reference/gio/urlmap.js | 10 + docs/reference/gio/version.xml.in | 1 - docs/reference/gio/xml/gtkdocentities.ent.in | 8 - docs/reference/gio/xml/meson.build | 14 - docs/reference/girepository/girepository.toml.in | 50 + docs/reference/girepository/meson.build | 23 + docs/reference/girepository/urlmap.js | 10 + docs/reference/glib/atomic.md | 75 + docs/reference/glib/auto-cleanup.md | 291 ++ docs/reference/glib/base64.md | 20 + docs/reference/glib/building.md | 180 + docs/reference/glib/building.xml | 339 -- docs/reference/glib/changes.xml | 174 - docs/reference/glib/character-set.md | 91 + docs/reference/glib/checked-math.md | 30 + docs/reference/glib/compiling.md | 71 + docs/reference/glib/compiling.xml | 125 - docs/reference/glib/conversion-macros.md | 281 ++ docs/reference/glib/cross-compiling.md | 88 + docs/reference/glib/cross.xml | 147 - docs/reference/glib/data-structures.md | 517 +++ docs/reference/glib/datalist-and-dataset.md | 78 + docs/reference/glib/error-reporting.md | 487 ++ docs/reference/glib/file-utils.md | 110 + docs/reference/glib/glib-docs.xml | 315 -- docs/reference/glib/glib-gettextize.rst | 59 + docs/reference/glib/glib-gettextize.xml | 88 - docs/reference/glib/glib-overrides.txt | 294 -- docs/reference/glib/glib-sections.txt.in | 3763 --------------- docs/reference/glib/glib.toml.in | 125 + docs/reference/glib/goption.md | 149 + docs/reference/glib/gtester-report.rst | 54 + docs/reference/glib/gtester-report.xml | 78 - docs/reference/glib/gtester.rst | 120 + docs/reference/glib/gtester.xml | 192 - docs/reference/glib/gvariant-format-strings.md | 503 ++ docs/reference/glib/gvariant-text-format.md | 346 ++ docs/reference/glib/gvariant-text.xml | 622 --- docs/reference/glib/gvariant-varargs.xml | 1178 ----- docs/reference/glib/host-utils.md | 30 + docs/reference/glib/i18n.md | 49 + docs/reference/glib/logging.md | 137 + docs/reference/glib/macros.md | 896 ++++ docs/reference/glib/main-loop.md | 107 + docs/reference/glib/markup.md | 50 + docs/reference/glib/memory-slices.md | 58 + docs/reference/glib/memory.md | 99 + docs/reference/glib/meson.build | 187 +- docs/reference/glib/misc-utils.md | 113 + docs/reference/glib/numerical.md | 35 + docs/reference/glib/programming.md | 71 + docs/reference/glib/programming.xml | 124 - docs/reference/glib/random.md | 61 + docs/reference/glib/reference-counting.md | 164 + docs/reference/glib/regex-syntax.xml | 2485 ---------- docs/reference/glib/resources.md | 43 + docs/reference/glib/resources.xml | 77 - docs/reference/glib/running.md | 295 ++ docs/reference/glib/running.xml | 371 -- docs/reference/glib/shell.md | 15 + docs/reference/glib/spawn.md | 76 + docs/reference/glib/string-utils.md | 187 + docs/reference/glib/testing.md | 183 + docs/reference/glib/threads-deprecated.md | 37 + docs/reference/glib/threads.md | 91 + docs/reference/glib/types.md | 882 ++++ docs/reference/glib/unicode.md | 37 + docs/reference/glib/unix.md | 48 + docs/reference/glib/urlmap.js | 9 + docs/reference/glib/uuid.md | 25 + docs/reference/glib/version.md | 46 + docs/reference/glib/version.xml.in | 1 - docs/reference/glib/warnings.md | 73 + docs/reference/glib/windows.md | 26 + docs/reference/glib/xml/gtkdocentities.ent.in | 8 - docs/reference/glib/xml/meson.build | 14 - docs/reference/gmodule/gmodule.toml.in | 49 + docs/reference/gmodule/meson.build | 26 + docs/reference/gmodule/modules.md | 92 + docs/reference/gmodule/urlmap.js | 9 + docs/reference/gobject/boxed.md | 113 + docs/reference/gobject/concepts.md | 1847 ++++++++ docs/reference/gobject/enum-types.md | 36 + docs/reference/gobject/floating-refs.md | 128 + docs/reference/gobject/glib-genmarshal.rst | 390 ++ docs/reference/gobject/glib-genmarshal.xml | 579 --- docs/reference/gobject/glib-mkenums.rst | 491 ++ docs/reference/gobject/glib-mkenums.xml | 659 --- docs/reference/gobject/gobject-docs.xml | 236 - docs/reference/gobject/gobject-overrides.txt | 0 docs/reference/gobject/gobject-query.rst | 74 + docs/reference/gobject/gobject-query.xml | 123 - docs/reference/gobject/gobject-sections.txt | 1060 ----- docs/reference/gobject/gobject.toml.in | 64 + docs/reference/gobject/gvalue.md | 108 + docs/reference/gobject/meson.build | 108 +- docs/reference/gobject/signals.md | 95 + docs/reference/gobject/tut_gobject.xml | 728 --- docs/reference/gobject/tut_gsignal.xml | 495 -- docs/reference/gobject/tut_gtype.xml | 1003 ---- docs/reference/gobject/tut_howto.xml | 1535 ------- docs/reference/gobject/tut_intro.xml | 185 - docs/reference/gobject/tut_tools.xml | 125 - docs/reference/gobject/tutorial.md | 1288 ++++++ docs/reference/gobject/types.md | 64 + docs/reference/gobject/urlmap.js | 9 + docs/reference/gobject/value-collection.md | 56 + docs/reference/gobject/version.xml.in | 1 - docs/reference/gobject/xml/gtkdocentities.ent.in | 8 - docs/reference/gobject/xml/meson.build | 14 - docs/reference/meson.build | 68 +- docs/roadmap.md | 2 +- docs/supported-platforms.md | 2 - docs/toolchain-requirements.md | 28 + gio/gaction.c | 62 +- gio/gactiongroup.c | 71 +- gio/gactiongroupexporter.c | 12 +- gio/gactionmap.c | 22 +- gio/gappinfo.c | 110 +- gio/gappinfo.h | 7 - gio/gapplication.c | 216 +- gio/gapplicationcommandline.c | 226 +- gio/gapplicationcommandline.h | 13 +- gio/gapplicationimpl-dbus.c | 17 +- gio/gasynchelper.c | 8 +- gio/gasyncinitable.c | 25 +- gio/gasyncinitable.h | 7 - gio/gasyncresult.c | 52 +- gio/gasyncresult.h | 6 - gio/gbufferedinputstream.c | 27 +- gio/gbufferedinputstream.h | 5 - gio/gbufferedoutputstream.c | 52 +- gio/gbufferedoutputstream.h | 5 - gio/gbytesicon.c | 15 +- gio/gbytesicon.h | 5 - gio/gcancellable.c | 8 +- gio/gcancellable.h | 5 - gio/gcharsetconverter.c | 48 +- gio/gcontenttype.c | 4 +- gio/gconverter.c | 11 +- gio/gconverter.h | 7 - gio/gconverterinputstream.c | 22 +- gio/gconverterinputstream.h | 6 - gio/gconverteroutputstream.c | 22 +- gio/gconverteroutputstream.h | 6 - gio/gcredentials.c | 54 +- gio/gdatagrambased.c | 47 +- gio/gdatagrambased.h | 7 - gio/gdatainputstream.c | 20 +- gio/gdatainputstream.h | 6 - gio/gdataoutputstream.c | 17 +- gio/gdataoutputstream.h | 6 - gio/gdbus-2.0/codegen/codegen.py | 4 +- gio/gdbus-2.0/codegen/meson.build | 9 +- gio/gdbus-2.0/codegen/utils.py | 4 +- gio/gdbusactiongroup.c | 19 +- gio/gdbusaddress.c | 5 +- gio/gdbusauth.c | 4 +- gio/gdbusauthmechanism.c | 8 +- gio/gdbusauthobserver.c | 51 +- gio/gdbusconnection.c | 859 +--- gio/gdbusdaemon.c | 4 +- gio/gdbuserror.c | 76 - gio/gdbusinterface.c | 14 +- gio/gdbusinterface.h | 8 - gio/gdbusinterfaceskeleton.c | 10 +- gio/gdbusinterfaceskeleton.h | 8 - gio/gdbusintrospection.c | 14 - gio/gdbusmenumodel.c | 17 +- gio/gdbusmessage.c | 56 +- gio/gdbusmessage.h | 3 +- gio/gdbusmethodinvocation.c | 23 +- gio/gdbusnameowning.c | 27 +- gio/gdbusnamewatching.c | 24 +- gio/gdbusobject.c | 17 +- gio/gdbusobjectmanager.c | 19 +- gio/gdbusobjectmanagerclient.c | 147 +- gio/gdbusobjectmanagerclient.h | 8 - gio/gdbusobjectmanagerserver.c | 27 +- gio/gdbusobjectmanagerserver.h | 8 - gio/gdbusobjectproxy.c | 18 +- gio/gdbusobjectproxy.h | 8 - gio/gdbusobjectskeleton.c | 14 +- gio/gdbusobjectskeleton.h | 8 - gio/gdbusprivate.c | 65 +- gio/gdbusprivate.h | 5 - gio/gdbusproxy.c | 106 +- gio/gdbusproxy.h | 8 - gio/gdbusserver.c | 55 +- gio/gdbusutils.c | 9 - gio/gdebugcontroller.c | 24 +- gio/gdebugcontroller.h | 8 - gio/gdebugcontrollerdbus.c | 45 +- gio/gdebugcontrollerdbus.h | 7 - gio/gdesktopappinfo.c | 47 +- gio/gdrive.c | 24 +- gio/gdtlsclientconnection.c | 28 +- gio/gdtlsconnection.c | 94 +- gio/gdtlsserverconnection.c | 13 +- gio/gdtlsserverconnection.h | 8 - gio/gdummytlsbackend.c | 4 +- gio/gemblem.c | 31 +- gio/gemblem.h | 5 - gio/gemblemedicon.c | 24 +- gio/gemblemedicon.h | 5 - gio/gfile.c | 208 +- gio/gfile.h | 10 - gio/gfileattribute-priv.h | 4 +- gio/gfileattribute.c | 107 - gio/gfiledescriptorbased.c | 12 +- gio/gfiledescriptorbased.h | 5 - gio/gfileenumerator.c | 36 +- gio/gfileenumerator.h | 5 - gio/gfileicon.c | 14 +- gio/gfileicon.h | 5 - gio/gfileinfo.c | 49 +- gio/gfileinfo.h | 5 - gio/gfileinputstream.c | 15 +- gio/gfileinputstream.h | 8 - gio/gfileiostream.c | 32 +- gio/gfileiostream.h | 8 - gio/gfilemonitor.c | 39 +- gio/gfilemonitor.h | 5 - gio/gfilenamecompleter.c | 7 +- gio/gfilenamecompleter.h | 5 - gio/gfileoutputstream.c | 22 +- gio/gfileoutputstream.h | 8 - gio/gfilterinputstream.c | 22 +- gio/gfilterinputstream.h | 5 - gio/gfilteroutputstream.c | 22 +- gio/gfilteroutputstream.h | 5 - gio/gicon.c | 46 +- gio/gicon.h | 5 - gio/ginetaddress.c | 86 +- gio/ginetaddressmask.c | 50 +- gio/ginetsocketaddress.c | 52 +- gio/ginitable.c | 29 +- gio/ginitable.h | 7 - gio/ginputstream.c | 18 +- gio/ginputstream.h | 5 - gio/gio-autocleanups.h | 4 + gio/gio-tool-copy.c | 4 + gio/gio-tool-info.c | 3 +- gio/gio-tool.c | 142 +- gio/gioenums.h | 7 +- gio/gioenumtypes.c.template | 6 +- gio/gioerror.c | 35 +- gio/giomodule.c | 76 +- gio/giomodule.h | 5 - gio/gioscheduler.c | 20 +- gio/giostream.c | 99 +- gio/giostream.h | 5 - gio/giotypes.h | 112 +- gio/gkeyfilesettingsbackend.c | 16 +- gio/glib-compile-resources.c | 2 +- gio/glistmodel.c | 65 +- gio/gliststore.c | 20 +- gio/gloadableicon.c | 9 +- gio/gloadableicon.h | 6 - gio/glocalfile.c | 6 +- gio/glocalfileinfo.c | 10 +- gio/glocalvfs.c | 25 +- gio/gmemoryinputstream.c | 11 +- gio/gmemoryinputstream.h | 5 - gio/gmemorymonitor.c | 34 +- gio/gmemoryoutputstream.c | 31 +- gio/gmemoryoutputstream.h | 5 - gio/gmenu.c | 24 +- gio/gmenuexporter.c | 15 - gio/gmenumodel.c | 85 +- gio/gmount.c | 37 +- gio/gmountoperation.c | 56 +- gio/gmountoperation.h | 6 - gio/gnativesocketaddress.c | 14 +- gio/gnetworkaddress.c | 49 +- gio/gnetworking.c | 25 - gio/gnetworking.h.in | 4 + gio/gnetworkmonitor.c | 30 +- gio/gnetworkmonitorbase.c | 9 +- gio/gnetworkmonitorportal.c | 6 +- gio/gnetworkservice.c | 64 +- gio/gnotification.c | 60 +- gio/gopenuriportal.c | 4 +- gio/gosxappinfo.m | 13 +- gio/goutputstream.c | 36 +- gio/goutputstream.h | 9 - gio/gpermission.c | 35 +- gio/gpollableinputstream.c | 16 +- gio/gpollableinputstream.h | 7 - gio/gpollableoutputstream.c | 20 +- gio/gpollableoutputstream.h | 7 - gio/gpollableutils.c | 9 - gio/gportalsupport.c | 2 +- gio/gpowerprofilemonitor.c | 31 +- gio/gpropertyaction.c | 85 +- gio/gproxy.c | 12 +- gio/gproxy.h | 7 - gio/gproxyaddress.c | 75 +- gio/gproxyaddressenumerator.c | 54 +- gio/gproxyaddressenumerator.h | 8 - gio/gproxyresolver.c | 23 +- gio/gregistrysettingsbackend.c | 2 +- gio/gremoteactiongroup.c | 30 +- gio/gresolver.c | 50 +- gio/gresource.c | 213 +- gio/gseekable.c | 21 +- gio/gseekable.h | 5 - gio/gsettings.c | 225 +- gio/gsettingsbackend.c | 29 +- gio/gsettingsbackend.h | 5 - gio/gsettingsschema.c | 54 +- gio/gsimpleaction.c | 40 +- gio/gsimpleactiongroup.c | 12 +- gio/gsimpleactiongroup.h | 7 - gio/gsimpleasyncresult.c | 92 +- gio/gsimpleasyncresult.h | 5 - gio/gsimpleiostream.c | 39 +- gio/gsimplepermission.c | 21 +- gio/gsimpleproxyresolver.c | 23 +- gio/gsimpleproxyresolver.h | 5 - gio/gsocket.c | 339 +- gio/gsocket.h | 13 + gio/gsocketaddress.c | 28 +- gio/gsocketaddressenumerator.c | 25 +- gio/gsocketaddressenumerator.h | 6 - gio/gsocketclient.c | 200 +- gio/gsocketconnectable.c | 16 +- gio/gsocketconnectable.h | 5 - gio/gsocketconnection.c | 40 +- gio/gsocketcontrolmessage.c | 24 +- gio/gsocketinputstream.c | 4 +- gio/gsocketlistener.c | 37 +- gio/gsocketoutputstream.c | 4 +- gio/gsocketservice.c | 36 +- gio/gsocks5proxy.c | 40 +- gio/gsrvtarget.c | 28 +- gio/gsubprocess.c | 73 +- gio/gsubprocesslauncher.c | 18 +- gio/gtask.c | 946 ++-- gio/gtask.h | 12 + gio/gtcpconnection.c | 19 +- gio/gtcpwrapperconnection.c | 36 +- gio/gtestdbus.c | 100 +- gio/gthemedicon.c | 27 +- gio/gthemedicon.h | 5 - gio/gthreadedresolver.c | 31 +- gio/gthreadedresolver.h | 2 + gio/gthreadedsocketservice.c | 32 +- gio/gtlsbackend.c | 51 +- gio/gtlscertificate.c | 76 +- gio/gtlsclientconnection.c | 29 +- gio/gtlsconnection.c | 76 +- gio/gtlsdatabase.c | 18 +- gio/gtlsfiledatabase.c | 20 +- gio/gtlsinteraction.c | 25 +- gio/gtlspassword.c | 47 +- gio/gtlsserverconnection.c | 12 +- gio/gtlsserverconnection.h | 8 - gio/gtrashportal.c | 4 +- gio/gunixconnection.c | 17 +- gio/gunixcredentialsmessage.c | 28 +- gio/gunixcredentialsmessage.h | 8 - gio/gunixfdlist.c | 22 +- gio/gunixfdmessage.c | 35 +- gio/gunixinputstream.c | 17 +- gio/gunixinputstream.h | 5 - gio/gunixmount.c | 2 +- gio/gunixmounts.c | 12 - gio/gunixoutputstream.c | 17 +- gio/gunixoutputstream.h | 5 - gio/gunixsocketaddress.c | 60 +- gio/gunixvolume.c | 2 +- gio/gvfs.c | 17 +- gio/gvfs.h | 5 - gio/gvolume.c | 68 +- gio/gvolume.h | 4 +- gio/gvolumemonitor.c | 17 +- gio/gvolumemonitor.h | 5 - gio/gwin32appinfo.c | 12 +- gio/gwin32inputstream.c | 15 +- gio/gwin32inputstream.h | 5 - gio/gwin32outputstream.c | 15 +- gio/gwin32outputstream.h | 5 - gio/gwin32registrykey.c | 58 +- gio/gwin32sid.c | 8 +- gio/gzlibcompressor.c | 39 +- gio/gzlibdecompressor.c | 26 +- gio/inotify/inotify-kernel.c | 4 +- gio/meson.build | 29 +- gio/tests/appinfo.c | 15 + gio/tests/application-command-line.c | 9 + gio/tests/apps.c | 46 +- gio/tests/codegen.py | 1 + gio/tests/contenttype.c | 53 + gio/tests/cxx.cpp | 2 +- gio/tests/desktop-app-info.c | 25 +- gio/tests/error.c | 2 +- gio/tests/file.c | 71 +- gio/tests/gapplication.c | 120 +- gio/tests/gdbus-connection.c | 106 +- gio/tests/gdbus-object-manager-example/meson.build | 7 +- gio/tests/gdbus-proxy.c | 6 - gio/tests/gdbus-subscribe.c | 1342 ------ gio/tests/gdbus-test-codegen.c | 6 +- gio/tests/gio-tool.py | 138 + gio/tests/gsettings.c | 12 +- gio/tests/memory-monitor-portal.py.in | 2 +- gio/tests/meson.build | 70 +- gio/tests/portal-support-env-var.c | 2 +- gio/tests/power-profile-monitor-portal.py.in | 2 +- gio/tests/proxy-test.c | 6 +- gio/tests/socket.c | 327 +- gio/tests/stream-rw_all.c | 32 +- gio/tests/task.c | 106 +- gio/tests/tls-interaction.c | 4 +- gio/tests/win32-streams.c | 30 +- girepository/cmph-bdz-test.c | 156 + girepository/cmph/README-CMPH-IMPORT.txt | 5 + girepository/cmph/bdz.c | 721 +++ girepository/cmph/bdz.h | 43 + girepository/cmph/bdz_gen_lookup_table.c | 33 + girepository/cmph/bdz_ph.c | 633 +++ girepository/cmph/bdz_ph.h | 42 + girepository/cmph/bdz_structs.h | 36 + girepository/cmph/bdz_structs_ph.h | 26 + girepository/cmph/bitbool.h | 179 + girepository/cmph/bmz.c | 638 +++ girepository/cmph/bmz.h | 42 + girepository/cmph/bmz8.c | 647 +++ girepository/cmph/bmz8.h | 42 + girepository/cmph/bmz8_structs.h | 25 + girepository/cmph/bmz_structs.h | 25 + girepository/cmph/brz.c | 1040 +++++ girepository/cmph/brz.h | 47 + girepository/cmph/brz_structs.h | 39 + girepository/cmph/buffer_entry.c | 103 + girepository/cmph/buffer_entry.h | 14 + girepository/cmph/buffer_manage.c | 66 + girepository/cmph/buffer_manage.h | 12 + girepository/cmph/buffer_manager.c | 64 + girepository/cmph/buffer_manager.h | 12 + girepository/cmph/chd.c | 280 ++ girepository/cmph/chd.h | 59 + girepository/cmph/chd_ph.c | 1001 ++++ girepository/cmph/chd_ph.h | 59 + girepository/cmph/chd_structs.h | 21 + girepository/cmph/chd_structs_ph.h | 29 + girepository/cmph/chm.c | 396 ++ girepository/cmph/chm.h | 42 + girepository/cmph/chm_structs.h | 24 + girepository/cmph/cmph.c | 844 ++++ girepository/cmph/cmph.h | 112 + girepository/cmph/cmph_structs.c | 76 + girepository/cmph/cmph_structs.h | 33 + girepository/cmph/cmph_time.h | 62 + girepository/cmph/cmph_types.h | 25 + girepository/cmph/compressed_rank.c | 327 ++ girepository/cmph/compressed_rank.h | 55 + girepository/cmph/compressed_seq.c | 384 ++ girepository/cmph/compressed_seq.h | 84 + girepository/cmph/debug.h | 53 + girepository/cmph/djb2_hash.c | 49 + girepository/cmph/djb2_hash.h | 18 + girepository/cmph/fch.c | 539 +++ girepository/cmph/fch.h | 48 + girepository/cmph/fch_buckets.c | 214 + girepository/cmph/fch_buckets.h | 30 + girepository/cmph/fch_structs.h | 30 + girepository/cmph/fnv_hash.c | 53 + girepository/cmph/fnv_hash.h | 18 + girepository/cmph/graph.c | 338 ++ girepository/cmph/graph.h | 40 + girepository/cmph/hash.c | 216 + girepository/cmph/hash.h | 76 + girepository/cmph/hash_state.h | 12 + girepository/cmph/hashtree.c | 289 ++ girepository/cmph/hashtree.h | 19 + girepository/cmph/hashtree_structs.h | 32 + girepository/cmph/jenkins_hash.c | 297 ++ girepository/cmph/jenkins_hash.h | 65 + girepository/cmph/main.c | 342 ++ girepository/cmph/meson.build | 86 + girepository/cmph/miller_rabin.c | 67 + girepository/cmph/miller_rabin.h | 5 + girepository/cmph/sdbm_hash.c | 49 + girepository/cmph/sdbm_hash.h | 18 + girepository/cmph/select.c | 337 ++ girepository/cmph/select.h | 61 + girepository/cmph/select_lookup_tables.h | 170 + girepository/cmph/vqueue.c | 51 + girepository/cmph/vqueue.h | 18 + girepository/cmph/vstack.c | 79 + girepository/cmph/vstack.h | 18 + girepository/cmph/wingetopt.c | 179 + girepository/cmph/wingetopt.h | 25 + girepository/gdump.c | 748 +++ girepository/gi-dump-types.c | 53 + girepository/giarginfo.c | 365 ++ girepository/giarginfo.h | 83 + girepository/gibaseinfo-private.h | 51 + girepository/gibaseinfo.c | 950 ++++ girepository/gibaseinfo.h | 103 + girepository/gicallableinfo.c | 835 ++++ girepository/gicallableinfo.h | 109 + girepository/gicallbackinfo.c | 52 + girepository/gicallbackinfo.h | 45 + girepository/giconstantinfo.c | 193 + girepository/giconstantinfo.h | 57 + girepository/gienuminfo.c | 269 ++ girepository/gienuminfo.h | 83 + girepository/gifieldinfo.c | 579 +++ girepository/gifieldinfo.h | 69 + girepository/gifunctioninfo.c | 316 ++ girepository/gifunctioninfo.h | 102 + girepository/giinterfaceinfo.c | 536 +++ girepository/giinterfaceinfo.h | 105 + girepository/ginvoke.c | 335 ++ girepository/giobjectinfo.c | 1181 +++++ girepository/giobjectinfo.h | 215 + girepository/gipropertyinfo.c | 228 + girepository/gipropertyinfo.h | 62 + girepository/giregisteredtypeinfo.c | 165 + girepository/giregisteredtypeinfo.h | 64 + girepository/girepository-private.h | 247 + girepository/girepository.c | 1986 ++++++++ girepository/girepository.h | 256 ++ girepository/girffi.c | 460 ++ girepository/girffi.h | 128 + girepository/girmodule-private.h | 85 + girepository/girmodule.c | 584 +++ girepository/girnode-private.h | 400 ++ girepository/girnode.c | 2444 ++++++++++ girepository/giroffsets.c | 593 +++ girepository/girparser-private.h | 49 + girepository/girparser.c | 3820 ++++++++++++++++ girepository/girwriter-private.h | 35 + girepository/girwriter.c | 1463 ++++++ girepository/gisignalinfo.c | 159 + girepository/gisignalinfo.h | 57 + girepository/gistructinfo.c | 364 ++ girepository/gistructinfo.h | 87 + girepository/gitypeinfo.c | 623 +++ girepository/gitypeinfo.h | 131 + girepository/gitypelib-internal.h | 1422 ++++++ girepository/gitypelib.c | 2570 +++++++++++ girepository/gitypelib.h | 65 + girepository/gitypes.h | 473 ++ girepository/giunioninfo.c | 351 ++ girepository/giunioninfo.h | 89 + girepository/giunresolvedinfo.c | 52 + girepository/giunresolvedinfo.h | 45 + girepository/givfuncinfo.c | 385 ++ girepository/givfuncinfo.h | 73 + girepository/gthash-test.c | 67 + girepository/gthash.c | 229 + girepository/meson.build | 259 ++ girepository/tests/meson.build | 89 + girepository/tests/repository-search-paths.c | 117 + girepository/tests/repository.c | 164 + glib/deprecated/gcache.c | 32 +- glib/deprecated/gcompletion.c | 55 +- glib/deprecated/gcompletion.h | 2 +- glib/deprecated/grel.c | 50 +- glib/deprecated/grel.h | 23 - glib/deprecated/gthread-deprecated.c | 13 +- glib/deprecated/gthread.h | 2 +- glib/docs.c | 1249 +---- glib/garcbox.c | 125 - glib/garray.c | 154 +- glib/gasyncqueue.c | 70 +- glib/gatomic.c | 99 +- glib/gatomic.h | 40 +- glib/gbase64.c | 24 - glib/gbitlock.c | 14 +- glib/gbookmarkfile.c | 45 - glib/gbookmarkfile.h | 40 +- glib/gcharset.c | 4 +- glib/gchecksum.c | 27 +- glib/gchecksum.h | 10 - glib/gconstructor.h | 25 +- glib/gconstructorprivate.h | 69 + glib/gconvert.c | 99 - glib/gdataset.c | 79 +- glib/gdate.c | 80 +- glib/gdate.h | 9 - glib/gdatetime-private.c | 257 ++ glib/gdatetime-private.h | 88 + glib/gdatetime.c | 474 +- glib/gdatetime.h | 34 +- glib/gdir.c | 108 +- glib/gdir.h | 5 + glib/gen-unicode-tables.pl | 13 +- glib/gerror.c | 489 +- glib/gfileutils.c | 67 +- glib/ggettext.c | 51 - glib/ghash.c | 123 +- glib/ghmac.c | 19 +- glib/ghmac.h | 9 - glib/ghook.c | 18 +- glib/ghostutils.c | 18 - glib/giochannel.c | 71 +- glib/giowin32.c | 2 +- glib/gkeyfile.c | 74 +- glib/glib-autocleanups.h | 4 + glib/glib-init.c | 55 +- glib/glib-private.c | 3 + glib/glib-private.h | 79 +- glib/glib-unix.c | 19 +- glib/glib-unix.h | 208 + glib/glist.c | 98 +- glib/gmacros.h | 1 + glib/gmain.c | 198 +- glib/gmarkup.c | 56 +- glib/gmem.c | 30 - glib/gmessages.c | 277 +- glib/gmessages.h | 3 + glib/gnode.c | 45 +- glib/goption.c | 172 +- glib/gpathbuf.c | 14 +- glib/gpathbuf.h | 7 - glib/gpattern.c | 32 +- glib/gprintf.c | 40 +- glib/gqsort.c | 2 +- glib/gquark.c | 42 +- glib/gqueue.c | 37 +- glib/grand.c | 65 +- glib/grcbox.c | 130 - glib/grefcount.c | 23 - glib/grefstring.c | 68 - glib/gregex.c | 37 +- glib/gregex.h | 8 - glib/gscanner.c | 13 +- glib/gscripttable.h | 5 +- glib/gsequence.c | 72 +- glib/gshell.c | 14 - glib/gslice.c | 59 - glib/gslist.c | 65 +- glib/gspawn.c | 231 +- glib/gstdio.h | 2 +- glib/gstrfuncs.c | 51 +- glib/gstring.c | 34 +- glib/gstringchunk.c | 39 +- glib/gstrvbuilder.c | 29 +- glib/gstrvbuilder.h | 12 +- glib/gtestutils.c | 258 +- glib/gtestutils.h | 5 + glib/gthread-win32.c | 44 +- glib/gthread.c | 186 +- glib/gthread.h | 25 + glib/gthreadpool.c | 66 +- glib/gtimer.c | 23 +- glib/gtimezone.c | 43 +- glib/gtrace.c | 4 - glib/gtrashstack.c | 32 +- glib/gtree.c | 44 +- glib/gunibreak.h | 1000 ++-- glib/gunichartables.h | 560 ++- glib/gunicode.h | 14 +- glib/gunicomp.h | 46 +- glib/gunidecomp.c | 37 - glib/gunidecomp.h | 132 +- glib/guri.c | 207 +- glib/gutils.c | 136 +- glib/gutilsprivate.h | 2 + glib/guuid.c | 22 - glib/gvariant-core.c | 8 - glib/gvariant.c | 179 +- glib/gvarianttype.c | 170 +- glib/gvarianttype.h | 11 +- glib/gversion.c | 22 - glib/gwakeup.c | 18 +- glib/gwin32.h | 8 +- glib/meson.build | 7 +- glib/tests/atomic.c | 106 +- glib/tests/casefold.txt | 2 +- glib/tests/casemap.txt | 2 +- glib/tests/constructor-helper.c | 239 + glib/tests/constructor.c | 260 ++ glib/tests/convert.c | 41 +- glib/tests/cxx.cpp | 2 +- glib/tests/dir.c | 24 + glib/tests/fileutils.c | 177 +- glib/tests/gdatetime.c | 345 +- glib/tests/io-channel-basic.c | 4 +- glib/tests/keyfile.c | 9 +- glib/tests/logging.c | 219 +- glib/tests/meson.build | 66 +- glib/tests/messages-low-memory.py | 1 + glib/tests/once.c | 4 +- glib/tests/onceinit.c | 8 +- glib/tests/private.c | 13 - glib/tests/regex.c | 10 + glib/tests/spawn-multithreaded.c | 7 +- glib/tests/string.c | 9 + glib/tests/strvbuilder.c | 20 + glib/tests/test-printf.c | 28 + glib/tests/testing.c | 20 + glib/tests/testutils.h | 50 + glib/tests/thread-pool-slow.c | 232 +- glib/tests/unicode.c | 5 + glib/tests/unix.c | 116 + glib/tests/uri.c | 2 + glib/tests/utils.c | 26 +- glib/tests/win32.c | 2 +- glib/valgrind.h | 15 +- gmodule/gmodule-dl.c | 4 +- gmodule/gmodule.c | 78 - gmodule/meson.build | 3 +- gobject/gbinding.c | 67 +- gobject/gbinding.h | 8 - gobject/gbindinggroup.c | 15 +- gobject/gbindinggroup.h | 8 - gobject/gboxed.c | 43 +- gobject/gclosure.c | 331 +- gobject/gclosure.h | 10 +- gobject/genums.c | 37 - gobject/glib-enumtypes.c.template | 6 +- gobject/glib-mkenums.in | 6 + gobject/glib-types.h | 33 + gobject/gobject-autocleanups.h | 4 + gobject/gobject.c | 352 +- gobject/gobject.h | 17 +- gobject/gparam.c | 61 +- gobject/gparam.h | 15 +- gobject/gparamspecs.c | 35 +- gobject/gsignal.c | 119 +- gobject/gsignal.h | 2 +- gobject/gsignalgroup.c | 29 +- gobject/gsignalgroup.h | 8 - gobject/gsourceclosure.c | 4 +- gobject/gtype.c | 141 +- gobject/gtype.h | 73 +- gobject/gtypemodule.c | 35 +- gobject/gtypemodule.h | 7 - gobject/gtypeplugin.c | 51 +- gobject/gtypeplugin.h | 6 - gobject/gvalue.c | 116 - gobject/gvaluearray.c | 44 +- gobject/gvaluearray.h | 7 - gobject/gvaluecollector.h | 12 +- gobject/gvaluetypes.c | 39 +- gobject/gvaluetypes.h | 2 + gobject/tests/genmarshal.py | 1 + gobject/tests/gobject-query.py | 1 + gobject/tests/meson.build | 1 + gobject/tests/mkenums.py | 27 + gobject/tests/param.c | 18 + gobject/tests/performance/meson.build | 6 +- gobject/tests/properties-introspection.c | 114 + gobject/tests/signals.c | 51 +- gobject/tests/type-flags.c | 2 +- gobject/tests/value.c | 23 +- introspection/meson.build | 159 + meson.build | 106 +- meson_options.txt | 26 +- po/en_GB.po | 677 ++- po/ka.po | 675 +-- po/pt_BR.po | 648 ++- po/ro.po | 53 +- po/ru.po | 1513 +++--- po/tr.po | 868 ++-- subprojects/gi-docgen.wrap | 5 + tools/glib.supp | 60 +- 832 files changed, 72890 insertions(+), 46380 deletions(-) create mode 100644 .gitlab-ci/alpine.Dockerfile create mode 100644 LICENSES/LGPL-2.1-only.txt create mode 100644 LICENSES/MPL-1.1.txt delete mode 100644 docs/reference/gio/concat-files-helper.py create mode 100644 docs/reference/gio/dbus-error.md create mode 100644 docs/reference/gio/dbus-introspection.md create mode 100644 docs/reference/gio/dbus-name-owning.md create mode 100644 docs/reference/gio/dbus-name-watching.md create mode 100644 docs/reference/gio/dbus-utils.md create mode 100644 docs/reference/gio/error.md create mode 100644 docs/reference/gio/file-attributes.md create mode 100644 docs/reference/gio/gapplication.rst delete mode 100644 docs/reference/gio/gapplication.xml create mode 100644 docs/reference/gio/gdbus-codegen.rst delete mode 100644 docs/reference/gio/gdbus-codegen.xml delete mode 100644 docs/reference/gio/gdbus-object-manager-example/.gitignore delete mode 100644 docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-docs.xml delete mode 100644 docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-sections.txt delete mode 100644 docs/reference/gio/gdbus-object-manager-example/meson.build create mode 100644 docs/reference/gio/gdbus.rst delete mode 100644 docs/reference/gio/gdbus.xml delete mode 100644 docs/reference/gio/gio-docs-unix.xml delete mode 100644 docs/reference/gio/gio-docs-win32.xml delete mode 100644 docs/reference/gio/gio-docs.xml create mode 100644 docs/reference/gio/gio-querymodules.rst delete mode 100644 docs/reference/gio/gio-querymodules.xml delete mode 100644 docs/reference/gio/gio-sections-common.txt delete mode 100644 docs/reference/gio/gio-sections-win32.txt create mode 100644 docs/reference/gio/gio.rst create mode 100644 docs/reference/gio/gio.toml.in delete mode 100644 docs/reference/gio/gio.xml create mode 100644 docs/reference/gio/glib-compile-resources.rst delete mode 100644 docs/reference/gio/glib-compile-resources.xml create mode 100644 docs/reference/gio/glib-compile-schemas.rst delete mode 100644 docs/reference/gio/glib-compile-schemas.xml create mode 100644 docs/reference/gio/gresource.rst delete mode 100644 docs/reference/gio/gresource.xml create mode 100644 docs/reference/gio/gsettings.rst delete mode 100644 docs/reference/gio/gsettings.xml create mode 100644 docs/reference/gio/io-scheduler.md create mode 100644 docs/reference/gio/menu-exporter.md create mode 100644 docs/reference/gio/migrating-gconf.md delete mode 100644 docs/reference/gio/migrating-gconf.xml create mode 100644 docs/reference/gio/migrating-gdbus.md delete mode 100644 docs/reference/gio/migrating-gdbus.xml create mode 100644 docs/reference/gio/migrating-gnome-vfs.md delete mode 100644 docs/reference/gio/migrating-gnome-vfs.xml create mode 100644 docs/reference/gio/migrating-posix.md delete mode 100644 docs/reference/gio/migrating-posix.xml create mode 100644 docs/reference/gio/networking.md create mode 100644 docs/reference/gio/overview.md delete mode 100644 docs/reference/gio/overview.xml create mode 100644 docs/reference/gio/pollable-utils.md create mode 100644 docs/reference/gio/tls-overview.md create mode 100644 docs/reference/gio/unix-mounts.md create mode 100644 docs/reference/gio/urlmap.js delete mode 100644 docs/reference/gio/version.xml.in delete mode 100644 docs/reference/gio/xml/gtkdocentities.ent.in delete mode 100644 docs/reference/gio/xml/meson.build create mode 100644 docs/reference/girepository/girepository.toml.in create mode 100644 docs/reference/girepository/meson.build create mode 100644 docs/reference/girepository/urlmap.js create mode 100644 docs/reference/glib/atomic.md create mode 100644 docs/reference/glib/auto-cleanup.md create mode 100644 docs/reference/glib/base64.md create mode 100644 docs/reference/glib/building.md delete mode 100644 docs/reference/glib/building.xml delete mode 100644 docs/reference/glib/changes.xml create mode 100644 docs/reference/glib/character-set.md create mode 100644 docs/reference/glib/checked-math.md create mode 100644 docs/reference/glib/compiling.md delete mode 100644 docs/reference/glib/compiling.xml create mode 100644 docs/reference/glib/conversion-macros.md create mode 100644 docs/reference/glib/cross-compiling.md delete mode 100644 docs/reference/glib/cross.xml create mode 100644 docs/reference/glib/data-structures.md create mode 100644 docs/reference/glib/datalist-and-dataset.md create mode 100644 docs/reference/glib/error-reporting.md create mode 100644 docs/reference/glib/file-utils.md delete mode 100644 docs/reference/glib/glib-docs.xml create mode 100644 docs/reference/glib/glib-gettextize.rst delete mode 100644 docs/reference/glib/glib-gettextize.xml delete mode 100644 docs/reference/glib/glib-overrides.txt delete mode 100644 docs/reference/glib/glib-sections.txt.in create mode 100644 docs/reference/glib/glib.toml.in create mode 100644 docs/reference/glib/goption.md create mode 100644 docs/reference/glib/gtester-report.rst delete mode 100644 docs/reference/glib/gtester-report.xml create mode 100644 docs/reference/glib/gtester.rst delete mode 100644 docs/reference/glib/gtester.xml create mode 100644 docs/reference/glib/gvariant-format-strings.md create mode 100644 docs/reference/glib/gvariant-text-format.md delete mode 100644 docs/reference/glib/gvariant-text.xml delete mode 100644 docs/reference/glib/gvariant-varargs.xml create mode 100644 docs/reference/glib/host-utils.md create mode 100644 docs/reference/glib/i18n.md create mode 100644 docs/reference/glib/logging.md create mode 100644 docs/reference/glib/macros.md create mode 100644 docs/reference/glib/main-loop.md create mode 100644 docs/reference/glib/markup.md create mode 100644 docs/reference/glib/memory-slices.md create mode 100644 docs/reference/glib/memory.md create mode 100644 docs/reference/glib/misc-utils.md create mode 100644 docs/reference/glib/numerical.md create mode 100644 docs/reference/glib/programming.md delete mode 100644 docs/reference/glib/programming.xml create mode 100644 docs/reference/glib/random.md create mode 100644 docs/reference/glib/reference-counting.md delete mode 100644 docs/reference/glib/regex-syntax.xml create mode 100644 docs/reference/glib/resources.md delete mode 100644 docs/reference/glib/resources.xml create mode 100644 docs/reference/glib/running.md delete mode 100644 docs/reference/glib/running.xml create mode 100644 docs/reference/glib/shell.md create mode 100644 docs/reference/glib/spawn.md create mode 100644 docs/reference/glib/string-utils.md create mode 100644 docs/reference/glib/testing.md create mode 100644 docs/reference/glib/threads-deprecated.md create mode 100644 docs/reference/glib/threads.md create mode 100644 docs/reference/glib/types.md create mode 100644 docs/reference/glib/unicode.md create mode 100644 docs/reference/glib/unix.md create mode 100644 docs/reference/glib/urlmap.js create mode 100644 docs/reference/glib/uuid.md create mode 100644 docs/reference/glib/version.md delete mode 100644 docs/reference/glib/version.xml.in create mode 100644 docs/reference/glib/warnings.md create mode 100644 docs/reference/glib/windows.md delete mode 100644 docs/reference/glib/xml/gtkdocentities.ent.in delete mode 100644 docs/reference/glib/xml/meson.build create mode 100644 docs/reference/gmodule/gmodule.toml.in create mode 100644 docs/reference/gmodule/meson.build create mode 100644 docs/reference/gmodule/modules.md create mode 100644 docs/reference/gmodule/urlmap.js create mode 100644 docs/reference/gobject/boxed.md create mode 100644 docs/reference/gobject/concepts.md create mode 100644 docs/reference/gobject/enum-types.md create mode 100644 docs/reference/gobject/floating-refs.md create mode 100644 docs/reference/gobject/glib-genmarshal.rst delete mode 100644 docs/reference/gobject/glib-genmarshal.xml create mode 100644 docs/reference/gobject/glib-mkenums.rst delete mode 100644 docs/reference/gobject/glib-mkenums.xml delete mode 100644 docs/reference/gobject/gobject-docs.xml delete mode 100644 docs/reference/gobject/gobject-overrides.txt create mode 100644 docs/reference/gobject/gobject-query.rst delete mode 100644 docs/reference/gobject/gobject-query.xml delete mode 100644 docs/reference/gobject/gobject-sections.txt create mode 100644 docs/reference/gobject/gobject.toml.in create mode 100644 docs/reference/gobject/gvalue.md create mode 100644 docs/reference/gobject/signals.md delete mode 100644 docs/reference/gobject/tut_gobject.xml delete mode 100644 docs/reference/gobject/tut_gsignal.xml delete mode 100644 docs/reference/gobject/tut_gtype.xml delete mode 100644 docs/reference/gobject/tut_howto.xml delete mode 100644 docs/reference/gobject/tut_intro.xml delete mode 100644 docs/reference/gobject/tut_tools.xml create mode 100644 docs/reference/gobject/tutorial.md create mode 100644 docs/reference/gobject/types.md create mode 100644 docs/reference/gobject/urlmap.js create mode 100644 docs/reference/gobject/value-collection.md delete mode 100644 docs/reference/gobject/version.xml.in delete mode 100644 docs/reference/gobject/xml/gtkdocentities.ent.in delete mode 100644 docs/reference/gobject/xml/meson.build delete mode 100644 gio/tests/gdbus-subscribe.c create mode 100644 gio/tests/gio-tool.py create mode 100644 girepository/cmph-bdz-test.c create mode 100644 girepository/cmph/README-CMPH-IMPORT.txt create mode 100644 girepository/cmph/bdz.c create mode 100644 girepository/cmph/bdz.h create mode 100644 girepository/cmph/bdz_gen_lookup_table.c create mode 100644 girepository/cmph/bdz_ph.c create mode 100644 girepository/cmph/bdz_ph.h create mode 100644 girepository/cmph/bdz_structs.h create mode 100644 girepository/cmph/bdz_structs_ph.h create mode 100644 girepository/cmph/bitbool.h create mode 100644 girepository/cmph/bmz.c create mode 100644 girepository/cmph/bmz.h create mode 100644 girepository/cmph/bmz8.c create mode 100644 girepository/cmph/bmz8.h create mode 100644 girepository/cmph/bmz8_structs.h create mode 100644 girepository/cmph/bmz_structs.h create mode 100644 girepository/cmph/brz.c create mode 100644 girepository/cmph/brz.h create mode 100644 girepository/cmph/brz_structs.h create mode 100644 girepository/cmph/buffer_entry.c create mode 100644 girepository/cmph/buffer_entry.h create mode 100644 girepository/cmph/buffer_manage.c create mode 100644 girepository/cmph/buffer_manage.h create mode 100644 girepository/cmph/buffer_manager.c create mode 100644 girepository/cmph/buffer_manager.h create mode 100644 girepository/cmph/chd.c create mode 100644 girepository/cmph/chd.h create mode 100644 girepository/cmph/chd_ph.c create mode 100644 girepository/cmph/chd_ph.h create mode 100644 girepository/cmph/chd_structs.h create mode 100644 girepository/cmph/chd_structs_ph.h create mode 100644 girepository/cmph/chm.c create mode 100644 girepository/cmph/chm.h create mode 100644 girepository/cmph/chm_structs.h create mode 100644 girepository/cmph/cmph.c create mode 100644 girepository/cmph/cmph.h create mode 100644 girepository/cmph/cmph_structs.c create mode 100644 girepository/cmph/cmph_structs.h create mode 100644 girepository/cmph/cmph_time.h create mode 100644 girepository/cmph/cmph_types.h create mode 100644 girepository/cmph/compressed_rank.c create mode 100644 girepository/cmph/compressed_rank.h create mode 100644 girepository/cmph/compressed_seq.c create mode 100644 girepository/cmph/compressed_seq.h create mode 100644 girepository/cmph/debug.h create mode 100644 girepository/cmph/djb2_hash.c create mode 100644 girepository/cmph/djb2_hash.h create mode 100644 girepository/cmph/fch.c create mode 100644 girepository/cmph/fch.h create mode 100644 girepository/cmph/fch_buckets.c create mode 100644 girepository/cmph/fch_buckets.h create mode 100644 girepository/cmph/fch_structs.h create mode 100644 girepository/cmph/fnv_hash.c create mode 100644 girepository/cmph/fnv_hash.h create mode 100644 girepository/cmph/graph.c create mode 100644 girepository/cmph/graph.h create mode 100644 girepository/cmph/hash.c create mode 100644 girepository/cmph/hash.h create mode 100644 girepository/cmph/hash_state.h create mode 100644 girepository/cmph/hashtree.c create mode 100644 girepository/cmph/hashtree.h create mode 100644 girepository/cmph/hashtree_structs.h create mode 100644 girepository/cmph/jenkins_hash.c create mode 100644 girepository/cmph/jenkins_hash.h create mode 100644 girepository/cmph/main.c create mode 100644 girepository/cmph/meson.build create mode 100644 girepository/cmph/miller_rabin.c create mode 100644 girepository/cmph/miller_rabin.h create mode 100644 girepository/cmph/sdbm_hash.c create mode 100644 girepository/cmph/sdbm_hash.h create mode 100644 girepository/cmph/select.c create mode 100644 girepository/cmph/select.h create mode 100644 girepository/cmph/select_lookup_tables.h create mode 100644 girepository/cmph/vqueue.c create mode 100644 girepository/cmph/vqueue.h create mode 100644 girepository/cmph/vstack.c create mode 100644 girepository/cmph/vstack.h create mode 100644 girepository/cmph/wingetopt.c create mode 100644 girepository/cmph/wingetopt.h create mode 100644 girepository/gdump.c create mode 100644 girepository/gi-dump-types.c create mode 100644 girepository/giarginfo.c create mode 100644 girepository/giarginfo.h create mode 100644 girepository/gibaseinfo-private.h create mode 100644 girepository/gibaseinfo.c create mode 100644 girepository/gibaseinfo.h create mode 100644 girepository/gicallableinfo.c create mode 100644 girepository/gicallableinfo.h create mode 100644 girepository/gicallbackinfo.c create mode 100644 girepository/gicallbackinfo.h create mode 100644 girepository/giconstantinfo.c create mode 100644 girepository/giconstantinfo.h create mode 100644 girepository/gienuminfo.c create mode 100644 girepository/gienuminfo.h create mode 100644 girepository/gifieldinfo.c create mode 100644 girepository/gifieldinfo.h create mode 100644 girepository/gifunctioninfo.c create mode 100644 girepository/gifunctioninfo.h create mode 100644 girepository/giinterfaceinfo.c create mode 100644 girepository/giinterfaceinfo.h create mode 100644 girepository/ginvoke.c create mode 100644 girepository/giobjectinfo.c create mode 100644 girepository/giobjectinfo.h create mode 100644 girepository/gipropertyinfo.c create mode 100644 girepository/gipropertyinfo.h create mode 100644 girepository/giregisteredtypeinfo.c create mode 100644 girepository/giregisteredtypeinfo.h create mode 100644 girepository/girepository-private.h create mode 100644 girepository/girepository.c create mode 100644 girepository/girepository.h create mode 100644 girepository/girffi.c create mode 100644 girepository/girffi.h create mode 100644 girepository/girmodule-private.h create mode 100644 girepository/girmodule.c create mode 100644 girepository/girnode-private.h create mode 100644 girepository/girnode.c create mode 100644 girepository/giroffsets.c create mode 100644 girepository/girparser-private.h create mode 100644 girepository/girparser.c create mode 100644 girepository/girwriter-private.h create mode 100644 girepository/girwriter.c create mode 100644 girepository/gisignalinfo.c create mode 100644 girepository/gisignalinfo.h create mode 100644 girepository/gistructinfo.c create mode 100644 girepository/gistructinfo.h create mode 100644 girepository/gitypeinfo.c create mode 100644 girepository/gitypeinfo.h create mode 100644 girepository/gitypelib-internal.h create mode 100644 girepository/gitypelib.c create mode 100644 girepository/gitypelib.h create mode 100644 girepository/gitypes.h create mode 100644 girepository/giunioninfo.c create mode 100644 girepository/giunioninfo.h create mode 100644 girepository/giunresolvedinfo.c create mode 100644 girepository/giunresolvedinfo.h create mode 100644 girepository/givfuncinfo.c create mode 100644 girepository/givfuncinfo.h create mode 100644 girepository/gthash-test.c create mode 100644 girepository/gthash.c create mode 100644 girepository/meson.build create mode 100644 girepository/tests/meson.build create mode 100644 girepository/tests/repository-search-paths.c create mode 100644 girepository/tests/repository.c create mode 100644 glib/gconstructorprivate.h create mode 100644 glib/gdatetime-private.c create mode 100644 glib/gdatetime-private.h create mode 100644 glib/tests/constructor-helper.c create mode 100644 glib/tests/constructor.c create mode 100644 glib/tests/testutils.h create mode 100644 gobject/tests/properties-introspection.c create mode 100644 introspection/meson.build create mode 100644 subprojects/gi-docgen.wrap diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 77c6bc9..647e374 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -11,18 +11,19 @@ cache: - _ccache/ variables: - FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v20" + FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v26" COVERITY_IMAGE: "registry.gitlab.gnome.org/gnome/glib/coverity:v7" - DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v14" - MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v10" + DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v19" + ALPINE_IMAGE: "registry.gitlab.gnome.org/gnome/glib/alpine:v3" + MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v15" MESON_TEST_TIMEOUT_MULTIPLIER: 4 G_MESSAGES_DEBUG: all MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings" # Default CI job setup; contrast with `.only-origin`. # -# Don’t execute the pipeline when a merge request is merged into `main`, as it -# will have already been tested +# Don’t execute the pipeline when a merge request is merged into `origin/main`, +# as it will have already been tested .only-default: only: - branches @@ -30,7 +31,16 @@ variables: refs: - tags variables: - - $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH + - $CI_PIPELINE_SOURCE == "push" && $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH && $CI_PROJECT_NAMESPACE == "GNOME" + +# As above, but does get executed on merge into `origin/main`. For use with +# updating code coverage results and docs builds. +.only-default-and-merges: + only: + - branches + except: + refs: + - tags # Some jobs run on CI runners which don’t have good isolation between CI jobs, # and don’t have much available resource. Limit those jobs to only ones on the @@ -61,6 +71,7 @@ variables: extends: .only-default before_script: - rm -rf subprojects/gvdb + - git config --global --add safe.directory "${PWD}" - git submodule update --init --depth 1 variables: GIT_SUBMODULE_STRATEGY: "none" @@ -81,6 +92,7 @@ sh-and-py-check: stage: style-check allow_failure: false script: + - git config --global --add safe.directory "${PWD}" - .gitlab-ci/run-shellcheck.sh - .gitlab-ci/run-black.sh - .gitlab-ci/run-flake8.sh @@ -100,7 +112,7 @@ style-check-mandatory: fedora-x86_64: extends: - .build-linux - - .only-default + - .only-default-and-merges image: $FEDORA_IMAGE stage: build needs: [] @@ -116,13 +128,22 @@ fedora-x86_64: -Dsystemtap=true -Ddtrace=true -Dinstalled_tests=true - -Dgtk_doc=true + -Ddocumentation=true + -Dintrospection=enabled + -Dman-pages=enabled _build - meson compile -C _build - mkdir -p _coverage - lcov --config-file .lcovrc --directory _build --capture --initial --output-file "_coverage/${CI_JOB_NAME}-baseline.lcov" - .gitlab-ci/run-tests.sh - lcov --config-file .lcovrc --directory _build --capture --output-file "_coverage/${CI_JOB_NAME}.lcov" + # Copy the built documentation to an artifact directory. The build for docs.gtk.org + # can then pull it from there — see https://gitlab.gnome.org/GNOME/gtk/-/blob/docs-gtk-org/README.md + - mkdir -p _reference/ + - mv _build/docs/reference/glib/glib/ _reference/glib/ + - mv _build/docs/reference/gmodule/gmodule/ _reference/gmodule/ + - mv _build/docs/reference/gobject/gobject/ _reference/gobject/ + - mv _build/docs/reference/gio/gio/ _reference/gio/ artifacts: reports: junit: @@ -135,16 +156,8 @@ fedora-x86_64: - "_build/config.h" - "_build/glib/glibconfig.h" - "_build/meson-logs" - - "_build/docs/reference/glib/glib-undeclared.txt" - - "_build/docs/reference/glib/glib-undocumented.txt" - - "_build/docs/reference/glib/glib-unused.txt" - - "_build/docs/reference/gobject/gobject-undeclared.txt" - - "_build/docs/reference/gobject/gobject-undocumented.txt" - - "_build/docs/reference/gobject/gobject-unused.txt" - - "_build/docs/reference/gio/gio-undeclared.txt" - - "_build/docs/reference/gio/gio-undocumented.txt" - - "_build/docs/reference/gio/gio-unused.txt" - "_coverage" + - "_reference" debian-stable-x86_64: extends: @@ -178,6 +191,67 @@ debian-stable-x86_64: - "_build/glib/glibconfig.h" - "_build/meson-logs" +hurd-i386: + extends: + - .only-schedules + stage: build + tags: + - hurd + needs: [] + script: + - meson setup ${MESON_COMMON_OPTIONS} + --werror + --default-library=both + --prefix=$HOME/glib-installed + --localstatedir=/var + --libdir=lib + _build + - meson compile -C _build + - .gitlab-ci/run-tests.sh + artifacts: + reports: + junit: + - _build/meson-logs/testlog.junit.xml + - _build/meson-logs/testlog-*.junit.xml + name: "glib-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + expire_in: 1 week + paths: + - "_build/config.h" + - "_build/glib/glibconfig.h" + - "_build/meson-logs" + +muslc-alpine-x86_64: + extends: + - .build-linux + - .only-schedules + image: $ALPINE_IMAGE + stage: build + needs: [] + script: + - meson setup ${MESON_COMMON_OPTIONS} + --werror + --default-library=both + --prefix=$HOME/glib-installed + --localstatedir=/var + --libdir=lib + -Dsystemtap=true + _build + - meson compile -C _build + - .gitlab-ci/run-tests.sh + artifacts: + reports: + junit: + - _build/meson-logs/testlog.junit.xml + - _build/meson-logs/testlog-*.junit.xml + name: "glib-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + expire_in: 1 week + paths: + - "_build/config.h" + - "_build/glib/glibconfig.h" + - "_build/meson-logs" + installed-tests: extends: - .build-linux @@ -230,6 +304,7 @@ G_DISABLE_ASSERT: -Ddtrace=true -Dinstalled_tests=true -Dglib_assert=false + -Dintrospection=enabled _build - meson compile -C _build - bash -x ./.gitlab-ci/run-tests.sh @@ -261,6 +336,7 @@ valgrind: -Dsystemtap=true -Ddtrace=true -Dinstalled_tests=true + -Dintrospection=enabled _build - meson compile -C _build # Valgrind doesn’t work when the soft FD limit is set too high @@ -329,7 +405,6 @@ cross-mingw64: - _build/gobject/libgobject-2.0-0.dll msys2-mingw32: - allow_failure: true extends: .only-default stage: build tags: @@ -340,10 +415,6 @@ msys2-mingw32: CHERE_INVOKING: "yes" CFLAGS: -coverage -ftest-coverage -fprofile-arcs PYTHONUTF8: "1" - # FIXME: For some reason enabling jit debugging "fixes" random python crashes - # see https://github.com/msys2/MINGW-packages/issues/11864 and - # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3280#note_1678973 - MSYS: "winjitdebug" script: - C:\msys64\usr\bin\pacman --noconfirm -Syyuu --ask 20 - C:\msys64\usr\bin\bash .gitlab-ci/show-execution-environment.sh @@ -361,7 +432,6 @@ msys2-mingw32: - _coverage/ msys2-clang64: - allow_failure: true extends: .only-schedules stage: build tags: @@ -371,10 +441,6 @@ msys2-clang64: MSYSTEM: "CLANG64" CHERE_INVOKING: "yes" PYTHONUTF8: "1" - # FIXME: For some reason enabling jit debugging "fixes" random python crashes - # see https://github.com/msys2/MINGW-packages/issues/11864 and - # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3280#note_1678973 - MSYS: "winjitdebug" script: - C:\msys64\usr\bin\pacman --noconfirm -Syyuu --ask 20 - C:\msys64\usr\bin\bash .gitlab-ci/show-execution-environment.sh @@ -446,8 +512,57 @@ vs2017-x64-static: paths: - _build/meson-logs +freebsd-12-x86_64: + # The FreeBSD 13 build is run on each commit, so the FreeBSD 12 build can be + # run less regularly to save CI resources. The chance of a regression on + # FreeBSD 12 and not FreeBSD 13 is tiny. + extends: .only-schedules + stage: build + tags: + # To run a FreeBSD builder, install gitlab-runner package and start both + # gitlab-runner and dbus service because we need /var/lib/dbus/machine-id. + # To compile GLib, you still have to install the following packages: + # desktop-file-utils gettext libiconv meson pkgconf python3 shared-mime-info + - freebsd-12 + needs: [] + variables: + # CPPFLAGS is required because libintl doesn't use pkg-config. + CPPFLAGS: -I/usr/local/include + # FIXME: Workaround meson inability to set LD_LIBRARY_PATH. + # https://github.com/mesonbuild/meson/issues/1383 + # https://github.com/mesonbuild/meson/issues/1635 + # https://github.com/mesonbuild/meson/issues/2881 + LDFLAGS: -L/usr/local/lib -Wl,--disable-new-dtags + # FreeBSD supports C.UTF-8 locale since 12.1. + LANG: C.UTF-8 + before_script: + - bash .gitlab-ci/show-execution-environment.sh + script: + # We cannot use -Wl,--no-undefined because GLib uses 'environ' variable. + # FreeBSD supports xattr, but its API is different from Linux xattr. + # FIXME: extattr(2) support: https://gitlab.gnome.org/GNOME/glib/issues/1404 + # localstatedir is needed for access to /var/lib/dbus/machine-id + - meson setup ${MESON_COMMON_OPTIONS} --localstatedir=/var -Db_lundef=false -Dxattr=false _build + - meson compile -C _build + - bash -x ./.gitlab-ci/run-tests.sh + artifacts: + reports: + junit: + - _build/meson-logs/testlog.junit.xml + - _build/meson-logs/testlog-*.junit.xml + name: "glib-${CI_JOB_NAME}-${CI_COMMIT_REF_NAME}" + when: always + expire_in: 1 week + paths: + - "_build/config.h" + - "_build/glib/glibconfig.h" + - "_build/meson-logs" + freebsd-13-x86_64: - extends: .only-origin + # FIXME: Temporarily only run the FreeBSD 13 CI on a schedule, rather than on + # every commit to origin, because it’s broken: + # https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3740#note_1935427 + extends: .only-schedules stage: build tags: - freebsd-13 @@ -459,14 +574,7 @@ freebsd-13-x86_64: before_script: - bash .gitlab-ci/show-execution-environment.sh script: - # FIXME: We can’t use ${MESON_COMMON_OPTIONS} here because the FreeBSD 13 - # runner has Meson 1.3 installed. This has an API hole where previous - # methods of getting paths from files() objects are rejected as deprecated, - # but no replacements are available. Hence, we can’t build with - # --fatal-meson-warnings. This should be fixed in Meson 1.4. It’s also fine - # with Meson 1.2.3 (which is what we use on all the other CI runners). - # See https://github.com/GNOME/glib/commit/71061fdcb33b8c26f5f8467cb3ac10704d65c87d - - meson setup --buildtype debug --wrap-mode=nodownload --localstatedir=/var -Db_lundef=false -Dxattr=false _build + - meson setup ${MESON_COMMON_OPTIONS} --localstatedir=/var -Db_lundef=false -Dxattr=false _build - meson compile -C _build - bash -x ./.gitlab-ci/run-tests.sh artifacts: @@ -512,8 +620,9 @@ macos-x86_64: - ln -s /opt/cmake/CMake.app/Contents/bin/cmake .venv/bin - ln -s /opt/ccache/ccache .venv/bin - source .venv/bin/activate - - pip3 install meson==1.2.0 + - pip3 install meson==1.2.3 - pip3 install ninja==1.11.1 + - pip3 install packaging==23.2 script: # FIXME: Use --wrap-mode=default so we download dependencies each time, # until the macOS runner is a VM where we can use a pre-made image which @@ -578,6 +687,7 @@ scan-build: -Dsystemtap=true -Ddtrace=true -Dinstalled_tests=true + -Dintrospection=enabled _scan_build - ninja -C _scan_build scan-build artifacts: @@ -607,6 +717,7 @@ scan-build: -Dsystemtap=true -Ddtrace=true -Dinstalled_tests=true + -Dintrospection=enabled _coverity_build - $HOME/cov-analysis-linux64-*/bin/cov-build --dir cov-int meson compile -C _coverity_build - tar cfz cov-int.tar.gz cov-int @@ -642,15 +753,16 @@ dist-job: - git submodule update --init - for m in $(git submodule foreach -q 'echo $path'); do git config --global --add safe.directory "${PWD}/${m}"; done - meson subprojects download - - meson setup ${MESON_COMMON_OPTIONS} --buildtype release -Dgtk_doc=true -Dman=true _build + - meson setup ${MESON_COMMON_OPTIONS} --buildtype release -Ddocumentation=true -Dman-pages=enabled _build - meson dist -C _build - - ninja -C _build glib-doc gobject-doc gio-doc - - tar -c -J -f "glib-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/glib html - - tar -c -J -f "gobject-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/gobject html - - tar -c -J -f "gio-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/gio html + - tar -c -J -f "glib-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/glib glib + - tar -c -J -f "gmodule-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/gmodule gmodule + - tar -c -J -f "gobject-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/gobject gobject + - tar -c -J -f "gio-docs-$CI_COMMIT_TAG.tar.xz" -C docs/reference/gio gio artifacts: paths: - "${CI_PROJECT_DIR}/_build/glib-docs-$CI_COMMIT_TAG.tar.xz" + - "${CI_PROJECT_DIR}/_build/gmodule-docs-$CI_COMMIT_TAG.tar.xz" - "${CI_PROJECT_DIR}/_build/gobject-docs-$CI_COMMIT_TAG.tar.xz" - "${CI_PROJECT_DIR}/_build/gio-docs-$CI_COMMIT_TAG.tar.xz" - "${CI_PROJECT_DIR}/_build/meson-dist/glib-*.tar.xz" diff --git a/.gitlab-ci/alpine.Dockerfile b/.gitlab-ci/alpine.Dockerfile new file mode 100644 index 0000000..8043a10 --- /dev/null +++ b/.gitlab-ci/alpine.Dockerfile @@ -0,0 +1,38 @@ +FROM alpine:3.19 + +RUN apk add --no-cache \ + bash \ + build-base \ + bzip2-dev \ + dbus \ + desktop-file-utils \ + docbook-xml \ + docbook-xsl \ + gettext-dev \ + git \ + libffi-dev \ + libxml2-utils \ + libxslt \ + meson \ + musl-locales \ + py3-pip \ + python3 \ + pcre2-dev \ + shared-mime-info \ + tzdata \ + util-linux-dev \ + zlib-dev + +ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8 MUSL_LOCPATH=/usr/share/i18n/locales/musl + +RUN pip3 install --break-system-packages meson==1.2.3 + +ARG HOST_USER_ID=5555 +ENV HOST_USER_ID ${HOST_USER_ID} +RUN adduser -D -u $HOST_USER_ID -s /bin/bash user + +USER user +WORKDIR /home/user + +COPY cache-subprojects.sh . +RUN ./cache-subprojects.sh diff --git a/.gitlab-ci/check-missing-install-tag.py b/.gitlab-ci/check-missing-install-tag.py index d9e53e1..ab23804 100755 --- a/.gitlab-ci/check-missing-install-tag.py +++ b/.gitlab-ci/check-missing-install-tag.py @@ -1,4 +1,10 @@ #!/usr/bin/env python3 +# +# Copyright © 2022 Collabora, Ltd. +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# Original author: Xavier Claessens """ This script checks Meson configuration logs to verify no installed file is diff --git a/.gitlab-ci/debian-stable.Dockerfile b/.gitlab-ci/debian-stable.Dockerfile index b2559ca..4bcee4e 100644 --- a/.gitlab-ci/debian-stable.Dockerfile +++ b/.gitlab-ci/debian-stable.Dockerfile @@ -1,4 +1,4 @@ -FROM debian:bullseye +FROM debian:bookworm RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \ bindfs \ @@ -16,8 +16,10 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \ gdb \ g++ \ gettext \ + gi-docgen \ git \ libc6-dev \ + gobject-introspection \ gtk-doc-tools \ itstool \ lcov \ @@ -25,6 +27,7 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \ libdbus-1-dev \ libelf-dev \ libffi-dev \ + libgirepository1.0-dev \ libmount-dev \ libpcre2-dev \ libselinux1-dev \ @@ -34,9 +37,11 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \ locales \ ninja-build \ python3 \ + python3-packaging \ python3-pip \ python3-setuptools \ python3-wheel \ + reuse \ shared-mime-info \ shellcheck \ systemtap-sdt-dev \ @@ -62,14 +67,12 @@ RUN locale-gen de_DE.UTF-8 \ && locale-gen lt_LT.UTF-8 \ && locale-gen pl_PL.UTF-8 \ && locale-gen ru_RU.UTF-8 \ + && locale-gen th_TH.UTF-8 \ && locale-gen tr_TR.UTF-8 ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8 -RUN pip3 install meson==0.60.3 - -# FIXME: Once we use Debian Bookworm, we can just install the `reuse` package -RUN pip3 install reuse==1.0.0 +RUN pip3 install --break-system-packages meson==1.2.3 ARG HOST_USER_ID=5555 ENV HOST_USER_ID ${HOST_USER_ID} diff --git a/.gitlab-ci/fedora.Dockerfile b/.gitlab-ci/fedora.Dockerfile index 85f910c..3713cc3 100644 --- a/.gitlab-ci/fedora.Dockerfile +++ b/.gitlab-ci/fedora.Dockerfile @@ -1,4 +1,4 @@ -FROM fedora:34 +FROM fedora:37 RUN dnf -y update \ && dnf -y install \ @@ -15,24 +15,28 @@ RUN dnf -y update \ gcc-c++ \ gdb \ gettext \ + gi-docgen \ git \ glibc-devel \ + glibc-gconv-extra \ glibc-headers \ glibc-langpack-de \ glibc-langpack-el \ - glibc-langpack-el \ glibc-langpack-en \ glibc-langpack-es \ - glibc-langpack-es \ glibc-langpack-fa \ glibc-langpack-fr \ + glibc-langpack-gu \ glibc-langpack-hr \ glibc-langpack-ja \ glibc-langpack-lt \ glibc-langpack-pl \ glibc-langpack-ru \ + glibc-langpack-th \ glibc-langpack-tr \ "gnome-desktop-testing >= 2018.1" \ + gobject-introspection \ + gobject-introspection-devel \ gtk-doc \ itstool \ lcov \ @@ -45,6 +49,8 @@ RUN dnf -y update \ ninja-build \ pcre2-devel \ "python3-dbusmock >= 0.18.3-2" \ + python3-docutils \ + python3-packaging \ python3-pip \ python3-pygments \ python3-wheel \ @@ -74,7 +80,7 @@ RUN dnf -y update \ make \ && dnf clean all -RUN pip3 install meson==0.60.3 +RUN pip3 install meson==1.2.3 COPY install-gitlab-cobertura-tools.sh . RUN ./install-gitlab-cobertura-tools.sh diff --git a/.gitlab-ci/mingw.Dockerfile b/.gitlab-ci/mingw.Dockerfile index b109122..d688a35 100644 --- a/.gitlab-ci/mingw.Dockerfile +++ b/.gitlab-ci/mingw.Dockerfile @@ -1,72 +1,17 @@ -FROM fedora:34 +FROM registry.gitlab.gnome.org/gnome/glib/fedora:v25 + +USER root RUN dnf -y install \ - bindfs \ - clang \ - clang-analyzer \ - desktop-file-utils \ - elfutils-libelf-devel \ - findutils \ - fuse \ - gcc \ - gcc-c++ \ - gettext \ - git \ - glibc-devel \ - glibc-headers \ - glibc-langpack-de \ - glibc-langpack-el \ - glibc-langpack-el \ - glibc-langpack-en \ - glibc-langpack-es \ - glibc-langpack-es \ - glibc-langpack-fa \ - glibc-langpack-fr \ - glibc-langpack-hr \ - glibc-langpack-ja \ - glibc-langpack-lt \ - glibc-langpack-pl \ - glibc-langpack-ru \ - glibc-langpack-tr \ - gtk-doc \ - itstool \ - lcov \ - libattr-devel \ - libffi-devel \ - libmount-devel \ - libselinux-devel \ - libxslt \ mingw64-gcc \ mingw64-gcc-c++ \ mingw64-gettext \ mingw64-libffi \ mingw64-zlib \ - ncurses-compat-libs \ - ninja-build \ - pcre2-devel \ - python3 \ - python3-pip \ - python3-wheel \ - systemtap-sdt-devel \ - unzip \ - wget \ - xz \ - zlib-devel \ && dnf clean all WORKDIR /opt COPY cross_file_mingw64.txt /opt -RUN pip3 install meson==0.60.3 - -ARG HOST_USER_ID=5555 -ENV HOST_USER_ID ${HOST_USER_ID} -RUN useradd -u $HOST_USER_ID -ms /bin/bash user - USER user -WORKDIR /home/user - -COPY cache-subprojects.sh . -RUN ./cache-subprojects.sh - -ENV LANG C.UTF-8 +WORKDIR /home/user \ No newline at end of file diff --git a/.gitlab-ci/run-style-check-diff.sh b/.gitlab-ci/run-style-check-diff.sh index 651f384..2dcf096 100755 --- a/.gitlab-ci/run-style-check-diff.sh +++ b/.gitlab-ci/run-style-check-diff.sh @@ -2,17 +2,15 @@ set -e -ancestor_horizon=28 # days (4 weeks) - # Wrap everything in a subshell so we can propagate the exit status. +exit_status=0 ( source .gitlab-ci/search-common-ancestor.sh -git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format-11" -p1 +git diff -U0 --no-color "${newest_common_ancestor_sha}" | .gitlab-ci/clang-format-diff.py -binary "clang-format-14" -p1 -) -exit_status=$? +) || exit_status=$? # The style check is not infallible. The clang-format configuration cannot # perfectly describe GLib’s coding style: in particular, it cannot align diff --git a/.gitlab-ci/test-msvc.bat b/.gitlab-ci/test-msvc.bat index aee77d3..73f972a 100644 --- a/.gitlab-ci/test-msvc.bat +++ b/.gitlab-ci/test-msvc.bat @@ -12,7 +12,7 @@ for %%x in (%*) do ( set args=%args:~1% :: FIXME: make warnings fatal -pip3 install --upgrade --user meson==1.0.0 || goto :error +pip3 install --upgrade --user meson==1.2.3 packaging==23.2 || goto :error meson setup %args% _build || goto :error python .gitlab-ci/check-missing-install-tag.py _build || goto :error meson compile -C _build || goto :error diff --git a/.gitlab-ci/test-msys2.sh b/.gitlab-ci/test-msys2.sh index aaeff16..6ee6f12 100755 --- a/.gitlab-ci/test-msys2.sh +++ b/.gitlab-ci/test-msys2.sh @@ -26,20 +26,14 @@ CCACHE_BASEDIR="$(pwd)" CCACHE_DIR="${CCACHE_BASEDIR}/_ccache" export CCACHE_BASEDIR CCACHE_DIR -pip3 install --upgrade --user meson==1.0.0 +pip3 install --upgrade --user meson==1.2.3 packaging==23.2 PATH="$(cygpath "$USERPROFILE")/.local/bin:$HOME/.local/bin:$PATH" DIR="$(pwd)" export PATH CFLAGS -if [[ "$MSYSTEM" == "CLANG64" ]]; then - # FIXME: fix the clang build warnings - # shellcheck disable=SC2086 - meson setup ${MESON_COMMON_OPTIONS} _build -else - # shellcheck disable=SC2086 - meson setup ${MESON_COMMON_OPTIONS} --werror _build -fi +# shellcheck disable=SC2086 +meson setup ${MESON_COMMON_OPTIONS} --werror _build meson compile -C _build diff --git a/.reuse/dep5 b/.reuse/dep5 index 979f2ea..40fa0f8 100644 --- a/.reuse/dep5 +++ b/.reuse/dep5 @@ -41,3 +41,10 @@ License: CC0-1.0 Files: docs/reference/glib/gvariant-*.svg Copyright: 2022 Philip Withnall License: CC-BY-SA-3.0 + +# libgirepository uses cmph as a copylib. Adding copyright/license data to the +# files there would cause divergence from upstream. See +# girepository/cmph/README-CMPH-IMPORT.txt. +Files: girepository/cmph/* +Copyright: CMPH contributors +License: LGPL-2.1-only or MPL-1.1 \ No newline at end of file diff --git a/LICENSES/LGPL-2.1-only.txt b/LICENSES/LGPL-2.1-only.txt new file mode 100644 index 0000000..c9aa530 --- /dev/null +++ b/LICENSES/LGPL-2.1-only.txt @@ -0,0 +1,175 @@ +GNU LESSER GENERAL PUBLIC LICENSE + +Version 2.1, February 1999 + +Copyright (C) 1991, 1999 Free Software Foundation, Inc. +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] + +Preamble + +The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. + +This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. + +When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. + +To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. + +For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. + +We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. + +To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. + +Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. + +Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. + +When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. + +We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. + +For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. + +In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. + +Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. + +The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. + +TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + +0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". + +A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. + +The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) + +"Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. + +Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. + +1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. + +You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. + +2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. + +(For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. + +Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. + +3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. + +Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. + +This option is useful when you wish to copy part of the code of the Library into a program that is not a library. + +4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. + +If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. + +5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. + +However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. + +When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. + +If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) + +Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. + +6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. + +You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: + + a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. + + e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. + +For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. + +It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. + +7. 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 not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. + + b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. + +8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. + +9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. + +10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. + +11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. + +This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. + +12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. + +13. The Free Software Foundation may publish revised and/or new versions of the 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 specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. + +14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. + +NO WARRANTY + +15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + +16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +END OF TERMS AND CONDITIONS + +How to Apply These Terms to Your New Libraries + +If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). + +To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. + + one line to give the library's name and an idea of what it does. + Copyright (C) year name of author + + This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: + +Yoyodyne, Inc., hereby disclaims all copyright interest in +the library `Frob' (a library for tweaking knobs) written +by James Random Hacker. + +signature of Ty Coon, 1 April 1990 +Ty Coon, President of Vice +That's all there is to it! diff --git a/LICENSES/MPL-1.1.txt b/LICENSES/MPL-1.1.txt new file mode 100644 index 0000000..e1c8428 --- /dev/null +++ b/LICENSES/MPL-1.1.txt @@ -0,0 +1,143 @@ +Mozilla Public License Version 1.1 + +1. Definitions. + + 1.0.1. "Commercial Use" means distribution or otherwise making the Covered Code available to a third party. + + 1.1. "Contributor" means each entity that creates or contributes to the creation of Modifications. + + 1.2. "Contributor Version" means the combination of the Original Code, prior Modifications used by a Contributor, and the Modifications made by that particular Contributor. + + 1.3. "Covered Code" means the Original Code or Modifications or the combination of the Original Code and Modifications, in each case including portions thereof. + + 1.4. "Electronic Distribution Mechanism" means a mechanism generally accepted in the software development community for the electronic transfer of data. + + 1.5. "Executable" means Covered Code in any form other than Source Code. + + 1.6. "Initial Developer" means the individual or entity identified as the Initial Developer in the Source Code notice required by Exhibit A. + + 1.7. "Larger Work" means a work which combines Covered Code or portions thereof with code not governed by the terms of this License. + + 1.8. "License" means this document. + + 1.8.1. "Licensable" means having the right to grant, to the maximum extent possible, whether at the time of the initial grant or subsequently acquired, any and all of the rights conveyed herein. + + 1.9. "Modifications" means any addition to or deletion from the substance or structure of either the Original Code or any previous Modifications. When Covered Code is released as a series of files, a Modification is: +Any addition to or deletion from the contents of a file containing Original Code or previous Modifications. +Any new file that contains any part of the Original Code or previous Modifications. + + 1.10. "Original Code" means Source Code of computer software code which is described in the Source Code notice required by Exhibit A as Original Code, and which, at the time of its release under this License is not already Covered Code governed by this License. + + 1.10.1. "Patent Claims" means any patent claim(s), now owned or hereafter acquired, including without limitation, method, process, and apparatus claims, in any patent Licensable by grantor. + + 1.11. "Source Code" means the preferred form of the Covered Code for making modifications to it, including all modules it contains, plus any associated interface definition files, scripts used to control compilation and installation of an Executable, or source code differential comparisons against either the Original Code or another well known, available Covered Code of the Contributor's choice. The Source Code can be in a compressed or archival form, provided the appropriate decompression or de-archiving software is widely available for no charge. + + 1.12. "You" (or "Your") means an individual or a legal entity exercising rights under, and complying with all of the terms of, this License or a future version of this License issued under Section 6.1. For legal entities, "You" includes any entity which controls, is controlled by, or is under common control with You. For purposes of this definition, "control" means (a) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (b) ownership of more than fifty percent (50%) of the outstanding shares or beneficial ownership of such entity. + +2. Source Code License. + + 2.1. The Initial Developer Grant. The Initial Developer hereby grants You a world-wide, royalty-free, non-exclusive license, subject to third party intellectual property claims: + + a. under intellectual property rights (other than patent or trademark) Licensable by Initial Developer to use, reproduce, modify, display, perform, sublicense and distribute the Original Code (or portions thereof) with or without Modifications, and/or as part of a Larger Work; and + b. under Patents Claims infringed by the making, using or selling of Original Code, to make, have made, use, practice, sell, and offer for sale, and/or otherwise dispose of the Original Code (or portions thereof). + c. the licenses granted in this Section 2.1 (a) and (b) are effective on the date Initial Developer first distributes Original Code under the terms of this License. + d. Notwithstanding Section 2.1 (b) above, no patent license is granted: 1) for code that You delete from the Original Code; 2) separate from the Original Code; or 3) for infringements caused by: i) the modification of the Original Code or ii) the combination of the Original Code with other software or devices. + + 2.2. Contributor Grant. Subject to third party intellectual property claims, each Contributor hereby grants You a world-wide, royalty-free, non-exclusive license + + a. under intellectual property rights (other than patent or trademark) Licensable by Contributor, to use, reproduce, modify, display, perform, sublicense and distribute the Modifications created by such Contributor (or portions thereof) either on an unmodified basis, with other Modifications, as Covered Code and/or as part of a Larger Work; and + b. under Patent Claims infringed by the making, using, or selling of Modifications made by that Contributor either alone and/or in combination with its Contributor Version (or portions of such combination), to make, use, sell, offer for sale, have made, and/or otherwise dispose of: 1) Modifications made by that Contributor (or portions thereof); and 2) the combination of Modifications made by that Contributor with its Contributor Version (or portions of such combination). + c. the licenses granted in Sections 2.2 (a) and 2.2 (b) are effective on the date Contributor first makes Commercial Use of the Covered Code. + d. Notwithstanding Section 2.2 (b) above, no patent license is granted: 1) for any code that Contributor has deleted from the Contributor Version; 2) separate from the Contributor Version; 3) for infringements caused by: i) third party modifications of Contributor Version or ii) the combination of Modifications made by that Contributor with other software (except as part of the Contributor Version) or other devices; or 4) under Patent Claims infringed by Covered Code in the absence of Modifications made by that Contributor. + +3. Distribution Obligations. + + 3.1. Application of License. The Modifications which You create or to which You contribute are governed by the terms of this License, including without limitation Section 2.2. The Source Code version of Covered Code may be distributed only under the terms of this License or a future version of this License released under Section 6.1, and You must include a copy of this License with every copy of the Source Code You distribute. You may not offer or impose any terms on any Source Code version that alters or restricts the applicable version of this License or the recipients' rights hereunder. However, You may include an additional document offering the additional rights described in Section 3.5. + + 3.2. Availability of Source Code. Any Modification which You create or to which You contribute must be made available in Source Code form under the terms of this License either on the same media as an Executable version or via an accepted Electronic Distribution Mechanism to anyone to whom you made an Executable version available; and if made available via Electronic Distribution Mechanism, must remain available for at least twelve (12) months after the date it initially became available, or at least six (6) months after a subsequent version of that particular Modification has been made available to such recipients. You are responsible for ensuring that the Source Code version remains available even if the Electronic Distribution Mechanism is maintained by a third party. + + 3.3. Description of Modifications. You must cause all Covered Code to which You contribute to contain a file documenting the changes You made to create that Covered Code and the date of any change. You must include a prominent statement that the Modification is derived, directly or indirectly, from Original Code provided by the Initial Developer and including the name of the Initial Developer in (a) the Source Code, and (b) in any notice in an Executable version or related documentation in which You describe the origin or ownership of the Covered Code. + + 3.4. Intellectual Property Matters + + (a) Third Party Claims + If Contributor has knowledge that a license under a third party's intellectual property rights is required to exercise the rights granted by such Contributor under Sections 2.1 or 2.2, Contributor must include a text file with the Source Code distribution titled "LEGAL" which describes the claim and the party making the claim in sufficient detail that a recipient will know whom to contact. If Contributor obtains such knowledge after the Modification is made available as described in Section 3.2, Contributor shall promptly modify the LEGAL file in all copies Contributor makes available thereafter and shall take other steps (such as notifying appropriate mailing lists or newsgroups) reasonably calculated to inform those who received the Covered Code that new knowledge has been obtained. + + (b) Contributor APIs + If Contributor's Modifications include an application programming interface and Contributor has knowledge of patent licenses which are reasonably necessary to implement that API, Contributor must also include this information in the LEGAL file. + + (c) Representations. + Contributor represents that, except as disclosed pursuant to Section 3.4 (a) above, Contributor believes that Contributor's Modifications are Contributor's original creation(s) and/or Contributor has sufficient rights to grant the rights conveyed by this License. + + 3.5. Required Notices. You must duplicate the notice in Exhibit A in each file of the Source Code. If it is not possible to put such notice in a particular Source Code file due to its structure, then You must include such notice in a location (such as a relevant directory) where a user would be likely to look for such a notice. If You created one or more Modification(s) You may add your name as a Contributor to the notice described in Exhibit A. You must also duplicate this License in any documentation for the Source Code where You describe recipients' rights or ownership rights relating to Covered Code. You may choose to offer, and to charge a fee for, warranty, support, indemnity or liability obligations to one or more recipients of Covered Code. However, You may do so only on Your own behalf, and not on behalf of the Initial Developer or any Contributor. You must make it absolutely clear than any such warranty, support, indemnity or liability obligation is offered by You alone, and You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of warranty, support, indemnity or liability terms You offer. + + 3.6. Distribution of Executable Versions. You may distribute Covered Code in Executable form only if the requirements of Sections 3.1, 3.2, 3.3, 3.4 and 3.5 have been met for that Covered Code, and if You include a notice stating that the Source Code version of the Covered Code is available under the terms of this License, including a description of how and where You have fulfilled the obligations of Section 3.2. The notice must be conspicuously included in any notice in an Executable version, related documentation or collateral in which You describe recipients' rights relating to the Covered Code. You may distribute the Executable version of Covered Code or ownership rights under a license of Your choice, which may contain terms different from this License, provided that You are in compliance with the terms of this License and that the license for the Executable version does not attempt to limit or alter the recipient's rights in the Source Code version from the rights set forth in this License. If You distribute the Executable version under a different license You must make it absolutely clear that any terms which differ from this License are offered by You alone, not by the Initial Developer or any Contributor. You hereby agree to indemnify the Initial Developer and every Contributor for any liability incurred by the Initial Developer or such Contributor as a result of any such terms You offer. + + 3.7. Larger Works. You may create a Larger Work by combining Covered Code with other code not governed by the terms of this License and distribute the Larger Work as a single product. In such a case, You must make sure the requirements of this License are fulfilled for the Covered Code. + +4. Inability to Comply Due to Statute or Regulation. + +If it is impossible for You to comply with any of the terms of this License with respect to some or all of the Covered Code due to statute, judicial order, or regulation then You must: (a) comply with the terms of this License to the maximum extent possible; and (b) describe the limitations and the code they affect. Such description must be included in the LEGAL file described in Section 3.4 and must be included with all distributions of the Source Code. Except to the extent prohibited by statute or regulation, such description must be sufficiently detailed for a recipient of ordinary skill to be able to understand it. + +5. Application of this License. +This License applies to code to which the Initial Developer has attached the notice in Exhibit A and to related Covered Code. + +6. Versions of the License. + + 6.1. New Versions + Netscape Communications Corporation ("Netscape") may publish revised and/or new versions of the License from time to time. Each version will be given a distinguishing version number. + + 6.2. Effect of New Versions + Once Covered Code has been published under a particular version of the License, You may always continue to use it under the terms of that version. You may also choose to use such Covered Code under the terms of any subsequent version of the License published by Netscape. No one other than Netscape has the right to modify the terms applicable to Covered Code created under this License. + + 6.3. Derivative Works + If You create or use a modified version of this License (which you may only do in order to apply it to code which is not already Covered Code governed by this License), You must (a) rename Your license so that the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", "MPL", "NPL" or any confusingly similar phrase do not appear in your license (except to note that your license differs from this License) and (b) otherwise make it clear that Your version of the license contains terms which differ from the Mozilla Public License and Netscape Public License. (Filling in the name of the Initial Developer, Original Code or Contributor in the notice described in Exhibit A shall not of themselves be deemed to be modifications of this License.) + +7. DISCLAIMER OF WARRANTY +COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT, YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. + +8. Termination + + 8.1. This License and the rights granted hereunder will terminate automatically if You fail to comply with terms herein and fail to cure such breach within 30 days of becoming aware of the breach. All sublicenses to the Covered Code which are properly granted shall survive any termination of this License. Provisions which, by their nature, must remain in effect beyond the termination of this License shall survive. + + 8.2. If You initiate litigation by asserting a patent infringement claim (excluding declatory judgment actions) against Initial Developer or a Contributor (the Initial Developer or Contributor against whom You file such action is referred to as "Participant") alleging that: + + a. such Participant's Contributor Version directly or indirectly infringes any patent, then any and all rights granted by such Participant to You under Sections 2.1 and/or 2.2 of this License shall, upon 60 days notice from Participant terminate prospectively, unless if within 60 days after receipt of notice You either: (i) agree in writing to pay Participant a mutually agreeable reasonable royalty for Your past and future use of Modifications made by such Participant, or (ii) withdraw Your litigation claim with respect to the Contributor Version against such Participant. If within 60 days of notice, a reasonable royalty and payment arrangement are not mutually agreed upon in writing by the parties or the litigation claim is not withdrawn, the rights granted by Participant to You under Sections 2.1 and/or 2.2 automatically terminate at the expiration of the 60 day notice period specified above. + b. any software, hardware, or device, other than such Participant's Contributor Version, directly or indirectly infringes any patent, then any rights granted to You by such Participant under Sections 2.1(b) and 2.2(b) are revoked effective as of the date You first made, used, sold, distributed, or had made, Modifications made by that Participant. + + 8.3. If You assert a patent infringement claim against Participant alleging that such Participant's Contributor Version directly or indirectly infringes any patent where such claim is resolved (such as by license or settlement) prior to the initiation of patent infringement litigation, then the reasonable value of the licenses granted by such Participant under Sections 2.1 or 2.2 shall be taken into account in determining the amount or value of any payment or license. + + 8.4. In the event of termination under Sections 8.1 or 8.2 above, all end user license agreements (excluding distributors and resellers) which have been validly granted by You or any distributor hereunder prior to termination shall survive termination. + +9. LIMITATION OF LIABILITY +UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. + +10. U.S. government end users +The Covered Code is a "commercial item," as that term is defined in 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer software" and "commercial computer software documentation," as such terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), all U.S. Government End Users acquire Covered Code with only those rights set forth herein. + +11. Miscellaneous +This License represents the complete agreement concerning subject matter hereof. If any provision of this License is held to be unenforceable, such provision shall be reformed only to the extent necessary to make it enforceable. This License shall be governed by California law provisions (except to the extent applicable law, if any, provides otherwise), excluding its conflict-of-law provisions. With respect to disputes in which at least one party is a citizen of, or an entity chartered or registered to do business in the United States of America, any litigation relating to this License shall be subject to the jurisdiction of the Federal Courts of the Northern District of California, with venue lying in Santa Clara County, California, with the losing party responsible for costs, including without limitation, court costs and reasonable attorneys' fees and expenses. The application of the United Nations Convention on Contracts for the International Sale of Goods is expressly excluded. Any law or regulation which provides that the language of a contract shall be construed against the drafter shall not apply to this License. + +12. Responsibility for claims +As between Initial Developer and the Contributors, each party is responsible for claims and damages arising, directly or indirectly, out of its utilization of rights under this License and You agree to work with Initial Developer and Contributors to distribute such responsibility on an equitable basis. Nothing herein is intended or shall be deemed to constitute any admission of liability. + +13. Multiple-licensed code +Initial Developer may designate portions of the Covered Code as "Multiple-Licensed". "Multiple-Licensed" means that the Initial Developer permits you to utilize portions of the Covered Code under Your choice of the MPL or the alternative licenses, if any, specified by the Initial Developer in the file described in Exhibit A. + +Exhibit A - Mozilla Public License. + +"The contents of this file are subject to the Mozilla Public License Version 1.1 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.mozilla.org/MPL/ + +Software distributed under the License is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License for the specific language governing rights and limitations under the License. + +The Original Code is ______________________________________. + +The Initial Developer of the Original Code is ________________________. +Portions created by ______________________ are Copyright (C) ______ +_______________________. All Rights Reserved. + +Contributor(s): ______________________________________. + +Alternatively, the contents of this file may be used under the terms of the _____ license (the "[___] License"), in which case the provisions of [______] License are applicable instead of those above. If you wish to allow use of your version of this file only under the terms of the [____] License and not to allow others to use your version of this file under the MPL, indicate your decision by deleting the provisions above and replace them with the notice and other provisions required by the [___] License. If you do not delete the provisions above, a recipient may use your version of this file under either the MPL or the [___] License." + +NOTE: The text of this Exhibit A may differ slightly from the text of the notices in the Source Code files of the Original Code. You should use the text of this Exhibit A rather than the text found in the Original Code Source Code for Your Modifications. diff --git a/NEWS b/NEWS index ce26707..ab3dc48 100644 --- a/NEWS +++ b/NEWS @@ -1,133 +1,230 @@ -Overview of changes in GLib 2.78.6, 2024-05-08 +Overview of changes in GLib 2.79.0, 2023-12-22 ============================================== -* Fix a regression with IBus caused by the fix for CVE-2024-34397 (#3353, - work by Simon McVittie) + * Port to gi-docgen and drop gtk-doc support — dependencies have changed, and + Meson needs `-Ddocumentation` now rather than `-Dgtk_doc` (#3037, work by + multiple people) -* Bugs fixed: - - #3353 Fixing CVE-2024-34397 caused regressions for ibus (Simon McVittie) - - !4056 Backport !4053 “gdbusconnection: Allow name owners to have the syntax - of a well-known name” to glib-2-78 - -Overview of changes in GLib 2.78.5, 2024-05-07 -============================================== - -* Fix CVE-2024-34397: GDBus signal subscriptions for well-known names are - vulnerable to unicast spoofing (#3268, work by Simon McVittie, reported by - Alicia Boya García) - -* Bugs fixed: - - #3168 gvfs-udisks2-volume-monitor SIGSEGV in g_content_type_guess_for_tree() - due to filename with bad encoding (Ondrej Holy) - - #3268 CVE-2024-34397: GDBus signal subscriptions for well-known names are - vulnerable to unicast spoofing (Simon McVittie) - - !3825 glib-2-78: ci: Drop FreeBSD 12 CI runner as it’s EOL - - !3960 gcontenttype: Make filename valid utf-8 string before processing - - !4040 Backport !4038 “gdbusconnection: Don't deliver signals if the sender - doesn't match” to glib-2-78 - - !4043 CI: Ignore MSYS2 CI failures for this older stable-branch - -* Translation updates: - - English (United Kingdom) (Andi Chandler) - - Georgian (Ekaterine Papava) - - Portuguese (Brazil) (Juliano de Souza Camargo) - - -Overview of changes in GLib 2.78.4, 2024-01-21 -============================================== - -* Bugs fixed: - - !3754 Backport !3751 “Fix generated RST anchors for methods, signals and - properties” to glib-2-78 - - !3756 docs/reference: depend on a native gtk-doc - - !3759 Backport !3753 “gobject_gdb.py: Do not break bt on optimized build” to - glib-2-78 - - !3766 Backport !3750 “gregex: clean up usage of _GRegex.jit_status” to - glib-2-78 - - -Overview of changes in GLib 2.78.3, 2023-12-06 -============================================== - -* Fix a crash-causing regression in xdgmime (#3191, work by Philip Withnall) - -* Bugs fixed: - - #3191 Crash in __gio_xdg_cache_mime_type_subclass (Philip Withnall) - - !3747 Backport !3742 “xdgmime: Update to upstream commit c2c814d4051f232” to - glib-2-78 - - -Overview of changes in GLib 2.78.2, 2023-12-05 -============================================== + * Move libgirepository into glib.git from gobject-introspection.git — but tools + like `g-ir-scanner` are currently still in gobject-introspection.git. For the + moment, glib.git needs to be built twice, once with `-Dintrospection=false`, + then build gobject-introspection.git, then re-build glib.git with + `-Dintrospection=true`. This process will evolve throughout the GLib 2.80 + cycle. The API and ABI of libgirepository has changed, and accordingly its + version number has been bumped from 1.0 to 2.0 (note: the version number of + `GIRepository-*.gir` has been bumped from 2.0 to 3.0; see !3786). The GIR and + typelib file formats have not been changed, and are still at version 1.0. + (#3155, work by multiple people) -* Bugs fixed: - - #3156 check for #ifdef PTRACE_O_EXITKILL will always fail since it isn't a - macro (Alessandro Bono) - - #3157 gsubprocess build-time test intermittently timing out since 2.78.1 - (Simon McVittie) - - !3673 Backport !3669 “meson: Improve PTRACE_O_EXITKILL presence check” to - glib-2-78 - - !3680 Backport !3677 “Make GQuark register intentional leaks” to glib-2-78 - - !3681 Backport 3678 “gsignalgroup: Avoid function call with side effect in - g_return_* macro” to glib-2-78 - - !3686 Backport !3685 “tests: Don't assume that sh optimizes simple commands - into exec” to glib-2-78 - - !3718 Backport !3714 “xdgmime: Handle buggy type definitions with circular - inheritance” to glib-2-78 - - !3727 Backport !3725 “collate: Don't segfault on bad input” to glib-2-78 + * Match behaviour for `GAppInfo` searches has changed (#3082, work by Nelson + Benítez León) -* Translation updates: - - Ukrainian (Yuri Chornoivan) - - -Overview of changes in GLib 2.78.1, 2023-10-25 -============================================== - -* Fix truncating files when `g_file_set_contents_full()` is called without - `G_FILE_SET_CONTENTS_CONSISTENT` (#3144, work by Philip Withnall) + * Rename `GTK_USE_PORTAL` environment variable to `GIO_USE_PORTALS` (#3107, + work by Philip Withnall) -* Fix `-Dlibelf=disabled` on Linux (#3120, work by Philip Withnall) + * Bump Meson dependency to 1.2.0 and depend on Python `packaging` module + (!3666, !3752) -* Bugs fixed: +Bugs fixed: + - #596 GApplication in Garbage Collected environments would benefit from a + g_application_command_line_exit() to enable remote instances to exit. + (Aleksandr Mezin) + - #791 Wish: Add a "nodelay" property to GSocket or GTcpConnection (Philip + Withnall) + - #2810 thread-pool-slow intermittent assertion failure in + test_thread_sort_entry_func() (Philip Withnall) + - #2824 G_REGEX_OPTIMIZE causes incorrect regex behaviour + - #2991 Drop translatable pspec nick/blurbs from properties in GIO (Sophie + Herold) + - #3082 Investigate prioritising prefix matches on GAppInfo keywords over + substring matches on names (Nelson Benítez León) + - #3087 glib doesn't cleanly unload on Windows (Luca Bacci) + - #3098 Make invalid escape sequences in GKeyFile fatal (Philip Withnall) + - #3103 mkenums: Can't parse an enum value with value ',' (Lukáš Tyrychtr) - #3105 NetworkManager 1.44.0 crashes repeatedly with glib 2.78.0 (Philip Withnall) + - #3107 Rename GTK_USE_PORTAL to avoid portal services being run with portals + force-enabled (Philip Withnall) - #3111 gsubprocess-testprog.c: build error with cygwin (sys/ptrace.h: No such file or directory) (Philip Withnall) + - #3112 Update to Unicode 15.1 (Philip Withnall) + - #3115 Support for additional strftime formatting capabilities - #3116 gio clears modification time in microseconds when setting with `set_modification_date_time` (Lukáš Tyrychtr) + - #3119 Add support for `%Ey` to g_date_time_format() (Philip Withnall) - #3120 Build of glib 2.78.0 ignores -Dlibelf=disabled (Philip Withnall) - #3128 glib-2.78.0 fails at gio/tests/gsubprocess.p/gsubprocess.c.o - #3130 Segfault when creating GIO GPropertyAction without properties + - #3134 glib incompatible with Python 3.12 due to distutils usage + - #3135 Add GNU/Hurd CI + - #3140 Add a flag to not copy modification time when copying files (Khalid + Abu Shawarib) - #3144 `g_file_set_contents_full()` doesn't truncate the file (without `G_FILE_SET_CONTENTS_CONSISTENT`) (Philip Withnall) + - #3156 check for #ifdef PTRACE_O_EXITKILL will always fail since it isn't a + macro (Alessandro Bono) + - #3157 gsubprocess build-time test intermittently timing out since 2.78.1 + (Simon McVittie) + - #3158 "CRITICAL" log when using --attributes option for "gio info" (Philip + Withnall) + - #3159 glib regex test fails JIT compiler tests under musl libc (Pablo Correa + Gómez) + - #3161 codegen installation is broken + - #3168 gvfs-udisks2-volume-monitor SIGSEGV in g_content_type_guess_for_tree() + due to filename with bad encoding (Ondrej Holy) + - #3183 g_dbus_connection_signal_subscribe with flag + G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH doesn't work with an arg0 that is an + object path (Philip Withnall) + - #3185 g_utf8_collate_key() segfaults when passed an invalid length + - #3186 [RFE] Increase gio sniff buffer for mime type magic detection to 16K + or so (Philip Withnall) + - #3187 g_vasprintf crashes when passed invalid UTF-8 (Philip Withnall) + - #3191 Crash in __gio_xdg_cache_mime_type_subclass (Philip Withnall) + - #3203 Fdo notification fails without AppID (Michael Catanzaro) + - !3143 gatomic: Use g(u)intptr where appropriate + - !3316 gobject: Separate GWeakRef from GWeakNotify + - !3394 gsocketclient: Document delays/timeouts better + - !3457 glib-unix: Add convenience API for pipes + - !3524 add muslc ci + - !3552 gutils: Use international symbol for bits + - !3566 Update annotations for GAsyncQueue and GDir + - !3567 Update annotations for GHmac + - !3568 Update GOptionContext annotations + - !3569 Small fixes and cleanups for Vectored Exception Handlers + - !3571 Update GStringChunk annotations + - !3572 Update GRand annotations + - !3573 Update GTimer annotations - !3576 guniprop.c: Avoid creating (temporarily) out-of-bounds pointers + - !3577 gthread: introduce g_once_init_{enter,leave}_pointer + - !3578 GType: Use guintptr as the underlying storage if larger than gsize - !3579 Fixes for integer cast warnings when targeting CHERI - !3580 Fix test_find_program on FreeBSD - - !3589 gconstructor.h: Ensure [c|d]tor prototypes are present for MSVC (Chun- - wei Fan) + - !3581 gthread: Fix optional/nullable annotations for g_once_init_*() + - !3582 Buffer needs to be aligned correctly to receive linux_dirent64. + - !3589 gconstructor.h: Ensure [c|d]tor prototypes are present for MSVC + (Chun-wei Fan) + - !3590 gtestutils.h: Fix warning with -Wsign-conversion caused by + g_assert_cmpint + - !3591 Switch to using gi-docgen for docs (batch 1) - !3594 Fix gutils-user-database test on macOS + - !3595 gobject: cache flags needed for g_type_create_instance() - !3596 Add value annotation to G_TYPE_FUNDAMENTAL_MAX + - !3597 Expand security policy to cover previous stable branch + - !3598 Document NULL pointer pitfall in toolchain requirements - !3601 meson: Fix Windows build with PCRE2 as sibling subproject - - !3604 Backport !3589 “gconstructor.h: Ensure [c|d]tor prototypes are present - for MSVC” to glib-2-78 - - !3608 Backport !3587 “glocalfileinfo: Preserve microseconds for - access/modify times” to glib-2-78 - - !3609 Backport !3607 “Make sure the `GTask` is freed on a graceful - disconnect” to glib-2-78 (Pavel Sobolev) - - !3614 Backport !3582 “Buffer needs to be aligned correctly to receive - linux_dirent64.” to glib-2-78 - - !3616 Backport !3590 “gtestutils.h: Fix warning with -Wsign-conversion - caused by g_assert_cmpint” to glib-2-78 - - !3619 Backport !3617 “tests: Drop unnecessary include from gsubprocess- - testprog.c” to glib-2-78 - - !3622 Backport !3621 “wakeup: do single read when using eventfd()” to - glib-2-78 - - !3625 Backport !3624 “wakeup: Fix g_wakeup_acknowledge if signal comes in” - to glib-2-78 - - !3644 Backport !3633 “Use g_task_return in task threads” to glib-2-78 - - !3649 Backport !3648 “build: Fix -Dlibelf=disabled on Linux” to glib-2-78 - - !3659 Backport !3650 “gfileutils: Add a missing ftruncate() call when - writing files” to glib-2-78 + - !3603 Add GBytes variants for GSocket receive methods + - !3605 build: Post-release version bump + - !3607 Make sure the `GTask` is freed on a graceful disconnect + - !3610 gdesktopappinfo: Do not search Comment field + - !3611 tests/constructor: Fix "unknown pragma ignored" warning on clang + - !3612 Update GStrv annotations + - !3613 tests: Fix gdatetime test on non-UTC systems + - !3620 gmain: avoid a GList traversal when removing source + - !3621 wakeup: do single read when using eventfd() + - !3623 Windows: Compile with the UNICODE / _UNICODE macros + - !3624 wakeup: Fix g_wakeup_acknowledge if signal comes in + - !3627 Add Hurd code owners + - !3628 glib-unix: Use full path to gstdio.h include + - !3629 glib/tests/meson.build: remove identical build targets + - !3630 glib-compile-resources: ensure alignment is at least sizeof(void *) + - !3632 Stop using enums in bitfields + - !3633 Use g_task_return in task threads + - !3634 Switch to using gi-docgen for docs (batch 2) + - !3635 Fix warnings with Clang on Windows and enable --Werror in CI + - !3636 Generate introspection data + - !3637 gstrvbuilder: Add g_strv_builder_take + - !3638 Cleanup and add content to glib debugging using gdb scripts + - !3640 GIO/tests: skip test_resources_binary on MIPS platforms + - !3641 build: Simplify MIPS test check + - !3645 Switch to using gi-docgen for docs (batch 3) + - !3646 ci: Update from clang-format-11 to clang-format-14 + - !3647 Switch to using gi-docgen for docs (batch 4) + - !3652 GApplicationCommandLine: add print[err]_literal() + - !3654 gdatetime: Fix minor leaks from strup/strdown calls + - !3655 gdatetime: Fix incorrect alt-digits being used after changing locale + - !3656 gmodule-dl: Use RTLD_DEFAULT on FreeBSD too + - !3660 Switch to using gi-docgen for docs (batch 5) + - !3661 Switch to using gi-docgen for docs (batch 6) + - !3662 Switch to using gi-docgen for docs (batch 7) + - !3663 gdbusconnection: don't cache G_IO_ERROR_CANCELLED errors + - !3664 gmain: optimize "context->sources" hash table to use as set + - !3665 ci: Remove .build-linux from Hurd CI scheduled job + - !3666 build: Bump Meson dependency to 1.2.0 + - !3667 Switch to using gi-docgen for docs (batch 8) + - !3668 Socket & readiness fixes + - !3671 gio/tests: Add test generated txt as the resources test dependency + - !3672 glib-private: Check for LSAN support at runtime when controlling it + - !3674 gtask: Add g_task_return_prefixed_error() + - !3677 Make GQuark register intentional leaks + - !3678 gsignalgroup: Avoid function call with side effect in g_return_* macro + - !3679 gmessages: fix dropping irrelevant log domains + - !3682 tests: Fix dependency of test.gresource on test-generated.txt + - !3683 glib: Disable dynamic asan loading on macOS + - !3687 fix: about libproc.h and PROC_PIDLISTFD_SIZE + - !3688 build: Fix the inclusion paths for GIR files in gi-docgen + - !3689 meson: Add missing dependencies for utility files for gdbus-codegen + - !3690 Switch to using gi-docgen for docs (batch 9) + - !3695 gvalue: add "steal_string" + - !3699 [th/prgname] use atomic pointers for g_prgname/g_application_name and + add g_set_prgname_once() + - !3701 tests: Fix gio-tool.py test on macOS + - !3702 glib.supp: Suppress the global_mime_dirs allocations + - !3703 Port GIRepository to GTypeInstance and add introspection + - !3704 girepository: Rename symbols to the GI namespace + - !3707 girepository: Ignore set-but-not-used warnings with G_DISABLE_ASSERT + - !3708 Fix various leaks in cmph-bdz-test and gutils + - !3709 Switch to using gi-docgen for docs (batch 10) + - !3710 gmessages: introduce g_log_writer_default_set_debug_domains() + - !3711 ghmac: Add a boxed type for GHmac and fix introspection build + accordingly + - !3712 Switch to using gi-docgen for docs (batch 11) + - !3713 gfileutils: Fix g_file_get_contents() silent under-read of large files + when off_t is wider than size_t + - !3714 xdgmime: Handle buggy type definitions with circular inheritance + - !3715 goption: Fix a typo + - !3716 tests: Improve build of cmph tests in girepository + - !3717 tests: provide reason for disabling convert test under musl + - !3721 gtestutils: Add g_test_trap_subprocess_with_envp() for testing envs + - !3722 gdir, gstrvbuilder: Add refcounting support and a boxed type + - !3723 gwin32: Un-hide symbols when building GIR + - !3726 tests: Fix fileutils build on FreeBSD and macOS + - !3731 tests: Fix string test failure on BSDs + - !3732 gspawn: Stop spewing debug messages + - !3733 ci: Make the Alpine CI name more consistent + - !3734 gdatetime: Disable ERA support on platforms which don’t support this + - !3735 ci: Fix printing info message at end of run-style-check-diff.sh + - !3736 build: Rename -Dgtk_doc option to -Ddocumentation and fix some + g-ir-scanner warnings + - !3739 Documentation only: Added clarification about GWeakNotify and removed + ambiguous text + - !3741 hash: Explicitly annotate key in iter_next as nullable + - !3743 ci: Install correct version of Meson on Alpine CI image + - !3745 tests: Assert there no errors first in gdbus-test-codegen + - !3751 Fix generated RST anchors for methods, signals and properties + - !3752 build: Make packaging module required + - !3753 gobject_gdb.py: Do not break bt on optimized build + - !3755 tests: Use textwrap.dedent to indent expected strings pleasingly + - !3757 ci: Re-add explicit Meson version to Alpine CI image + - !3758 docs: Add a section on version checking macros + - !3760 girepository: Various API cleanups + - !3761 gerror: Fix an old allow-none annotation + - !3762 [th/notify-queue] some optimization around + g_object_freeze_notify()/g_object_thaw_notify() + - !3763 girepository: Drop libgio dependency from gdump.c + - !3764 gsignal: fix reference to signals documentation page + - !3765 gapplication: Fix minor typo in docs + - !3767 girepository: Port documentation to gi-docgen and update + - !3768 ci: Build docs artifacts for deployment to docs.gtk.org + - !3770 GDateTime: Add usec precision API for unix time + - !3771 gtask: Add g_task_return_new_error_literal() + - !3772 gobject: Make GLib-2.0 gir build depend on GObject dependency + - !3773 girepository: Return enumerated versions and search paths as a GStrv + - !3776 glocalvfs: Remove unnecessary and buggy code + - !3777 Fix detecting size_t size when `-Wmissing-prototypes` is in CFLAGS + - !3779 gtypemodule: Add assertions in finalize() + - !3782 docs: fix a typo + - !3786 girepository: Re-number GIR file from 2.0 to 3.0 + - !3787 docs: Install the gi-docgen docs * Translation updates: - Catalan (Jordi Mas i Hernandez) @@ -135,15 +232,15 @@ Overview of changes in GLib 2.78.1, 2023-10-25 - Czech (Daniel Rusek) - Esperanto (Kristjan SCHMIDT) - French (Alexandre Franke) - - Georgian (Ekaterine Papava) - Italian (Milo Casagrande) - Latvian (Rūdolfs Mazurs) - Portuguese (Brazil) (Rafael Fontenelle) - - Romanian (Daniel Șerbănescu) + - Romanian (Florentina Mușat) - Russian (Artur S0) - Slovenian (Matej Urbančič) - Spanish (Daniel Mustieles) - Turkish (Sabri Ünal) + - Ukrainian (Yuri Chornoivan) Overview of changes in GLib 2.78.0, 2023-09-08 diff --git a/README.md b/README.md index 13f8aa2..6e19a38 100644 --- a/README.md +++ b/README.md @@ -19,9 +19,10 @@ GLib on Windows. ## Supported versions -Only the most recent unstable and stable release series are supported. All -older versions are not supported upstream and may contain bugs, some of -which may be exploitable security vulnerabilities. +Upstream GLib only supports the most recent stable release series, the previous +stable release series, and the current development release series. All +older versions are not supported upstream and may contain bugs, some of which +may be exploitable security vulnerabilities. See [SECURITY.md](SECURITY.md) for more details. diff --git a/SECURITY.md b/SECURITY.md index c7fb816..c7797d5 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -7,11 +7,16 @@ ## Supported Versions -Upstream GLib only supports the most recent stable release series, and the -current development release series. Any older stable release series are no -longer supported, although they may still receive backported security updates -in long-term support distributions. Such support is up to the distributions, -though. +Upstream GLib only supports the most recent stable release series, the previous +stable release series, and the current development release series. Any older +stable release series are no longer supported, although they may still receive +backported security updates in long-term support distributions. Such support is +up to the distributions, though. + +The previous stable release series will generally receive fixes only for high +impact security issues, at maintainer discretion. Since such issues are rare, +it's expected that there may be no backports or releases on the previous stable +branch. Under GLib’s versioning scheme, stable release series have an *even* minor component (for example, 2.66.0, 2.66.1, 2.68.3), and development release series diff --git a/docs/CODEOWNERS b/docs/CODEOWNERS index cd4ef73..69e9e85 100644 --- a/docs/CODEOWNERS +++ b/docs/CODEOWNERS @@ -53,6 +53,9 @@ subprojects/ @xclaesse @nirbheek @pwithnall *bsd* @jmatthew @ajacoutot @lantw @pwithnall *kqueue* @jmatthew @ajacoutot @lantw @pwithnall +# GNU Hurd support +*hurd* @bugaevc @sthibaul + # flatpak portals gio/*portal* @matthiasc @alexl @pwithnall diff --git a/docs/reference/gio/concat-files-helper.py b/docs/reference/gio/concat-files-helper.py deleted file mode 100644 index d434f9e..0000000 --- a/docs/reference/gio/concat-files-helper.py +++ /dev/null @@ -1,36 +0,0 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- - -# Copyright (C) 2018 Collabora Inc. -# -# This library is free software; you can redistribute it and/or -# modify it under the terms of the GNU Lesser General Public -# License as published by the Free Software Foundation; either -# version 2.1 of the License, or (at your option) any later version. -# -# This library is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -# Lesser General Public License for more details. -# -# You should have received a copy of the GNU Lesser General -# Public License along with this library; if not, see . -# -# Author: Xavier Claessens - -import os -import sys - -if len(sys.argv) < 3: - print( - "Usage: {} ...".format( - os.path.basename(sys.argv[0]) - ) - ) - sys.exit(1) - -with open(sys.argv[1], "w") as outfile: - for fname in sys.argv[2:]: - with open(fname) as infile: - for line in infile: - outfile.write(line) diff --git a/docs/reference/gio/dbus-error.md b/docs/reference/gio/dbus-error.md new file mode 100644 index 0000000..fc1a1a6 --- /dev/null +++ b/docs/reference/gio/dbus-error.md @@ -0,0 +1,79 @@ +Title: D-Bus Error Handling +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 David Zeuthen +SPDX-FileCopyrightText: 2012 Aleksander Morgado + +# D-Bus Error Handling + +All facilities that return errors from remote methods (such as +[method@Gio.DBusConnection.call_sync]) use [type@GLib.Error] to represent both +D-Bus errors (e.g. errors returned from the other peer) and locally in-process +generated errors. + +To check if a returned [type@GLib.Error] is an error from a remote peer, use +[func@Gio.DBusError.is_remote_error]. To get the actual D-Bus error name, +use [func@Gio.DBusError.get_remote_error]. Before presenting an error, always +use [func@Gio.DBusError.strip_remote_error]. + +In addition, facilities used to return errors to a remote peer also use +[type@GLib.Error]. See [method@Gio.DBusMethodInvocation.return_error] for +discussion about how the D-Bus error name is set. + +Applications can associate a [type@GLib.Error] error domain with a set of D-Bus +errors in order to automatically map from D-Bus errors to [type@GLib.Error] and +back. This is typically done in the function returning the [type@GLib.Quark] for +the error domain: + +```c +// foo-bar-error.h: + +#define FOO_BAR_ERROR (foo_bar_error_quark ()) +GQuark foo_bar_error_quark (void); + +typedef enum +{ + FOO_BAR_ERROR_FAILED, + FOO_BAR_ERROR_ANOTHER_ERROR, + FOO_BAR_ERROR_SOME_THIRD_ERROR, + FOO_BAR_N_ERRORS / *< skip >* / +} FooBarError; + +// foo-bar-error.c: + +static const GDBusErrorEntry foo_bar_error_entries[] = +{ + {FOO_BAR_ERROR_FAILED, "org.project.Foo.Bar.Error.Failed"}, + {FOO_BAR_ERROR_ANOTHER_ERROR, "org.project.Foo.Bar.Error.AnotherError"}, + {FOO_BAR_ERROR_SOME_THIRD_ERROR, "org.project.Foo.Bar.Error.SomeThirdError"}, +}; + +// Ensure that every error code has an associated D-Bus error name +G_STATIC_ASSERT (G_N_ELEMENTS (foo_bar_error_entries) == FOO_BAR_N_ERRORS); + +GQuark +foo_bar_error_quark (void) +{ + static gsize quark = 0; + g_dbus_error_register_error_domain ("foo-bar-error-quark", + &quark, + foo_bar_error_entries, + G_N_ELEMENTS (foo_bar_error_entries)); + return (GQuark) quark; +} +``` + +With this setup, a D-Bus peer can transparently pass e.g. +`FOO_BAR_ERROR_ANOTHER_ERROR` and other peers will see the D-Bus error name +`org.project.Foo.Bar.Error.AnotherError`. + +If the other peer is using GDBus, and has registered the association with +[func@Gio.DBusError.register_error_domain] in advance (e.g. by invoking the +`FOO_BAR_ERROR` quark generation itself in the previous example) the peer will +see also `FOO_BAR_ERROR_ANOTHER_ERROR` instead of `G_IO_ERROR_DBUS_ERROR`. Note +that GDBus clients can still recover `org.project.Foo.Bar.Error.AnotherError` +using [func@Gio.DBusError.get_remote_error]. + +Note that the `G_DBUS_ERROR` error domain is intended only for returning errors +from a remote message bus process. Errors generated locally in-process by e.g. +[class@Gio.DBusConnection] should use the `G_IO_ERROR` domain. + diff --git a/docs/reference/gio/dbus-introspection.md b/docs/reference/gio/dbus-introspection.md new file mode 100644 index 0000000..2eacc26 --- /dev/null +++ b/docs/reference/gio/dbus-introspection.md @@ -0,0 +1,23 @@ +Title: D-Bus Introspection Data +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 David Zeuthen +SPDX-FileCopyrightText: 2010 Matthias Clasen + +# D-Bus Introspection Data + +Various data structures and convenience routines to parse and +generate D-Bus introspection XML. Introspection information is +used when registering objects with [method@Gio.DBusConnection.register_object]. + +The format of D-Bus introspection XML is specified in the +[D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format). + +The main introspection data structures are: + * [type@Gio.DBusNodeInfo] + * [type@Gio.DBusInterfaceInfo] + * [type@Gio.DBusPropertyInfo] + * [type@Gio.DBusMethodInfo] + * [type@Gio.DBusSignalInfo] + * [type@Gio.DBusArgInfo] + * [type@Gio.DBusAnnotationInfo] + diff --git a/docs/reference/gio/dbus-name-owning.md b/docs/reference/gio/dbus-name-owning.md new file mode 100644 index 0000000..a8daaaf --- /dev/null +++ b/docs/reference/gio/dbus-name-owning.md @@ -0,0 +1,14 @@ +Title: D-Bus Name Owning +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 David Zeuthen + +# D-Bus Name Owning + +Convenience API for owning bus names. + +A simple example for owning a name can be found in +[`gdbus-example-own-name.c`](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-own-name.c). + +The main API for owning names is: + * [func@Gio.bus_own_name] + * [func@Gio.bus_unown_name] diff --git a/docs/reference/gio/dbus-name-watching.md b/docs/reference/gio/dbus-name-watching.md new file mode 100644 index 0000000..07ff334 --- /dev/null +++ b/docs/reference/gio/dbus-name-watching.md @@ -0,0 +1,14 @@ +Title: D-Bus Name Watching +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 David Zeuthen + +# D-Bus Name Watching + +Convenience API for watching bus names. + +A simple example for watching a name can be found in +[`gdbus-example-watch-name.c`](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-name.c). + +The main API for watching names is: + * [func@Gio.bus_watch_name] + * [func@Gio.bus_unwatch_name] diff --git a/docs/reference/gio/dbus-utils.md b/docs/reference/gio/dbus-utils.md new file mode 100644 index 0000000..70ff84c --- /dev/null +++ b/docs/reference/gio/dbus-utils.md @@ -0,0 +1,28 @@ +Title: D-Bus Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 David Zeuthen + +# D-Bus Utilities + +Various utility routines related to D-Bus. + +GUID support: + * [func@Gio.dbus_is_guid] + * [func@Gio.dbus_generate_guid] + +Name validation: + * [func@Gio.dbus_is_name] + * [func@Gio.dbus_is_unique_name] + * [func@Gio.dbus_is_member_name] + * [func@Gio.dbus_is_interface_name] + * [func@Gio.dbus_is_error_name] + +Conversion between [type@GLib.Variant] and [type@GObject.Value]: + * [func@Gio.dbus_gvariant_to_gvalue] + * [func@Gio.dbus_gvalue_to_gvariant] + +Path escaping: + * [func@Gio.dbus_escape_object_path_bytestring] + * [func@Gio.dbus_escape_object_path] + * [func@Gio.dbus_unescape_object_path] + diff --git a/docs/reference/gio/error.md b/docs/reference/gio/error.md new file mode 100644 index 0000000..bc61b94 --- /dev/null +++ b/docs/reference/gio/error.md @@ -0,0 +1,12 @@ +Title: GIOError +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007 A. Walton + +# GIOError + +Contains helper functions for reporting errors to the user. + +Functions for converting between different error reporting mechanisms: + * [func@Gio.io_error_from_errno] + * [func@Gio.io_error_from_file_error] + diff --git a/docs/reference/gio/file-attributes.md b/docs/reference/gio/file-attributes.md new file mode 100644 index 0000000..c9f1fe7 --- /dev/null +++ b/docs/reference/gio/file-attributes.md @@ -0,0 +1,111 @@ +Title: File Attributes +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007 Andrew Walton +SPDX-FileCopyrightText: 2007 Alexander Larsson +SPDX-FileCopyrightText: 2008, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2011 Murray Cumming +SPDX-FileCopyrightText: 2012 David King + +# File Attributes + +File attributes in GIO consist of a list of key-value pairs. + +Keys are strings that contain a key namespace and a key name, separated +by a colon, e.g. `namespace::keyname`. Namespaces are included to sort +key-value pairs by namespaces for relevance. Keys can be retrieved +using wildcards, e.g. `standard::*` will return all of the keys in the +`standard` namespace. + +The list of possible attributes for a filesystem (pointed to by a +[iface@Gio.File]) is available as a [struct@Gio.FileAttributeInfoList]. This +list is queryable by key names as indicated earlier. + +Information is stored within the list in [struct@Gio.FileAttributeInfo] +structures. The info structure can store different types, listed in the enum +[type@Gio.FileAttributeType]. Upon creation of a [struct@Gio.FileAttributeInfo], +the type will be set to `G_FILE_ATTRIBUTE_TYPE_INVALID`. + +Classes that implement [iface@Gio.File] will create a +[struct@Gio.FileAttributeInfoList] and install default keys and values for their +given file system, architecture, and other possible implementation details +(e.g., on a UNIX system, a file attribute key will be registered for the user ID +for a given file). + +## Default Namespaces + +- `"standard"`: The ‘Standard’ namespace. General file information that + any application may need should be put in this namespace. Examples + include the file’s name, type, and size. +- `"etag`: The [Entity Tag](gfile.html#entity-tags) namespace. Currently, the + only key in this namespace is `value`, which contains the value of the current + entity tag. +- `"id"`: The ‘Identification’ namespace. This namespace is used by file + managers and applications that list directories to check for loops and + to uniquely identify files. +- `"access"`: The ‘Access’ namespace. Used to check if a user has the + proper privileges to access files and perform file operations. Keys in + this namespace are made to be generic and easily understood, e.g. the + `can_read` key is true if the current user has permission to read the + file. UNIX permissions and NTFS ACLs in Windows should be mapped to + these values. +- `"mountable"`: The ‘Mountable’ namespace. Includes simple boolean keys + for checking if a file or path supports mount operations, e.g. mount, + unmount, eject. These are used for files of type `G_FILE_TYPE_MOUNTABLE`. +- `"time"`: The ‘Time’ namespace. Includes file access, changed, created + times. +- `"unix"`: The ‘Unix’ namespace. Includes UNIX-specific information and + may not be available for all files. Examples include the UNIX UID, + GID, etc. +- `"dos"`: The ‘DOS’ namespace. Includes DOS-specific information and may + not be available for all files. Examples include `is_system` for checking + if a file is marked as a system file, and `is_archive` for checking if a + file is marked as an archive file. +- `"owner"`: The ‘Owner’ namespace. Includes information about who owns a + file. May not be available for all file systems. Examples include `user` + for getting the user name of the file owner. This information is often + mapped from some backend specific data such as a UNIX UID. +- `"thumbnail"`: The ‘Thumbnail’ namespace. Includes information about file + thumbnails and their location within the file system. Examples of keys in + this namespace include `path` to get the location of a thumbnail, `failed` + to check if thumbnailing of the file failed, and `is-valid` to check if + the thumbnail is outdated. +- `"filesystem"`: The ‘Filesystem’ namespace. Gets information about the + file system where a file is located, such as its type, how much space is + left available, and the overall size of the file system. +- `"gvfs"`: The ‘GVFS’ namespace. Keys in this namespace contain information + about the current GVFS backend in use. +- `"xattr"`: The ‘xattr’ namespace. Gets information about extended user + attributes. See [`attr(5)`](man:attr(5)). The `user.` prefix of the extended + user attribute name is stripped away when constructing keys in this namespace, + e.g. `xattr::mime_type` for the extended attribute with the name + `user.mime_type`. Note that this information is only available if + GLib has been built with extended attribute support. +- `"xattr-sys"`: The ‘xattr-sys’ namespace. Gets information about + extended attributes which are not user-specific. See [`attr(5)`](man:attr(5)). + Note that this information is only available if GLib has been built with + extended attribute support. +- `"selinux"`: The ‘SELinux’ namespace. Includes information about the + SELinux context of files. Note that this information is only available + if GLib has been built with SELinux support. + +Please note that these are not all of the possible namespaces. +More namespaces can be added from GIO modules or by individual applications. +For more information about writing GIO modules, see [class@Gio.IOModule]. + + + +## Default Keys + +For a list of the built-in keys and their types, see the [class@Gio.FileInfo] +documentation. + +Note that there are no predefined keys in the `xattr` and `xattr-sys` +namespaces. Keys for the `xattr` namespace are constructed by stripping +away the `user.` prefix from the extended user attribute, and prepending +`xattr::`. Keys for the `xattr-sys` namespace are constructed by +concatenating `xattr-sys::` with the extended attribute name. All extended +attribute values are returned as hex-encoded strings in which bytes outside +the ASCII range are encoded as escape sequences of the form `\xnn` +where `nn` is a 2-digit hexadecimal number. + diff --git a/docs/reference/gio/gapplication.rst b/docs/reference/gio/gapplication.rst new file mode 100644 index 0000000..338b3a7 --- /dev/null +++ b/docs/reference/gio/gapplication.rst @@ -0,0 +1,195 @@ +.. _gapplication(1): +.. meta:: + :copyright: Copyright 2013 Allison Karlitskaya + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2013 Allison Karlitskaya + SPDX-License-Identifier: LGPL-2.1-or-later + +============ +gapplication +============ + +-------------------------- +D-Bus application launcher +-------------------------- + +SYNOPSIS +-------- + +| **gapplication** help [COMMAND] +| **gapplication** version +| **gapplication** list-apps +| **gapplication** launch +| **gapplication** launch [FILE…] +| **gapplication** list-actions +| **gapplication** action [PARAMETER] + +DESCRIPTION +----------- + +``gapplication`` is a commandline implementation of the client-side of the +``org.freedesktop.Application`` interface as specified by the freedesktop.org +Desktop Entry Specification. + +``gapplication`` can be used to start applications that have ``DBusActivatable`` +set to ``true`` in their ``.desktop`` files and can be used to send messages to +already-running instances of other applications. + +It is possible for applications to refer to ``gapplication`` in the ``Exec`` +line of their ``.desktop`` file to maintain backwards compatibility with +implementations that do not directly support ``DBusActivatable``. + +``gapplication`` ships as part of GLib. + +COMMANDS +-------- + +``help [COMMAND]`` + + Displays a short synopsis of the available commands or provides detailed help + on a specific command. + +``version`` + + Prints the GLib version whence ``gapplication`` came. + +``list-apps`` + + Prints a list of all application IDs that are known to support D-Bus + activation. This list is generated by scanning ``.desktop`` files as per the + current ``XDG_DATA_DIRS``. + +``launch [FILE…]`` + + Launches an application. + + The first parameter is the application ID in the familiar ‘reverse DNS’ style + (e.g. ``org.gnome.app``) without the ``.desktop`` suffix. + + Optionally, if additional parameters are given, they are treated as the names + of files to open and may be filenames or URIs. If no files are given then the + application is simply activated. + +``list-actions `` + + List the actions declared in the application’s ``.desktop`` file. The + parameter is the application ID, as above. + +``action [PARAMETER]`` + + Invokes the named action (in the same way as would occur when activating an + action specified in the ``.desktop`` file). + + The application ID (as above) is the first parameter. The action name + follows. + + Optionally, following the action name can be one parameter, in GVariant + format, given as a single argument. Make sure to use sufficient quoting. + +EXAMPLES +-------- + +From the commandline +^^^^^^^^^^^^^^^^^^^^ + +Launching an application:: + + gapplication launch org.example.fooview + +Opening a file with an application:: + + gapplication launch org.example.fooview ~/file.foo + +Opening many files with an application:: + + gapplication launch org.example.fooview ~/foos/*.foo + +Invoking an action on an application:: + + gapplication action org.example.fooview create + +Invoking an action on an application, with an action:: + + gapplication action org.example.fooview show-item '"item_id_828739"' + +From the ``Exec`` lines of a ``.desktop`` file +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +The commandline interface of ``gapplication`` was designed so that it could be +used directly from the ``Exec`` line of a ``.desktop`` file. + +You might want to do this to allow for backwards compatibility with +implementations of the specification that do not understand how to do D-Bus +activation, without having to install a separate utility program. + +Consider the following example:: + + [Desktop Entry] + Version=1.1 + Type=Application + Name=Foo Viewer + DBusActivatable=true + MimeType=image/x-foo; + Exec=gapplication launch org.example.fooview %F + Actions=gallery;create; + + [Desktop Action gallery] + Name=Browse Gallery + Exec=gapplication action org.example.fooview gallery + + [Desktop Action create] + Name=Create a new Foo! + Exec=gapplication action org.example.fooview create + +From a script +^^^^^^^^^^^^^ + +If installing an application that supports D-Bus activation you may still want +to put a file in ``/usr/bin`` so that your program can be started from a +terminal. + +It is possible for this file to be a shell script. The script can handle +arguments such as ``--help`` and ``--version`` directly. It can also parse +other command line arguments and convert them to uses of ``gapplication`` to +activate the application, open files, or invoke actions. + +Here is a simplified example, as may be installed in ``/usr/bin/fooview``:: + + #!/bin/sh + + case "$1" in + --help) + echo "see ‘man fooview’ for more information" + ;; + + --version) + echo "fooview 1.2" + ;; + + --gallery) + gapplication action org.example.fooview gallery + ;; + + --create) + gapplication action org.example.fooview create + ;; + + -*) + echo "unrecognised commandline argument" + exit 1 + ;; + + *) + gapplication launch org.example.fooview "$@" + ;; + esac + +SEE ALSO +-------- + +`Desktop Entry Specification `_, +`gdbus(1) `_, +`xdg-open(1) `_, +`desktop-file-validate(1) `_ \ No newline at end of file diff --git a/docs/reference/gio/gapplication.xml b/docs/reference/gio/gapplication.xml deleted file mode 100644 index 13e3f23..0000000 --- a/docs/reference/gio/gapplication.xml +++ /dev/null @@ -1,352 +0,0 @@ - - - gapplication - GIO - - - Developer - Ryan - Lortie - - - - - - gapplication - 1 - User Commands - - - - gapplication - D-Bus application launcher - - - - - gapplication - help - COMMAND - - - gapplication - version - - - gapplication - list-apps - - - gapplication - launch - APPID - - - gapplication - launch - APPID - FILE - - - gapplication - list-actions - APPID - - - gapplication - action - APPID - ACTION - PARAMETER - - - - - Description - - - gapplication is a commandline implementation of the client-side of the - org.freedesktop.Application interface as specified by the freedesktop.org - Desktop Entry Specification. - - - - gapplication can be used to start applications that have - DBusActivatable set to true in their .desktop - files and can be used to send messages to already-running instances of other applications. - - - - It is possible for applications to refer to gapplication in the Exec - line of their .desktop file to maintain backwards compatibility - with implementations that do not directly support DBusActivatable. - - - - gapplication ships as part of GLib. - - - - - Commands - - - Global commands - - - - - help - COMMAND - - - - Displays a short synopsis of the available commands or provides detailed help on a specific - command. - - - - - - - version - - - - Prints the GLib version whence gapplication came. - - - - - - - list-apps - - - - Prints a list of all application IDs that are known to support D-Bus activation. This list is - generated by scanning .desktop files as per the current - XDG_DATA_DIRS. - - - - - - - launch - APPID - FILE - - - - Launches an application. - - - The first parameter is the application ID in the familiar "reverse DNS" style (eg: - 'org.gnome.app') without the .desktop - suffix. - - - Optionally, if additional parameters are given, they are treated as the names of files to open and - may be filenames or URIs. If no files are given then the application is simply activated. - - - - - - - list-actions - APPID - - - - List the actions declared in the application's .desktop - file. The parameter is the application ID, as above. - - - - - - - action - APPID - ACTION - PARAMETER - - - - Invokes the named action (in the same way as would occur when activating an action specified in - the .desktop file). - - - The application ID (as above) is the first parameter. The action name follows. - - - Optionally, following the action name can be one parameter, in GVariant format, given as a single - argument. Make sure to use sufficient quoting. - - - - - - - - - - Examples - - - From the commandline - - - Launching an application: - - - - gapplication launch org.example.fooview - - - - Opening a file with an application: - - - - gapplication launch org.example.fooview ~/file.foo - - - - Opening many files with an application: - - - - gapplication launch org.example.fooview ~/foos/*.foo - - - - Invoking an action on an application: - - - - gapplication action org.example.fooview create - - - - Invoking an action on an application, with an action: - - - - gapplication action org.example.fooview show-item '"item_id_828739"' - - - - - - From the <varname>Exec</varname> lines of a <filename class='extension'>.desktop</filename> file - - - - The commandline interface of gapplication was designed so that it could be used - directly from the Exec line of a .desktop - file. - - - - You might want to do this to allow for backwards compatibility with implementations of the specification - that do not understand how to do D-Bus activation, without having to install a separate utility program. - - - - Consider the following example: - - - - [Desktop Entry] - Version=1.1 - Type=Application - Name=Foo Viewer - DBusActivatable=true - MimeType=image/x-foo; - Exec=gapplication launch org.example.fooview %F - Actions=gallery;create; - - [Desktop Action gallery] - Name=Browse Gallery - Exec=gapplication action org.example.fooview gallery - - [Desktop Action create] - Name=Create a new Foo! - Exec=gapplication action org.example.fooview create - - - - - From a script - - - If installing an application that supports D-Bus activation you may still want to put a file in - /usr/bin so that your program can be started from a terminal. - - - - It is possible for this file to be a shell script. The script can handle arguments such as --help and - --version directly. It can also parse other command line arguments and convert them to uses of - gapplication to activate the application, open files, or invoke actions. - - - - Here is a simplified example, as may be installed in /usr/bin/fooview: - - - - #!/bin/sh - - case "$1" in - --help) - echo "see 'man fooview' for more information" - ;; - - --version) - echo "fooview 1.2" - ;; - - --gallery) - gapplication action org.example.fooview gallery - ;; - - --create) - gapplication action org.example.fooview create - ;; - - -*) - echo "unrecognised commandline argument" - exit 1 - ;; - - *) - gapplication launch org.example.fooview "$@" - ;; - esac - - - - - - See also - - Desktop Entry Specification, - - gdbus - 1 - , - - xdg-open - 1 - , - - desktop-file-validate - 1 - - - - - diff --git a/docs/reference/gio/gdbus-codegen.rst b/docs/reference/gio/gdbus-codegen.rst new file mode 100644 index 0000000..4a4c07f --- /dev/null +++ b/docs/reference/gio/gdbus-codegen.rst @@ -0,0 +1,805 @@ +.. _gdbus-codegen(1): +.. meta:: + :copyright: Copyright 2011, 2013, 2016 Red Hat, Inc. + :copyright: Copyright 2013, 2022 Emmanuele Bassi + :copyright: Copyright 2017 Patrick Griffis + :copyright: Copyright 2018 Iñigo Martínez + :copyright: Copyright 2018, 2019 Endless Mobile, Inc. + :copyright: Copyright 2020 Endless OS Foundation, LLC + :copyright: Copyright 2020 Chun-wei Fan + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2011, 2013, 2016 Red Hat, Inc. + SPDX-FileCopyrightText: 2013, 2022 Emmanuele Bassi + SPDX-FileCopyrightText: 2017 Patrick Griffis + SPDX-FileCopyrightText: 2018 Iñigo Martínez + SPDX-FileCopyrightText: 2018, 2019 Endless Mobile, Inc. + SPDX-FileCopyrightText: 2020 Endless OS Foundation, LLC + SPDX-FileCopyrightText: 2020 Chun-wei Fan + SPDX-License-Identifier: LGPL-2.1-or-later + +============= +gdbus-codegen +============= + +-------------------------------------- +D-Bus code and documentation generator +-------------------------------------- + +SYNOPSIS +-------- + +| **gdbus-codegen** +| [--help] +| [--interface-prefix *org.project.Prefix*] +| [--header | --body | --interface-info-header | --interface-info-body | --generate-c-code *OUTFILES*] +| [--c-namespace *YourProject*] +| [--c-generate-object-manager] +| [--c-generate-autocleanup none|objects|all] +| [--output-directory *OUTDIR* | --output *OUTFILE*] +| [--generate-docbook *OUTFILES*] +| [--generate-rst *OUTFILES*] +| [--pragma-once] +| [--xml-files *FILE*] +| [--symbol-decorator *DECORATOR* [--symbol-decorator-header *HEADER*] [--symbol-decorator-define *DEFINE*]] +| [--annotate *ELEMENT* *KEY* *VALUE*]… +| [--glib-min-required *VERSION*] +| [--glib-max-allowed *VERSION*] +| *FILE*… + +DESCRIPTION +----------- + +``gdbus-codegen`` is used to generate code and/or documentation for one or more +D-Bus interfaces. + +``gdbus-codegen`` reads +`D-Bus Introspection XML `_ +from files passed as additional arguments on the command line and generates +output files. It currently supports generating C source code (via ``--body``) or +header (via ``--header``) and DocBook XML (via ``--generate-docbook``). +Alternatively, more restricted C source code and headers can be generated, which +just contain the interface information (as ``GDBusInterfaceInfo`` structures) +using ``--interface-info-body`` and ``--interface-info-header``. + +GENERATING C CODE +----------------- + +When generating C code, a ``GInterface`` derived type is generated for each +D-Bus interface. Additionally, for every generated type, ``FooBar``, two +concrete instantiatable types, ``FooBarProxy`` and ``FooBarSkeleton``, +implementing said interface are also generated. The former is derived from +``GDBusProxy`` and intended for use on the client side while the latter is +derived from the ``GDBusInterfaceSkeleton`` type making it easy to export on a +``GDBusConnection`` either directly or via a ``GDBusObjectManagerServer`` +instance. + +For C code generation either ``--body`` that generates source code, ``--header`` +that generates headers, ``--interface-info-body`` that generates interface +information source code, or ``--interface-info-header`` that generates interface +information headers, can be used. These options must be used along with +``--output``, which is used to specify the file to output to. + +Both files can be generated at the same time by using ``--generate-c-code``, but +this option is deprecated. In this case ``--output`` cannot be used due to the +generation of multiple files. Instead pass ``--output-directory`` to specify the +directory to put the output files in. By default the current directory will be +used. + +The name of each generated C type is derived from the D-Bus interface name +stripped with the prefix given with ``--interface-prefix`` and with the dots +removed and initial characters capitalized. For example, for the D-Bus +interface ``com.acme.Coyote`` the name used is ``ComAcmeCoyote``. For the D-Bus +interface ``org.project.Bar.Frobnicator`` with ``--interface-prefix`` set to +``org.project.``, the name used is ``BarFrobnicator``. + +For methods, signals and properties, if not specified, the name defaults to the +name of the method, signal or property. + +Two forms of the name are used — the CamelCase form and the lower-case form. The +CamelCase form is used for the ``GType`` and struct name, while lower-case form +is used in function names. The lower-case form is calculated by converting from +CamelCase to lower-case and inserting underscores at word boundaries (using +certain heuristics). + +If the value given by the ``org.gtk.GDBus.C.Name`` annotation or the +``--c-namespace`` option contains an underscore (sometimes called *Ugly_Case*), +then the camel-case name is derived by removing all underscores, and the +lower-case name is derived by lower-casing the string. This is useful in some +situations where abbreviations are used. For example, if the annotation is used +on the interface ``net.MyCorp.MyApp.iSCSITarget`` with the value +``iSCSI_Target`` the CamelCase form is ``iSCSITarget`` while the lower-case form +is ``iscsi_target``. If the annotation is used on the method ``EjectTheiPod`` +with the value ``Eject_The_iPod``, the lower-case form is ``eject_the_ipod``. + +GENERATING DOCBOOK DOCUMENTATION +-------------------------------- + +Each generated DocBook XML file (see the ``--generate-docbook`` option for +details) is a ``RefEntry`` article describing the D-Bus interface. (See the +`DocBook documentation `_.) + +GENERATING RESTRUCTUREDTEXT DOCUMENTATION +----------------------------------------- + +Each generated reStructuredText file (see the ``--generate-rst`` option for +details) is a plain text +`reStructuredText `_ document +describing the D-Bus interface. + +OPTIONS +------- + +The following options are supported: + +``-h``, ``--help`` + + Show help and exit. + +``--xml-files`` *FILE* + + This option is deprecated; use positional arguments instead. The D-Bus + introspection XML file. + +``--interface-prefix`` *org.project.Prefix.* + + A prefix to strip from all D-Bus interface names when + calculating the type name for the C binding and the DocBook ``sortas`` + `attribute `_. + +``--generate-docbook`` *OUTFILES* + + Generate DocBook Documentation for each D-Bus interface and put it in + ``OUTFILES-NAME.xml`` where ``NAME`` is a placeholder for the interface + name, e.g. ``net.Corp.FooBar`` and so on. + + Pass ``--output-directory`` to specify the directory to put the output files + in. By default the current directory will be used. + +``--generate-rst`` *OUTFILES* + + Generate reStructuredText Documentation for each D-Bus interface and put it in + ``OUTFILES-NAME.rst`` where ``NAME`` is a placeholder for the interface + name, e.g. ``net.Corp.FooBar`` and so on. + + Pass ``--output-directory`` to specify the directory to put the output files + in. By default the current directory will be used. + +``--generate-c-code`` *OUTFILES* + + Generate C code for all D-Bus interfaces and put it in ``OUTFILES.c`` and + ``OUTFILES.h`` including any sub-directories. If you want the files to be + output in a different location use ``--output-directory`` as ``OUTFILES.h`` + including sub-directories will be referenced from ``OUTFILES.c``. + + The full paths would then be + ``$(OUTDIR)/$(dirname $OUTFILES)/$(basename $OUTFILES).{c,h}``. + +``--c-namespace`` *YourProject* + + The namespace to use for generated C code. This is expected to be in + `CamelCase `_ or *Ugly_Case* (see + above). + +``--pragma-once`` + + If this option is passed, the + `#pragma once `_ preprocessor + directive is used instead of include guards. + +``--c-generate-object-manager`` + + If this option is passed, suitable ``GDBusObject``, ``GDBusObjectProxy``, + ``GDBusObjectSkeleton`` and ``GDBusObjectManagerClient`` subclasses are + generated. + +``--c-generate-autocleanup`` none|objects|all + + This option influences what types autocleanup functions are + generated for. ``none`` means to not generate any autocleanup functions. + ``objects`` means to generate them for object types, and ``all`` means to + generate them for object types and interfaces. The default is ``objects`` + due to a corner case in backwards compatibility with a few projects, + but you should likely switch your project to use ``all``. + This option was added in GLib 2.50. + +``--output-directory`` *OUTDIR* + + Directory to output generated source to. Equivalent to changing directory + before generation. + + This option cannot be used with ``--body``, ``--header``, + ``--interface-info-body`` or ``--interface-info-header``; and ``--output`` + must be used. + +``--header`` + + If this option is passed, it will generate the header code and write it to the + disk by using the path and file name provided by ``--output``. + + Using ``--generate-c-code``, ``--generate-docbook`` or ``--output-directory`` + are not allowed to be used along with ``--header`` and ``--body`` options, + because these options are used to generate only one file. + +``--body`` + + If this option is passed, it will generate the source code and write it to the + disk by using the path and file name provided by ``--output``. + + Using ``--generate-c-code``, ``--generate-docbook`` or ``--output-directory`` + are not allowed to be used along with ``--header`` and ``--body`` options, + because these options are used to generate only one file. + +``--interface-info-header`` + + If this option is passed, it will generate the header code for the + ``GDBusInterfaceInfo`` structures only and will write it to the disk by using + the path and file name provided by ``--output``. + + Using ``--generate-c-code``, ``--generate-docbook`` or ``--output-directory`` + are not allowed to be used along with the ``--interface-info-header`` and + ``--interface-info-body`` options, because these options are used to generate + only one file. + +``--interface-info-body`` + + If this option is passed, it will generate the source code for the + ``GDBusInterfaceInfo`` structures only and will write it to the disk by using + the path and file name provided by ``--output``. + + Using ``--generate-c-code``, ``--generate-docbook`` or ``--output-directory`` + are not allowed to be used along with the ``--interface-info-header`` and + ``--interface-info-body`` options, because these options are used to generate + only one file. + +``--symbol-decorator`` *DECORATOR* + + If a ``DECORATOR`` is passed in with this option, all the generated function + prototypes in the generated header will be marked with ``DECORATOR``. This can + be used, for instance, to export symbols from code generated with + ``gdbus-codegen``. + + This option was added in GLib 2.66. + +``--symbol-decorator-header`` *HEADER* + + If a ``HEADER`` is passed in with this option, the generated header will put a + ``#include HEADER`` before the rest of the items, except for the inclusion + guards or ``#pragma once`` (if ``--pragma-once`` is used). This is used if + using another header file is needed for the decorator passed in via + ``--symbol-decorator`` to be defined. + + This option was added in GLib 2.66. + + This option can only be used if ``--symbol-decorator`` is used. + +``--symbol-decorator-define`` *DEFINE* + + If a ``DEFINE`` is passed in with this option, the generated source will add a + ``#define DEFINE`` before the rest of the items. This is used if a particular + macro is needed to ensure the decorator passed in via ``--symbol-decorator`` + uses the correct definition when the generated source is being compiled. + + This option was added in GLib 2.66. + + This option can only be used if ``--symbol-decorator`` is used. + +``--output`` *OUTFILE* + + The full path where the header (``--header``, ``--interface-info-header``) or + the source code (``--body``, ``--interface-info-body``) will be written, using + the path and filename provided by ``--output``. The full path could be + something like ``$($OUTFILE).{c,h}``. + + Using ``--generate-c-code``, ``--generate-docbook`` or ``--output-directory`` + is not allowed along with ``--output``, because the latter is used to generate + only one file. + +``--annotate`` *ELEMENT* *KEY* *VALUE* + + Used to inject D-Bus annotations into the given XML files. It can be used with + interfaces, methods, signals, properties and arguments in the following way:: + + gdbus-codegen --c-namespace MyApp \ + --generate-c-code myapp-generated \ + --annotate "org.project.InterfaceName" \ + org.gtk.GDBus.C.Name MyFrobnicator \ + --annotate "org.project.InterfaceName:Property" \ + bar bat \ + --annotate "org.project.InterfaceName.Method()" \ + org.freedesktop.DBus.Deprecated true \ + --annotate "org.project.InterfaceName.Method()[arg_name]" \ + snake hiss \ + --annotate "org.project.InterfaceName::Signal" \ + cat meow \ + --annotate "org.project.InterfaceName::Signal[arg_name]" \ + dog wuff \ + myapp-dbus-interfaces.xml + + Any UTF-8 string can be used for *KEY* and *VALUE*. + +``--glib-min-required`` *VERSION* + + Specifies the minimum version of GLib which the code generated by + ``gdbus-codegen`` can depend on. This may be used to make + backwards-incompatible changes in the output or behaviour of ``gdbus-codegen`` + in future, which users may opt in to by increasing the value they pass for + ``--glib-min-required``. If this option is not passed, the output from + ``gdbus-codegen`` is guaranteed to be compatible with all versions of GLib + from 2.30 upwards, as that is when ``gdbus-codegen`` was first released. + + Note that some version parameters introduce incompatible changes: all callers + of the generated code might need to be updated, and if the generated code is + part of a library’s API or ABI, then increasing the version parameter can + result in an API or ABI break. + + The version number must be of the form ``MAJOR.MINOR.MICRO``, where all parts + are integers. ``MINOR`` and ``MICRO`` are optional. The version number may not + be smaller than ``2.30``. + + If the version number is ``2.64`` or greater, the generated code will + have the following features: + + 1. If a method has ``h`` (file descriptor) parameter(s), a ``GUnixFDList`` + parameter will exist in the generated code for it (whereas previously the + annotation ``org.gtk.GDBus.C.UnixFD`` was required), and + 2. Method call functions will have two additional arguments to allow the user + to specify ``GDBusCallFlags`` and a timeout value, as is possible when + using ``g_dbus_proxy_call()``. + +``--glib-max-allowed`` *VERSION* + + Specifies the maximum version of GLib which the code generated by + ``gdbus-codegen`` can depend on. This may be used to ensure that code + generated by ``gdbus-codegen`` is compilable with specific older versions of + GLib that your software has to support. + + The version number must be of the form ``MAJOR.MINOR.MICRO``, where all parts + are integers. ``MINOR`` and ``MICRO`` are optional. The version number must be + greater than or equal to that passed to ``--glib-min-required``. + It defaults to the version of GLib which provides this ``gdbus-codegen``. + +SUPPORTED D-BUS ANNOTATIONS +--------------------------- + +The following D-Bus annotations are supported by ``gdbus-codegen``: + +``org.freedesktop.DBus.Deprecated`` + + Can be used on any ````, ````, ```` and + ```` element to specify that the element is deprecated if its value + is ``true``. Note that this annotation is defined in the + `D-Bus specification `_ + and can only assume the values ``true`` and ``false``. In particular, you + cannot specify the version that the element was deprecated in nor any helpful + deprecation message. Such information should be added to the element + documentation instead. + + When generating C code, this annotation is used to add ``G_GNUC_DEPRECATED`` + to generated functions for the element. + + When generating DocBook XML, a deprecation warning will appear along the + documentation for the element. + +``org.gtk.GDBus.Since`` + + Can be used on any ````, ````, ```` and + ```` element to specify the version (any free-form string but + compared using a version-aware sort function) the element appeared in. + + When generating C code, this field is used to ensure + function pointer order for preserving ABI/API, see ‘STABILITY GUARANTEES’. + + When generating DocBook XML, the value of this tag appears in the + documentation. + +``org.gtk.GDBus.DocString`` + + A string with DocBook content for documentation. This annotation can + be used on ````, ````, ````, ```` and + ```` elements. + +``org.gtk.GDBus.DocString.Short`` + + A string with DocBook content for short/brief documentation. This annotation + can only be used on ```` elements. + +``org.gtk.GDBus.C.Name`` + + Can be used on any ````, ````, ```` and + ```` element to specify the name to use when generating C code. The + value is expected to be in + `CamelCase `_ or *Ugly_Case* (see + above). + +``org.gtk.GDBus.C.ForceGVariant`` + + If set to a non-empty string, a ``GVariant`` instance will be used instead of + the natural C type. This annotation can be used on any ```` and + ```` element. + +``org.gtk.GDBus.C.UnixFD`` + + If set to a non-empty string, the generated code will include parameters to + exchange file descriptors using the ``GUnixFDList`` type. This annotation can + be used on ```` elements. + +As an easier alternative to using the ``org.gtk.GDBus.DocString`` annotation, +note that parser used by ``gdbus-codegen`` parses XML comments in a way similar +to `gtk-doc `_:: + + + + + + + + + + + + + + + + + + + +Note that ``@since`` can be used in any inline documentation bit (e.g. for +interfaces, methods, signals and properties) to set the ``org.gtk.GDBus.Since`` +annotation. For the ``org.gtk.GDBus.DocString`` annotation (and inline +comments), note that substrings of the form ``#net.Corp.Bar``, +``net.Corp.Bar.FooMethod()``, ``#net.Corp.Bar::BarSignal`` and +``#net.Corp.InlineDocs:BazProperty`` are all expanded to links to the respective +interface, method, signal and property. Additionally, substrings starting with +``@`` and ``%`` characters are rendered as +`parameter `_ and +`constant `_ respectively. + +If both XML comments and ``org.gtk.GDBus.DocString`` or +``org.gtk.GDBus.DocString.Short`` annotations are present, the latter wins. + +EXAMPLE +------- + +Consider the following D-Bus Introspection XML:: + + + + + + + + + + + + + + + + + + +If ``gdbus-codegen`` is used on this file like this:: + + gdbus-codegen --generate-c-code myapp-generated \ + --c-namespace MyApp \ + --interface-prefix net.corp.MyApp. \ + net.Corp.MyApp.Frobber.xml + +two files called ``myapp-generated.[ch]`` are generated. The files provide an +abstract ``GTypeInterface`` derived type called ``MyAppFrobber`` as well as two +instantiatable types with the same name but suffixed with ``Proxy`` and +``Skeleton``. The generated file, roughly, contains the following facilities:: + + /* GType macros for the three generated types */ + #define MY_APP_TYPE_FROBBER (my_app_frobber_get_type ()) + #define MY_APP_TYPE_FROBBER_SKELETON (my_app_frobber_skeleton_get_type ()) + #define MY_APP_TYPE_FROBBER_PROXY (my_app_frobber_proxy_get_type ()) + + typedef struct _MyAppFrobber MyAppFrobber; /* Dummy typedef */ + + typedef struct + { + GTypeInterface parent_iface; + + /* Signal handler for the ::notification signal */ + void (*notification) (MyAppFrobber *proxy, + GVariant *icon_blob, + gint height, + const gchar* const *messages); + + /* Signal handler for the ::handle-hello-world signal */ + gboolean (*handle_hello_world) (MyAppFrobber *proxy, + GDBusMethodInvocation *invocation, + const gchar *greeting); + } MyAppFrobberIface; + + /* Asynchronously calls HelloWorld() */ + void + my_app_frobber_call_hello_world (MyAppFrobber *proxy, + const gchar *greeting, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gp ointer user_data); + gboolean + my_app_frobber_call_hello_world_finish (MyAppFrobber *proxy, + gchar **out_response, + GAsyncResult *res, + GError **error); + + /* Synchronously calls HelloWorld(). Blocks calling thread. */ + gboolean + my_app_frobber_call_hello_world_sync (MyAppFrobber *proxy, + const gchar *greeting, + gchar **out_response, + GCancellable *cancellable, + GError **error); + + /* Completes handling the HelloWorld() method call */ + void + my_app_frobber_complete_hello_world (MyAppFrobber *object, + GDBusMethodInvocation *invocation, + const gchar *response); + + /* Emits the ::notification signal / Notification() D-Bus signal */ + void + my_app_frobber_emit_notification (MyAppFrobber *object, + GVariant *icon_blob, + gint height, + const gchar* const *messages); + + /* Gets the :verbose GObject property / Verbose D-Bus property. + * Does no blocking I/O. + */ + gboolean my_app_frobber_get_verbose (MyAppFrobber *object); + + /* Sets the :verbose GObject property / Verbose D-Bus property. + * Does no blocking I/O. + */ + void my_app_frobber_set_verbose (MyAppFrobber *object, + gboolean value); + + /* Gets the interface info */ + GDBusInterfaceInfo *my_app_frobber_interface_info (void); + + /* Creates a new skeleton object, ready to be exported */ + MyAppFrobber *my_app_frobber_skeleton_new (void); + + /* Client-side proxy constructors. + * + * Additionally, _new_for_bus(), _new_for_bus_finish() and + * _new_for_bus_sync() proxy constructors are also generated. + */ + void + my_app_frobber_proxy_new (GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GAsyncReadyCallback callback, + gpointer user_data); + MyAppFrobber * + my_app_frobber_proxy_new_finish (GAsyncResult *res, + GError **error); + MyAppFrobber * + my_app_frobber_proxy_new_sync (GDBusConnection *connection, + GDBusProxyFlags flags, + const gchar *name, + const gchar *object_path, + GCancellable *cancellable, + GError **error); + +Thus, for every D-Bus method, there will be three C functions for calling the +method, one ``GObject`` signal for handling an incoming call and one C function +for completing an incoming call. For every D-Bus signal, there’s one ``GObject`` +signal and one C function for emitting it. For every D-Bus property, two C +functions are generated (one setter, one getter) and one ``GObject`` property. +The following table summarizes the generated facilities and where they are +applicable: + +.. table:: + :widths: auto + + ==================== ========================================================= ================================================================================================================= + Symbol type Client Server + ==================== ========================================================= ================================================================================================================= + Types Use ``MyAppFrobberProxy``. Any type implementing the ``MyAppFrobber`` interface. + Methods Use ``m_a_f_hello_world()`` to call. Receive via the ``handle_hello_world()`` signal handler. Complete the call with ``m_a_f_complete_hello_world()``. + Signals Connect to the ``::notification`` signal. Use ``m_a_f_emit_notification()`` to emit signal. + Properties (Reading) Use ``m_a_f_get_verbose()`` or the ``:verbose`` property. Implement the ``get_property()`` vfunc of ``GObject``. + Properties (writing) Use ``m_a_f_set_verbose()`` or the ``:verbose`` property. Implement the ``set_property()`` vfunc of ``GObject``. + ==================== ========================================================= ================================================================================================================= + +Client-side usage +^^^^^^^^^^^^^^^^^ + +You can use the generated proxy type with the generated constructors:: + + MyAppFrobber *proxy; + GError *error; + + error = NULL; + proxy = my_app_frobber_proxy_new_for_bus_sync ( + G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_NONE, + "net.Corp.MyApp", /* bus name */ + "/net/Corp/MyApp/SomeFrobber", /* object */ + NULL, /* GCancellable* */ + &error); + /* do stuff with proxy */ + g_object_unref (proxy); + +Instead of using the generic ``GDBusProxy`` facilities, one can use the +generated methods such as ``my_app_frobber_call_hello_world()`` to invoke +the ``net.Corp.MyApp.Frobber.HelloWorld()`` D-Bus method, connect to the +``::notification`` ``GObject`` signal to receive the +``net.Corp.MyApp.Frobber::Notification`` D-Bus signal and get/set the +``net.Corp.MyApp.Frobber:Verbose`` D-Bus Property using either the ``GObject`` +property ``:verbose`` or the ``my_app_get_verbose()`` and +``my_app_set_verbose()`` methods. Use the standard ``GObject::notify`` signal to +listen to property changes. + +Note that all property access is via the ``GDBusProxy`` property cache so no I/O +is ever done when reading properties. Also note that setting a property will +cause the ``org.freedesktop.DBus.Properties.Set`` method +(`documentation `_) +to be called on the remote object. This call, however, is asynchronous so +setting a property won’t block. Further, the change is delayed and no error +checking is possible. + +Server-side usage +^^^^^^^^^^^^^^^^^ + +The generated ``MyAppFrobber`` interface is designed so it is easy to implement +it in a ``GObject`` subclass. For example, to handle ``HelloWorld()`` method +invocations, set the vfunc for ``handle_hello_hello_world()`` in the +``MyAppFrobberIface`` structure. Similarly, to handle the +``net.Corp.MyApp.Frobber:Verbose`` property override the ``:verbose`` +``GObject`` property from the subclass. To emit a signal, use e.g. +``my_app_emit_signal()`` or ``g_signal_emit_by_name()``. + +Instead of subclassing, it is often easier to use the generated +``MyAppFrobberSkeleton`` subclass. To handle incoming method calls, use +``g_signal_connect()`` with the ``::handle-*`` signals and instead of +overriding the ``get_property()`` and ``set_property()`` vfuncs from +``GObject``, use ``g_object_get()`` and ``g_object_set()`` or the generated +property getters and setters (the generated class has an internal property bag +implementation). + +For example:: + + static gboolean + on_handle_hello_world (MyAppFrobber *interface, + GDBusMethodInvocation *invocation, + const gchar *greeting, + gpointer user_data) + { + if (g_strcmp0 (greeting, "Boo") != 0) + { + gchar *response; + response = g_strdup_printf ("Word! You said ‘%s’.", greeting); + my_app_complete_hello_world (interface, invocation, response); + g_free (response); + } + else + { + g_dbus_method_invocation_return_error (invocation, + MY_APP_ERROR, + MY_APP_ERROR_NO_WHINING, + "Hey, %s, there will be no whining!", + g_dbus_method_invocation_get_sender (invocation)); + } + return TRUE; + } + + […] + + interface = my_app_frobber_skeleton_new (); + my_app_frobber_set_verbose (interface, TRUE); + + g_signal_connect (interface, + "handle-hello-world", + G_CALLBACK (on_handle_hello_world), + some_user_data); + + […] + + error = NULL; + if (!g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (interface), + connection, + "/path/of/dbus_object", + &error)) + { + /* handle error */ + } + +To facilitate atomic changesets (multiple properties changing at the same time), +``GObject::notify`` signals are queued up when received. The queue is drained in +an idle handler (which is called from the thread-default main loop of the thread +where the skeleton object was constructed) and will cause emissions of the +``org.freedesktop.DBus.Properties::PropertiesChanged`` +(`documentation `_) +signal with all the properties that have changed. Use +``g_dbus_interface_skeleton_flush()`` or ``g_dbus_object_skeleton_flush()`` to +empty the queue immediately. Use ``g_object_freeze_notify()`` and +``g_object_thaw_notify()`` for atomic changesets if on a different thread. + +C TYPE MAPPING +-------------- + +Scalar types (type strings ``b``, ``y``, ``n``, ``q``, ``i``, ``u``, ``x``, +``t`` and ``d``), strings (type strings ``s``, ``ay``, ``o`` and ``g``) and +arrays of strings (type strings ``as``, ``ao`` and ``aay``) are mapped to the +natural types, e.g. ``gboolean``, ``gdouble``, ``gint``, ``gchar*``, ``gchar**`` +and so on. Everything else is mapped to the ``GVariant`` type. + +This automatic mapping can be turned off by using the annotation +``org.gtk.GDBus.C.ForceGVariant`` — if used then a ``GVariant`` is always +exchanged instead of the corresponding native C type. This annotation may be +convenient to use when using bytestrings (type string ``ay``) for data that +could have embedded nul bytes. + +STABILITY GUARANTEES +-------------------- + +The generated C functions are guaranteed to not change their ABI. That is, if a +method, signal or property does not change its signature in the introspection +XML, the generated C functions will not change their C ABI either. The ABI of +the generated instance and class structures will be preserved as well. + +The ABI of the generated ``GType`` instances will be preserved only if the +``org.gtk.GDBus.Since`` annotation is used judiciously — this is because the +VTable for the ``GInterface`` relies on function pointers for signal handlers. +Specifically, if a D-Bus method, property or signal or is added to a D-Bus +interface, then ABI of the generated ``GInterface`` type is preserved if, and +only if, each added method, property signal is annotated with the +``org.gtk.GDBus.Since`` annotation using a greater version number than previous +versions. + +The generated C code currently happens to be annotated with +`gtk-doc `_ and +`GObject Introspection `_ comments and +annotations. The layout and contents might change in the future so no guarantees +about e.g. ``SECTION`` usage etc. are given. + +While the generated DocBook for D-Bus interfaces isn’t expected to change, no +guarantees are given at this point. + +It is important to note that the generated code should not be checked into +version control systems, nor it should be included in distributed source +archives. + +BUGS +---- + +Please send bug reports to either the distribution bug tracker or the +`upstream bug tracker `_. + +SEE ALSO +-------- + +`gdbus(1) `_ \ No newline at end of file diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml deleted file mode 100644 index 91d1f07..0000000 --- a/docs/reference/gio/gdbus-codegen.xml +++ /dev/null @@ -1,1193 +0,0 @@ - - - - gdbus - GIO - - - Developer - David - Zeuthen - zeuthen@gmail.com - - - - - - gdbus-codegen - 1 - User Commands - - - - gdbus-codegen - D-Bus code and documentation generator - - - - - gdbus-codegen - , - org.project.Prefix - OUTFILES - YourProject - - none|objects|all - OUTDIR - OUTFILES - OUTFILES - - FILE - - - - - DECORATOR - HEADER - DEFINE - OUTFILE - - - - ELEMENT - KEY - VALUE - - - VERSION - VERSION - FILE - - FILE - - - - - - Description - - gdbus-codegen is used to generate code and/or - documentation for one or more D-Bus interfaces. - - - gdbus-codegen reads - D-Bus - Introspection XML from files passed as additional - arguments on the command line and generates output files. - It currently supports generating C source code (via - ) or header (via ) - and Docbook XML (via ). Alternatively, - more restricted C source code and headers can be generated, which just - contain the interface information (as GDBusInterfaceInfo - structures) using and - . - - - - - Generating C code - - When generating C code, a - #GInterface-derived type is generated for each D-Bus - interface. Additionally, for every generated type, - FooBar, two concrete instantiatable types, - FooBarProxy and FooBarSkeleton, implementing - said interface are also generated. The former is derived from - #GDBusProxy and intended for use on the client side - while the latter is derived from the - #GDBusInterfaceSkeleton type making it easy to export on a - #GDBusConnection either directly or via a - #GDBusObjectManagerServer instance. - - - For C code generation either that - generates source code, that - generates headers, that generates - interface information source code, or - that generates interface information - headers, can be used. These options must be used along with - , which is used to specify the file to output to. - - - Both files can be generated at the same time by using - , but this option is deprecated. - In this case cannot be used due to the - generation of multiple files. Instead pass - to specify the directory to put - the output files in. By default the current directory will be used. - - - The name of each generated C type is derived from the D-Bus - interface name stripped with the prefix given with - and with the dots removed and - initial characters capitalized. For example, for the D-Bus - interface com.acme.Coyote the name used is - ComAcmeCoyote. For the D-Bus interface - org.project.Bar.Frobnicator with - - org.project., the name used is - BarFrobnicator. - - - For methods, signals and properties, if not specified, the name - defaults to the name of the method, signal or property. - - - Two forms of the name are used - the CamelCase form and the - lower-case form. The CamelCase form is used for the #GType and - struct name, while lower-case form is used in function names. The - lower-case form is calculated by converting from CamelCase to - lower-case and inserting underscores at word boundaries (using - certain heuristics). - - - If the value given by the org.gtk.GDBus.C.Name - annotation or the option contains - an underscore (sometimes called Ugly_Case), - then the camel-case name is derived by removing all underscores, - and the lower-case name is derived by lower-casing the - string. This is useful in some situations where abbreviations are - used. For example, if the annotation is used on the interface - net.MyCorp.MyApp.iSCSITarget with the value - iSCSI_Target the CamelCase form is - iSCSITarget while the lower-case form is - iscsi_target. If the annotation is used on the - method EjectTheiPod with the value - Eject_The_iPod, the lower-case form is - eject_the_ipod. - - - - - Generating Docbook documentation - - Each generated Docbook XML file (see the - option for details) is a RefEntry - article describing the D-Bus interface. - - - - - Generating reStructuredText documentation - - Each generated reStructuredText file (see the - option for details) is a plain text - reStructuredText - document describing the D-Bus interface. - - - - - Options - - The following options are supported: - - - - - , - - - Show help and exit. - - - - - - FILE - - - This option is deprecated; use positional arguments instead. - The D-Bus introspection XML file. - - - - - - org.project.Prefix. - - - A prefix to strip from all D-Bus interface names when - calculating the typename for the C binding and the Docbook - sortas - attribute. - - - - - - OUTFILES - - - Generate Docbook Documentation for each D-Bus interface and - put it in OUTFILES-NAME.xml - where NAME is a place-holder for the interface - name, e.g. net.Corp.FooBar and so on. - - - Pass to specify the directory - to put the output files in. By default the current directory - will be used. - - - - - - OUTFILES - - - Generate reStructuredText Documentation for each D-Bus interface and - put it in OUTFILES-NAME.rst - where NAME is a place-holder for the interface - name, e.g. net.Corp.FooBar and so on. - - - Pass to specify the directory - to put the output files in. By default the current directory - will be used. - - - - - - OUTFILES - - - Generate C code for all D-Bus interfaces and put it in - OUTFILES.c and - OUTFILES.h including any sub-directories. If you want the files to - be output in a different location use as OUTFILES.h - including sub-directories will be referenced from OUTFILES.c. - - - The full paths would then be $(OUTDIR)/$(dirname $OUTFILES)/$(basename $OUTFILES).{c,h}. - - - - - - YourProject - - - The namespace to use for generated C code. This is expected - to be in CamelCase - or Ugly_Case (see above). - - - - - - - - - If this option is passed, the - #pragma once - preprocessor directive is used instead of include guards. - - - - - - - - - If this option is passed, suitable #GDBusObject, - #GDBusObjectProxy, #GDBusObjectSkeleton and - #GDBusObjectManagerClient subclasses are generated. - - - - - - none|objects|all - - - This option influences what types autocleanup functions are - generated for. 'none' means to not generate any autocleanup functions. - 'objects' means to generate them for object types, and 'all' means to - generate them for object types and interfaces. The default is 'objects' - due to a corner case in backwards compatibility with a few projects, - but you should likely switch your project to use 'all'. - This option was added in GLib 2.50. - - - - - - OUTDIR - - - Directory to output generated source to. Equivalent to changing directory before generation. - - - This option cannot be used with , - , or - ; and - must be used. - - - - - - - - - - If this option is passed, it will generate the header code and write it to the disk by - using the path and file name provided by . - - - Using , or - are not allowed to be used along with - and options, because these options - are used to generate only one file. - - - - - - - - - If this option is passed, it will generate the source code and write it to the disk by - using the path and file name provided by . - - - Using , or - are not allowed to be used along with - and options, because these options - are used to generate only one file. - - - - - - - - - If this option is passed, it will generate the header code for the - GDBusInterfaceInfo structures only and will write it to - the disk by using the path and file name provided by - . - - - Using , or - are not allowed to be used along with - the and - options, because these options - are used to generate only one file. - - - - - - - - - If this option is passed, it will generate the source code for the - GDBusInterfaceInfo structures only and will write it to - the disk by using the path and file name provided by - . - - - Using , or - are not allowed to be used along with - the and - options, because these options - are used to generate only one file. - - - - - - DECORATOR - - - If a DECORATOR is passed in with this option, all the - generated function prototypes in the generated header will be marked with - DECORATOR. This can be used, for instance, to export - symbols from code generated with gdbus-codegen. - This option is added in GLib-2.66 - - - - - - HEADER - - - If a HEADER is passed in with this option, the - generated header will put a #include HEADER before the rest of the - items, except for the inclusion guards or #pragma once - (if is used). This is used if using another header file is - needed for the decorator passed in via to be defined. - This option is added in GLib-2.66. - - - This option can only be used if is used. - - - - - - DEFINE - - - If a DEFINE is passed in with this option, the - generated source will add a #define DEFINE before the rest of the - items. This is used if a particular macro is needed to ensure the decorator - passed in via uses the correct definition when the - generated source is being compiled. This option is added in GLib-2.66. - - - This option can only be used if is used. - - - - - - OUTFILE - - - The full path where the header (, - ) or the source code - (, ) will - be written, using the path and filename provided by - . The full path could be something like - $($OUTFILE).{c,h}. - - - Using , or - is not allowed along with - , because the latter is used to generate only one file. - - - - - - ELEMENT KEY VALUE - - - Used to inject D-Bus annotations into the given XML - files. It can be used with interfaces, methods, signals, - properties and arguments in the following way: - - - - Any UTF-8 string can be used for KEY and VALUE. - - - - - - VERSION - - - Specifies the minimum version of GLib which the code generated by - gdbus-codegen can depend on. This may be used to - make backwards-incompatible changes in the output or behaviour of - gdbus-codegen in future, which users may opt in to - by increasing the value they pass for . - If this option is not passed, the output from gdbus-codegen - is guaranteed to be compatible with all versions of GLib from 2.30 - upwards, as that is when gdbus-codegen was first - released. - - - Note that some version parameters introduce incompatible changes: all callers - of the generated code might need to be updated, and if the generated code is part of - a library's API or ABI, then increasing the version parameter can result in an API - or ABI break. - - - The version number must be of the form - MAJOR.MINOR.MICRO, - where all parts are integers. MINOR and - MICRO are optional. The version number may not be smaller - than 2.30. - - - If the version number is 2.64 or greater, the generated code will - have the following features: (1) If a method has h (file - descriptor) parameter(s), a GUnixFDList parameter will exist in the - generated code for it (whereas previously the annotation - org.gtk.GDBus.C.UnixFD was required), and (2) Method call functions will - have two additional arguments to allow the user to specify GDBusCallFlags - and a timeout value, as is possible when using g_dbus_proxy_call(). - - - - - - VERSION - - - Specifies the maximum version of GLib which the code generated by - gdbus-codegen can depend on. This may be used to - ensure that code generated by gdbus-codegen is - compilable with specific older versions of GLib that your software has - to support. - - - The version number must be of the form - MAJOR.MINOR.MICRO, - where all parts are integers. MINOR and - MICRO are optional. The version number must - be greater than or equal to that passed to . - It defaults to the version of GLib which provides this gdbus-codegen. - - - - - - - - - Supported D-Bus Annotations - - The following D-Bus annotations are supported by - gdbus-codegen: - - - - - - org.freedesktop.DBus.Deprecated - - - Can be used on any <interface>, - <method>, - <signal> and - <property> element to specify that - the element is deprecated if its value is - true. Note that this annotation is - defined in the D-Bus - specification and can only assume the values - true and false. In - particular, you cannot specify the version that the element - was deprecated in nor any helpful deprecation message. Such - information should be added to the element documentation - instead. - - - When generating C code, this annotation is used to add - #G_GNUC_DEPRECATED to generated functions for the element. - - - When generating Docbook XML, a deprecation warning will - appear along the documentation for the element. - - - - - - org.gtk.GDBus.Since - - - Can be used on any <interface>, - <method>, - <signal> and - <property> element to specify the - version (any free-form string but compared using a - version-aware sort function) the element appeared in. - - - When generating C code, this field is used to ensure - function pointer order for preserving ABI/API, see . - - - When generating Docbook XML, the value of this tag appears - in the documentation. - - - - - - org.gtk.GDBus.DocString - - - A string with Docbook content for documentation. This annotation can - be used on <interface>, - <method>, - <signal>, - <property> and - <arg> elements. - - - - - - org.gtk.GDBus.DocString.Short - - - A string with Docbook content for short/brief - documentation. This annotation can only be used on - <interface> elements. - - - - - - org.gtk.GDBus.C.Name - - - Can be used on any <interface>, - <method>, - <signal> and - <property> element to specify the - name to use when generating C code. The value is expected to - be in CamelCase - or Ugly_Case (see above). - - - - - - org.gtk.GDBus.C.ForceGVariant - - - If set to a non-empty string, a #GVariant instance will - be used instead of the natural C type. This annotation can - be used on any <arg> and - <property> element. - - - - - - org.gtk.GDBus.C.UnixFD - - - If set to a non-empty string, the generated code will - include parameters to exchange file descriptors using the - #GUnixFDList type. This annotation can be used on - <method> elements. - - - - - - - - As an easier alternative to using the - org.gtk.GDBus.DocString annotation, note that - parser used by gdbus-codegen parses XML - comments in a way similar to gtk-doc: -longer description. - - This is a new paragraph. ---> - - - - - - - - - - - - - - - - -]]> - - - Note that can be used in any inline - documentation bit (e.g. for interfaces, methods, signals and - properties) to set the org.gtk.GDBus.Since - annotation. For the org.gtk.GDBus.DocString - annotation (and inline comments), note that substrings of the form - , - , - and - are all - expanded to links to the respective interface, method, signal and - property. - Additionally, substrings starting with @ and % characters are rendered as - parameter and - constant respectively. - - - If both XML comments and - org.gtk.GDBus.DocString or - org.gtk.GDBus.DocString.Short annotations are - present, the latter wins. - - - - - Example - - Consider the following D-Bus Introspection XML. - - - - - - - - - - - - - - - - - -]]> - - - If gdbus-codegen is used on this file like this: - - - - two files called - myapp-generated.[ch] are - generated. The files provide an abstract - #GTypeInterface-derived type called - MyAppFrobber as well as two instantiatable types with - the same name but suffixed with Proxy and - Skeleton. The generated file, roughly, contains the - following facilities: - - - - Thus, for every D-Bus method, there will be three C functions for - calling the method, one #GObject signal for handling an incoming - call and one C function for completing an incoming call. For every - D-Bus signal, there's one #GObject signal and one C function for - emitting it. For every D-Bus property, two C functions are - generated (one setter, one getter) and one #GObject property. The - following table summarizes the generated facilities and where they - are applicable: - - - - - - - Client - Server - - - - - Types - Use MyAppFrobberProxy - Any type implementing the MyAppFrobber interface - - - Methods - Use m_a_f_hello_world() to call. - Receive via the handle_hello_world() signal handler. Complete the call with m_a_f_complete_hello_world() - - - Signals - Connect to the ::notification GObject signal. - Use m_a_f_emit_notification() to emit signal. - - - Properties (Reading) - Use m_a_f_get_verbose() or :verbose. - Implement #GObject's get_property() vfunc. - - - Properties (writing) - Use m_a_f_set_verbose() or :verbose. - Implement #GObject's set_property() vfunc. - - - - - - - Client-side usage - - You can use the generated proxy type with the generated - constructors: - - - - Instead of using the generic #GDBusProxy facilities, one can use - the generated methods such as - my_app_frobber_call_hello_world() to invoke - the net.Corp.MyApp.Frobber.HelloWorld() - D-Bus method, connect to the - ::notification GObject signal to receive - the net.Corp.MyApp.Frobber::Notification - D-Bus signal and get/set the - net.Corp.MyApp.Frobber:Verbose D-Bus - Property using either the GObject property - :verbose or the - my_app_get_verbose() and - my_app_set_verbose() methods. Use the - standard #GObject::notify signal to listen to property changes. - - - Note that all property access is via #GDBusProxy's - property cache so no I/O is ever done when reading properties. - Also note that setting a property will cause the - org.freedesktop.DBus.Properties.Set method to be - called on the remote object. This call, however, is asynchronous - so setting a property won't block. Further, the change is - delayed and no error checking is possible. - - - - - Server-side usage - - The generated MyAppFrobber interface is designed so - it is easy to implement it in a #GObject - subclass. For example, to handle - HelloWorld() method invocations, set the - vfunc for handle_hello_hello_world() in the - MyAppFrobberIface structure. Similarly, to handle - the net.Corp.MyApp.Frobber:Verbose - property override the :verbose #GObject - property from the subclass. To emit a signal, use - e.g. my_app_emit_signal() or - g_signal_emit_by_name(). - - - Instead of subclassing, it is often easier to use the generated - MyAppFrobberSkeleton subclass. To handle incoming - method calls, use g_signal_connect() with - the ::handle-* signals and instead of - overriding #GObject's - get_property() and - set_property() vfuncs, use - g_object_get() and - g_object_set() or the generated property - getters and setters (the generated class has an internal - property bag implementation). - - - - To facilitate atomic changesets (multiple properties changing at - the same time), #GObject::notify signals are queued up when - received. The queue is drained in an idle handler (which is called from the - thread-default main loop - of the thread where the skeleton object was - constructed) and will cause emissions of the org.freedesktop.DBus.Properties::PropertiesChanged - signal with all the properties that have changed. Use - g_dbus_interface_skeleton_flush() or - g_dbus_object_skeleton_flush() to empty the queue - immediately. Use g_object_freeze_notify() and - g_object_thaw_notify() for atomic changesets if on a different - thread. - - - - - - C Type Mapping - - Scalar types - (type-strings - 'b', - 'y', - 'n', - 'q', - 'i', - 'u', - 'x', - 't' and - 'd') - ), - strings (type-strings - 's', - 'ay', - 'o' and - 'g') and - arrays of string (type-strings - 'as', - 'ao' and - 'aay') - are mapped to the natural types, - e.g. #gboolean, #gdouble, #gint, gchar*, - gchar** and - so on. Everything else is mapped to the #GVariant - type. - - - This automatic mapping can be turned off by using the annotation - org.gtk.GDBus.C.ForceGVariant - if used then a - #GVariant is always exchanged instead of the - corresponding native C type. This annotation may be convenient to - use when using - bytestrings (type-string 'ay') - for data that could have embedded NUL bytes. - - - - - Stability Guarantees - - The generated C functions are guaranteed to not change their ABI. - That is, if a method, signal or property does not change its - signature in the introspection XML, the generated C functions will - not change their C ABI either. The ABI of the generated instance and - class structures will be preserved as well. - - - The ABI of the generated #GTypes will be preserved only if - the org.gtk.GDBus.Since annotation is used - judiciously — this is because the VTable for the #GInterface - relies on functions pointers for signal handlers. Specifically, if - a D-Bus method, property or signal or is added to a D-Bus - interface, then ABI of the generated #GInterface type is preserved - if, and only if, each added method, property signal is annotated - with the org.gtk.GDBus.Since annotation using - a greater version number than previous versions. - - - The generated C code currently happens to be annotated with gtk-doc / GObject - Introspection comments / annotations. The layout and - contents might change in the future so no guarantees about - e.g. SECTION usage etc. is given. - - - While the generated Docbook for D-Bus interfaces isn't expected to - change, no guarantees are given at this point. - - - It is important to note that the generated code should not be - checked into revision control systems, nor it should be included - in distributed source archives. - - - - - Bugs - - Please send bug reports to either the distribution bug tracker - or the upstream bug tracker at - https://gitlab.gnome.org/GNOME/glib/issues/new. - - - - - See also - - - gdbus1 - - - - - diff --git a/docs/reference/gio/gdbus-object-manager-example/.gitignore b/docs/reference/gio/gdbus-object-manager-example/.gitignore deleted file mode 100644 index cc8a11d..0000000 --- a/docs/reference/gio/gdbus-object-manager-example/.gitignore +++ /dev/null @@ -1 +0,0 @@ -gdbus-object-manager-example-overrides.txt diff --git a/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-docs.xml b/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-docs.xml deleted file mode 100644 index fd4c307..0000000 --- a/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-docs.xml +++ /dev/null @@ -1,19 +0,0 @@ - - -]> - - - GDBus ObjctManager Example - - Interfaces - - - - - - - - - diff --git a/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-sections.txt b/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-sections.txt deleted file mode 100644 index 1e3b8b8..0000000 --- a/docs/reference/gio/gdbus-object-manager-example/gdbus-object-manager-example-sections.txt +++ /dev/null @@ -1,161 +0,0 @@ -
-ExampleAnimal -ExampleAnimal -ExampleAnimal -ExampleAnimalIface -example_animal_interface_info -example_animal_override_properties -example_animal_call_poke -example_animal_call_poke_finish -example_animal_call_poke_sync -example_animal_complete_poke -example_animal_emit_jumped -example_animal_get_mood -example_animal_get_foo -example_animal_get_bar -example_animal_dup_mood -example_animal_dup_foo -example_animal_dup_bar -example_animal_set_mood -example_animal_set_foo -example_animal_set_bar -ExampleAnimalProxy -ExampleAnimalProxyClass -example_animal_proxy_new -example_animal_proxy_new_finish -example_animal_proxy_new_sync -example_animal_proxy_new_for_bus -example_animal_proxy_new_for_bus_finish -example_animal_proxy_new_for_bus_sync -ExampleAnimalSkeleton -ExampleAnimalSkeletonClass -example_animal_skeleton_new - -example_animal_get_type -example_animal_proxy_get_type -example_animal_skeleton_get_type -ExampleAnimalSkeletonPrivate -ExampleAnimalProxyPrivate -EXAMPLE_TYPE_ANIMAL -EXAMPLE_TYPE_ANIMAL_PROXY -EXAMPLE_TYPE_ANIMAL_SKELETON -EXAMPLE_ANIMAL -EXAMPLE_ANIMAL_GET_IFACE -EXAMPLE_ANIMAL_PROXY -EXAMPLE_ANIMAL_PROXY_CLASS -EXAMPLE_ANIMAL_PROXY_GET_CLASS -EXAMPLE_ANIMAL_SKELETON -EXAMPLE_ANIMAL_SKELETON_CLASS -EXAMPLE_ANIMAL_SKELETON_GET_CLASS -EXAMPLE_IS_ANIMAL -EXAMPLE_IS_ANIMAL_PROXY -EXAMPLE_IS_ANIMAL_PROXY_CLASS -EXAMPLE_IS_ANIMAL_SKELETON -EXAMPLE_IS_ANIMAL_SKELETON_CLASS -
- -
-ExampleCat -ExampleCat -ExampleCat -ExampleCatIface -example_cat_interface_info -example_cat_override_properties -ExampleCatProxy -ExampleCatProxyClass -example_cat_proxy_new -example_cat_proxy_new_finish -example_cat_proxy_new_sync -example_cat_proxy_new_for_bus -example_cat_proxy_new_for_bus_finish -example_cat_proxy_new_for_bus_sync -ExampleCatSkeleton -ExampleCatSkeletonClass -example_cat_skeleton_new - -example_cat_get_type -example_cat_proxy_get_type -example_cat_skeleton_get_type -ExampleCatProxyPrivate -ExampleCatSkeletonPrivate -EXAMPLE_TYPE_CAT -EXAMPLE_TYPE_CAT_PROXY -EXAMPLE_TYPE_CAT_SKELETON -EXAMPLE_CAT -EXAMPLE_CAT_GET_IFACE -EXAMPLE_CAT_PROXY -EXAMPLE_CAT_PROXY_CLASS -EXAMPLE_CAT_PROXY_GET_CLASS -EXAMPLE_CAT_SKELETON -EXAMPLE_CAT_SKELETON_CLASS -EXAMPLE_CAT_SKELETON_GET_CLASS -EXAMPLE_IS_CAT -EXAMPLE_IS_CAT_PROXY -EXAMPLE_IS_CAT_PROXY_CLASS -EXAMPLE_IS_CAT_SKELETON -EXAMPLE_IS_CAT_SKELETON_CLASS -
- -
-ExampleObject -ExampleObject -ExampleObject -ExampleObjectIface -example_object_get_animal -example_object_get_cat -example_object_peek_animal -example_object_peek_cat -ExampleObjectProxy -ExampleObjectProxyClass -example_object_proxy_new -ExampleObjectSkeleton -ExampleObjectSkeletonClass -example_object_skeleton_new -example_object_skeleton_set_animal -example_object_skeleton_set_cat - -example_object_get_type -example_object_proxy_get_type -example_object_skeleton_get_type -ExampleObjectProxyPrivate -ExampleObjectSkeletonPrivate -EXAMPLE_IS_OBJECT -EXAMPLE_IS_OBJECT_PROXY -EXAMPLE_IS_OBJECT_PROXY_CLASS -EXAMPLE_IS_OBJECT_SKELETON -EXAMPLE_IS_OBJECT_SKELETON_CLASS -EXAMPLE_OBJECT -EXAMPLE_OBJECT_GET_IFACE -EXAMPLE_OBJECT_PROXY -EXAMPLE_OBJECT_PROXY_CLASS -EXAMPLE_OBJECT_PROXY_GET_CLASS -EXAMPLE_OBJECT_SKELETON -EXAMPLE_OBJECT_SKELETON_CLASS -EXAMPLE_OBJECT_SKELETON_GET_CLASS -EXAMPLE_TYPE_OBJECT -EXAMPLE_TYPE_OBJECT_PROXY -EXAMPLE_TYPE_OBJECT_SKELETON -
- -
-ExampleObjectManagerClient -ExampleObjectManagerClient -ExampleObjectManagerClient -ExampleObjectManagerClientClass -example_object_manager_client_get_proxy_type -example_object_manager_client_new -example_object_manager_client_new_finish -example_object_manager_client_new_sync -example_object_manager_client_new_for_bus -example_object_manager_client_new_for_bus_finish -example_object_manager_client_new_for_bus_sync - -example_object_manager_client_get_type -EXAMPLE_IS_OBJECT_MANAGER_CLIENT -EXAMPLE_IS_OBJECT_MANAGER_CLIENT_CLASS -EXAMPLE_OBJECT_MANAGER_CLIENT -EXAMPLE_OBJECT_MANAGER_CLIENT_CLASS -EXAMPLE_OBJECT_MANAGER_CLIENT_GET_CLASS -EXAMPLE_TYPE_OBJECT_MANAGER_CLIENT -ExampleObjectManagerClientPrivate -
diff --git a/docs/reference/gio/gdbus-object-manager-example/meson.build b/docs/reference/gio/gdbus-object-manager-example/meson.build deleted file mode 100644 index 8a80501..0000000 --- a/docs/reference/gio/gdbus-object-manager-example/meson.build +++ /dev/null @@ -1,11 +0,0 @@ -gdbus_object_manager_example_doc = gnome.gtkdoc('gdbus-object-manager-example', - main_xml : 'gdbus-object-manager-example-docs.xml', - namespace : 'example', - dependencies : [libgdbus_example_objectmanager_dep], - src_dir : 'gio/tests/gdbus-object-manager-example', - scan_args : [ - '--rebuild-types', - ], - install : false, -) - diff --git a/docs/reference/gio/gdbus.rst b/docs/reference/gio/gdbus.rst new file mode 100644 index 0000000..b0ea98d --- /dev/null +++ b/docs/reference/gio/gdbus.rst @@ -0,0 +1,278 @@ +.. _gdbus(1): +.. meta:: + :copyright: Copyright 2010, 2011, 2012, 2020 Red Hat, Inc. + :copyright: Copyright 2015 Collabora, Ltd. + :copyright: Copyright 2021 Endless OS Foundation, LLC + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2010, 2011, 2012, 2020 Red Hat, Inc. + SPDX-FileCopyrightText: 2015 Collabora, Ltd. + SPDX-FileCopyrightText: 2021 Endless OS Foundation, LLC + SPDX-License-Identifier: LGPL-2.1-or-later + +===== +gdbus +===== + +----------------------------------- +Tool for working with D-Bus objects +----------------------------------- + +SYNOPSIS +-------- + +| **gdbus** introspect [--system | --session | --address *address*] --dest *bus_name* --object-path */path/to/object* [--xml] [--recurse] [--only-properties] +| **gdbus** monitor [--system | --session | --address *address*] --dest *bus_name* [--object-path */path/to/object*] +| **gdbus** call [--system | --session | --address *address*] --dest *bus_name* --object-path */path/to/object* --method *org.project.InterfaceName.MethodName* [--timeout *seconds* | --interactive] [*ARG*…] +| **gdbus** emit [--system | --session | --address *address*] --object-path */path/to/object* --signal *org.project.InterfaceName.SignalName* [--dest *unique_bus_name*] [*ARG*…] +| **gdbus** wait [--system | --session | --address *address*] --activate *bus_name* [--timeout *seconds*] *bus_name* +| **gdbus** help + +DESCRIPTION +----------- + +``gdbus`` is a simple tool for working with D-Bus objects. + +COMMANDS +-------- + +``introspect`` + + Prints out interfaces and property values for a remote object. For this to + work, the owner of the object needs to implement the + ``org.freedesktop.DBus.Introspectable`` interface. If the ``--xml`` option is + used, the returned introspection XML is printed, otherwise a parsed pretty + representation is printed. The ``--recurse`` option can be used to introspect + children (and their children and so on) and the ``--only-properties`` option + can be used to only print the interfaces with properties. + +``monitor`` + + Monitors one or all objects owned by the owner of ``bus_name``. + +``call`` + + Invokes a method on a remote object. Each argument to pass to the method must + be specified as a serialized ``GVariant`` except that strings do not need + explicit quotes. The return values are printed out as serialized ``GVariant`` + values. + +``emit`` + + Emits a signal. Each argument to include in the signal must be specified as a + serialized ``GVariant`` except that strings do not need explicit quotes. + +``wait`` + + Waits until ``bus_name`` is owned by some process on the bus. If the + ``--activate`` is specified, that bus name will be auto-started first. It may + be the same as the bus name being waited for, or different. + +``help`` + + Prints help and exits. + +BASH COMPLETION +--------------- + +``gdbus`` ships with a bash completion script to complete commands, +destinations, bus names, object paths and interface/method names. + +EXAMPLES +-------- + +This shows how to introspect an object — note that the value of each property is +displayed:: + + $ gdbus introspect --system \ + --dest org.freedesktop.NetworkManager \ + --object-path /org/freedesktop/NetworkManager/Devices/0 + node /org/freedesktop/NetworkManager/Devices/0 { + interface org.freedesktop.DBus.Introspectable { + methods: + Introspect(out s data); + }; + interface org.freedesktop.DBus.Properties { + methods: + Get(in s interface, + in s propname, + out v value); + Set(in s interface, + in s propname, + in v value); + GetAll(in s interface, + out a{sv} props); + }; + interface org.freedesktop.NetworkManager.Device.Wired { + signals: + PropertiesChanged(a{sv} arg_0); + properties: + readonly b Carrier = false; + readonly u Speed = 0; + readonly s HwAddress = '00:1D:72:88:BE:97'; + }; + interface org.freedesktop.NetworkManager.Device { + methods: + Disconnect(); + signals: + StateChanged(u arg_0, + u arg_1, + u arg_2); + properties: + readonly u DeviceType = 1; + readonly b Managed = true; + readwrite o Ip6Config = '/'; + readwrite o Dhcp4Config = '/'; + readwrite o Ip4Config = '/'; + readonly u State = 2; + readwrite u Ip4Address = 0; + readonly u Capabilities = 3; + readonly s Driver = 'e1000e'; + readwrite s Interface = 'eth0'; + readonly s Udi = '/sys/devices/pci0000:00/0000:00:19.0/net/eth0'; + }; + }; + +The ``--recurse`` and ``--only-properties`` options can be useful when wanting +to inspect all objects owned by a particular process:: + + $ gdbus introspect --system --dest org.freedesktop.UPower --object-path / --recurse --only-properties + node / { + node /org { + node /org/freedesktop { + node /org/freedesktop/UPower { + interface org.freedesktop.UPower { + properties: + readonly b IsDocked = true; + readonly b LidForceSleep = false; + readonly b LidIsPresent = false; + readonly b LidIsClosed = false; + readonly b OnLowBattery = false; + readonly b OnBattery = false; + readonly b CanHibernate = true; + readonly b CanSuspend = true; + readonly s DaemonVersion = '0.9.10'; + }; + node /org/freedesktop/UPower/Policy { + }; + node /org/freedesktop/UPower/Wakeups { + interface org.freedesktop.UPower.Wakeups { + properties: + readonly b HasCapability = true; + }; + }; + }; + }; + }; + }; + +In a similar fashion, the ``introspect`` command can be used to learn details +about the ``Notify`` method:: + + […] + interface org.freedesktop.Notifications { + methods: + GetServerInformation(out s return_name, + out s return_vendor, + out s return_version, + out s return_spec_version); + GetCapabilities(out as return_caps); + CloseNotification(in u id); + Notify(in s app_name, + in u id, + in s icon, + in s summary, + in s body, + in as actions, + in a{sv} hints, + in i timeout, + out u return_id); + }; + […] + +With this information, it’s easy to use the ``call`` command to display a +notification:: + + $ gdbus call --session \ + --dest org.freedesktop.Notifications \ + --object-path /org/freedesktop/Notifications \ + --method org.freedesktop.Notifications.Notify \ + my_app_name \ + 42 \ + gtk-dialog-info \ + "The Summary" \ + "Here’s the body of the notification" \ + [] \ + {} \ + 5000 + (uint32 12,) + +Call a method with file handle argument:: + + $ gdbus call --session \ + --dest org.example.foo \ + --object-path /org/example/foo \ + --method SendFDs \ + 1 \ + 10 \ + 10},) + /org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': },) + /org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': },) + /org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': },) + +Emitting a signal:: + + $ gdbus emit --session --object-path /foo --signal org.bar.Foo "['foo', 'bar', 'baz']" + +Emitting a signal to a specific process:: + + $ gdbus emit --session --object-path /bar --signal org.bar.Bar someString --dest :1.42 + +Waiting for a well-known name to be owned on the bus; this will *not* auto-start +the service:: + + $ gdbus wait --session org.bar.SomeName + +Auto-starting then waiting for a well-known name to be owned on the bus:: + + $ gdbus wait --session --activate org.bar.SomeName + +Auto-starting a different service, then waiting for a well-known name to be +owned on the bus. This is useful in situations where ``SomeName`` is not +directly activatable:: + + $ gdbus wait --session --activate org.bar.PrerequisiteName org.bar.SomeName + +Waiting for a well-known name and giving up after 30 seconds. By default, the +timeout is disabled; or set ``--timeout`` to ``0`` to disable it:: + + $ gdbus wait --session --timeout 30 org.bar.SomeName + +BUGS +---- + +Please send bug reports to either the distribution bug tracker or the +`upstream bug tracker `_. + +SEE ALSO +-------- + +`dbus-send(1) `_ \ No newline at end of file diff --git a/docs/reference/gio/gdbus.xml b/docs/reference/gio/gdbus.xml deleted file mode 100644 index 60c172e..0000000 --- a/docs/reference/gio/gdbus.xml +++ /dev/null @@ -1,429 +0,0 @@ - - - - gdbus - GIO - - - Developer - David - Zeuthen - zeuthen@gmail.com - - - - - - gdbus - 1 - User Commands - - - - gdbus - Tool for working with D-Bus objects - - - - - gdbus - introspect - - --system - --session - --address address - - --dest bus_name - --object-path /path/to/object - - --xml - - - --recurse - - - --only-properties - - - - gdbus - monitor - - --system - --session - --address address - - --dest bus_name - - --object-path /path/to/object - - - - gdbus - call - - --system - --session - --address address - - --dest bus_name - --object-path /path/to/object - --method org.project.InterfaceName.MethodName - - --timeout seconds - --interactive - - ARG1 - ARG2 - - - gdbus - emit - - --system - --session - --address address - - --object-path /path/to/object - --signal org.project.InterfaceName.SignalName - - --dest unique_bus_name - - ARG1 - ARG2 - - - gdbus - wait - - --system - --session - --address address - - --activate bus_name - - --timeout seconds - - bus_name - - - gdbus - help - - - - - Description - - gdbus is a simple tool for working with D-Bus objects. - - - - Commands - - - - - Prints out interfaces and property values for a remote object. - For this to work, the owner of the object needs to implement the - org.freedesktop.DBus.Introspectable interface. - If the option is used, the returned - introspection XML is printed, otherwise a parsed pretty - representation is printed. - The option can be used to - introspect children (and their children and so on) and the - option can be used to - only print the interfaces with properties. - - - - - - Monitors one or all objects owned by the owner of - bus_name. - - - - - - Invokes a method on a remote object. Each argument to pass to the - method must be specified as a serialized - GVariant except that strings do - not need explicit quotes. The return values are printed out as - serialized GVariant - values. - - - - - - Emits a signal. Each argument to include in the signal must be specified as a serialized - GVariant except that strings do - not need explicit quotes. - - - - - - Waits until bus_name is owned by some - process on the bus. If the is specified, - that bus name will be auto-started first. It may be the same as the - bus name being waited for, or different. - - - - - - Prints help and exit. - - - - - - - Bash Completion - - gdbus ships with a bash completion script to - complete commands, destinations, bus names, object paths and - interface/method names. - - - - - Examples - This shows how to introspect an object - note that the value of each - property is displayed: - -$ gdbus introspect --system \ - --dest org.freedesktop.NetworkManager \ - --object-path /org/freedesktop/NetworkManager/Devices/0 -node /org/freedesktop/NetworkManager/Devices/0 { - interface org.freedesktop.DBus.Introspectable { - methods: - Introspect(out s data); - }; - interface org.freedesktop.DBus.Properties { - methods: - Get(in s interface, - in s propname, - out v value); - Set(in s interface, - in s propname, - in v value); - GetAll(in s interface, - out a{sv} props); - }; - interface org.freedesktop.NetworkManager.Device.Wired { - signals: - PropertiesChanged(a{sv} arg_0); - properties: - readonly b Carrier = false; - readonly u Speed = 0; - readonly s HwAddress = '00:1D:72:88:BE:97'; - }; - interface org.freedesktop.NetworkManager.Device { - methods: - Disconnect(); - signals: - StateChanged(u arg_0, - u arg_1, - u arg_2); - properties: - readonly u DeviceType = 1; - readonly b Managed = true; - readwrite o Ip6Config = '/'; - readwrite o Dhcp4Config = '/'; - readwrite o Ip4Config = '/'; - readonly u State = 2; - readwrite u Ip4Address = 0; - readonly u Capabilities = 3; - readonly s Driver = 'e1000e'; - readwrite s Interface = 'eth0'; - readonly s Udi = '/sys/devices/pci0000:00/0000:00:19.0/net/eth0'; - }; -}; - - - The and options can be useful when wanting to inspect all objects owned by a particular process: - - -$ gdbus introspect --system --dest org.freedesktop.UPower --object-path / --recurse --only-properties -node / { - node /org { - node /org/freedesktop { - node /org/freedesktop/UPower { - interface org.freedesktop.UPower { - properties: - readonly b IsDocked = true; - readonly b LidForceSleep = false; - readonly b LidIsPresent = false; - readonly b LidIsClosed = false; - readonly b OnLowBattery = false; - readonly b OnBattery = false; - readonly b CanHibernate = true; - readonly b CanSuspend = true; - readonly s DaemonVersion = '0.9.10'; - }; - node /org/freedesktop/UPower/Policy { - }; - node /org/freedesktop/UPower/Wakeups { - interface org.freedesktop.UPower.Wakeups { - properties: - readonly b HasCapability = true; - }; - }; - }; - }; - }; -}; - - - In a similar fashion, the command can be - used to learn details about the Notify method: - - -[...] - interface org.freedesktop.Notifications { - methods: - GetServerInformation(out s return_name, - out s return_vendor, - out s return_version, - out s return_spec_version); - GetCapabilities(out as return_caps); - CloseNotification(in u id); - Notify(in s app_name, - in u id, - in s icon, - in s summary, - in s body, - in as actions, - in a{sv} hints, - in i timeout, - out u return_id); - }; -[...] - - - With this information, it's easy to use the - command to display a notification - - -$ gdbus call --session \ - --dest org.freedesktop.Notifications \ - --object-path /org/freedesktop/Notifications \ - --method org.freedesktop.Notifications.Notify \ - my_app_name \ - 42 \ - gtk-dialog-info \ - "The Summary" \ - "Here's the body of the notification" \ - [] \ - {} \ - 5000 -(uint32 12,) - - - Call a method with file handle argument: - - -$ gdbus call --session \ - --dest org.example.foo \ - --object-path /org/example/foo \ - --method SendFDs \ - 1 \ - 10 \ - 10<file.foo - - - Monitoring all objects on a service: - - -$ gdbus monitor --system --dest org.freedesktop.ConsoleKit -Monitoring signals from all objects owned by org.freedesktop.ConsoleKit -The name org.freedesktop.ConsoleKit is owned by :1.15 -/org/freedesktop/ConsoleKit/Session2: org.freedesktop.ConsoleKit.Session.ActiveChanged (false,) -/org/freedesktop/ConsoleKit/Seat1: org.freedesktop.ConsoleKit.Seat.ActiveSessionChanged ('',) -/org/freedesktop/ConsoleKit/Session2: org.freedesktop.ConsoleKit.Session.ActiveChanged (true,) -/org/freedesktop/ConsoleKit/Seat1: org.freedesktop.ConsoleKit.Seat.ActiveSessionChanged ('/org/freedesktop/ConsoleKit/Session2',) - - - Monitoring a single object on a service: - - -$ gdbus monitor --system --dest org.freedesktop.NetworkManager --object-path /org/freedesktop/NetworkManager/AccessPoint/4141 -Monitoring signals on object /org/freedesktop/NetworkManager/AccessPoint/4141 owned by org.freedesktop.NetworkManager -The name org.freedesktop.NetworkManager is owned by :1.5 -/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x5c>},) -/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x64>},) -/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x5e>},) -/org/freedesktop/NetworkManager/AccessPoint/4141: org.freedesktop.NetworkManager.AccessPoint.PropertiesChanged ({'Strength': <byte 0x64>},) - - - - Emitting a signal: - - -$ gdbus emit --session --object-path /foo --signal org.bar.Foo "['foo', 'bar', 'baz']" - - - - Emitting a signal to a specific process: - - -$ gdbus emit --session --object-path /bar --signal org.bar.Bar someString --dest :1.42 - - - - Waiting for a well-known name to be owned on the bus; this will - not auto-start the service: - - -$ gdbus wait --session org.bar.SomeName - - - - Auto-starting then waiting for a well-known name to be owned on the bus: - - -$ gdbus wait --session --activate org.bar.SomeName - - - - Auto-starting a different service, then waiting for a well-known name to be - owned on the bus. This is useful in situations where - SomeName is not directly activatable: - - -$ gdbus wait --session --activate org.bar.PrerequisiteName org.bar.SomeName - - - - Waiting for a well-known name and giving up after 30 seconds. By default, - the timeout is disabled; or set to 0 to disable it: - - -$ gdbus wait --session --timeout 30 org.bar.SomeName - - - - - - Bugs - - Please send bug reports to either the distribution bug tracker - or the upstream bug tracker at - . - - - - - See Also - - - dbus-send1 - - - - - - diff --git a/docs/reference/gio/gio-docs-unix.xml b/docs/reference/gio/gio-docs-unix.xml deleted file mode 100644 index b78edda..0000000 --- a/docs/reference/gio/gio-docs-unix.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - diff --git a/docs/reference/gio/gio-docs-win32.xml b/docs/reference/gio/gio-docs-win32.xml deleted file mode 100644 index f34a6e6..0000000 --- a/docs/reference/gio/gio-docs-win32.xml +++ /dev/null @@ -1,6 +0,0 @@ - - Win32 support - - - - diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml deleted file mode 100644 index c68bf8a..0000000 --- a/docs/reference/gio/gio-docs.xml +++ /dev/null @@ -1,418 +0,0 @@ - - - -]> - -GIO Reference Manual - - GIO Reference Manual - - for GIO &version; - The latest version of this documentation can be found on-line at - https://developer.gnome.org/gio/unstable/. - - - - - - - API Reference - - File Operations - - - - - - - - - File System Monitoring - - - - File-related Utilities - - - - Asynchronous I/O - - - - - - - - Data conversion - - - - - - - Streaming I/O - - - - - - - - - - - - - - - - - - - - - - - - - - - File types and applications - - - - - - - Volumes and Drives - - - - - - - - Icons - - - - - - - - - - Failable Initialization - - - - - Subprocesses - - - - - Low-level network support - - - - - - - - - - - - - - - - - - - High-level network functionality - - - - - - - - - - - - TLS (SSL) support - - - - - - - - - - - - - - - - DNS resolution - - - - - - - - - - - - Low-level D-Bus Support - - - - - - - - - - - - High-level D-Bus Support - - - - - - - - - - - - - - Settings - - - - - - Resources - - - - Permissions - - - - - Data Models - - - - - - Application support - - - - - - - - - - - - - - - - - - - - - - - Extending GIO - - - - - - GIO Tools - - - - - - - - - - - - GIO Testing - - - - - - - Migrating to GIO - - - - - - - - Object Hierarchy - - - - - Index - - - - Index of deprecated symbols - - - - Index of new symbols in 2.18 - - - - Index of new symbols in 2.20 - - - - Index of new symbols in 2.22 - - - - Index of new symbols in 2.24 - - - - Index of new symbols in 2.26 - - - - Index of new symbols in 2.28 - - - - Index of new symbols in 2.30 - - - - Index of new symbols in 2.32 - - - - Index of new symbols in 2.34 - - - - Index of new symbols in 2.36 - - - - Index of new symbols in 2.38 - - - - Index of new symbols in 2.40 - - - - Index of new symbols in 2.42 - - - - Index of new symbols in 2.44 - - - - Index of new symbols in 2.46 - - - - Index of new symbols in 2.48 - - - - Index of new symbols in 2.50 - - - - Index of new symbols in 2.52 - - - - Index of new symbols in 2.54 - - - - Index of new symbols in 2.56 - - - - Index of new symbols in 2.58 - - - - Index of new symbols in 2.60 - - - - Index of new symbols in 2.62 - - - - Index of new symbols in 2.64 - - - - Index of new symbols in 2.66 - - - - Index of new symbols in 2.68 - - - - Index of new symbols in 2.70 - - - - Index of new symbols in 2.72 - - - - Index of new symbols in 2.74 - - - - Index of new symbols in 2.76 - - - - Index of new symbols in 2.78 - - - - - - diff --git a/docs/reference/gio/gio-querymodules.rst b/docs/reference/gio/gio-querymodules.rst new file mode 100644 index 0000000..79141b5 --- /dev/null +++ b/docs/reference/gio/gio-querymodules.rst @@ -0,0 +1,31 @@ +.. _gio-querymodules(1): +.. meta:: + :copyright: Copyright 2010, 2012 Red Hat, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2010, 2012 Red Hat, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +================ +gio-querymodules +================ + +------------------------- +GIO module cache creation +------------------------- + +SYNOPSIS +-------- + +| **gio-querymodules** *DIRECTORY*… + +DESCRIPTION +----------- + +``gio-querymodules`` creates a ``giomodule.cache`` file in the listed +directories. This file lists the implemented extension points for each module +that has been found. It is used by GIO at runtime to avoid opening all modules +just to find out which extension points they are implementing. + +GIO modules are usually installed in the ``gio/modules`` subdirectory of libdir. \ No newline at end of file diff --git a/docs/reference/gio/gio-querymodules.xml b/docs/reference/gio/gio-querymodules.xml deleted file mode 100644 index c9c5eec..0000000 --- a/docs/reference/gio/gio-querymodules.xml +++ /dev/null @@ -1,45 +0,0 @@ - - - - glib-compile-schemas - GIO - - - Developer - Alexander - Larsson - - - - - - gio-querymodules - 1 - User Commands - - - - gio-querymodules - GIO module cache creation - - - - - gio-querymodules - DIRECTORY - - - -Description -gio-querymodules creates a -giomodule.cache file in the listed directories. -This file lists the implemented extension points for each module -that has been found. It is used by GIO at runtime to avoid opening -all modules just to find out which extension points they are implementing. - - -GIO modules are usually installed in the gio/modules -subdirectory of libdir. - - - diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt deleted file mode 100644 index 43da80c..0000000 --- a/docs/reference/gio/gio-sections-common.txt +++ /dev/null @@ -1,4808 +0,0 @@ -
-ginitable -GInitable -GInitable -GInitableIface -g_initable_init -g_initable_new -g_initable_new_valist -g_initable_newv - -G_INITABLE -G_INITABLE_GET_IFACE -G_IS_INITABLE -G_TYPE_INITABLE -G_TYPE_IS_INITABLE - -g_initable_get_type -
- -
-gasyncinitable -GAsyncInitable -GAsyncInitable -GAsyncInitableIface -g_async_initable_init_async -g_async_initable_init_finish -g_async_initable_new_async -g_async_initable_new_finish -g_async_initable_new_valist_async -g_async_initable_newv_async - -G_ASYNC_INITABLE -G_ASYNC_INITABLE_GET_IFACE -G_IS_ASYNC_INITABLE -G_TYPE_ASYNC_INITABLE -G_TYPE_IS_ASYNC_INITABLE - -g_async_initable_get_type -
- -
-gvfs -GVfs -GVfs -GVfsFileLookupFunc -G_VFS_EXTENSION_POINT_NAME -g_vfs_get_file_for_path -g_vfs_get_file_for_uri -g_vfs_parse_name -g_vfs_get_default -g_vfs_get_local -g_vfs_is_active -g_vfs_get_supported_uri_schemes -g_vfs_register_uri_scheme -g_vfs_unregister_uri_scheme - -GVfsClass -G_VFS -G_IS_VFS -G_TYPE_VFS -G_VFS_CLASS -G_IS_VFS_CLASS -G_VFS_GET_CLASS - -g_vfs_get_type -
- -
-gfile -GFile -GFile -GFileIface -GFileQueryInfoFlags -GFileCreateFlags -GFileCopyFlags -GFileMonitorFlags -GFileMeasureFlags -GFilesystemPreviewType -GFileProgressCallback -GFileReadMoreCallback -GFileMeasureProgressCallback -g_file_new_for_path -g_file_new_for_uri -g_file_new_for_commandline_arg -g_file_new_for_commandline_arg_and_cwd -g_file_new_tmp -g_file_new_tmp_async -g_file_new_tmp_finish -g_file_new_tmp_dir_async -g_file_new_tmp_dir_finish -g_file_parse_name -g_file_new_build_filename -g_file_new_build_filenamev -g_file_dup -g_file_hash -g_file_equal -g_file_get_basename -g_file_get_path -g_file_peek_path -g_file_get_uri -g_file_get_parse_name -g_file_get_parent -g_file_has_parent -g_file_get_child -g_file_get_child_for_display_name -g_file_has_prefix -g_file_get_relative_path -g_file_resolve_relative_path -g_file_is_native -g_file_has_uri_scheme -g_file_get_uri_scheme -g_file_read -g_file_read_async -g_file_read_finish -g_file_append_to -g_file_create -g_file_replace -g_file_append_to_async -g_file_append_to_finish -g_file_create_async -g_file_create_finish -g_file_replace_async -g_file_replace_finish -g_file_query_info -g_file_query_info_async -g_file_query_info_finish -g_file_query_exists -g_file_query_file_type -g_file_query_filesystem_info -g_file_query_filesystem_info_async -g_file_query_filesystem_info_finish -g_file_query_default_handler -g_file_query_default_handler_async -g_file_query_default_handler_finish -g_file_measure_disk_usage -g_file_measure_disk_usage_async -g_file_measure_disk_usage_finish -g_file_find_enclosing_mount -g_file_find_enclosing_mount_async -g_file_find_enclosing_mount_finish -g_file_enumerate_children -g_file_enumerate_children_async -g_file_enumerate_children_finish -g_file_set_display_name -g_file_set_display_name_async -g_file_set_display_name_finish -g_file_delete -g_file_delete_async -g_file_delete_finish -g_file_trash -g_file_trash_async -g_file_trash_finish -g_file_copy -g_file_copy_async -g_file_copy_finish -g_file_move -g_file_move_async -g_file_move_finish -g_file_make_directory -g_file_make_directory_async -g_file_make_directory_finish -g_file_make_directory_with_parents -g_file_make_symbolic_link -g_file_make_symbolic_link_async -g_file_make_symbolic_link_finish -g_file_query_settable_attributes -g_file_query_writable_namespaces -g_file_set_attribute -g_file_set_attributes_from_info -g_file_set_attributes_async -g_file_set_attributes_finish -g_file_set_attribute_string -g_file_set_attribute_byte_string -g_file_set_attribute_uint32 -g_file_set_attribute_int32 -g_file_set_attribute_uint64 -g_file_set_attribute_int64 -g_file_mount_mountable -g_file_mount_mountable_finish -g_file_unmount_mountable -g_file_unmount_mountable_finish -g_file_unmount_mountable_with_operation -g_file_unmount_mountable_with_operation_finish -g_file_eject_mountable -g_file_eject_mountable_finish -g_file_eject_mountable_with_operation -g_file_eject_mountable_with_operation_finish -g_file_start_mountable -g_file_start_mountable_finish -g_file_stop_mountable -g_file_stop_mountable_finish -g_file_poll_mountable -g_file_poll_mountable_finish -g_file_mount_enclosing_volume -g_file_mount_enclosing_volume_finish -g_file_monitor_directory -g_file_monitor_file -g_file_monitor -g_file_load_bytes -g_file_load_bytes_async -g_file_load_bytes_finish -g_file_load_contents -g_file_load_contents_async -g_file_load_contents_finish -g_file_load_partial_contents_async -g_file_load_partial_contents_finish -g_file_replace_contents -g_file_replace_contents_async -g_file_replace_contents_bytes_async -g_file_replace_contents_finish -g_file_build_attribute_list_for_copy -g_file_copy_attributes -g_file_create_readwrite -g_file_create_readwrite_async -g_file_create_readwrite_finish -g_file_open_readwrite -g_file_open_readwrite_async -g_file_open_readwrite_finish -g_file_replace_readwrite -g_file_replace_readwrite_async -g_file_replace_readwrite_finish -g_file_supports_thread_contexts - -G_FILE -G_IS_FILE -G_TYPE_FILE -G_FILE_GET_IFACE -G_TYPE_FILESYSTEM_PREVIEW_TYPE -G_TYPE_FILE_COPY_FLAGS -G_TYPE_FILE_CREATE_FLAGS -G_TYPE_FILE_MEASURE_FLAGS -G_TYPE_FILE_MONITOR_EVENT -G_TYPE_FILE_MONITOR_FLAGS -G_TYPE_FILE_QUERY_INFO_FLAGS - -g_file_get_type -g_file_copy_flags_get_type -g_file_create_flags_get_type -g_file_measure_flags_get_type -g_file_monitor_event_get_type -g_file_monitor_flags_get_type -g_file_query_info_flags_get_type -g_filesystem_preview_type_get_type -
- -
-gfileenumerator -GFileEnumerator -GFileEnumerator -g_file_enumerator_iterate -g_file_enumerator_next_file -g_file_enumerator_close -g_file_enumerator_next_files_async -g_file_enumerator_next_files_finish -g_file_enumerator_close_async -g_file_enumerator_close_finish -g_file_enumerator_is_closed -g_file_enumerator_has_pending -g_file_enumerator_set_pending -g_file_enumerator_get_container -g_file_enumerator_get_child - -GFileEnumeratorClass -G_FILE_ENUMERATOR -G_IS_FILE_ENUMERATOR -G_TYPE_FILE_ENUMERATOR -G_FILE_ENUMERATOR_CLASS -G_IS_FILE_ENUMERATOR_CLASS -G_FILE_ENUMERATOR_GET_CLASS - -g_file_enumerator_get_type -GFileEnumeratorPrivate -
- -
-gfileinfo -GFileInfo -GFileAttributeMatcher -GFileType -GFileInfo -G_FILE_ATTRIBUTE_STANDARD_TYPE -G_FILE_ATTRIBUTE_STANDARD_IS_HIDDEN -G_FILE_ATTRIBUTE_STANDARD_IS_BACKUP -G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK -G_FILE_ATTRIBUTE_STANDARD_IS_VIRTUAL -G_FILE_ATTRIBUTE_STANDARD_IS_VOLATILE -G_FILE_ATTRIBUTE_STANDARD_NAME -G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME -G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME -G_FILE_ATTRIBUTE_STANDARD_COPY_NAME -G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION -G_FILE_ATTRIBUTE_STANDARD_ICON -G_FILE_ATTRIBUTE_STANDARD_SYMBOLIC_ICON -G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE -G_FILE_ATTRIBUTE_STANDARD_FAST_CONTENT_TYPE -G_FILE_ATTRIBUTE_STANDARD_SIZE -G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE -G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET -G_FILE_ATTRIBUTE_STANDARD_TARGET_URI -G_FILE_ATTRIBUTE_STANDARD_SORT_ORDER -G_FILE_ATTRIBUTE_ETAG_VALUE -G_FILE_ATTRIBUTE_ID_FILE -G_FILE_ATTRIBUTE_ID_FILESYSTEM -G_FILE_ATTRIBUTE_ACCESS_CAN_READ -G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE -G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE -G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE -G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH -G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT -G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE -G_FILE_ATTRIBUTE_MOUNTABLE_UNIX_DEVICE_FILE -G_FILE_ATTRIBUTE_MOUNTABLE_HAL_UDI -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP -G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE -G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL -G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC -G_FILE_ATTRIBUTE_TIME_MODIFIED -G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC -G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC -G_FILE_ATTRIBUTE_TIME_ACCESS -G_FILE_ATTRIBUTE_TIME_ACCESS_USEC -G_FILE_ATTRIBUTE_TIME_ACCESS_NSEC -G_FILE_ATTRIBUTE_TIME_CHANGED -G_FILE_ATTRIBUTE_TIME_CHANGED_USEC -G_FILE_ATTRIBUTE_TIME_CHANGED_NSEC -G_FILE_ATTRIBUTE_TIME_CREATED -G_FILE_ATTRIBUTE_TIME_CREATED_USEC -G_FILE_ATTRIBUTE_TIME_CREATED_NSEC -G_FILE_ATTRIBUTE_UNIX_DEVICE -G_FILE_ATTRIBUTE_UNIX_INODE -G_FILE_ATTRIBUTE_UNIX_MODE -G_FILE_ATTRIBUTE_UNIX_NLINK -G_FILE_ATTRIBUTE_UNIX_UID -G_FILE_ATTRIBUTE_UNIX_GID -G_FILE_ATTRIBUTE_UNIX_RDEV -G_FILE_ATTRIBUTE_UNIX_BLOCK_SIZE -G_FILE_ATTRIBUTE_UNIX_BLOCKS -G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT -G_FILE_ATTRIBUTE_DOS_IS_ARCHIVE -G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT -G_FILE_ATTRIBUTE_DOS_IS_SYSTEM -G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG -G_FILE_ATTRIBUTE_OWNER_USER -G_FILE_ATTRIBUTE_OWNER_USER_REAL -G_FILE_ATTRIBUTE_OWNER_GROUP -G_FILE_ATTRIBUTE_THUMBNAIL_PATH -G_FILE_ATTRIBUTE_THUMBNAILING_FAILED -G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID -G_FILE_ATTRIBUTE_THUMBNAIL_PATH_NORMAL -G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_NORMAL -G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_NORMAL -G_FILE_ATTRIBUTE_THUMBNAIL_PATH_LARGE -G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_LARGE -G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_LARGE -G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XLARGE -G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XLARGE -G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XLARGE -G_FILE_ATTRIBUTE_THUMBNAIL_PATH_XXLARGE -G_FILE_ATTRIBUTE_THUMBNAILING_FAILED_XXLARGE -G_FILE_ATTRIBUTE_THUMBNAIL_IS_VALID_XXLARGE -G_FILE_ATTRIBUTE_PREVIEW_ICON -G_FILE_ATTRIBUTE_FILESYSTEM_SIZE -G_FILE_ATTRIBUTE_FILESYSTEM_FREE -G_FILE_ATTRIBUTE_FILESYSTEM_USED -G_FILE_ATTRIBUTE_FILESYSTEM_TYPE -G_FILE_ATTRIBUTE_FILESYSTEM_READONLY -G_FILE_ATTRIBUTE_FILESYSTEM_USE_PREVIEW -G_FILE_ATTRIBUTE_FILESYSTEM_REMOTE -G_FILE_ATTRIBUTE_GVFS_BACKEND -G_FILE_ATTRIBUTE_SELINUX_CONTEXT -G_FILE_ATTRIBUTE_TRASH_ITEM_COUNT -G_FILE_ATTRIBUTE_TRASH_ORIG_PATH -G_FILE_ATTRIBUTE_TRASH_DELETION_DATE -G_FILE_ATTRIBUTE_RECENT_MODIFIED -g_file_info_new -g_file_info_dup -g_file_info_copy_into -g_file_info_has_attribute -g_file_info_has_namespace -g_file_info_list_attributes -g_file_info_get_attribute_type -g_file_info_remove_attribute -g_file_info_get_attribute_as_string -g_file_info_get_attribute_data -g_file_info_get_attribute_status -g_file_info_get_attribute_string -g_file_info_get_attribute_stringv -g_file_info_get_attribute_byte_string -g_file_info_get_attribute_file_path -g_file_info_get_attribute_boolean -g_file_info_get_attribute_uint32 -g_file_info_get_attribute_int32 -g_file_info_get_attribute_uint64 -g_file_info_get_attribute_int64 -g_file_info_get_attribute_object -g_file_info_set_attribute -g_file_info_set_attribute_status -g_file_info_set_attribute_string -g_file_info_set_attribute_stringv -g_file_info_set_attribute_byte_string -g_file_info_set_attribute_file_path -g_file_info_set_attribute_boolean -g_file_info_set_attribute_uint32 -g_file_info_set_attribute_int32 -g_file_info_set_attribute_uint64 -g_file_info_set_attribute_int64 -g_file_info_set_attribute_object -g_file_info_clear_status -g_file_info_get_file_type -g_file_info_get_is_hidden -g_file_info_get_is_backup -g_file_info_get_is_symlink -g_file_info_get_name -g_file_info_get_display_name -g_file_info_get_edit_name -g_file_info_get_icon -g_file_info_get_symbolic_icon -g_file_info_get_content_type -g_file_info_get_size -g_file_info_get_modification_time -g_file_info_get_modification_date_time -g_file_info_get_access_date_time -g_file_info_get_creation_date_time -g_file_info_get_symlink_target -g_file_info_get_etag -g_file_info_get_sort_order -g_file_info_get_deletion_date -g_file_info_set_attribute_mask -g_file_info_unset_attribute_mask -g_file_info_set_file_type -g_file_info_set_is_hidden -g_file_info_set_is_symlink -g_file_info_set_name -g_file_info_set_display_name -g_file_info_set_edit_name -g_file_info_set_icon -g_file_info_set_symbolic_icon -g_file_info_set_content_type -g_file_info_set_size -g_file_info_set_modification_time -g_file_info_set_modification_date_time -g_file_info_set_access_date_time -g_file_info_set_creation_date_time -g_file_info_set_symlink_target -g_file_info_set_sort_order -g_file_attribute_matcher_new -g_file_attribute_matcher_ref -g_file_attribute_matcher_subtract -g_file_attribute_matcher_unref -g_file_attribute_matcher_matches -g_file_attribute_matcher_matches_only -g_file_attribute_matcher_enumerate_namespace -g_file_attribute_matcher_enumerate_next -g_file_attribute_matcher_to_string - -GFileInfoClass -G_FILE_INFO -G_IS_FILE_INFO -G_TYPE_FILE_INFO -G_FILE_INFO_CLASS -G_IS_FILE_INFO_CLASS -G_FILE_INFO_GET_CLASS -g_file_attribute_matcher_get_type -G_TYPE_FILE_TYPE - -g_file_info_get_type -g_file_type_get_type -
- -
-gfileattribute -GFileAttribute -GFileAttributeType -GFileAttributeInfoFlags -GFileAttributeStatus -GFileAttributeInfo -GFileAttributeInfoList -g_file_attribute_info_list_new -g_file_attribute_info_list_ref -g_file_attribute_info_list_unref -g_file_attribute_info_list_dup -g_file_attribute_info_list_lookup -g_file_attribute_info_list_add - -G_TYPE_FILE_ATTRIBUTE_INFO_FLAGS -G_TYPE_FILE_ATTRIBUTE_INFO_LIST -G_TYPE_FILE_ATTRIBUTE_MATCHER -G_TYPE_FILE_ATTRIBUTE_STATUS -G_TYPE_FILE_ATTRIBUTE_TYPE - -g_file_attribute_info_list_get_type -g_file_attribute_info_flags_get_type -g_file_attribute_status_get_type -g_file_attribute_type_get_type -
- -
-gfilemonitor -GFileMonitor -GFileMonitorEvent -GFileMonitor -g_file_monitor_cancel -g_file_monitor_is_cancelled -g_file_monitor_set_rate_limit -g_file_monitor_emit_event - -GFileMonitorClass -G_FILE_MONITOR -G_IS_FILE_MONITOR -G_TYPE_FILE_MONITOR -G_FILE_MONITOR_CLASS -G_IS_FILE_MONITOR_CLASS -G_FILE_MONITOR_GET_CLASS - -g_file_monitor_get_type -GFileMonitorPrivate -
- -
-gicon -GIcon -GIcon -GIconIface -g_icon_hash -g_icon_equal -g_icon_to_string -g_icon_new_for_string -g_icon_serialize -g_icon_deserialize - -G_ICON -G_IS_ICON -G_TYPE_ICON -G_ICON_GET_IFACE - -g_icon_get_type -
- -
-gthemedicon -GThemedIcon -GThemedIcon -g_themed_icon_new -g_themed_icon_new_from_names -g_themed_icon_new_with_default_fallbacks -g_themed_icon_prepend_name -g_themed_icon_append_name -g_themed_icon_get_names - -GThemedIconClass -G_THEMED_ICON -G_IS_THEMED_ICON -G_TYPE_THEMED_ICON -G_THEMED_ICON_CLASS -G_IS_THEMED_ICON_CLASS -G_THEMED_ICON_GET_CLASS - -g_themed_icon_get_type -
- -
-gloadableicon -GLoadableIcon -GLoadableIcon -GLoadableIconIface -g_loadable_icon_load -g_loadable_icon_load_async -g_loadable_icon_load_finish - -G_LOADABLE_ICON -G_IS_LOADABLE_ICON -G_TYPE_LOADABLE_ICON -G_LOADABLE_ICON_GET_IFACE - -g_loadable_icon_get_type -
- -
-gfileicon -GFileIcon -GFileIcon -g_file_icon_new -g_file_icon_get_file - -GFileIconClass -G_FILE_ICON -G_IS_FILE_ICON -G_TYPE_FILE_ICON -G_FILE_ICON_CLASS -G_IS_FILE_ICON_CLASS -G_FILE_ICON_GET_CLASS - -g_file_icon_get_type -
- -
-gbytesicon -GBytesIcon -GBytesIcon -g_bytes_icon_new -g_bytes_icon_get_bytes - -G_BYTES_ICON -G_IS_BYTES_ICON -G_TYPE_BYTES_ICON - -g_bytes_icon_get_type -
- -
-gemblemedicon -GEmblemedIcon -GEmblemedIcon -g_emblemed_icon_new -g_emblemed_icon_get_icon -g_emblemed_icon_get_emblems -g_emblemed_icon_add_emblem -g_emblemed_icon_clear_emblems - -GEmblemedIconClass -G_EMBLEMED_ICON -G_EMBLEMED_ICON_CLASS -G_EMBLEMED_ICON_GET_CLASS -G_IS_EMBLEMED_ICON -G_IS_EMBLEMED_ICON_CLASS -G_TYPE_EMBLEMED_ICON - - -GEmblemedIconPrivate -g_emblemed_icon_get_type -
- -
-gemblem -GEmblem -GEmblem -GEmblemOrigin -g_emblem_new -g_emblem_new_with_origin -g_emblem_get_icon -g_emblem_get_origin - -GEmblemClass -g_emblem_get_type -G_EMBLEM -G_EMBLEM_CLASS -G_EMBLEM_GET_CLASS -G_IS_EMBLEM -G_IS_EMBLEM_CLASS -G_TYPE_EMBLEM -G_TYPE_EMBLEM_ORIGIN -g_emblem_origin_get_type -
- -
-ginputstream -GInputStream -GInputStream -g_input_stream_read -g_input_stream_read_all -g_input_stream_read_all_async -g_input_stream_read_all_finish -g_input_stream_skip -g_input_stream_close -g_input_stream_read_async -g_input_stream_read_finish -g_input_stream_skip_async -g_input_stream_skip_finish -g_input_stream_close_async -g_input_stream_close_finish -g_input_stream_is_closed -g_input_stream_has_pending -g_input_stream_set_pending -g_input_stream_clear_pending -g_input_stream_read_bytes -g_input_stream_read_bytes_async -g_input_stream_read_bytes_finish - -GInputStreamClass -G_INPUT_STREAM -G_IS_INPUT_STREAM -G_TYPE_INPUT_STREAM -G_INPUT_STREAM_CLASS -G_IS_INPUT_STREAM_CLASS -G_INPUT_STREAM_GET_CLASS - -g_input_stream_get_type -GInputStreamPrivate -
- -
-gfileinputstream -GFileInputStream -GFileInputStream -g_file_input_stream_query_info -g_file_input_stream_query_info_async -g_file_input_stream_query_info_finish - -GFileInputStreamClass -G_FILE_INPUT_STREAM -G_IS_FILE_INPUT_STREAM -G_TYPE_FILE_INPUT_STREAM -G_FILE_INPUT_STREAM_CLASS -G_IS_FILE_INPUT_STREAM_CLASS -G_FILE_INPUT_STREAM_GET_CLASS - -g_file_input_stream_get_type -GFileInputStreamPrivate -
- -
-gfilterinputstream -GFilterInputStream -GFilterInputStream -g_filter_input_stream_get_base_stream -g_filter_input_stream_get_close_base_stream -g_filter_input_stream_set_close_base_stream - -GFilterInputStreamClass -G_FILTER_INPUT_STREAM -G_IS_FILTER_INPUT_STREAM -G_TYPE_FILTER_INPUT_STREAM -G_FILTER_INPUT_STREAM_CLASS -G_IS_FILTER_INPUT_STREAM_CLASS -G_FILTER_INPUT_STREAM_GET_CLASS - -g_filter_input_stream_get_type -
- -
-gunixinputstream -GUnixInputStream -GUnixInputStream -g_unix_input_stream_new -g_unix_input_stream_set_close_fd -g_unix_input_stream_get_close_fd -g_unix_input_stream_get_fd - -GUnixInputStreamClass -G_UNIX_INPUT_STREAM -G_IS_UNIX_INPUT_STREAM -G_TYPE_UNIX_INPUT_STREAM -G_UNIX_INPUT_STREAM_CLASS -G_IS_UNIX_INPUT_STREAM_CLASS -G_UNIX_INPUT_STREAM_GET_CLASS - -g_unix_input_stream_get_type -GUnixInputStreamPrivate -
- -
-gmemoryinputstream -GMemoryInputStream -GMemoryInputStream -g_memory_input_stream_new -g_memory_input_stream_new_from_data -g_memory_input_stream_new_from_bytes -g_memory_input_stream_add_data -g_memory_input_stream_add_bytes - -GMemoryInputStreamClass -G_MEMORY_INPUT_STREAM -G_IS_MEMORY_INPUT_STREAM -G_TYPE_MEMORY_INPUT_STREAM -G_MEMORY_INPUT_STREAM_CLASS -G_IS_MEMORY_INPUT_STREAM_CLASS -G_MEMORY_INPUT_STREAM_GET_CLASS - -GMemoryInputStreamPrivate -g_memory_input_stream_get_type -
- -
-gdatainputstream -GDataInputStream -GDataInputStream -GDataStreamByteOrder -GDataStreamNewlineType -g_data_input_stream_new -g_data_input_stream_set_byte_order -g_data_input_stream_get_byte_order -g_data_input_stream_set_newline_type -g_data_input_stream_get_newline_type -g_data_input_stream_read_byte -g_data_input_stream_read_int16 -g_data_input_stream_read_uint16 -g_data_input_stream_read_int32 -g_data_input_stream_read_uint32 -g_data_input_stream_read_int64 -g_data_input_stream_read_uint64 -g_data_input_stream_read_line -g_data_input_stream_read_line_utf8 -g_data_input_stream_read_line_async -g_data_input_stream_read_line_finish -g_data_input_stream_read_line_finish_utf8 -g_data_input_stream_read_upto -g_data_input_stream_read_upto_async -g_data_input_stream_read_upto_finish -g_data_input_stream_read_until -g_data_input_stream_read_until_async -g_data_input_stream_read_until_finish - -GDataInputStreamClass -G_DATA_INPUT_STREAM -G_IS_DATA_INPUT_STREAM -G_TYPE_DATA_INPUT_STREAM -G_DATA_INPUT_STREAM_CLASS -G_IS_DATA_INPUT_STREAM_CLASS -G_DATA_INPUT_STREAM_GET_CLASS -G_TYPE_DATA_STREAM_BYTE_ORDER -G_TYPE_DATA_STREAM_NEWLINE_TYPE - -g_data_input_stream_get_type -GDataInputStreamPrivate -g_data_stream_byte_order_get_type -g_data_stream_newline_type_get_type -
- -
-gbufferedinputstream -GBufferedInputStream -GBufferedInputStream -g_buffered_input_stream_new -g_buffered_input_stream_new_sized -g_buffered_input_stream_get_buffer_size -g_buffered_input_stream_set_buffer_size -g_buffered_input_stream_get_available -g_buffered_input_stream_peek_buffer -g_buffered_input_stream_peek -g_buffered_input_stream_fill -g_buffered_input_stream_fill_async -g_buffered_input_stream_fill_finish -g_buffered_input_stream_read_byte - -GBufferedInputStreamClass -G_BUFFERED_INPUT_STREAM -G_IS_BUFFERED_INPUT_STREAM -G_TYPE_BUFFERED_INPUT_STREAM -G_BUFFERED_INPUT_STREAM_CLASS -G_IS_BUFFERED_INPUT_STREAM_CLASS -G_BUFFERED_INPUT_STREAM_GET_CLASS - -g_buffered_input_stream_get_type -GBufferedInputStreamPrivate -
- -
-goutputstream -GOutputStream -GOutputStreamSpliceFlags -GOutputStream -g_output_stream_write -g_output_stream_write_all -g_output_stream_write_all_async -g_output_stream_write_all_finish -g_output_stream_writev -g_output_stream_writev_all -g_output_stream_writev_async -g_output_stream_writev_finish -g_output_stream_writev_all_async -g_output_stream_writev_all_finish -g_output_stream_splice -g_output_stream_flush -g_output_stream_close -g_output_stream_write_async -g_output_stream_write_finish -g_output_stream_splice_async -g_output_stream_splice_finish -g_output_stream_flush_async -g_output_stream_flush_finish -g_output_stream_close_async -g_output_stream_close_finish -g_output_stream_is_closing -g_output_stream_is_closed -g_output_stream_has_pending -g_output_stream_set_pending -g_output_stream_clear_pending -g_output_stream_write_bytes -g_output_stream_write_bytes_async -g_output_stream_write_bytes_finish -g_output_stream_printf -g_output_stream_vprintf - -GOutputStreamClass -G_OUTPUT_STREAM -G_IS_OUTPUT_STREAM -G_TYPE_OUTPUT_STREAM -G_OUTPUT_STREAM_CLASS -G_IS_OUTPUT_STREAM_CLASS -G_OUTPUT_STREAM_GET_CLASS -G_TYPE_OUTPUT_STREAM_SPLICE_FLAGS - -g_output_stream_get_type -GOutputStreamPrivate -g_output_stream_splice_flags_get_type -
- -
-gfileoutputstream -GFileOutputStream -GFileOutputStream -g_file_output_stream_query_info -g_file_output_stream_query_info_async -g_file_output_stream_query_info_finish -g_file_output_stream_get_etag - -GFileOutputStreamClass -G_FILE_OUTPUT_STREAM -G_IS_FILE_OUTPUT_STREAM -G_TYPE_FILE_OUTPUT_STREAM -G_FILE_OUTPUT_STREAM_CLASS -G_IS_FILE_OUTPUT_STREAM_CLASS -G_FILE_OUTPUT_STREAM_GET_CLASS - -g_file_output_stream_get_type -GFileOutputStreamPrivate -
- -
-gfilteroutputstream -GFilterOutputStream -GFilterOutputStream -g_filter_output_stream_get_base_stream -g_filter_output_stream_get_close_base_stream -g_filter_output_stream_set_close_base_stream - -GFilterOutputStreamClass -G_FILTER_OUTPUT_STREAM -G_IS_FILTER_OUTPUT_STREAM -G_TYPE_FILTER_OUTPUT_STREAM -G_FILTER_OUTPUT_STREAM_CLASS -G_IS_FILTER_OUTPUT_STREAM_CLASS -G_FILTER_OUTPUT_STREAM_GET_CLASS - -g_filter_output_stream_get_type -
- -
-gbufferedoutputstream -GBufferedOutputStream -GBufferedOutputStream -g_buffered_output_stream_new -g_buffered_output_stream_new_sized -g_buffered_output_stream_get_buffer_size -g_buffered_output_stream_set_buffer_size -g_buffered_output_stream_get_auto_grow -g_buffered_output_stream_set_auto_grow - -GBufferedOutputStreamClass -G_BUFFERED_OUTPUT_STREAM -G_IS_BUFFERED_OUTPUT_STREAM -G_TYPE_BUFFERED_OUTPUT_STREAM -G_BUFFERED_OUTPUT_STREAM_CLASS -G_IS_BUFFERED_OUTPUT_STREAM_CLASS -G_BUFFERED_OUTPUT_STREAM_GET_CLASS - -g_buffered_output_stream_get_type -GBufferedOutputStreamPrivate -
- -
-gmemoryoutputstream -GMemoryOutputStream -GReallocFunc -GMemoryOutputStream -g_memory_output_stream_new -g_memory_output_stream_new_resizable -g_memory_output_stream_get_data -g_memory_output_stream_get_size -g_memory_output_stream_get_data_size -g_memory_output_stream_steal_data -g_memory_output_stream_steal_as_bytes - -GMemoryOutputStreamClass -G_MEMORY_OUTPUT_STREAM -G_IS_MEMORY_OUTPUT_STREAM -G_TYPE_MEMORY_OUTPUT_STREAM -G_MEMORY_OUTPUT_STREAM_CLASS -G_IS_MEMORY_OUTPUT_STREAM_CLASS -G_MEMORY_OUTPUT_STREAM_GET_CLASS - -g_memory_output_stream_get_type -GMemoryOutputStreamPrivate -
- -
-gdataoutputstream -GDataOutputStream -GDataOutputStream -g_data_output_stream_new -g_data_output_stream_set_byte_order -g_data_output_stream_get_byte_order -g_data_output_stream_put_byte -g_data_output_stream_put_int16 -g_data_output_stream_put_uint16 -g_data_output_stream_put_int32 -g_data_output_stream_put_uint32 -g_data_output_stream_put_int64 -g_data_output_stream_put_uint64 -g_data_output_stream_put_string - -GDataOutputStreamClass -G_DATA_OUTPUT_STREAM -G_IS_DATA_OUTPUT_STREAM -G_TYPE_DATA_OUTPUT_STREAM -G_DATA_OUTPUT_STREAM_CLASS -G_IS_DATA_OUTPUT_STREAM_CLASS -G_DATA_OUTPUT_STREAM_GET_CLASS - -g_data_output_stream_get_type -GDataOutputStreamPrivate -
- -
-gunixoutputstream -GUnixOutputStream -GUnixOutputStream -g_unix_output_stream_new -g_unix_output_stream_set_close_fd -g_unix_output_stream_get_close_fd -g_unix_output_stream_get_fd - -GUnixOutputStreamClass -G_UNIX_OUTPUT_STREAM -G_IS_UNIX_OUTPUT_STREAM -G_TYPE_UNIX_OUTPUT_STREAM -G_UNIX_OUTPUT_STREAM_CLASS -G_IS_UNIX_OUTPUT_STREAM_CLASS -G_UNIX_OUTPUT_STREAM_GET_CLASS - -g_unix_output_stream_get_type -GUnixOutputStreamPrivate -
- -
-giostream -GIOStream -GIOStreamSpliceFlags -GIOStream -g_io_stream_get_input_stream -g_io_stream_get_output_stream -g_io_stream_splice_async -g_io_stream_splice_finish -g_io_stream_close -g_io_stream_close_async -g_io_stream_close_finish -g_io_stream_is_closed -g_io_stream_has_pending -g_io_stream_set_pending -g_io_stream_clear_pending - -GIOStreamClass -G_IO_STREAM -G_IO_STREAM_CLASS -G_IO_STREAM_GET_CLASS -G_IS_IO_STREAM -G_IS_IO_STREAM_CLASS -G_TYPE_IO_STREAM -G_TYPE_IO_STREAM_SPLICE_FLAGS - -GIOStreamPrivate -GIOStreamAdapter -g_io_stream_get_type -g_io_stream_splice_flags_get_type -
- -
-gsimpleiostream -GSimpleIOStream -GSimpleIOStream -g_simple_io_stream_new - -GIOStreamClass -G_TYPE_SIMPLE_IO_STREAM -G_IS_SIMPLE_IO_STREAM -G_SIMPLE_IO_STREAM - -g_simple_io_stream_get_type -
- -
-gfileiostream -GFileIOStream -GFileIOStream -g_file_io_stream_get_etag -g_file_io_stream_query_info -g_file_io_stream_query_info_async -g_file_io_stream_query_info_finish - -GFileIOStreamClass -G_FILE_IO_STREAM -G_FILE_IO_STREAM_CLASS -G_FILE_IO_STREAM_GET_CLASS -G_IS_FILE_IO_STREAM -G_IS_FILE_IO_STREAM_CLASS -G_TYPE_FILE_IO_STREAM - -GFileIOStreamPrivate -g_file_io_stream_get_type -
- -
-gseekable -GSeekable -GSeekable -GSeekableIface -g_seekable_tell -g_seekable_can_seek -g_seekable_seek -g_seekable_can_truncate -g_seekable_truncate - -G_SEEKABLE -G_IS_SEEKABLE -G_TYPE_SEEKABLE -G_SEEKABLE_GET_IFACE - -g_seekable_get_type -
- -
-gvolumemonitor -GVolumeMonitor -GVolumeMonitor -G_VOLUME_MONITOR_EXTENSION_POINT_NAME -g_volume_monitor_get -g_volume_monitor_get_connected_drives -g_volume_monitor_get_volumes -g_volume_monitor_get_mounts -g_volume_monitor_adopt_orphan_mount -g_volume_monitor_get_mount_for_uuid -g_volume_monitor_get_volume_for_uuid - -GVolumeMonitorClass -G_VOLUME_MONITOR -G_IS_VOLUME_MONITOR -G_TYPE_VOLUME_MONITOR -G_VOLUME_MONITOR_CLASS -G_IS_VOLUME_MONITOR_CLASS -G_VOLUME_MONITOR_GET_CLASS - -g_volume_monitor_get_type -
- -
-gmount -GMount -GMount -GMountIface -g_mount_get_name -g_mount_get_uuid -g_mount_get_icon -g_mount_get_symbolic_icon -g_mount_get_drive -g_mount_get_root -g_mount_get_volume -g_mount_get_default_location -g_mount_can_unmount -GMountMountFlags -GMountUnmountFlags -g_mount_unmount -g_mount_unmount_finish -g_mount_unmount_with_operation -g_mount_unmount_with_operation_finish -g_mount_remount -g_mount_remount_finish -g_mount_can_eject -g_mount_eject -g_mount_eject_finish -g_mount_eject_with_operation -g_mount_eject_with_operation_finish -g_mount_guess_content_type -g_mount_guess_content_type_finish -g_mount_guess_content_type_sync -g_mount_is_shadowed -g_mount_shadow -g_mount_unshadow -g_mount_get_sort_key - -G_IS_MOUNT -G_MOUNT -G_MOUNT_GET_IFACE -G_TYPE_MOUNT -G_TYPE_MOUNT_MOUNT_FLAGS -G_TYPE_MOUNT_UNMOUNT_FLAGS - -g_mount_get_type -g_mount_mount_flags_get_type -g_mount_unmount_flags_get_type -
- -
-gvolume -GVolume -GVolume -GVolumeIface -g_volume_get_name -g_volume_get_uuid -g_volume_get_icon -g_volume_get_symbolic_icon -g_volume_get_drive -g_volume_get_mount -g_volume_can_mount -g_volume_should_automount -g_volume_get_activation_root -g_volume_mount -g_volume_mount_finish -g_volume_can_eject -g_volume_eject -g_volume_eject_finish -g_volume_eject_with_operation -g_volume_eject_with_operation_finish -G_VOLUME_IDENTIFIER_KIND_HAL_UDI -G_VOLUME_IDENTIFIER_KIND_LABEL -G_VOLUME_IDENTIFIER_KIND_NFS_MOUNT -G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE -G_VOLUME_IDENTIFIER_KIND_UUID -G_VOLUME_IDENTIFIER_KIND_CLASS -g_volume_enumerate_identifiers -g_volume_get_identifier -g_volume_get_sort_key - -G_VOLUME -G_IS_VOLUME -G_TYPE_VOLUME -G_VOLUME_GET_IFACE - -g_volume_get_type -
- -
-gdrive -GDrive -GDrive -GDriveIface -GDriveStartFlags -GDriveStartStopType -g_drive_get_name -g_drive_get_icon -g_drive_get_symbolic_icon -g_drive_has_volumes -g_drive_get_volumes -g_drive_can_eject -g_drive_get_start_stop_type -g_drive_can_start -g_drive_can_start_degraded -g_drive_can_stop -g_drive_can_poll_for_media -g_drive_poll_for_media -g_drive_poll_for_media_finish -g_drive_has_media -g_drive_is_media_check_automatic -g_drive_is_removable -g_drive_is_media_removable -g_drive_eject -g_drive_eject_finish -g_drive_eject_with_operation -g_drive_eject_with_operation_finish -g_drive_start -g_drive_start_finish -g_drive_stop -g_drive_stop_finish -g_drive_enumerate_identifiers -g_drive_get_identifier -g_drive_get_sort_key -G_DRIVE_IDENTIFIER_KIND_UNIX_DEVICE - -G_DRIVE -G_IS_DRIVE -G_TYPE_DRIVE -G_DRIVE_GET_IFACE -G_TYPE_DRIVE_START_FLAGS -G_TYPE_DRIVE_START_STOP_TYPE - -g_drive_get_type -g_drive_start_flags_get_type -g_drive_start_stop_type_get_type -
- -
-gcancellable -GCancellable -GCancellable -g_cancellable_new -g_cancellable_is_cancelled -g_cancellable_set_error_if_cancelled -g_cancellable_get_fd -g_cancellable_make_pollfd -g_cancellable_release_fd -g_cancellable_source_new -GCancellableSourceFunc -g_cancellable_get_current -g_cancellable_pop_current -g_cancellable_push_current -g_cancellable_reset -g_cancellable_connect -g_cancellable_disconnect -g_cancellable_cancel - -GCancellableClass -G_CANCELLABLE -G_IS_CANCELLABLE -G_TYPE_CANCELLABLE -G_CANCELLABLE_CLASS -G_IS_CANCELLABLE_CLASS -G_CANCELLABLE_GET_CLASS - -GCancellablePrivate -g_cancellable_get_type -
- -
-gasyncresult -GAsyncResult -GAsyncResult -GAsyncResultIface -GAsyncReadyCallback -g_async_result_get_user_data -g_async_result_get_source_object -g_async_result_is_tagged -g_async_result_legacy_propagate_error - -G_ASYNC_RESULT -G_IS_ASYNC_RESULT -G_TYPE_ASYNC_RESULT -G_ASYNC_RESULT_GET_IFACE - -g_async_result_get_type -
- -
-gsimpleasyncresult -GSimpleAsyncResult -GSimpleAsyncResult -GSimpleAsyncThreadFunc -g_simple_async_result_new -g_simple_async_result_new_error -g_simple_async_result_new_from_error -g_simple_async_result_new_take_error -g_simple_async_result_set_check_cancellable -g_simple_async_result_set_op_res_gpointer -g_simple_async_result_get_op_res_gpointer -g_simple_async_result_set_op_res_gssize -g_simple_async_result_get_op_res_gssize -g_simple_async_result_set_op_res_gboolean -g_simple_async_result_get_op_res_gboolean -g_simple_async_result_get_source_tag -g_simple_async_result_is_valid -g_simple_async_result_set_handle_cancellation -g_simple_async_result_complete -g_simple_async_result_complete_in_idle -g_simple_async_result_run_in_thread -g_simple_async_result_set_from_error -g_simple_async_result_take_error -g_simple_async_result_propagate_error -g_simple_async_result_set_error -g_simple_async_result_set_error_va -g_simple_async_report_error_in_idle -g_simple_async_report_gerror_in_idle -g_simple_async_report_take_gerror_in_idle - -GSimpleAsyncResultClass -G_SIMPLE_ASYNC_RESULT -G_IS_SIMPLE_ASYNC_RESULT -G_TYPE_SIMPLE_ASYNC_RESULT -G_SIMPLE_ASYNC_RESULT_CLASS -G_IS_SIMPLE_ASYNC_RESULT_CLASS -G_SIMPLE_ASYNC_RESULT_GET_CLASS - -g_simple_async_result_get_type -
- -
-gioscheduler -GIOScheduler -GIOSchedulerJob -GIOSchedulerJobFunc -g_io_scheduler_push_job -g_io_scheduler_cancel_all_jobs -g_io_scheduler_job_send_to_mainloop -g_io_scheduler_job_send_to_mainloop_async -
- -
-gioerror -GIOError -G_IO_ERROR -GIOErrorEnum -g_io_error_from_errno -g_io_error_from_file_error -g_io_error_from_win32_error - -G_TYPE_IO_ERROR_ENUM - -g_io_error_quark -g_io_error_enum_get_type -
- -
-gcontenttype -GContentType -g_content_type_equals -g_content_type_is_a -g_content_type_is_mime_type -g_content_type_is_unknown -g_content_type_get_description -g_content_type_get_mime_type -g_content_type_get_icon -g_content_type_get_symbolic_icon -g_content_type_get_generic_icon_name -g_content_type_can_be_executable -g_content_type_from_mime_type -g_content_type_guess -g_content_type_guess_for_tree -g_content_types_get_registered -
- -
-gappinfo -GAppInfo -GAppInfoCreateFlags -GAppInfo -GAppInfoIface -GAppLaunchContext -g_app_info_create_from_commandline -g_app_info_dup -g_app_info_equal -g_app_info_get_id -g_app_info_get_name -g_app_info_get_display_name -g_app_info_get_description -g_app_info_get_executable -g_app_info_get_commandline -g_app_info_get_icon -g_app_info_launch -g_app_info_supports_files -g_app_info_supports_uris -g_app_info_launch_uris -g_app_info_launch_uris_async -g_app_info_launch_uris_finish -g_app_info_should_show -g_app_info_can_delete -g_app_info_delete -g_app_info_reset_type_associations -g_app_info_set_as_default_for_type -g_app_info_set_as_default_for_extension -g_app_info_set_as_last_used_for_type -g_app_info_add_supports_type -g_app_info_can_remove_supports_type -g_app_info_remove_supports_type -g_app_info_get_supported_types -g_app_info_get_all -g_app_info_get_all_for_type -g_app_info_get_default_for_type -g_app_info_get_default_for_type_async -g_app_info_get_default_for_type_finish -g_app_info_get_default_for_uri_scheme -g_app_info_get_default_for_uri_scheme_async -g_app_info_get_default_for_uri_scheme_finish -g_app_info_get_fallback_for_type -g_app_info_get_recommended_for_type -g_app_info_launch_default_for_uri -g_app_info_launch_default_for_uri_async -g_app_info_launch_default_for_uri_finish -g_app_launch_context_setenv -g_app_launch_context_unsetenv -g_app_launch_context_get_environment -g_app_launch_context_get_display -g_app_launch_context_get_startup_notify_id -g_app_launch_context_launch_failed -g_app_launch_context_new - -GAppLaunchContextClass -G_APP_INFO -G_IS_APP_INFO -G_TYPE_APP_INFO -G_APP_INFO_GET_IFACE -G_APP_LAUNCH_CONTEXT -G_APP_LAUNCH_CONTEXT_CLASS -G_APP_LAUNCH_CONTEXT_GET_CLASS -G_IS_APP_LAUNCH_CONTEXT -G_IS_APP_LAUNCH_CONTEXT_CLASS -G_TYPE_APP_LAUNCH_CONTEXT -G_TYPE_APP_INFO_CREATE_FLAGS - -g_app_info_get_type -g_app_info_create_flags_get_type -g_app_launch_context_get_type -GAppLaunchContextPrivate -
- -
-gappinfomonitor -GAppInfoMonitor -g_app_info_monitor_get - -GAppInfoMonitor -G_APP_INFO_MONITOR -G_IS_APP_INFO_MONITOR -G_TYPE_APP_INFO_MONITOR - -g_app_info_monitor_get_type -
- -
-gmountoperation -GMountOperation -GAskPasswordFlags -GPasswordSave -GMountOperation -GMountOperationResult -g_mount_operation_new -g_mount_operation_get_username -g_mount_operation_set_username -g_mount_operation_get_password -g_mount_operation_set_password -g_mount_operation_get_anonymous -g_mount_operation_set_anonymous -g_mount_operation_get_domain -g_mount_operation_set_domain -g_mount_operation_get_password_save -g_mount_operation_set_password_save -g_mount_operation_get_choice -g_mount_operation_set_choice -g_mount_operation_get_is_tcrypt_hidden_volume -g_mount_operation_set_is_tcrypt_hidden_volume -g_mount_operation_get_is_tcrypt_system_volume -g_mount_operation_set_is_tcrypt_system_volume -g_mount_operation_get_pim -g_mount_operation_set_pim -g_mount_operation_reply - -GMountOperationClass -G_MOUNT_OPERATION -G_IS_MOUNT_OPERATION -G_TYPE_MOUNT_OPERATION -G_MOUNT_OPERATION_CLASS -G_IS_MOUNT_OPERATION_CLASS -G_MOUNT_OPERATION_GET_CLASS -G_TYPE_ASK_PASSWORD_FLAGS -G_TYPE_MOUNT_OPERATION_RESULT -G_TYPE_PASSWORD_SAVE - -g_mount_operation_get_type -g_ask_password_flags_get_type -GMountOperationPrivate -g_mount_operation_result_get_type -g_password_save_get_type -
- -
-gfilenamecompleter -GFilenameCompleter -GFilenameCompleter -g_filename_completer_new -g_filename_completer_get_completion_suffix -g_filename_completer_get_completions -g_filename_completer_set_dirs_only - -GFilenameCompleterClass -G_FILENAME_COMPLETER -G_IS_FILENAME_COMPLETER -G_TYPE_FILENAME_COMPLETER -G_FILENAME_COMPLETER_CLASS -G_IS_FILENAME_COMPLETER_CLASS -G_FILENAME_COMPLETER_GET_CLASS - -g_filename_completer_get_type -
- -
-gunixmounts -Unix Mounts -GUnixMountPoint -GUnixMountEntry -GUnixMountMonitor -g_unix_mount_free -g_unix_mount_compare -g_unix_mount_copy -g_unix_mount_get_mount_path -g_unix_mount_get_device_path -g_unix_mount_get_root_path -g_unix_mount_get_fs_type -g_unix_mount_get_options -g_unix_mount_is_readonly -g_unix_mount_is_system_internal -g_unix_mount_guess_icon -g_unix_mount_guess_symbolic_icon -g_unix_mount_guess_name -g_unix_mount_guess_can_eject -g_unix_mount_guess_should_display -g_unix_mount_point_free -g_unix_mount_point_compare -g_unix_mount_point_copy -g_unix_mount_point_get_mount_path -g_unix_mount_point_get_device_path -g_unix_mount_point_get_fs_type -g_unix_mount_point_get_options -g_unix_mount_point_is_readonly -g_unix_mount_point_is_user_mountable -g_unix_mount_point_is_loopback -g_unix_mount_point_guess_icon -g_unix_mount_point_guess_symbolic_icon -g_unix_mount_point_guess_name -g_unix_mount_point_guess_can_eject -g_unix_mount_points_get -g_unix_mount_point_at -g_unix_mounts_get -g_unix_mount_at -g_unix_mount_for -g_unix_mounts_changed_since -g_unix_mount_points_changed_since -g_unix_mount_monitor_get -g_unix_mount_monitor_new -g_unix_mount_monitor_set_rate_limit -g_unix_is_mount_path_system_internal -g_unix_is_system_fs_type -g_unix_is_system_device_path - -GUnixMountMonitorClass -G_UNIX_MOUNT_MONITOR -G_IS_UNIX_MOUNT_MONITOR -G_TYPE_UNIX_MOUNT_MONITOR -G_UNIX_MOUNT_MONITOR_CLASS -G_IS_UNIX_MOUNT_MONITOR_CLASS -G_TYPE_UNIX_MOUNT_ENTRY -G_TYPE_UNIX_MOUNT_POINT - -g_unix_mount_monitor_get_type -g_unix_mount_entry_get_type -g_unix_mount_point_get_type -
- -
-gdesktopappinfo -Desktop file based GAppInfo -GDesktopAppInfo -g_desktop_app_info_new_from_filename -g_desktop_app_info_new_from_keyfile -g_desktop_app_info_new -g_desktop_app_info_get_filename -g_desktop_app_info_get_is_hidden -g_desktop_app_info_get_nodisplay -g_desktop_app_info_get_show_in -g_desktop_app_info_get_generic_name -g_desktop_app_info_get_categories -g_desktop_app_info_get_keywords -g_desktop_app_info_get_startup_wm_class -g_desktop_app_info_set_desktop_env -g_desktop_app_info_get_string -g_desktop_app_info_get_locale_string -g_desktop_app_info_get_boolean -g_desktop_app_info_get_string_list -g_desktop_app_info_has_key -GDesktopAppLaunchCallback -g_desktop_app_info_launch_uris_as_manager -g_desktop_app_info_launch_uris_as_manager_with_fds - -g_desktop_app_info_list_actions -g_desktop_app_info_get_action_name -g_desktop_app_info_launch_action - -g_desktop_app_info_search -g_desktop_app_info_get_implementations - -GDesktopAppInfoLookup -GDesktopAppInfoLookupIface -G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME - -GDesktopAppInfoClass -G_TYPE_DESKTOP_APP_INFO -G_DESKTOP_APP_INFO -G_DESKTOP_APP_INFO_CLASS -G_IS_DESKTOP_APP_INFO -G_IS_DESKTOP_APP_INFO_CLASS -G_DESKTOP_APP_INFO_GET_CLASS -G_DESKTOP_APP_INFO_LOOKUP -G_DESKTOP_APP_INFO_LOOKUP_GET_IFACE -G_IS_DESKTOP_APP_INFO_LOOKUP -G_TYPE_DESKTOP_APP_INFO_LOOKUP - -g_desktop_app_info_get_type -g_desktop_app_info_lookup_get_default_for_uri_scheme -g_desktop_app_info_lookup_get_type -
- -
-giomodule -GIOModule -GIOModule -GIOModuleScope -GIOModuleScopeFlags -g_io_module_new -g_io_module_scope_block -g_io_module_scope_free -g_io_module_scope_new -g_io_modules_load_all_in_directory -g_io_modules_load_all_in_directory_with_scope -g_io_modules_scan_all_in_directory -g_io_modules_scan_all_in_directory_with_scope -g_io_module_load -g_io_module_unload -g_io_module_query - -GIOModuleClass -G_IO_MODULE -G_IO_IS_MODULE -G_IO_TYPE_MODULE -G_IO_MODULE_CLASS -G_IO_IS_MODULE_CLASS -G_IO_MODULE_GET_CLASS -G_TYPE_IO_MODULE_SCOPE_FLAGS - -g_io_module_get_type -g_io_module_scope_flags_get_type -
- -
-extensionpoints -Extension Points -GIOExtension -GIOExtensionPoint -g_io_extension_get_name -g_io_extension_get_priority -g_io_extension_get_type -g_io_extension_point_get_extension_by_name -g_io_extension_point_get_extensions -g_io_extension_point_get_required_type -g_io_extension_point_implement -g_io_extension_point_lookup -g_io_extension_point_register -g_io_extension_point_set_required_type -g_io_extension_ref_class -
- -
-gunixfdlist -GUnixFDList -GUnixFDList -g_unix_fd_list_new_from_array -g_unix_fd_list_new -g_unix_fd_list_get_length -g_unix_fd_list_get -g_unix_fd_list_peek_fds -g_unix_fd_list_steal_fds -g_unix_fd_list_append - -GUnixFDListClass -G_UNIX_FD_LIST -G_UNIX_FD_LIST_CLASS -G_IS_UNIX_FD_LIST -G_IS_UNIX_FD_LIST_CLASS -G_UNIX_FD_LIST_GET_CLASS -G_TYPE_UNIX_FD_LIST - -GUnixFDListPrivate -g_unix_fd_list_get_type -
- -
-ginetaddress -GInetAddress -GInetAddress -g_inet_address_new_from_string -g_inet_address_new_from_bytes -g_inet_address_new_any -g_inet_address_new_loopback -g_inet_address_equal -g_inet_address_to_bytes -g_inet_address_get_native_size -g_inet_address_to_string -g_inet_address_get_family -g_inet_address_get_is_any -g_inet_address_get_is_loopback -g_inet_address_get_is_link_local -g_inet_address_get_is_site_local -g_inet_address_get_is_multicast -g_inet_address_get_is_mc_link_local -g_inet_address_get_is_mc_node_local -g_inet_address_get_is_mc_site_local -g_inet_address_get_is_mc_org_local -g_inet_address_get_is_mc_global - -GInetAddressClass -GInetAddressPrivate -G_INET_ADDRESS -G_INET_ADDRESS_CLASS -G_INET_ADDRESS_GET_CLASS -G_IS_INET_ADDRESS -G_IS_INET_ADDRESS_CLASS -G_TYPE_INET_ADDRESS - -g_inet_address_get_type -
- -
-ginetaddressmask -GInetAddressMask -GInetAddressMask -g_inet_address_mask_new -g_inet_address_mask_new_from_string -g_inet_address_mask_to_string -g_inet_address_mask_get_family -g_inet_address_mask_get_address -g_inet_address_mask_get_length -g_inet_address_mask_matches -g_inet_address_mask_equal - -GInetAddressMaskClass -GInetAddressMaskPrivate -G_INET_ADDRESS_MASK -G_INET_ADDRESS_MASK_CLASS -G_INET_ADDRESS_MASK_GET_CLASS -G_IS_INET_ADDRESS_MASK -G_IS_INET_ADDRESS_MASK_CLASS -G_TYPE_INET_ADDRESS_MASK - -g_inet_address_mask_get_type -
- -
-gsocketaddress -GSocketAddress -GSocketAddress -GSocketFamily -g_socket_address_new_from_native -g_socket_address_get_family -g_socket_address_to_native -g_socket_address_get_native_size - -GSocketAddressClass -G_IS_SOCKET_ADDRESS -G_IS_SOCKET_ADDRESS_CLASS -G_SOCKET_ADDRESS -G_SOCKET_ADDRESS_CLASS -G_SOCKET_ADDRESS_GET_CLASS -G_TYPE_SOCKET_ADDRESS -G_TYPE_SOCKET_FAMILY - -g_socket_address_get_type -g_socket_family_get_type -
- -
-ginetsocketaddress -GInetSocketAddress -GInetSocketAddress -g_inet_socket_address_new -g_inet_socket_address_new_from_string -g_inet_socket_address_get_address -g_inet_socket_address_get_port -g_inet_socket_address_get_flowinfo -g_inet_socket_address_get_scope_id - -GInetSocketAddressClass -GInetSocketAddressPrivate -G_INET_SOCKET_ADDRESS -G_INET_SOCKET_ADDRESS_CLASS -G_INET_SOCKET_ADDRESS_GET_CLASS -G_IS_INET_SOCKET_ADDRESS -G_IS_INET_SOCKET_ADDRESS_CLASS -G_TYPE_INET_SOCKET_ADDRESS - -g_inet_socket_address_get_type -
- -
-gunixsocketaddress -GUnixSocketAddress -GUnixSocketAddress -GUnixSocketAddressType -g_unix_socket_address_new -g_unix_socket_address_new_abstract -g_unix_socket_address_new_with_type -g_unix_socket_address_get_is_abstract -g_unix_socket_address_get_address_type -g_unix_socket_address_get_path -g_unix_socket_address_get_path_len -g_unix_socket_address_abstract_names_supported - -GUnixSocketAddressClass -GUnixSocketAddressPrivate -G_IS_UNIX_SOCKET_ADDRESS -G_IS_UNIX_SOCKET_ADDRESS_CLASS -G_TYPE_UNIX_SOCKET_ADDRESS -G_UNIX_SOCKET_ADDRESS -G_UNIX_SOCKET_ADDRESS_CLASS -G_UNIX_SOCKET_ADDRESS_GET_CLASS -G_TYPE_UNIX_SOCKET_ADDRESS_TYPE - -g_unix_socket_address_get_type -g_unix_socket_address_type_get_type -
- -
-gnativesocketaddress -GNativeSocketAddress -GNativeSocketAddress -g_native_socket_address_new - -GNativeSocketAddressClass -GNativeSocketAddressPrivate -G_IS_NATIVE_SOCKET_ADDRESS -G_IS_NATIVE_SOCKET_ADDRESS_CLASS -G_TYPE_NATIVE_SOCKET_ADDRESS -G_NATIVE_SOCKET_ADDRESS -G_NATIVE_SOCKET_ADDRESS_CLASS -G_NATIVE_SOCKET_ADDRESS_GET_CLASS -G_TYPE_NATIVE_SOCKET_ADDRESS_TYPE - -g_native_socket_address_get_type -
- -
-gresolver -GResolver -GResolver -g_resolver_get_default -g_resolver_set_default -g_resolver_lookup_by_name -g_resolver_lookup_by_name_async -g_resolver_lookup_by_name_finish -GResolverNameLookupFlags -g_resolver_lookup_by_name_with_flags -g_resolver_lookup_by_name_with_flags_async -g_resolver_lookup_by_name_with_flags_finish -g_resolver_free_addresses -g_resolver_lookup_by_address -g_resolver_lookup_by_address_async -g_resolver_lookup_by_address_finish -g_resolver_lookup_service -g_resolver_lookup_service_async -g_resolver_lookup_service_finish -g_resolver_free_targets -g_resolver_get_timeout -g_resolver_set_timeout - -GResolverRecordType -g_resolver_lookup_records -g_resolver_lookup_records_async -g_resolver_lookup_records_finish - - -G_RESOLVER_ERROR -GResolverError - - -GResolverClass -G_IS_RESOLVER -G_IS_RESOLVER_CLASS -G_RESOLVER -G_RESOLVER_CLASS -G_RESOLVER_GET_CLASS -G_TYPE_RESOLVER -G_TYPE_RESOLVER_ERROR -G_TYPE_RESOLVER_RECORD_TYPE -G_TYPE_RESOLVER_NAME_LOOKUP_FLAGS - - -GResolverPrivate -g_resolver_get_type -g_resolver_error_quark -g_resolver_record_type_get_type -g_resolver_error_get_type -g_resolver_name_lookup_flags_get_type -
- -
-gsrvtarget -GSrvTarget -GSrvTarget -g_srv_target_new -g_srv_target_copy -g_srv_target_free -g_srv_target_get_hostname -g_srv_target_get_port -g_srv_target_get_priority -g_srv_target_get_weight -g_srv_target_list_sort - -G_TYPE_SRV_TARGET - -g_srv_target_get_type -
- -
-gsocketconnectable -GSocketConnectable -GSocketConnectable -GSocketConnectableIface -g_socket_connectable_enumerate -g_socket_connectable_proxy_enumerate -g_socket_connectable_to_string - -G_IS_SOCKET_CONNECTABLE -G_SOCKET_CONNECTABLE -G_SOCKET_CONNECTABLE_GET_IFACE -G_TYPE_SOCKET_CONNECTABLE - -g_socket_connectable_get_type -
- -
-gsocketaddressenumerator -GSocketAddressEnumerator -GSocketAddressEnumerator -GSocketAddressEnumeratorClass -g_socket_address_enumerator_next -g_socket_address_enumerator_next_async -g_socket_address_enumerator_next_finish - -G_IS_SOCKET_ADDRESS_ENUMERATOR -G_IS_SOCKET_ADDRESS_ENUMERATOR_CLASS -G_SOCKET_ADDRESS_ENUMERATOR -G_SOCKET_ADDRESS_ENUMERATOR_CLASS -G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS -G_TYPE_SOCKET_ADDRESS_ENUMERATOR - -g_socket_address_enumerator_get_type -
- -
-gproxyaddressenumerator -GProxyAddressEnumerator -GProxyAddressEnumerator -GProxyAddressEnumeratorClass - -G_IS_PROXY_ADDRESS_ENUMERATOR -G_IS_PROXY_ADDRESS_ENUMERATOR_CLASS -G_PROXY_ADDRESS_ENUMERATOR -G_PROXY_ADDRESS_ENUMERATOR_CLASS -G_PROXY_ADDRESS_ENUMERATOR_GET_CLASS -G_TYPE_PROXY_ADDRESS_ENUMERATOR - -GProxyAddressEnumeratorPrivate -g_proxy_address_enumerator_get_type -
- -
-gnetworkaddress -GNetworkAddress -GNetworkAddress -g_network_address_new -g_network_address_new_loopback -g_network_address_parse -g_network_address_parse_uri -g_network_address_get_hostname -g_network_address_get_port -g_network_address_get_scheme - -GNetworkAddressClass -GNetworkAddressPrivate -G_IS_NETWORK_ADDRESS -G_IS_NETWORK_ADDRESS_CLASS -G_NETWORK_ADDRESS -G_NETWORK_ADDRESS_CLASS -G_NETWORK_ADDRESS_GET_CLASS -G_TYPE_NETWORK_ADDRESS - -g_network_address_get_type -
- -
-gnetworkservice -GNetworkService -GNetworkService -g_network_service_new -g_network_service_get_service -g_network_service_get_protocol -g_network_service_get_domain -g_network_service_get_scheme -g_network_service_set_scheme - -GNetworkServiceClass -GNetworkServicePrivate -G_IS_NETWORK_SERVICE -G_IS_NETWORK_SERVICE_CLASS -G_NETWORK_SERVICE -G_NETWORK_SERVICE_CLASS -G_NETWORK_SERVICE_GET_CLASS -G_TYPE_NETWORK_SERVICE - -g_network_service_get_type -
- -
-gdatagrambased -GDatagramBased -GDatagramBased -GDatagramBasedInterface -GDatagramBasedSourceFunc -g_datagram_based_receive_messages -g_datagram_based_send_messages -g_datagram_based_create_source -g_datagram_based_condition_check -g_datagram_based_condition_wait - -G_DATAGRAM_BASED -G_DATAGRAM_BASED_GET_IFACE -G_IS_DATAGRAM_BASED -G_TYPE_DATAGRAM_BASED -G_TYPE_IS_DATAGRAM_BASED - -g_datagram_based_get_type -
- -
-gsocket -GSocket -GSocket -GSocketSourceFunc -GSocketType -GSocketProtocol -GSocketMsgFlags -GInputVector -GInputMessage -GOutputVector -GOutputMessage -g_socket_new -g_socket_new_from_fd -g_socket_bind -g_socket_listen -g_socket_accept -g_socket_connect -g_socket_check_connect_result -g_socket_receive -g_socket_receive_from -g_socket_receive_message -g_socket_receive_messages -g_socket_receive_with_blocking -g_socket_send -g_socket_send_to -g_socket_send_message -g_socket_send_message_with_timeout -g_socket_send_messages -g_socket_send_with_blocking -g_socket_close -g_socket_is_closed -g_socket_shutdown -g_socket_is_connected -g_socket_create_source -g_socket_condition_check -g_socket_condition_wait -g_socket_condition_timed_wait -g_socket_get_available_bytes -g_socket_set_listen_backlog -g_socket_get_listen_backlog -g_socket_get_blocking -g_socket_set_blocking -g_socket_get_keepalive -g_socket_set_keepalive -g_socket_get_timeout -g_socket_set_timeout -g_socket_set_ttl -g_socket_get_ttl -g_socket_get_broadcast -g_socket_set_broadcast -g_socket_get_option -g_socket_set_option -g_socket_get_family -g_socket_get_fd -g_socket_get_local_address -g_socket_get_protocol -g_socket_get_remote_address -g_socket_get_socket_type -g_socket_speaks_ipv4 -g_socket_get_credentials - -g_socket_join_multicast_group -g_socket_leave_multicast_group -g_socket_join_multicast_group_ssm -g_socket_leave_multicast_group_ssm -g_socket_get_multicast_loopback -g_socket_set_multicast_loopback -g_socket_get_multicast_ttl -g_socket_set_multicast_ttl - -GSocketClass -G_IS_SOCKET -G_IS_SOCKET_CLASS -G_SOCKET -G_SOCKET_CLASS -G_TYPE_SOCKET -G_SOCKET_GET_CLASS -G_TYPE_SOCKET_MSG_FLAGS -G_TYPE_SOCKET_PROTOCOL -G_TYPE_SOCKET_TYPE - -g_socket_get_type -GSocketPrivate -g_socket_msg_flags_get_type -g_socket_protocol_get_type -g_socket_type_get_type -
- -
-gsocketclient -GSocketClient -GSocketClient -GSocketClientEvent -g_socket_client_new -g_socket_client_connect -g_socket_client_connect_async -g_socket_client_connect_finish -g_socket_client_connect_to_host -g_socket_client_connect_to_host_async -g_socket_client_connect_to_host_finish -g_socket_client_connect_to_service -g_socket_client_connect_to_service_async -g_socket_client_connect_to_service_finish -g_socket_client_connect_to_uri -g_socket_client_connect_to_uri_async -g_socket_client_connect_to_uri_finish -g_socket_client_set_family -g_socket_client_set_local_address -g_socket_client_set_protocol -g_socket_client_set_socket_type -g_socket_client_set_timeout -g_socket_client_set_enable_proxy -g_socket_client_set_proxy_resolver -g_socket_client_set_tls -g_socket_client_set_tls_validation_flags -g_socket_client_get_family -g_socket_client_get_local_address -g_socket_client_get_protocol -g_socket_client_get_socket_type -g_socket_client_get_timeout -g_socket_client_get_enable_proxy -g_socket_client_get_proxy_resolver -g_socket_client_get_tls -g_socket_client_get_tls_validation_flags -g_socket_client_add_application_proxy - -GSocketClientClass -G_IS_SOCKET_CLIENT -G_IS_SOCKET_CLIENT_CLASS -G_SOCKET_CLIENT -G_SOCKET_CLIENT_CLASS -G_SOCKET_CLIENT_GET_CLASS -G_TYPE_SOCKET_CLIENT -G_TYPE_SOCKET_CLIENT_EVENT - -GSocketClientPrivate -g_socket_client_get_type -g_socket_client_event_get_type -
- -
-gsocketconnection -GSocketConnection -GSocketConnection -g_socket_connection_connect -g_socket_connection_connect_async -g_socket_connection_connect_finish - -g_socket_connection_is_connected -g_socket_connection_get_local_address -g_socket_connection_get_remote_address -g_socket_connection_get_socket - -g_socket_connection_factory_create_connection -g_socket_connection_factory_lookup_type -g_socket_connection_factory_register_type - -GSocketConnectionClass -G_IS_SOCKET_CONNECTION -G_IS_SOCKET_CONNECTION_CLASS -G_SOCKET_CONNECTION -G_SOCKET_CONNECTION_CLASS -G_SOCKET_CONNECTION_GET_CLASS -G_TYPE_SOCKET_CONNECTION - -GSocketConnectionPrivate -g_socket_connection_get_type -
- -
-gunixconnection -GUnixConnection -GUnixConnection -g_unix_connection_receive_fd -g_unix_connection_send_fd -g_unix_connection_receive_credentials -g_unix_connection_receive_credentials_async -g_unix_connection_receive_credentials_finish -g_unix_connection_send_credentials -g_unix_connection_send_credentials_async -g_unix_connection_send_credentials_finish - -GUnixConnectionClass -G_IS_UNIX_CONNECTION -G_IS_UNIX_CONNECTION_CLASS -G_TYPE_UNIX_CONNECTION -G_UNIX_CONNECTION -G_UNIX_CONNECTION_CLASS -G_UNIX_CONNECTION_GET_CLASS - -GUnixConnectionPrivate -g_unix_connection_get_type -
- -
-gtcpconnection -GTcpConnection -GTcpConnection -g_tcp_connection_set_graceful_disconnect -g_tcp_connection_get_graceful_disconnect - -GTcpConnectionClass -G_IS_TCP_CONNECTION -G_IS_TCP_CONNECTION_CLASS -G_TYPE_TCP_CONNECTION -G_TCP_CONNECTION -G_TCP_CONNECTION_CLASS -G_TCP_CONNECTION_GET_CLASS - -GTcpConnectionPrivate -g_tcp_connection_get_type -
- -
-gtcpwrapperconnection -GTcpWrapperConnection -GTcpWrapperConnection -g_tcp_wrapper_connection_new -g_tcp_wrapper_connection_get_base_io_stream - -GTcpWrapperConnectionClass -G_IS_TCP_WRAPPER_CONNECTION -G_IS_TCP_WRAPPER_CONNECTION_CLASS -G_TYPE_TCP_WRAPPER_CONNECTION -G_TCP_WRAPPER_CONNECTION -G_TCP_WRAPPER_CONNECTION_CLASS -G_TCP_WRAPPER_CONNECTION_GET_CLASS - -GTcpWrapperConnectionPrivate -g_tcp_wrapper_connection_get_type -
- -
-gsocketcontrolmessage -GSocketControlMessage -GSocketControlMessage -g_socket_control_message_deserialize -g_socket_control_message_get_level -g_socket_control_message_get_msg_type -g_socket_control_message_get_size -g_socket_control_message_serialize - -GSocketControlMessageClass -G_IS_SOCKET_CONTROL_MESSAGE -G_IS_SOCKET_CONTROL_MESSAGE_CLASS -G_SOCKET_CONTROL_MESSAGE -G_SOCKET_CONTROL_MESSAGE_CLASS -G_SOCKET_CONTROL_MESSAGE_GET_CLASS -G_TYPE_SOCKET_CONTROL_MESSAGE - -GSocketControlMessagePrivate -g_socket_control_message_get_type -
- -
-gsocketlistener -GSocketListener -GSocketListener -GSocketListenerEvent -g_socket_listener_new -g_socket_listener_add_socket -g_socket_listener_add_address -g_socket_listener_add_inet_port -g_socket_listener_add_any_inet_port -g_socket_listener_accept -g_socket_listener_accept_async -g_socket_listener_accept_finish -g_socket_listener_accept_socket -g_socket_listener_accept_socket_async -g_socket_listener_accept_socket_finish -g_socket_listener_close -g_socket_listener_set_backlog - -GSocketListenerClass -G_IS_SOCKET_LISTENER -G_IS_SOCKET_LISTENER_CLASS -G_SOCKET_LISTENER -G_SOCKET_LISTENER_CLASS -G_SOCKET_LISTENER_GET_CLASS -G_TYPE_SOCKET_LISTENER -G_TYPE_SOCKET_LISTENER_EVENT - -GSocketListenerPrivate -g_socket_listener_get_type -g_socket_listener_event_get_type -
- -
-gsocketservice -GSocketService -GSocketService -g_socket_service_new -g_socket_service_start -g_socket_service_stop -g_socket_service_is_active - -GSocketServiceClass -G_IS_SOCKET_SERVICE -G_IS_SOCKET_SERVICE_CLASS -G_SOCKET_SERVICE -G_SOCKET_SERVICE_CLASS -G_SOCKET_SERVICE_GET_CLASS -G_TYPE_SOCKET_SERVICE - -GSocketServicePrivate -g_socket_service_get_type -
- -
-gthreadedsocketservice -GThreadedSocketService -GThreadedSocketService -g_threaded_socket_service_new - -GThreadedSocketServiceClass -G_IS_THREADED_SOCKET_SERVICE -G_IS_THREADED_SOCKET_SERVICE_CLASS -G_THREADED_SOCKET_SERVICE -G_THREADED_SOCKET_SERVICE_CLASS -G_THREADED_SOCKET_SERVICE_GET_CLASS -G_TYPE_THREADED_SOCKET_SERVICE - -GThreadedSocketServicePrivate -g_threaded_socket_service_get_type -
- -
-gunixfdmessage -GUnixFDMessage -GUnixFDMessage -g_unix_fd_message_new_with_fd_list -g_unix_fd_message_new -g_unix_fd_message_get_fd_list -g_unix_fd_message_append_fd -g_unix_fd_message_steal_fds - -GUnixFDMessageClass -G_IS_UNIX_FD_MESSAGE -G_IS_UNIX_FD_MESSAGE_CLASS -G_TYPE_UNIX_FD_MESSAGE -G_UNIX_FD_MESSAGE -G_UNIX_FD_MESSAGE_CLASS -G_UNIX_FD_MESSAGE_GET_CLASS - -GUnixFDMessagePrivate -g_unix_fd_message_get_type -
- -
-gconverter -GConverter -GConverter -GConverterIface -GConverterResult -GConverterFlags -g_converter_convert -g_converter_reset - -G_TYPE_CONVERTER -G_CONVERTER -G_IS_CONVERTER -G_CONVERTER_GET_IFACE -G_TYPE_CONVERTER_FLAGS -G_TYPE_CONVERTER_RESULT - -g_converter_get_type -g_converter_flags_get_type -g_converter_result_get_type -
- -
-gcharsetconverter -GCharsetConverter -GCharsetConverter -g_charset_converter_new -g_charset_converter_set_use_fallback -g_charset_converter_get_use_fallback -g_charset_converter_get_num_fallbacks - -GCharsetConverterClass -G_TYPE_CHARSET_CONVERTER -G_CHARSET_CONVERTER -G_IS_CHARSET_CONVERTER -G_CHARSET_CONVERTER_CLASS -G_IS_CHARSET_CONVERTER_CLASS -G_CHARSET_CONVERTER_GET_CLASS - -g_charset_converter_get_type -
- -
-gconverterinputstream -GConverterInputStream -GConverterInputStream -g_converter_input_stream_new -g_converter_input_stream_get_converter - -GConverterInputStreamClass -G_TYPE_CONVERTER_INPUT_STREAM -G_CONVERTER_INPUT_STREAM -G_IS_CONVERTER_INPUT_STREAM -G_CONVERTER_INPUT_STREAM_CLASS -G_IS_CONVERTER_INPUT_STREAM_CLASS -G_CONVERTER_INPUT_STREAM_GET_CLASS - -GConverterInputStreamPrivate -g_converter_input_stream_get_type -
- -
-gconverteroutputstream -GConverterOutputStream -GConverterOutputStream -g_converter_output_stream_new -g_converter_output_stream_get_converter - -GConverterOutputStreamClass -G_TYPE_CONVERTER_OUTPUT_STREAM -G_CONVERTER_OUTPUT_STREAM -G_IS_CONVERTER_OUTPUT_STREAM -G_CONVERTER_OUTPUT_STREAM_CLASS -G_IS_CONVERTER_OUTPUT_STREAM_CLASS -G_CONVERTER_OUTPUT_STREAM_GET_CLASS - -GConverterOutputStreamPrivate -g_converter_output_stream_get_type -
- -
-gzlibcompressor -GZlibCompressor -GZlibCompressor -GZlibCompressorFormat -g_zlib_compressor_new -g_zlib_compressor_get_file_info -g_zlib_compressor_set_file_info - -GZlibCompressorClass -G_TYPE_ZLIB_COMPRESSOR -G_ZLIB_COMPRESSOR -G_IS_ZLIB_COMPRESSOR -G_ZLIB_COMPRESSOR_CLASS -G_IS_ZLIB_COMPRESSOR_CLASS -G_ZLIB_COMPRESSOR_GET_CLASS -G_TYPE_ZLIB_COMPRESSOR_FORMAT - -g_zlib_compressor_get_type -g_zlib_compressor_format_get_type -
- -
-gzlibdecompressor -GZlibDecompressor -GZlibDecompressor -g_zlib_decompressor_new -g_zlib_decompressor_get_file_info - -GZlibDecompressorClass -G_TYPE_ZLIB_DECOMPRESSOR -G_ZLIB_DECOMPRESSOR -G_IS_ZLIB_DECOMPRESSOR -G_ZLIB_DECOMPRESSOR_CLASS -G_IS_ZLIB_DECOMPRESSOR_CLASS -G_ZLIB_DECOMPRESSOR_GET_CLASS - -g_zlib_decompressor_get_type -
- -
-gfiledescriptorbased -GFileDescriptorBased -GFileDescriptorBased -GFileDescriptorBasedIface -g_file_descriptor_based_get_fd - -g_file_descriptor_based_get_type -G_FILE_DESCRIPTOR_BASED -G_FILE_DESCRIPTOR_BASED_GET_IFACE -G_IS_FILE_DESCRIPTOR_BASED -G_TYPE_FILE_DESCRIPTOR_BASED -
- -
-gsettingsbackend -GSettingsBackend -GSettingsBackend -GSettingsBackendClass -G_SETTINGS_BACKEND_EXTENSION_POINT_NAME -g_settings_backend_get_default -g_settings_backend_changed -g_settings_backend_path_changed -g_settings_backend_keys_changed -g_settings_backend_path_writable_changed -g_settings_backend_writable_changed -g_settings_backend_changed_tree -g_settings_backend_flatten_tree -g_keyfile_settings_backend_new -g_memory_settings_backend_new -g_null_settings_backend_new - - -G_IS_SETTINGS_BACKEND -G_IS_SETTINGS_BACKEND_CLASS -G_SETTINGS_BACKEND -G_SETTINGS_BACKEND_CLASS -G_SETTINGS_BACKEND_GET_CLASS -G_TYPE_SETTINGS_BACKEND - - -g_settings_backend_get_type -GSettingsBackendPrivate -
- -
-gsettingsschema -GSettingsSchema, GSettingsSchemaSource -GSettingsSchemaSource -g_settings_schema_source_get_default -g_settings_schema_source_ref -g_settings_schema_source_unref - - -g_settings_schema_source_new_from_directory - - -g_settings_schema_source_list_schemas -g_settings_schema_source_lookup - - -GSettingsSchema -g_settings_schema_ref -g_settings_schema_unref - - -g_settings_schema_get_id -g_settings_schema_get_path - - -GSettingsSchemaKey -g_settings_schema_has_key -g_settings_schema_get_key -g_settings_schema_key_ref -g_settings_schema_key_unref -g_settings_schema_list_children -g_settings_schema_list_keys - - -g_settings_schema_key_get_value_type -g_settings_schema_key_get_default_value -g_settings_schema_key_get_range -g_settings_schema_key_range_check - - -g_settings_schema_key_get_name -g_settings_schema_key_get_summary -g_settings_schema_key_get_description - - -G_TYPE_SETTINGS_SCHEMA_KEY -G_TYPE_SETTINGS_SCHEMA -G_TYPE_SETTINGS_SCHEMA_SOURCE - - -g_settings_schema_get_type -g_settings_schema_key_get_type -g_settings_schema_source_get_type -
- -
-gsettings -GSettings -GSettings -g_settings_new -g_settings_new_with_path -g_settings_new_with_backend -g_settings_new_with_backend_and_path -g_settings_new_full -g_settings_sync -g_settings_get_value -g_settings_set_value -g_settings_is_writable -g_settings_delay -g_settings_apply -g_settings_revert -g_settings_get_has_unapplied -g_settings_get_child -g_settings_reset -g_settings_get_user_value -g_settings_get_default_value - - -g_settings_list_schemas -g_settings_list_relocatable_schemas -g_settings_list_keys -g_settings_list_children -g_settings_get_range -g_settings_range_check - - -g_settings_get -g_settings_set -g_settings_get_boolean -g_settings_set_boolean -g_settings_get_int -g_settings_set_int -g_settings_get_int64 -g_settings_set_int64 -g_settings_get_uint -g_settings_set_uint -g_settings_get_uint64 -g_settings_set_uint64 -g_settings_get_double -g_settings_set_double -g_settings_get_string -g_settings_set_string -g_settings_get_strv -g_settings_set_strv -g_settings_get_enum -g_settings_set_enum -g_settings_get_flags -g_settings_set_flags - - -GSettingsGetMapping -g_settings_get_mapped - - -GSettingsBindFlags -g_settings_bind -g_settings_bind_with_mapping -g_settings_bind_writable -g_settings_unbind -GSettingsBindSetMapping -GSettingsBindGetMapping - - -g_settings_create_action - - -GSettingsClass -G_IS_SETTINGS -G_IS_SETTINGS_CLASS -G_SETTINGS -G_SETTINGS_CLASS -G_SETTINGS_GET_CLASS -G_TYPE_SETTINGS -G_TYPE_SETTINGS_BIND_FLAGS - - -GSettingsPrivate -g_settings_get_type -g_settings_bind_flags_get_type -
- -
-gunixcredentialsmessage -GUnixCredentialsMessage -GUnixCredentialsMessage -GUnixCredentialsMessageClass -g_unix_credentials_message_new -g_unix_credentials_message_new_with_credentials -g_unix_credentials_message_get_credentials -g_unix_credentials_message_is_supported - -G_IS_UNIX_CREDENTIALS_MESSAGE -G_IS_UNIX_CREDENTIALS_MESSAGE_CLASS -G_TYPE_UNIX_CREDENTIALS_MESSAGE -G_UNIX_CREDENTIALS_MESSAGE -G_UNIX_CREDENTIALS_MESSAGE_CLASS -G_UNIX_CREDENTIALS_MESSAGE_GET_CLASS - -GUnixCredentialsMessagePrivate -g_unix_credentials_message_get_type -
- -
-gcredentials -GCredentials -GCredentials -GCredentialsType -g_credentials_new -g_credentials_to_string -g_credentials_get_native -g_credentials_set_native -g_credentials_is_same_user -g_credentials_get_unix_user -g_credentials_set_unix_user -g_credentials_get_unix_pid - -G_CREDENTIALS -G_IS_CREDENTIALS -G_TYPE_CREDENTIALS -G_CREDENTIALS_CLASS -G_IS_CREDENTIALS_CLASS -G_CREDENTIALS_GET_CLASS -G_TYPE_CREDENTIALS_TYPE - -g_credentials_get_type -g_credentials_type_get_type -G_CREDENTIALS_NATIVE_SIZE -G_CREDENTIALS_NATIVE_TYPE -G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED -G_CREDENTIALS_SPOOFING_SUPPORTED -G_CREDENTIALS_SUPPORTED -G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED -G_CREDENTIALS_USE_FREEBSD_CMSGCRED -G_CREDENTIALS_USE_LINUX_UCRED -G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED -G_CREDENTIALS_USE_SOLARIS_UCRED -
- -
-gdbusaddress -g_dbus_is_address -g_dbus_is_supported_address -g_dbus_address_get_stream -g_dbus_address_get_stream_finish -g_dbus_address_get_stream_sync -g_dbus_address_get_for_bus_sync -g_dbus_address_escape_value -
- -
-gdbusutils -g_dbus_generate_guid -g_dbus_is_guid -g_dbus_is_name -g_dbus_is_unique_name -g_dbus_is_member_name -g_dbus_is_interface_name -g_dbus_is_error_name -g_dbus_gvalue_to_gvariant -g_dbus_gvariant_to_gvalue -g_dbus_escape_object_path_bytestring -g_dbus_escape_object_path -g_dbus_unescape_object_path -
- -
-gdbusauthobserver -GDBusAuthObserver -GDBusAuthObserver -g_dbus_auth_observer_new -g_dbus_auth_observer_authorize_authenticated_peer -g_dbus_auth_observer_allow_mechanism - -G_DBUS_AUTH_OBSERVER -G_IS_DBUS_AUTH_OBSERVER -G_TYPE_DBUS_AUTH_OBSERVER - -g_dbus_auth_observer_get_type -
- -
-gdbusserver -GDBusServer -GDBusServer -GDBusServerFlags -g_dbus_server_new_sync -g_dbus_server_start -g_dbus_server_stop -g_dbus_server_is_active -g_dbus_server_get_guid -g_dbus_server_get_flags -g_dbus_server_get_client_address - -G_DBUS_SERVER -G_IS_DBUS_SERVER -G_TYPE_DBUS_SERVER -G_TYPE_DBUS_SERVER_FLAGS - -g_dbus_server_get_type -g_dbus_server_flags_get_type -
- -
-gdbusmessage -GDBusMessage -GDBusMessage -GDBusMessageType -GDBusMessageFlags -GDBusMessageHeaderField -GDBusMessageByteOrder -g_dbus_message_new -g_dbus_message_new_signal -g_dbus_message_new_method_call -g_dbus_message_new_method_reply -g_dbus_message_new_method_error -g_dbus_message_new_method_error_valist -g_dbus_message_new_method_error_literal -g_dbus_message_print -g_dbus_message_get_locked -g_dbus_message_lock -g_dbus_message_copy -g_dbus_message_get_byte_order -g_dbus_message_set_byte_order -g_dbus_message_get_message_type -g_dbus_message_set_message_type -g_dbus_message_get_serial -g_dbus_message_set_serial -g_dbus_message_get_flags -g_dbus_message_set_flags -g_dbus_message_get_body -g_dbus_message_set_body -g_dbus_message_get_unix_fd_list -g_dbus_message_set_unix_fd_list -g_dbus_message_get_num_unix_fds -g_dbus_message_set_num_unix_fds -g_dbus_message_get_header_fields -g_dbus_message_get_header -g_dbus_message_set_header -g_dbus_message_get_destination -g_dbus_message_set_destination -g_dbus_message_get_error_name -g_dbus_message_set_error_name -g_dbus_message_get_interface -g_dbus_message_set_interface -g_dbus_message_get_member -g_dbus_message_set_member -g_dbus_message_get_path -g_dbus_message_set_path -g_dbus_message_get_reply_serial -g_dbus_message_set_reply_serial -g_dbus_message_get_sender -g_dbus_message_set_sender -g_dbus_message_get_signature -g_dbus_message_set_signature -g_dbus_message_get_arg0 -g_dbus_message_to_blob -g_dbus_message_bytes_needed -g_dbus_message_new_from_blob -g_dbus_message_to_gerror - -G_DBUS_MESSAGE -G_IS_DBUS_MESSAGE -G_TYPE_DBUS_MESSAGE -G_TYPE_DBUS_MESSAGE_BYTE_ORDER -G_TYPE_DBUS_MESSAGE_FLAGS -G_TYPE_DBUS_MESSAGE_HEADER_FIELD -G_TYPE_DBUS_MESSAGE_TYPE - -g_dbus_message_get_type -g_dbus_message_byte_order_get_type -g_dbus_message_flags_get_type -g_dbus_message_header_field_get_type -g_dbus_message_type_get_type -
- -
-gdbusconnection -GDBusConnection -GBusType -g_bus_get -g_bus_get_finish -g_bus_get_sync -GDBusConnection -GDBusConnectionFlags -g_dbus_connection_new -g_dbus_connection_new_finish -g_dbus_connection_new_sync -g_dbus_connection_new_for_address -g_dbus_connection_new_for_address_finish -g_dbus_connection_new_for_address_sync -g_dbus_connection_start_message_processing -g_dbus_connection_close -g_dbus_connection_close_finish -g_dbus_connection_close_sync -g_dbus_connection_is_closed -g_dbus_connection_flush -g_dbus_connection_flush_finish -g_dbus_connection_flush_sync -g_dbus_connection_get_exit_on_close -g_dbus_connection_set_exit_on_close -g_dbus_connection_get_stream -g_dbus_connection_get_flags -g_dbus_connection_get_guid -g_dbus_connection_get_unique_name -GDBusCapabilityFlags -g_dbus_connection_get_capabilities -g_dbus_connection_get_peer_credentials -g_dbus_connection_get_last_serial -GDBusCallFlags -g_dbus_connection_call -g_dbus_connection_call_finish -g_dbus_connection_call_sync -g_dbus_connection_call_with_unix_fd_list -g_dbus_connection_call_with_unix_fd_list_finish -g_dbus_connection_call_with_unix_fd_list_sync -g_dbus_connection_emit_signal -GDBusSignalFlags -GDBusSignalCallback -g_dbus_connection_signal_subscribe -g_dbus_connection_signal_unsubscribe -GDBusSendMessageFlags -g_dbus_connection_send_message -g_dbus_connection_send_message_with_reply -g_dbus_connection_send_message_with_reply_finish -g_dbus_connection_send_message_with_reply_sync -GDBusMessageFilterFunction -g_dbus_connection_add_filter -g_dbus_connection_remove_filter -GDBusInterfaceVTable -GDBusInterfaceMethodCallFunc -GDBusInterfaceGetPropertyFunc -GDBusInterfaceSetPropertyFunc -g_dbus_connection_register_object -g_dbus_connection_unregister_object -g_dbus_connection_register_object_with_closures -GDBusSubtreeVTable -GDBusSubtreeEnumerateFunc -GDBusSubtreeIntrospectFunc -GDBusSubtreeDispatchFunc -GDBusSubtreeFlags -g_dbus_connection_register_subtree -g_dbus_connection_unregister_subtree - -G_DBUS_CONNECTION -G_IS_DBUS_CONNECTION -G_TYPE_DBUS_CONNECTION -G_TYPE_BUS_TYPE -G_TYPE_DBUS_CALL_FLAGS -G_TYPE_DBUS_CAPABILITY_FLAGS -G_TYPE_DBUS_CONNECTION_FLAGS -G_TYPE_DBUS_SEND_MESSAGE_FLAGS -G_TYPE_DBUS_SIGNAL_FLAGS -G_TYPE_DBUS_SUBTREE_FLAGS - -g_dbus_connection_get_type -g_bus_type_get_type -g_dbus_call_flags_get_type -g_dbus_capability_flags_get_type -g_dbus_connection_flags_get_type -g_dbus_send_message_flags_get_type -g_dbus_signal_flags_get_type -g_dbus_subtree_flags_get_type -
- -
-gdbusmethodinvocation -GDBusMethodInvocation -GDBusMethodInvocation -g_dbus_method_invocation_get_sender -g_dbus_method_invocation_get_object_path -g_dbus_method_invocation_get_interface_name -g_dbus_method_invocation_get_method_name -g_dbus_method_invocation_get_method_info -g_dbus_method_invocation_get_property_info -g_dbus_method_invocation_get_connection -g_dbus_method_invocation_get_message -g_dbus_method_invocation_get_parameters -g_dbus_method_invocation_get_user_data -g_dbus_method_invocation_return_value -g_dbus_method_invocation_return_error -g_dbus_method_invocation_return_error_valist -g_dbus_method_invocation_return_error_literal -g_dbus_method_invocation_return_gerror -g_dbus_method_invocation_return_dbus_error -g_dbus_method_invocation_take_error -g_dbus_method_invocation_return_value_with_unix_fd_list -G_DBUS_METHOD_INVOCATION_HANDLED -G_DBUS_METHOD_INVOCATION_UNHANDLED - -G_DBUS_METHOD_INVOCATION -G_IS_DBUS_METHOD_INVOCATION -G_TYPE_DBUS_METHOD_INVOCATION - -g_dbus_method_invocation_get_type -
- -
-gdbusnameowning -GBusAcquiredCallback -GBusNameAcquiredCallback -GBusNameLostCallback -GBusNameOwnerFlags -g_bus_own_name -g_bus_own_name_on_connection -g_bus_unown_name -g_bus_own_name_with_closures -g_bus_own_name_on_connection_with_closures - - -G_TYPE_BUS_NAME_OWNER_FLAGS - -g_bus_name_owner_flags_get_type -
- -
-gdbusnamewatching -GBusNameAppearedCallback -GBusNameVanishedCallback -GBusNameWatcherFlags -g_bus_watch_name -g_bus_watch_name_on_connection -g_bus_unwatch_name -g_bus_watch_name_with_closures -g_bus_watch_name_on_connection_with_closures - - -G_TYPE_BUS_NAME_WATCHER_FLAGS - -g_bus_name_watcher_flags_get_type -
- -
-gdbuserror -GDBusError -G_DBUS_ERROR -g_dbus_error_is_remote_error -g_dbus_error_get_remote_error -g_dbus_error_strip_remote_error -GDBusErrorEntry -g_dbus_error_register_error_domain -g_dbus_error_register_error -g_dbus_error_unregister_error -g_dbus_error_new_for_dbus_error -g_dbus_error_set_dbus_error -g_dbus_error_set_dbus_error_valist -g_dbus_error_encode_gerror - -G_TYPE_DBUS_ERROR -g_dbus_error_quark -g_dbus_error_get_type -
- -
-gdbusproxy -GDBusProxy -GDBusProxyFlags -GDBusProxy -GDBusProxyClass -g_dbus_proxy_new -g_dbus_proxy_new_finish -g_dbus_proxy_new_sync -g_dbus_proxy_new_for_bus -g_dbus_proxy_new_for_bus_finish -g_dbus_proxy_new_for_bus_sync -g_dbus_proxy_get_flags -g_dbus_proxy_get_connection -g_dbus_proxy_get_name -g_dbus_proxy_get_name_owner -g_dbus_proxy_get_object_path -g_dbus_proxy_get_interface_name -g_dbus_proxy_get_default_timeout -g_dbus_proxy_set_default_timeout -g_dbus_proxy_get_cached_property -g_dbus_proxy_set_cached_property -g_dbus_proxy_get_cached_property_names -g_dbus_proxy_set_interface_info -g_dbus_proxy_get_interface_info -g_dbus_proxy_call -g_dbus_proxy_call_finish -g_dbus_proxy_call_sync -g_dbus_proxy_call_with_unix_fd_list -g_dbus_proxy_call_with_unix_fd_list_finish -g_dbus_proxy_call_with_unix_fd_list_sync - -G_DBUS_PROXY -G_IS_DBUS_PROXY -G_TYPE_DBUS_PROXY -G_DBUS_PROXY_CLASS -G_IS_DBUS_PROXY_CLASS -G_DBUS_PROXY_GET_CLASS -G_TYPE_DBUS_PROXY_FLAGS - -GDBusProxyPrivate -g_dbus_proxy_get_type -g_dbus_proxy_flags_get_type -
- -
-gdbusintrospection -GDBusAnnotationInfo -GDBusArgInfo -GDBusMethodInfo -GDBusSignalInfo -GDBusPropertyInfoFlags -GDBusPropertyInfo -GDBusInterfaceInfo -GDBusNodeInfo -g_dbus_annotation_info_lookup -g_dbus_interface_info_lookup_method -g_dbus_interface_info_lookup_signal -g_dbus_interface_info_lookup_property -g_dbus_interface_info_cache_build -g_dbus_interface_info_cache_release -g_dbus_interface_info_generate_xml -g_dbus_node_info_new_for_xml -g_dbus_node_info_lookup_interface -g_dbus_node_info_generate_xml -G_TYPE_DBUS_NODE_INFO -G_TYPE_DBUS_INTERFACE_INFO -G_TYPE_DBUS_METHOD_INFO -G_TYPE_DBUS_SIGNAL_INFO -G_TYPE_DBUS_PROPERTY_INFO -G_TYPE_DBUS_ARG_INFO -G_TYPE_DBUS_ANNOTATION_INFO -g_dbus_node_info_ref -g_dbus_interface_info_ref -g_dbus_method_info_ref -g_dbus_signal_info_ref -g_dbus_property_info_ref -g_dbus_arg_info_ref -g_dbus_annotation_info_ref -g_dbus_node_info_unref -g_dbus_interface_info_unref -g_dbus_method_info_unref -g_dbus_signal_info_unref -g_dbus_property_info_unref -g_dbus_arg_info_unref -g_dbus_annotation_info_unref - -G_TYPE_DBUS_PROPERTY_INFO_FLAGS - -g_dbus_annotation_info_get_type -g_dbus_arg_info_get_type -g_dbus_interface_info_get_type -g_dbus_method_info_get_type -g_dbus_node_info_get_type -g_dbus_property_info_get_type -g_dbus_signal_info_get_type -g_dbus_property_info_flags_get_type -
- -
-gpermission -GPermission -g_permission_get_allowed -g_permission_get_can_acquire -g_permission_get_can_release - -g_permission_acquire -g_permission_acquire_async -g_permission_acquire_finish -g_permission_release -g_permission_release_async -g_permission_release_finish - -g_permission_impl_update - -G_PERMISSION -G_PERMISSION_CLASS -G_PERMISSION_GET_CLASS -G_IS_PERMISSION -G_IS_PERMISSION_CLASS -GPermissionClass -G_TYPE_PERMISSION - -g_permission_get_type -GPermissionPrivate -
- -
-gsimplepermission -GSimplePermission -g_simple_permission_new - - -G_SIMPLE_PERMISSION -G_IS_SIMPLE_PERMISSION -G_TYPE_SIMPLE_PERMISSION - - -g_simple_permission_get_type -
- -
-gapplication -GApplication -GApplicationClass - -GApplicationFlags -g_application_id_is_valid -g_application_new - -g_application_get_application_id -g_application_set_application_id - -g_application_get_inactivity_timeout -g_application_set_inactivity_timeout - -g_application_get_flags -g_application_set_flags - -g_application_get_resource_base_path -g_application_set_resource_base_path - -g_application_get_dbus_connection -g_application_get_dbus_object_path - -g_application_set_action_group - -g_application_get_is_registered -g_application_get_is_remote -g_application_register - -g_application_hold -g_application_release -g_application_quit - -g_application_activate -g_application_open - -g_application_send_notification -g_application_withdraw_notification - -g_application_run -g_application_add_main_option_entries -g_application_add_main_option -g_application_add_option_group -g_application_set_option_context_parameter_string -g_application_set_option_context_summary -g_application_set_option_context_description - -g_application_set_default -g_application_get_default - -g_application_mark_busy -g_application_unmark_busy -g_application_get_is_busy -g_application_bind_busy_property -g_application_unbind_busy_property - -G_TYPE_APPLICATION -G_APPLICATION -G_APPLICATION_CLASS -G_IS_APPLICATION -G_IS_APPLICATION_CLASS -G_APPLICATION_GET_CLASS -G_TYPE_APPLICATION_FLAGS - -GApplicationPrivate -g_application_get_type -g_application_flags_get_type -
- -
-gapplicationcommandline -GApplicationCommandLine -GApplicationCommandLineClass - -g_application_command_line_get_arguments -g_application_command_line_get_cwd -g_application_command_line_get_environ -g_application_command_line_get_options_dict -g_application_command_line_get_stdin -g_application_command_line_create_file_for_arg -g_application_command_line_getenv -g_application_command_line_get_is_remote -g_application_command_line_get_platform_data - -g_application_command_line_set_exit_status -g_application_command_line_get_exit_status - -g_application_command_line_print -g_application_command_line_printerr - -G_TYPE_APPLICATION_COMMAND_LINE -G_APPLICATION_COMMAND_LINE -G_APPLICATION_COMMAND_LINE_CLASS -G_IS_APPLICATION_COMMAND_LINE -G_IS_APPLICATION_COMMAND_LINE_CLASS -G_APPLICATION_COMMAND_LINE_GET_CLASS - -GApplicationCommandLinePrivate -g_application_command_line_get_type -
- - -
-gactiongroup -GActionGroup -GActionGroup -GActionGroupInterface - - -g_action_group_list_actions -g_action_group_query_action - - -g_action_group_has_action -g_action_group_get_action_enabled -g_action_group_get_action_parameter_type -g_action_group_get_action_state_type -g_action_group_get_action_state_hint -g_action_group_get_action_state - - -g_action_group_change_action_state -g_action_group_activate_action - - -g_action_group_action_added -g_action_group_action_removed -g_action_group_action_enabled_changed -g_action_group_action_state_changed - - -g_action_group_get_type -G_TYPE_ACTION_GROUP -G_IS_ACTION_GROUP -G_ACTION_GROUP_GET_IFACE -G_ACTION_GROUP -
- -
-gactiongroupexporter -g_dbus_connection_export_action_group -g_dbus_connection_unexport_action_group -
- -
-gdbusactiongroup -GDBusActionGroup -g_dbus_action_group_get - - -G_TYPE_DBUS_ACTION_GROUP -G_DBUS_ACTION_GROUP -G_DBUS_ACTION_GROUP_CLASS -G_IS_DBUS_ACTION_GROUP -G_IS_DBUS_ACTION_GROUP_CLASS -G_DBUS_ACTION_GROUP_GET_CLASS - - -g_dbus_action_group_get_type -
- -
-gremoteactiongroup -GRemoteActionGroup -GRemoteActionGroupInterface - - -g_remote_action_group_activate_action_full -g_remote_action_group_change_action_state_full - - -G_TYPE_REMOTE_ACTION_GROUP -G_REMOTE_ACTION_GROUP -G_IS_REMOTE_ACTION_GROUP -G_REMOTE_ACTION_GROUP_GET_IFACE -g_remote_action_group_get_type -
- -
-gaction -GAction -GAction -GActionInterface - - -g_action_name_is_valid -g_action_get_name -g_action_get_parameter_type -g_action_get_state_type -g_action_get_state_hint - - -g_action_get_enabled -g_action_get_state - - -g_action_change_state -g_action_activate - - -g_action_parse_detailed_name -g_action_print_detailed_name - - -g_action_get_type -G_TYPE_ACTION -G_IS_ACTION -G_ACTION_GET_IFACE -G_ACTION -
- -
-gsimpleaction -GSimpleAction -GSimpleAction - - -g_simple_action_new -g_simple_action_new_stateful - - -g_simple_action_set_enabled -g_simple_action_set_state -g_simple_action_set_state_hint - - -g_simple_action_get_type -G_TYPE_SIMPLE_ACTION -G_IS_SIMPLE_ACTION -G_SIMPLE_ACTION -
- -
-gpropertyaction -GPropertyAction -GPropertyAction - - -g_property_action_new - - -g_property_action_get_type -G_TYPE_PROPERTY_ACTION -G_IS_PROPERTY_ACTION -G_PROPERTY_ACTION -
- -
-gsimpleactiongroup -GSimpleActionGroup -GSimpleActionGroup - - -g_simple_action_group_new - - -g_simple_action_group_lookup -g_simple_action_group_insert -g_simple_action_group_remove - - -g_simple_action_group_add_entries - - -GSimpleActionGroupClass -GSimpleActionGroupPrivate -g_simple_action_group_get_type -G_TYPE_SIMPLE_ACTION_GROUP -G_IS_SIMPLE_ACTION_GROUP -G_SIMPLE_ACTION_GROUP_CLASS -G_SIMPLE_ACTION_GROUP_GET_CLASS -G_IS_SIMPLE_ACTION_GROUP_CLASS -G_SIMPLE_ACTION_GROUP -
- -
-gactionmap -GActionMap -GActionMap -GActionMapInterface -g_action_map_lookup_action -GActionEntry -g_action_map_add_action_entries -g_action_map_add_action -g_action_map_remove_action_entries -g_action_map_remove_action - - -G_TYPE_ACTION_MAP -G_ACTION_MAP -G_IS_ACTION_MAP -G_ACTION_MAP_GET_IFACE - - -g_action_map_get_type -
- -
-gproxyresolver -GProxyResolver -GProxyResolver -GProxyResolverInterface -G_PROXY_RESOLVER_EXTENSION_POINT_NAME -g_proxy_resolver_get_default -g_proxy_resolver_is_supported -g_proxy_resolver_lookup -g_proxy_resolver_lookup_async -g_proxy_resolver_lookup_finish - -G_PROXY_RESOLVER -G_IS_PROXY_RESOLVER -G_TYPE_PROXY_RESOLVER -G_PROXY_RESOLVER_GET_IFACE - -g_proxy_resolver_get_type -
- -
-gproxyaddress -GProxyAddress -GProxyAddress -GProxyAddressClass -g_proxy_address_get_destination_protocol -g_proxy_address_get_destination_hostname -g_proxy_address_get_destination_port -g_proxy_address_get_password -g_proxy_address_get_protocol -g_proxy_address_get_username -g_proxy_address_get_uri -g_proxy_address_new - -G_PROXY_ADDRESS -G_PROXY_ADDRESS_CLASS -G_PROXY_ADDRESS_GET_CLASS -G_IS_PROXY_ADDRESS -G_IS_PROXY_ADDRESS_CLASS -G_TYPE_PROXY_ADDRESS - -GProxyAddressPrivate -g_proxy_address_get_type -
- -
-gproxy -GProxy -GProxy -GProxyInterface -G_PROXY_EXTENSION_POINT_NAME -g_proxy_connect -g_proxy_connect_async -g_proxy_connect_finish -g_proxy_get_default_for_protocol -g_proxy_supports_hostname - -G_PROXY -G_PROXY_GET_IFACE -G_IS_PROXY -G_TYPE_PROXY - -g_proxy_get_type -
- -
-gpollableinputstream -GPollableInputStream -GPollableInputStream -GPollableInputStreamInterface - -g_pollable_input_stream_can_poll -g_pollable_input_stream_is_readable -g_pollable_input_stream_create_source -g_pollable_input_stream_read_nonblocking - -G_POLLABLE_INPUT_STREAM -G_POLLABLE_INPUT_STREAM_GET_INTERFACE -G_IS_POLLABLE_INPUT_STREAM -G_TYPE_POLLABLE_INPUT_STREAM - -g_pollable_input_stream_get_type -
- -
-gpollableoutputstream -GPollableOutputStream -GPollableOutputStream -GPollableOutputStreamInterface - -g_pollable_output_stream_can_poll -g_pollable_output_stream_is_writable -g_pollable_output_stream_create_source -g_pollable_output_stream_write_nonblocking -g_pollable_output_stream_writev_nonblocking - -G_POLLABLE_OUTPUT_STREAM -G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE -G_IS_POLLABLE_OUTPUT_STREAM -G_TYPE_POLLABLE_OUTPUT_STREAM - -g_pollable_output_stream_get_type -
- -
-gpollableutils -GPollableReturn -GPollableSourceFunc -g_pollable_source_new -g_pollable_source_new_full - -g_pollable_stream_read -g_pollable_stream_write -g_pollable_stream_write_all - -G_TYPE_POLLABLE_RETURN - -g_pollable_return_get_type -
- -
-gtls -G_TLS_ERROR -GTlsError -G_TLS_CHANNEL_BINDING_ERROR -GTlsChannelBindingError - -GTlsAuthenticationMode -GTlsCertificateFlags -GTlsProtocolVersion - -G_TYPE_TLS_AUTHENTICATION_MODE -G_TYPE_TLS_CERTIFICATE_FLAGS -G_TYPE_TLS_CHANNEL_BINDING_ERROR -G_TYPE_TLS_ERROR -G_TYPE_TLS_PROTOCOL_VERSION -g_tls_authentication_mode_get_type -g_tls_certificate_flags_get_type -g_tls_channel_binding_error_get_type -g_tls_channel_binding_error_quark -g_tls_error_get_type -g_tls_protocol_version_get_type -
- -
-gtlsbackend -GTlsBackend -G_TLS_BACKEND_EXTENSION_POINT_NAME -GTlsBackend -GTlsBackendInterface -g_tls_backend_get_default -g_tls_backend_supports_tls -g_tls_backend_supports_dtls -g_tls_backend_get_default_database -g_tls_backend_set_default_database -g_tls_backend_get_certificate_type -g_tls_backend_get_client_connection_type -g_tls_backend_get_server_connection_type -g_tls_backend_get_dtls_client_connection_type -g_tls_backend_get_dtls_server_connection_type -g_tls_backend_get_file_database_type - -G_IS_TLS_BACKEND -G_TLS_BACKEND -G_TLS_BACKEND_GET_INTERFACE -G_TYPE_TLS_BACKEND -g_tls_error_quark - -g_tls_backend_get_type -
- -
-gtlscertificate -GTlsCertificate -GTlsCertificate -g_tls_certificate_new_from_pem -g_tls_certificate_new_from_pkcs12 -g_tls_certificate_new_from_file -g_tls_certificate_new_from_file_with_password -g_tls_certificate_new_from_files -g_tls_certificate_new_from_pkcs11_uris -g_tls_certificate_list_new_from_file -g_tls_certificate_get_dns_names -g_tls_certificate_get_ip_addresses -g_tls_certificate_get_issuer -g_tls_certificate_get_issuer_name -g_tls_certificate_get_not_valid_before -g_tls_certificate_get_not_valid_after -g_tls_certificate_get_subject_name -g_tls_certificate_verify -g_tls_certificate_is_same - -GTlsCertificateClass -GTlsCertificatePrivate -G_IS_TLS_CERTIFICATE -G_IS_TLS_CERTIFICATE_CLASS -G_TLS_CERTIFICATE -G_TLS_CERTIFICATE_CLASS -G_TLS_CERTIFICATE_GET_CLASS -G_TYPE_TLS_CERTIFICATE - -g_tls_certificate_get_type -
- -
-gtlsconnection -GTlsConnection -GTlsConnection -GTlsChannelBindingType -g_tls_connection_set_certificate -g_tls_connection_get_certificate -g_tls_connection_get_peer_certificate -g_tls_connection_get_peer_certificate_errors -g_tls_connection_get_channel_binding_data -g_tls_connection_set_require_close_notify -g_tls_connection_get_require_close_notify -GTlsRehandshakeMode -g_tls_connection_set_rehandshake_mode -g_tls_connection_get_rehandshake_mode -g_tls_connection_set_advertised_protocols -g_tls_connection_get_negotiated_protocol -g_tls_connection_set_use_system_certdb -g_tls_connection_get_use_system_certdb -g_tls_connection_get_database -g_tls_connection_set_database -g_tls_connection_get_interaction -g_tls_connection_set_interaction -g_tls_connection_get_protocol_version -g_tls_connection_get_ciphersuite_name - -g_tls_connection_handshake -g_tls_connection_handshake_async -g_tls_connection_handshake_finish - -g_tls_connection_emit_accept_certificate - -GTlsConnectionClass -GTlsConnectionPrivate -G_IS_TLS_CONNECTION -G_IS_TLS_CONNECTION_CLASS -G_TLS_CONNECTION -G_TLS_CONNECTION_CLASS -G_TLS_CONNECTION_GET_CLASS -G_TYPE_TLS_CHANNEL_BINDING_TYPE -G_TYPE_TLS_CONNECTION -G_TYPE_TLS_REHANDSHAKE_MODE - -g_tls_channel_binding_type_get_type -g_tls_connection_get_type -g_tls_rehandshake_mode_get_type -
- -
-gtlsclientconnection -GTlsClientConnection -GTlsClientConnection -GTlsClientConnectionInterface -g_tls_client_connection_new -g_tls_client_connection_set_server_identity -g_tls_client_connection_get_server_identity -g_tls_client_connection_set_validation_flags -g_tls_client_connection_get_validation_flags -g_tls_client_connection_set_use_ssl3 -g_tls_client_connection_get_use_ssl3 -g_tls_client_connection_get_accepted_cas -g_tls_client_connection_copy_session_state - -G_IS_TLS_CLIENT_CONNECTION -G_TLS_CLIENT_CONNECTION -G_TLS_CLIENT_CONNECTION_GET_INTERFACE -G_TYPE_TLS_CLIENT_CONNECTION - -g_tls_client_connection_get_type -
- -
-gtlsdatabase -GTlsDatabase -GTlsDatabase -GTlsDatabaseClass -GTlsDatabaseVerifyFlags -G_TLS_DATABASE_PURPOSE_AUTHENTICATE_SERVER -G_TLS_DATABASE_PURPOSE_AUTHENTICATE_CLIENT -g_tls_database_verify_chain -g_tls_database_verify_chain_async -g_tls_database_verify_chain_finish -GTlsDatabaseLookupFlags -g_tls_database_lookup_certificate_issuer -g_tls_database_lookup_certificate_issuer_async -g_tls_database_lookup_certificate_issuer_finish -g_tls_database_lookup_certificates_issued_by -g_tls_database_lookup_certificates_issued_by_async -g_tls_database_lookup_certificates_issued_by_finish -g_tls_database_create_certificate_handle -g_tls_database_lookup_certificate_for_handle -g_tls_database_lookup_certificate_for_handle_async -g_tls_database_lookup_certificate_for_handle_finish - -G_IS_TLS_DATABASE -G_IS_TLS_DATABASE_CLASS -G_TLS_DATABASE -G_TLS_DATABASE_CLASS -G_TLS_DATABASE_GET_CLASS -G_TYPE_TLS_DATABASE -G_TYPE_TLS_DATABASE_LOOKUP_FLAGS -G_TYPE_TLS_DATABASE_VERIFY_FLAGS - -g_tls_database_lookup_flags_get_type -g_tls_database_verify_flags_get_type -g_tls_database_get_type -GTlsDatabasePrivate -
- -
-gtlsfiledatabase -GTlsFileDatabase -GTlsFileDatabase -GTlsFileDatabaseInterface -g_tls_file_database_new - -G_TLS_FILE_DATABASE -G_TLS_FILE_DATABASE_GET_INTERFACE -G_TYPE_TLS_FILE_DATABASE -G_IS_TLS_FILE_DATABASE - -g_tls_file_database_get_type -
- -
-gtlsserverconnection -GTlsServerConnection -GTlsServerConnection -GTlsServerConnectionInterface -g_tls_server_connection_new - -G_IS_TLS_SERVER_CONNECTION -G_TLS_SERVER_CONNECTION -G_TLS_SERVER_CONNECTION_GET_INTERFACE -G_TYPE_TLS_SERVER_CONNECTION - -g_tls_server_connection_get_type -
- -
-gtlspassword -GTlsPassword -GTlsPassword -GTlsPasswordClass -GTlsPasswordFlags -g_tls_password_new -g_tls_password_get_value -g_tls_password_set_value -g_tls_password_set_value_full -g_tls_password_get_description -g_tls_password_set_description -g_tls_password_get_flags -g_tls_password_set_flags -g_tls_password_get_warning -g_tls_password_set_warning - -g_tls_password_flags_get_type -g_tls_password_get_type -G_IS_TLS_PASSWORD -G_TLS_PASSWORD -G_TYPE_TLS_PASSWORD -G_TYPE_TLS_PASSWORD_FLAGS -G_TLS_PASSWORD_CLASS -G_TLS_PASSWORD_GET_CLASS -G_IS_TLS_PASSWORD_CLASS - -GTlsPasswordPrivate -
- -
-gtlsinteraction -GTlsInteraction -GTlsInteraction -GTlsInteractionResult -GTlsCertificateRequestFlags -GTlsInteractionClass -g_tls_interaction_invoke_ask_password -g_tls_interaction_invoke_request_certificate -g_tls_interaction_ask_password -g_tls_interaction_ask_password_async -g_tls_interaction_ask_password_finish -g_tls_interaction_request_certificate -g_tls_interaction_request_certificate_async -g_tls_interaction_request_certificate_finish - -G_IS_TLS_INTERACTION -G_IS_TLS_INTERACTION_CLASS -G_TYPE_TLS_INTERACTION -G_TLS_INTERACTION -G_TLS_INTERACTION_CLASS -G_TLS_INTERACTION_GET_CLASS -G_TYPE_TLS_INTERACTION_RESULT -G_TYPE_TLS_CERTIFICATE_REQUEST_FLAGS - -GTlsInteractionPrivate -g_tls_interaction_get_type -g_tls_interaction_result_get_type -g_tls_certificate_request_flags_get_type -
- -
-gdtlsconnection -GDtlsConnection -GDtlsConnection -g_dtls_connection_set_certificate -g_dtls_connection_get_certificate -g_dtls_connection_get_peer_certificate -g_dtls_connection_get_peer_certificate_errors -g_dtls_connection_get_channel_binding_data -g_dtls_connection_set_require_close_notify -g_dtls_connection_get_require_close_notify -g_dtls_connection_set_rehandshake_mode -g_dtls_connection_get_rehandshake_mode -g_dtls_connection_set_advertised_protocols -g_dtls_connection_get_negotiated_protocol -g_dtls_connection_get_database -g_dtls_connection_set_database -g_dtls_connection_get_interaction -g_dtls_connection_set_interaction -g_dtls_connection_get_protocol_version -g_dtls_connection_get_ciphersuite_name - -g_dtls_connection_handshake -g_dtls_connection_handshake_async -g_dtls_connection_handshake_finish - -g_dtls_connection_shutdown -g_dtls_connection_shutdown_async -g_dtls_connection_shutdown_finish -g_dtls_connection_close -g_dtls_connection_close_async -g_dtls_connection_close_finish - -g_dtls_connection_emit_accept_certificate - -GDtlsConnectionClass -GDtlsConnectionPrivate -G_IS_DTLS_CONNECTION -G_IS_DTLS_CONNECTION_CLASS -G_DTLS_CONNECTION -G_DTLS_CONNECTION_CLASS -G_DTLS_CONNECTION_GET_CLASS -G_TYPE_DTLS_CONNECTION -G_DTLS_CONNECTION_GET_INTERFACE - -g_dtls_connection_get_type -
- -
-gdtlsclientconnection -GDtlsClientConnection -GDtlsClientConnection -GDtlsClientConnectionInterface -g_dtls_client_connection_new -g_dtls_client_connection_set_server_identity -g_dtls_client_connection_get_server_identity -g_dtls_client_connection_set_validation_flags -g_dtls_client_connection_get_validation_flags -g_dtls_client_connection_get_accepted_cas - -G_IS_DTLS_CLIENT_CONNECTION -G_DTLS_CLIENT_CONNECTION -G_DTLS_CLIENT_CONNECTION_GET_INTERFACE -G_TYPE_DTLS_CLIENT_CONNECTION - -g_dtls_client_connection_get_type -
- -
-gdtlsserverconnection -GDtlsServerConnection -GDtlsServerConnection -GDtlsServerConnectionInterface -g_dtls_server_connection_new - -G_IS_DTLS_SERVER_CONNECTION -G_DTLS_SERVER_CONNECTION -G_DTLS_SERVER_CONNECTION_GET_INTERFACE -G_TYPE_DTLS_SERVER_CONNECTION - -g_dtls_server_connection_get_type -
- -
-gdbusinterface -GDBusInterface -GDBusInterface -GDBusInterfaceIface -g_dbus_interface_get_info -g_dbus_interface_get_object -g_dbus_interface_dup_object -g_dbus_interface_set_object - -G_DBUS_INTERFACE -G_IS_DBUS_INTERFACE -G_TYPE_DBUS_INTERFACE -g_dbus_interface_get_type -G_DBUS_INTERFACE_GET_IFACE -
- - -
-gdbusinterfaceskeleton -GDBusInterfaceSkeleton -GDBusInterfaceSkeleton -GDBusInterfaceSkeletonClass -g_dbus_interface_skeleton_flush -g_dbus_interface_skeleton_get_info -g_dbus_interface_skeleton_get_vtable -g_dbus_interface_skeleton_get_properties -g_dbus_interface_skeleton_export -g_dbus_interface_skeleton_unexport -g_dbus_interface_skeleton_unexport_from_connection -g_dbus_interface_skeleton_get_connection -g_dbus_interface_skeleton_get_connections -g_dbus_interface_skeleton_has_connection -g_dbus_interface_skeleton_get_object_path -GDBusInterfaceSkeletonFlags -g_dbus_interface_skeleton_get_flags -g_dbus_interface_skeleton_set_flags - -G_DBUS_INTERFACE_SKELETON -G_IS_DBUS_INTERFACE_SKELETON -G_TYPE_DBUS_INTERFACE_SKELETON -g_dbus_interface_skeleton_get_type -G_DBUS_INTERFACE_SKELETON_CLASS -G_IS_DBUS_INTERFACE_SKELETON_CLASS -G_DBUS_INTERFACE_SKELETON_GET_CLASS - -GDBusInterfaceSkeletonPrivate -G_TYPE_DBUS_INTERFACE_SKELETON_FLAGS -g_dbus_interface_skeleton_flags_get_type -
- -
-gdbusobject -GDBusObject -GDBusObject -GDBusObjectIface -g_dbus_object_get_object_path -g_dbus_object_get_interfaces -g_dbus_object_get_interface - -G_DBUS_OBJECT -G_IS_DBUS_OBJECT -G_TYPE_DBUS_OBJECT -g_dbus_object_get_type -G_DBUS_OBJECT_GET_IFACE -
- -
-gdbusobjectproxy -GDBusObjectProxy -GDBusObjectProxy -GDBusObjectProxyClass -g_dbus_object_proxy_new -g_dbus_object_proxy_get_connection - -G_DBUS_OBJECT_PROXY -G_IS_DBUS_OBJECT_PROXY -G_TYPE_DBUS_OBJECT_PROXY -g_dbus_object_proxy_get_type -G_DBUS_OBJECT_PROXY_CLASS -G_IS_DBUS_OBJECT_PROXY_CLASS -G_DBUS_OBJECT_PROXY_GET_CLASS - -GDBusObjectProxyPrivate -
- -
-gdbusobjectskeleton -GDBusObjectSkeleton -GDBusObjectSkeleton -GDBusObjectSkeletonClass -g_dbus_object_skeleton_new -g_dbus_object_skeleton_flush -g_dbus_object_skeleton_add_interface -g_dbus_object_skeleton_remove_interface -g_dbus_object_skeleton_remove_interface_by_name -g_dbus_object_skeleton_set_object_path - -G_DBUS_OBJECT_SKELETON -G_IS_DBUS_OBJECT_SKELETON -G_TYPE_DBUS_OBJECT_SKELETON -g_dbus_object_skeleton_get_type -G_DBUS_OBJECT_SKELETON_CLASS -G_IS_DBUS_OBJECT_SKELETON_CLASS -G_DBUS_OBJECT_SKELETON_GET_CLASS - -GDBusObjectSkeletonPrivate -
- -
-gdbusobjectmanager -GDBusObjectManager -GDBusObjectManager -GDBusObjectManagerIface -g_dbus_object_manager_get_object_path -g_dbus_object_manager_get_objects -g_dbus_object_manager_get_object -g_dbus_object_manager_get_interface - -G_DBUS_OBJECT_MANAGER -G_IS_DBUS_OBJECT_MANAGER -G_TYPE_DBUS_OBJECT_MANAGER -g_dbus_object_manager_get_type -G_DBUS_OBJECT_MANAGER_GET_IFACE -
- -
-gdbusobjectmanagerclient -GDBusObjectManagerClient -GDBusObjectManagerClient -GDBusObjectManagerClientClass -GDBusObjectManagerClientFlags -GDBusProxyTypeFunc -g_dbus_object_manager_client_new -g_dbus_object_manager_client_new_finish -g_dbus_object_manager_client_new_sync -g_dbus_object_manager_client_new_for_bus -g_dbus_object_manager_client_new_for_bus_finish -g_dbus_object_manager_client_new_for_bus_sync -g_dbus_object_manager_client_get_connection -g_dbus_object_manager_client_get_flags -g_dbus_object_manager_client_get_name -g_dbus_object_manager_client_get_name_owner - -G_DBUS_OBJECT_MANAGER_CLIENT -G_IS_DBUS_OBJECT_MANAGER_CLIENT -G_TYPE_DBUS_OBJECT_MANAGER_CLIENT -g_dbus_object_manager_client_get_type -G_DBUS_OBJECT_MANAGER_CLIENT_CLASS -G_IS_DBUS_OBJECT_MANAGER_CLIENT_CLASS -G_DBUS_OBJECT_MANAGER_CLIENT_GET_CLASS - -GDBusObjectManagerClientPrivate -G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS -g_dbus_object_manager_client_flags_get_type -
- -
-gdbusobjectmanagerserver -GDBusObjectManagerServer -GDBusObjectManagerServer -GDBusObjectManagerServerClass -g_dbus_object_manager_server_new -g_dbus_object_manager_server_get_connection -g_dbus_object_manager_server_set_connection -g_dbus_object_manager_server_export -g_dbus_object_manager_server_export_uniquely -g_dbus_object_manager_server_is_exported -g_dbus_object_manager_server_unexport - -G_DBUS_OBJECT_MANAGER_SERVER -G_IS_DBUS_OBJECT_MANAGER_SERVER -G_TYPE_DBUS_OBJECT_MANAGER_SERVER -g_dbus_object_manager_server_get_type -G_DBUS_OBJECT_MANAGER_SERVER_CLASS -G_IS_DBUS_OBJECT_MANAGER_SERVER_CLASS -G_DBUS_OBJECT_MANAGER_SERVER_GET_CLASS - -GDBusObjectManagerServerPrivate -
- -
-gdebugcontroller -GDebugController -GDebugController -GDebugControllerInterface -G_DEBUG_CONTROLLER_EXTENSION_POINT_NAME -g_debug_controller_get_debug_enabled -g_debug_controller_set_debug_enabled - -g_debug_controller_get_type -G_TYPE_DEBUG_CONTROLLER -G_DEBUG_CONTROLLER -G_IS_DEBUG_CONTROLLER -G_DEBUG_CONTROLLER_GET_INTERFACE -
- -
-gdebugcontrollerdbus -GDebugControllerDBus -GDebugControllerDBus -g_debug_controller_dbus_new -g_debug_controller_dbus_stop - -g_debug_controller_dbus_get_type -G_TYPE_DEBUG_CONTROLLER_DBUS -G_DEBUG_CONTROLLER_DBUS -G_IS_DEBUG_CONTROLLER_DBUS -G_DEBUG_CONTROLLER_DBUS_GET_CLASS -
- -
-gmemorymonitor -GMemoryMonitor -GMemoryMonitor -GMemoryMonitorInterface -GMemoryMonitorWarningLevel -G_MEMORY_MONITOR_EXTENSION_POINT_NAME -g_memory_monitor_dup_default - -g_memory_monitor_get_type -G_TYPE_MEMORY_MONITOR -G_MEMORY_MONITOR -G_IS_MEMORY_MONITOR -G_MEMORY_MONITOR_GET_INTERFACE -G_TYPE_MEMORY_MONITOR_WARNING_LEVEL -g_memory_monitor_warning_level_get_type -
- -
-gnetworkmonitor -GNetworkMonitor -GNetworkMonitor -GNetworkMonitorInterface -G_NETWORK_MONITOR_EXTENSION_POINT_NAME -g_network_monitor_get_default -g_network_monitor_get_network_available -g_network_monitor_get_network_metered -g_network_monitor_can_reach -g_network_monitor_can_reach_async -g_network_monitor_can_reach_finish -GNetworkConnectivity -g_network_monitor_get_connectivity - -g_network_monitor_get_type -G_TYPE_NETWORK_CONNECTIVITY -G_TYPE_NETWORK_MONITOR -G_NETWORK_MONITOR -G_IS_NETWORK_MONITOR -G_NETWORK_MONITOR_GET_INTERFACE -g_network_connectivity_get_type -
- -
-gpowerprofilemonitor -GPowerProfileMonitor -GPowerProfileMonitor -GPowerProfileMonitorInterface -G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME -g_power_profile_monitor_dup_default -g_power_profile_monitor_get_power_saver_enabled - -g_power_profile_monitor_get_type -G_TYPE_POWER_PROFILE_MONITOR -G_POWER_PROFILE_MONITOR -G_IS_POWER_PROFILE_MONITOR -G_POWER_PROFILE_MONITOR_GET_INTERFACE -G_TYPE_POWER_PROFILE_LEVEL -g_power_profile_level_get_type -
- -
-gmenuexporter -G_MENU_EXPORTER_MAX_SECTION_SIZE -g_dbus_connection_export_menu_model -g_dbus_connection_unexport_menu_model -
- -
-gdbusmenumodel -GDBusMenuModel -g_dbus_menu_model_get - - -G_TYPE_DBUS_MENU_MODEL -G_DBUS_MENU_MODEL -G_IS_DBUS_MENU_MODEL - - -g_dbus_menu_model_get_type -
- -
-gmenu -GMenu -g_menu_new -g_menu_freeze - - -g_menu_insert -g_menu_prepend -g_menu_append - - -g_menu_insert_item -g_menu_append_item -g_menu_prepend_item - - -g_menu_insert_section -g_menu_prepend_section -g_menu_append_section - - -g_menu_append_submenu -g_menu_insert_submenu -g_menu_prepend_submenu - - -g_menu_remove -g_menu_remove_all - - -GMenuItem -g_menu_item_new -g_menu_item_new_section -g_menu_item_new_submenu -g_menu_item_new_from_model - - -g_menu_item_set_label -g_menu_item_set_icon -g_menu_item_set_action_and_target_value -g_menu_item_set_action_and_target -g_menu_item_set_detailed_action -g_menu_item_set_section -g_menu_item_set_submenu - - -g_menu_item_get_attribute_value -g_menu_item_get_attribute -g_menu_item_get_link -g_menu_item_set_attribute_value -g_menu_item_set_attribute -g_menu_item_set_link - - -g_menu_item_get_type -g_menu_get_type - - -G_TYPE_MENU -G_MENU -G_IS_MENU - -G_TYPE_MENU_ITEM -G_MENU_ITEM -G_IS_MENU_ITEM -
- -
-gmenumodel -GMenuModel -g_menu_model_is_mutable -g_menu_model_get_n_items - - -G_MENU_ATTRIBUTE_ACTION -G_MENU_ATTRIBUTE_ACTION_NAMESPACE -G_MENU_ATTRIBUTE_TARGET -G_MENU_ATTRIBUTE_LABEL -G_MENU_ATTRIBUTE_ICON -G_MENU_LINK_SECTION -G_MENU_LINK_SUBMENU - - -g_menu_model_get_item_attribute_value -g_menu_model_get_item_attribute -g_menu_model_get_item_link -g_menu_model_iterate_item_attributes -g_menu_model_iterate_item_links - - -g_menu_model_items_changed - - -GMenuAttributeIter -g_menu_attribute_iter_get_next -g_menu_attribute_iter_get_name -g_menu_attribute_iter_get_value -g_menu_attribute_iter_next - - -GMenuLinkIter -g_menu_link_iter_get_name -g_menu_link_iter_get_next -g_menu_link_iter_get_value -g_menu_link_iter_next - - -g_menu_attribute_iter_get_type -g_menu_link_iter_get_type -g_menu_model_get_type -g_menu_model_get_label_quark -g_menu_model_get_action_quark -g_menu_model_get_section_quark -g_menu_model_get_submenu_quark -g_menu_model_get_target_quark - - -GMenuModelClass -GMenuModelPrivate -G_TYPE_MENU_MODEL -G_MENU_MODEL -G_IS_MENU_MODEL -G_MENU_MODEL_CLASS -G_IS_MENU_MODEL_CLASS -G_MENU_MODEL_GET_CLASS - -GMenuAttributeIterClass -GMenuAttributeIterPrivate -G_TYPE_MENU_LINK_ITER -G_MENU_LINK_ITER -G_IS_MENU_LINK_ITER -G_MENU_LINK_ITER_CLASS -G_IS_MENU_LINK_ITER_CLASS -G_MENU_LINK_ITER_GET_CLASS - -GMenuLinkIterClass -GMenuLinkIterPrivate -G_TYPE_MENU_ATTRIBUTE_ITER -G_MENU_ATTRIBUTE_ITER -G_IS_MENU_ATTRIBUTE_ITER -G_MENU_ATTRIBUTE_ITER_CLASS -G_IS_MENU_ATTRIBUTE_ITER_CLASS -G_MENU_ATTRIBUTE_ITER_GET_CLASS -
- -
-gresource -GResource -GResource -GResourceFlags -GResourceLookupFlags -g_resource_load -g_resource_new_from_data -g_resource_ref -g_resource_unref -g_resource_lookup_data -g_resource_open_stream -g_resource_enumerate_children -g_resource_get_info - - -GStaticResource -g_static_resource_init -g_static_resource_fini -g_static_resource_get_resource - - -g_resources_register -g_resources_unregister -g_resources_lookup_data -g_resources_open_stream -g_resources_enumerate_children -g_resources_get_info - - -G_RESOURCE_ERROR -GResourceError - - -G_TYPE_RESOURCE -G_TYPE_RESOURCE_ERROR -G_TYPE_RESOURCE_FILE -G_TYPE_RESOURCE_FLAGS -G_TYPE_RESOURCE_LOOKUP_FLAGS - - -g_resource_get_type -g_resource_error_get_type -g_resource_flags_get_type -g_resource_lookup_flags_get_type -g_resource_error_quark -
- -
-gtestdbus -GTestDBus -GTestDBus -GTestDBusFlags -g_test_dbus_new -g_test_dbus_get_flags -g_test_dbus_get_bus_address -g_test_dbus_add_service_dir -g_test_dbus_up -g_test_dbus_stop -g_test_dbus_down -g_test_dbus_unset - -g_test_dbus_get_type -g_test_dbus_flags_get_type - -G_TEST_DBUS -G_IS_TEST_DBUS -G_TYPE_TEST_DBUS -G_TYPE_TEST_DBUS_FLAGS -
- -
-gtask -GTask -GTask -g_task_new -g_task_set_task_data -g_task_set_priority -g_task_set_check_cancellable -g_task_set_return_on_cancel -g_task_set_source_tag -g_task_set_name -g_task_set_static_name - -g_task_report_error -g_task_report_new_error - -g_task_get_task_data -g_task_get_priority -g_task_get_cancellable -g_task_get_check_cancellable -g_task_get_return_on_cancel -g_task_get_context -g_task_get_source_object -g_task_get_source_tag -g_task_get_name - -g_task_return_boolean -g_task_return_int -g_task_return_pointer -g_task_return_value -g_task_return_error -g_task_return_new_error -g_task_return_error_if_cancelled - -g_task_propagate_boolean -g_task_propagate_int -g_task_propagate_pointer -g_task_propagate_value -g_task_had_error -g_task_get_completed - -g_task_run_in_thread -g_task_run_in_thread_sync -GTaskThreadFunc -g_task_attach_source - -g_task_is_valid - -GTaskClass -GTaskPrivate -G_TYPE_TASK -G_TASK -G_IS_TASK -G_TASK_CLASS -G_IS_TASK_CLASS -G_TASK_GET_CLASS -g_task_get_type -
- -
-gnetworking -gnetworking.h -g_networking_init - -CMSG_LEN -CMSG_SPACE -GLIB_ALIGN_TO_SIZEOF -T_SRV -
- -
-gsimpleproxyresolver -GSimpleProxyResolver -GSimpleProxyResolver -g_simple_proxy_resolver_new -g_simple_proxy_resolver_set_default_proxy -g_simple_proxy_resolver_set_ignore_hosts -g_simple_proxy_resolver_set_uri_proxy - -GSimpleProxyResolverClass -GSimpleProxyResolverPrivate -G_TYPE_SIMPLE_PROXY_RESOLVER -G_SIMPLE_PROXY_RESOLVER -G_IS_SIMPLE_PROXY_RESOLVER -G_SIMPLE_PROXY_RESOLVER_CLASS -G_IS_SIMPLE_PROXY_RESOLVER_CLASS -G_SIMPLE_PROXY_RESOLVER_GET_CLASS -g_simple_proxy_resolver_get_type -
- -
-gsubprocess -GSubprocess -GSubprocess -GSubprocessFlags -g_subprocess_new -g_subprocess_newv -g_subprocess_get_identifier - -g_subprocess_get_stdin_pipe -g_subprocess_get_stdout_pipe -g_subprocess_get_stderr_pipe - -g_subprocess_wait -g_subprocess_wait_async -g_subprocess_wait_finish -g_subprocess_wait_check -g_subprocess_wait_check_async -g_subprocess_wait_check_finish - -g_subprocess_get_successful -g_subprocess_get_if_exited -g_subprocess_get_exit_status -g_subprocess_get_if_signaled -g_subprocess_get_term_sig -g_subprocess_get_status - -g_subprocess_send_signal -g_subprocess_force_exit - -g_subprocess_communicate -g_subprocess_communicate_async -g_subprocess_communicate_finish -g_subprocess_communicate_utf8 -g_subprocess_communicate_utf8_async -g_subprocess_communicate_utf8_finish - -G_IS_SUBPROCESS -G_TYPE_SUBPROCESS -G_SUBPROCESS -G_TYPE_SUBPROCESS_FLAGS -g_subprocess_get_type -g_subprocess_flags_get_type -
- -
-gsubprocesslauncher -GSubprocessLauncher -GSubprocessLauncher -g_subprocess_launcher_new -g_subprocess_launcher_spawn -g_subprocess_launcher_spawnv -g_subprocess_launcher_set_environ -g_subprocess_launcher_setenv -g_subprocess_launcher_unsetenv -g_subprocess_launcher_getenv -g_subprocess_launcher_set_cwd -g_subprocess_launcher_set_flags -g_subprocess_launcher_set_stdin_file_path -g_subprocess_launcher_take_stdin_fd -g_subprocess_launcher_set_stdout_file_path -g_subprocess_launcher_take_stdout_fd -g_subprocess_launcher_set_stderr_file_path -g_subprocess_launcher_take_stderr_fd -g_subprocess_launcher_take_fd -g_subprocess_launcher_close -g_subprocess_launcher_set_child_setup - -G_IS_SUBPROCESS_LAUNCHER -G_SUBPROCESS_LAUNCHER -G_TYPE_SUBPROCESS_LAUNCHER -g_subprocess_launcher_get_type -
- -
-gnotification -GNotification -GNotification -g_notification_new - -g_notification_set_title -g_notification_set_body -g_notification_set_icon -GNotificationPriority -g_notification_set_priority -g_notification_set_urgent -g_notification_set_category - -g_notification_set_default_action -g_notification_set_default_action_and_target -g_notification_set_default_action_and_target_value - -g_notification_add_button -g_notification_add_button_with_target -g_notification_add_button_with_target_value - -G_IS_NOTIFICATION -G_NOTIFICATION -G_TYPE_NOTIFICATION -G_TYPE_NOTIFICATION_BACKEND -g_notification_get_type -G_TYPE_NOTIFICATION_PRIORITY -g_notification_priority_get_type -
- -
-glistmodel -GListModel -GListModel -GListModelInterface - -g_list_model_get_item_type -g_list_model_get_n_items -g_list_model_get_item -g_list_model_get_object -g_list_model_items_changed - -G_TYPE_LIST_MODEL -G_LIST_MODEL -G_IS_LIST_MODEL -G_LIST_MODEL_GET_IFACE - -g_list_model_get_type -
- -
-gliststore -GListStore -GListStore - -g_list_store_new -g_list_store_insert -g_list_store_insert_sorted -g_list_store_append -g_list_store_remove -g_list_store_remove_all -g_list_store_splice -g_list_store_sort -g_list_store_find -g_list_store_find_with_equal_func -g_list_store_find_with_equal_func_full - -G_TYPE_LIST_STORE - -g_list_store_get_type -
diff --git a/docs/reference/gio/gio-sections-win32.txt b/docs/reference/gio/gio-sections-win32.txt deleted file mode 100644 index de60cdd..0000000 --- a/docs/reference/gio/gio-sections-win32.txt +++ /dev/null @@ -1,122 +0,0 @@ -
-gwin32inputstream -GWin32InputStream -GWin32InputStream -g_win32_input_stream_new -g_win32_input_stream_set_close_handle -g_win32_input_stream_get_close_handle -g_win32_input_stream_get_handle - -GWin32InputStreamClass -G_WIN32_INPUT_STREAM -G_IS_WIN32_INPUT_STREAM -G_TYPE_WIN32_INPUT_STREAM -G_WIN32_INPUT_STREAM_CLASS -G_IS_WIN32_INPUT_STREAM_CLASS -G_WIN32_INPUT_STREAM_GET_CLASS - -g_win32_input_stream_get_type -GWin32InputStreamPrivate -
- -
-gwin32outputstream -GWin32OutputStream -GWin32OutputStream -g_win32_output_stream_new -g_win32_output_stream_set_close_handle -g_win32_output_stream_get_close_handle -g_win32_output_stream_get_handle - -GWin32OutputStreamClass -G_WIN32_OUTPUT_STREAM -G_IS_WIN32_OUTPUT_STREAM -G_TYPE_WIN32_OUTPUT_STREAM -G_WIN32_OUTPUT_STREAM_CLASS -G_IS_WIN32_OUTPUT_STREAM_CLASS -G_WIN32_OUTPUT_STREAM_GET_CLASS - -g_win32_output_stream_get_type -GWin32OutputStreamPrivate -
- -
-gwin32registrykey - - -GWin32RegistrySubkeyIter -g_win32_registry_subkey_iter_copy -g_win32_registry_subkey_iter_free -g_win32_registry_subkey_iter_assign - - -GWin32RegistryValueIter -g_win32_registry_value_iter_copy -g_win32_registry_value_iter_free -g_win32_registry_value_iter_assign - - -GWin32RegistryKey -g_win32_registry_key_new -g_win32_registry_key_new_w -g_win32_registry_key_get_child -g_win32_registry_key_get_child_w - - -g_win32_registry_subkey_iter_init -g_win32_registry_subkey_iter_clear -g_win32_registry_subkey_iter_n_subkeys -g_win32_registry_subkey_iter_next -g_win32_registry_subkey_iter_get_name -g_win32_registry_subkey_iter_get_name_w - - -g_win32_registry_value_iter_init -g_win32_registry_value_iter_clear -g_win32_registry_value_iter_n_values -g_win32_registry_value_iter_next -GWin32RegistryValueType -g_win32_registry_value_iter_get_value_type -g_win32_registry_value_iter_get_name -g_win32_registry_value_iter_get_name_w -g_win32_registry_value_iter_get_data -g_win32_registry_value_iter_get_data_w - - -g_win32_registry_key_get_value -g_win32_registry_key_get_value_w -g_win32_registry_key_get_path -g_win32_registry_key_get_path_w -GWin32RegistryKeyWatchCallbackFunc -GWin32RegistryKeyWatcherFlags -g_win32_registry_key_watch -g_win32_registry_key_has_changed -g_win32_registry_key_erase_change_indicator - - -GWin32RegistryKeyClass - - -GWin32RegistryKeyPrivate -g_win32_registry_key_get_type -g_win32_registry_subkey_iter_get_type -g_win32_registry_value_iter_get_type -G_TYPE_WIN32_REGISTRY_KEY -G_WIN32_REGISTRY_KEY -G_WIN32_REGISTRY_KEY_CLASS -G_IS_WIN32_REGISTRY_KEY -G_IS_WIN32_REGISTRY_KEY_CLASS -G_WIN32_REGISTRY_KEY_GET_CLASS -G_TYPE_WIN32_REGISTRY_SUBKEY_ITER -G_TYPE_WIN32_REGISTRY_VALUE_ITER -
- -
-gregistrysettingsbackend -GRegistrySettingsBackend -GRegistrySettingsBackend -g_registry_settings_backend_new - - -g_registry_settings_backend_get_type -
diff --git a/docs/reference/gio/gio.rst b/docs/reference/gio/gio.rst new file mode 100644 index 0000000..d3ffa3e --- /dev/null +++ b/docs/reference/gio/gio.rst @@ -0,0 +1,528 @@ +.. _gio(1): +.. meta:: + :copyright: Copyright 2015, 2019, 2020 Red Hat, Inc. + :copyright: Copyright 2018, 2019 Endless Mobile, Inc. + :copyright: Copyright 2018 segfault + :copyright: Copyright 2020 Frederic Martinsons + :copyright: Copyright 2022 Marco Trevisan + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2015, 2019, 2020 Red Hat, Inc. + SPDX-FileCopyrightText: 2018, 2019 Endless Mobile, Inc. + SPDX-FileCopyrightText: 2018 segfault + SPDX-FileCopyrightText: 2020 Frederic Martinsons + SPDX-FileCopyrightText: 2022 Marco Trevisan + SPDX-License-Identifier: LGPL-2.1-or-later + +=== +gio +=== + +-------------------- +GIO commandline tool +-------------------- + +SYNOPSIS +-------- + +| **gio** help [*COMMAND*] +| **gio** version +| **gio** cat *LOCATION*… +| **gio** copy [*OPTION*…] *SOURCE*… *DESTINATION* +| **gio** info [*OPTION*…] *LOCATION*… +| **gio** launch *DESKTOP-FILE* [*FILE-ARG*…] +| **gio** list [*OPTION*…] [*LOCATION*…] +| **gio** mime *MIME-TYPE* [*HANDLER*] +| **gio** mkdir [*OPTION*…] *LOCATION*… +| **gio** monitor [*OPTION*…] [*LOCATION*…] +| **gio** mount [*OPTION*…] [*LOCATION*…] +| **gio** move [*OPTION*…] *SOURCE*… *DESTINATION* +| **gio** open *LOCATION*… +| **gio** rename *LOCATION* *NAME* +| **gio** remove [*OPTION*…] *LOCATION*… +| **gio** save [*OPTION*…] *DESTINATION* +| **gio** set [*OPTION*…] *LOCATION* *ATTRIBUTE* *VALUE*… +| **gio** trash [*OPTION*…] [*LOCATION*…] +| **gio** tree [*OPTION*…] [*LOCATION*…] + +DESCRIPTION +----------- + +``gio`` is a utility that makes many of the GIO features available from the +commandline. In doing so, it provides commands that are similar to traditional +utilities, but let you use GIO locations instead of local files: for example you +can use something like ``smb://server/resource/file.txt`` as a location. + +Plain filenames which contain a colon will be interpreted as URIs with an +unknown protocol. To avoid this, prefix them with a path such as ``./``, or with +the ``file:`` protocol. + +COMMANDS +-------- + +``help`` *COMMAND* + + Displays a short synopsis of the available commands or provides detailed help + on a specific command. + +``version`` + + Prints the GLib version to which ``gio`` belongs. + +``cat`` *LOCATION*… + + Concatenates the given files and prints them to the standard output. + + The ``cat`` command works just like the traditional ``cat`` utility. + + Mote: just pipe through ``cat`` if you need its formatting options like + ``-n``, ``-T`` or other. + +``copy`` [*OPTION*…] *SOURCE*… *DESTINATION* + + Copies one or more files from ``SOURCE`` to ``DESTINATION``. If more than one + source is specified, the destination must be a directory. + + The ``copy`` command is similar to the traditional ``cp`` utility. + + **Options** + + ``-T``, ``--no-target-directory`` + + Don’t copy into ``DESTINATION`` even if it is a directory. + + ``-p``, ``--progress`` + + Show progress. + + ``-i``, ``--interactive`` + + Prompt for confirmation before overwriting files. + + ``--preserve`` + + Preserve all attributes of copied files. + + ``-b``, ``--backup`` + + Create backups of existing destination files. + + ``-P``, ``--no-dereference`` + + Never follow symbolic links. + + ``--default-permissions`` + + Use the default permissions of the current process for the destination file, + rather than copying the permissions of the source file. + +``info`` [*OPTION*…] *LOCATION*… + + Shows information about the given locations. + + The ``info`` command is similar to the traditional ``ls`` utility. + + **Options** + + ``-w``, ``--query-writable`` + + List writable attributes. + + ``-f``, ``--filesystem`` + + Show information about the filesystem that the given locations reside on. + + ``-a``, ``--attributes=`` + + The attributes to get. + + Attributes can be specified with their GIO name, e.g. ``standard::icon``, + or just by namespace, e.g. ``unix``, or by ``*``, which matches all + attributes. Several attributes or groups of attributes can be specified, + separated by commas. + + By default, all attributes are listed. + + ``-n``, ``--nofollow-symlinks`` + + Don’t follow symbolic links. + +``launch`` *DESKTOP-FILE* [*FILE-ARG*…] + + Launch a desktop file from any location given. + + The ``launch`` command extends the behavior of the ``open`` command by + allowing any desktop file to be launched, not only those registered as file + handlers. + +``list`` [*OPTION*…] [*LOCATION*…] + + Lists the contents of the given locations. If no location is given, the + contents of the current directory are shown. + + The ``list`` command is similar to the traditional ``ls`` utility. + + **Options** + + ``-a``, ``--attributes=`` + + The attributes to get. + + Attributes can be specified with their GIO name, e.g. ``standard::icon``, or + just by namespace, e.g. ``unix``, or by ``*``, which matches all attributes. + Several attributes or groups of attributes can be specified, separated by + commas. + + By default, all attributes are listed. + + ``-h``, ``--hidden`` + + Show hidden files. + + ``-l``, ``--long`` + + Use a long listing format. + + ``-n``, ``--nofollow-symlinks`` + + Don’t follow symbolic links. + + ``-d``, ``--print-display-names`` + + Print display names. + + ``-u``, ``--print-uris`` + + Print full URIs. + +``mime`` *MIME-TYPE* [*HANDLER*] + + If no handler is given, the ``mime`` command lists the registered and + recommended applications for the MIME type. If a handler is given, it is set + as the default handler for the MIME type. + + Handlers must be specified by their desktop file name, including the + extension. Example: ``org.gnome.gedit.desktop``. + +``mkdir`` [*OPTION*…] *LOCATION*… + + Creates directories. + + The ``mkdir`` command is similar to the traditional ``mkdir`` utility. + + **Options** + + ``-p``, ``--parent`` + + Create parent directories when necessary. + +``monitor`` [*OPTION*…] [*LOCATION*…] + + Monitors files or directories for changes, such as creation deletion, content + and attribute changes, and mount and unmount operations affecting the + monitored locations. + + The ``monitor`` command uses the GIO file monitoring APIs to do its job. GIO + has different implementations for different platforms. The most common + implementation on Linux uses inotify. + + **Options** + + ``-d``, ``--dir=`` + + Monitor the given location as a directory. Normally, the file type is used + to determine whether to monitor as a file or as a directory. + + ``-f``, ``--file=`` + + Monitor the given location as a file. Normally, the file type is used to + determine whether to monitor as a file or as a directory. + + ``-D``, ``--direct=`` + + Monitor the file directly. This allows changes made via hardlinks to be + captured. + + ``-s``, ``--silent=`` + + Monitor the file directly, but don’t report changes. + + ``-n``, ``--no-moves`` + + Report moves and renames as simple deleted/created events. + + ``-m``, ``--mounts`` + + Watch for mount events. + +``mount`` [*OPTION*…] [*LOCATION*…] + + Provides commandline access to various aspects of GIO’s mounting + functionality. + + Mounting refers to the traditional concept of arranging multiple file systems + and devices in a single tree, rooted at ``/``. Classical mounting happens in + the kernel and is controlled by the mount utility. GIO expands this concept by + introducing mount daemons that can make file systems available to GIO + applications without kernel involvement. + + GIO mounts can require authentication, and the ``mount`` command may ask for + user IDs, passwords, and so on, when required. + + **Options** + + ``-m``, ``--mountable`` + + Mount as mountable. + + ``-d``, ``--device=`` + + Mount volume with device file, or other identifier. + + ``-u``, ``--unmount`` + + Unmount the location. + + ``-e``, ``--eject`` + + Eject the location. + + ``-t``, ``--stop=`` + + Stop drive with device file. + + ``-s``, ``--unmount-scheme=`` + + Unmount all mounts with the given scheme. + + ``-f``, ``--force`` + + Ignore outstanding file operations when unmounting or ejecting. + + ``-a``, ``--anonymous`` + + Use an anonymous user when authenticating. + + ``-l``, ``--list`` + + List all GIO mounts. + + ``-o``, ``--monitor`` + + Monitor mount-related events. + + ``-i``, ``--detail`` + + Show extra information. + + ``--tcrypt-pim`` + + The numeric PIM when unlocking a VeraCrypt volume. + + ``--tcrypt-hidden`` + + Mount a TCRYPT hidden volume. + + ``--tcrypt-system`` + + Mount a TCRYPT system volume. + +``move`` [*OPTION*…] *SOURCE*… *DESTINATION* + + Moves one or more files from ``SOURCE`` to ``DESTINATION``. If more than one + source is specified, the destination must be a directory. + + The ``move`` command is similar to the traditional ``mv`` utility. + + **Options** + + ``-T``, ``--no-target-directory`` + + Don’t copy into ``DESTINATION`` even if it is a directory. + + ``-p``, ``--progress`` + + Show progress. + + ``-i``, ``--interactive`` + + Prompt for confirmation before overwriting files. + + ``-b``, ``--backup`` + + Create backups of existing destination files. + + ``-C``, ``--no-copy-fallback`` + + Don’t use copy and delete fallback. + +``open`` *LOCATION*… + + Opens files with the default application that is registered to handle files of + this type. + + GIO obtains this information from the shared-mime-info database, with per-user + overrides stored in ``$XDG_DATA_HOME/applications/mimeapps.list``. + + The ``mime`` command can be used to change the default handler for a MIME + type. + + Environment variables will not be set on the application, as it may be an + existing process which is activated to handle the new file. + +``rename`` *LOCATION* *NAME* + + Renames a file. + + The ``rename`` command is similar to the traditional ``rename`` utility. + +``remove`` [*OPTION*…] *LOCATION*… + + Deletes each given file. + + This command removes files irreversibly. If you want a reversible way to + remove files, see the ``trash`` command. + + Note that not all URI schemes that are supported by GIO may allow deletion of + files. + + The ``remove`` command is similar to the traditional ``rm`` utility. + + **Options** + + ``-f``, ``--force`` + + Ignore non-existent and non-deletable files. + +``save`` [*OPTION*…] *DESTINATION* + + Reads from standard input and saves the data to the given location. + + This is similar to just redirecting output to a file using traditional shell + syntax, but the ``save`` command allows saving to location that GIO can write + to. + + **Options** + + ``-b``, ``--backup`` + + Back up existing destination files. + + ``-c``, ``--create`` + + Only create the destination if it doesn’t exist yet. + + ``-a``, ``--append`` + + Append to the end of the file. + + ``-p``, ``--private`` + + When creating, restrict access to the current user. + + ``-u``, ``--unlink`` + + When replacing, replace as if the destination did not exist. + + ``-v``, ``--print-etag`` + + Print the new ETag in the end. + + ``-e``, ``--etag=`` + + The ETag of the file that is overwritten. + +``set`` [*OPTION*…] *LOCATION* *ATTRIBUTE* *VALUE*… + + Sets a file attribute on a file. + + File attributes can be specified with their GIO name, e.g ``standard::icon``. + Note that not all GIO file attributes are writable. Use the + ``--query-writable`` option of the ``info`` command to list writable file + attributes. + + If the ``TYPE`` is unset, ``VALUE`` does not have to be specified. If the + ``TYPE`` is ``stringv``, multiple values can be given. + + **Options** + + ``-t``, ``--type=`` + + Specifies the type of the attribute. Supported types are ``string``, + ``stringv``, ``bytestring``, ``boolean``, ``uint32``, ``int32``, ``uint64``, + ``int64`` and ``unset``. + + If the type is not specified, ``string`` is assumed. + + ``-d``, ``--delete`` + + Unsets an attribute (same as setting its type to ``unset``). + + ``-n``, ``--nofollow-symlinks`` + + Don’t follow symbolic links. + +``trash`` [*OPTION*…] [*LOCATION*…] + + Sends files or directories to the ‘Trashcan’ or restore them from ‘Trashcan’. + This can be a different folder depending on where the file is located, and not + all file systems support this concept. In the common case that the file lives + inside a user’s home directory, the trash folder is ``$XDG_DATA_HOME/Trash``. + + Note that moving files to the trash does not free up space on the file system + until the ‘Trashcan’ is emptied. If you are interested in deleting a file + irreversibly, see the ``remove`` command. + + Inspecting and emptying the ‘Trashcan’ is normally supported by graphical file + managers such as Nautilus, but you can also see the trash with the command: + ``gio trash --list`` or ``gio list trash://``. + + **Options** + + ``-f``, ``--force`` + + Ignore non-existent and non-deletable files. + + ``--empty`` + + Empty the trash. + + ``--list`` + + List files in the trash with their original locations. + + ``--restore`` + + Restore a file from trash to its original location. A URI beginning with + ``trash://`` is expected here. If the original directory doesn’t exist, it + will be recreated. + +``tree`` [*OPTION*…] [*LOCATION*…] + + Lists the contents of the given locations recursively, in a tree-like format. + If no location is given, it defaults to the current directory. + + The ``tree`` command is similar to the traditional ``tree`` utility. + + **Options** + + ``-h``, ``--hidden`` + + Show hidden files. + + ``-l``, ``--follow-symlinks`` + + Follow symbolic links. + +EXIT STATUS +----------- + +On success, ``0`` is returned, a non-zero failure code otherwise. + +SEE ALSO +-------- + +`cat(1) `_, `cp(1) `_, `ls(1) `_, +`mkdir(1) `_, `mv(1) `_, `rm(1) `_, +`tree(1) `_ \ No newline at end of file diff --git a/docs/reference/gio/gio.toml.in b/docs/reference/gio/gio.toml.in new file mode 100644 index 0000000..40559fa --- /dev/null +++ b/docs/reference/gio/gio.toml.in @@ -0,0 +1,72 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2023 Matthias Clasen +# Copyright 2023 Philip Withnall + +[library] +name = "Gio" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/glib/" +repository_url = "https://gitlab.gnome.org/GNOME/glib.git" +website_url = "https://www.gtk.org" +docs_urls = "https://docs.gtk.org/gio/" +authors = "GLib Development Team" +license = "LGPL-2.1-or-later" +description = "Gio is a library providing useful classes for general purpose I/O, networking, IPC, settings, and other high level application functionality" +dependencies = [ "GLib-2.0", "GModule-2.0", "GObject-2.0" ] +devhelp = true +search_index = true + + [dependencies."GLib-2.0"] + name = "GLib" + description = "The base utility library" + docs_url = "https://docs.gtk.org/glib/" + + [dependencies."GModule-2.0"] + name = "GModule" + description = "Portable API for dynamically loading modules" + docs_url = "https://docs.gtk.org/gmodule/" + + [dependencies."GObject-2.0"] + name = "GObject" + description = "The base type system library" + docs_url = "https://docs.gtk.org/gobject/" + +[theme] +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +[extra] +urlmap_file = "urlmap.js" +# The same order will be used when generating the index +content_files = [ + "overview.md", + "file-attributes.md", + "tls-overview.md", + + "error.md", + + "pollable-utils.md", + "unix-mounts.md", + + "dbus-error.md", + "dbus-introspection.md", + "dbus-name-owning.md", + "dbus-name-watching.md", + "dbus-utils.md", + "menu-exporter.md", + + "networking.md", + + "migrating-gdbus.md", + "migrating-gconf.md", + "migrating-gnome-vfs.md", + "migrating-posix.md", + + "io-scheduler.md", +] +content_images = [ + "gvfs-overview.png", + "menu-example.png", + "menu-model.png", +] diff --git a/docs/reference/gio/gio.xml b/docs/reference/gio/gio.xml deleted file mode 100644 index 1805b27..0000000 --- a/docs/reference/gio/gio.xml +++ /dev/null @@ -1,809 +0,0 @@ - - - - - gio - GIO - - - Developer - Matthias - Clasen - mclasen@redhat.com - - - - - - gio - 1 - User Commands - - - - gio - GIO commandline tool - - - - - gio - help - COMMAND - - - gio - version - - - gio - cat - LOCATION - - - gio - copy - OPTION - SOURCE - DESTINATION - - - gio - info - OPTION - LOCATION - - - gio - launch - DESKTOP-FILE - FILE-ARG - - - gio - list - OPTION - LOCATION - - - gio - mime - MIMETYPE - HANDLER - - - gio - mkdir - OPTION - LOCATION - - - gio - monitor - OPTION - LOCATION - - - gio - mount - OPTION - LOCATION - - - gio - move - OPTION - SOURCE - DESTINATION - - - gio - open - LOCATION - - - gio - rename - LOCATION - NAME - - - gio - remove - OPTION - LOCATION - - - gio - save - OPTION - DESTINATION - - - gio - set - OPTION - LOCATION - ATTRIBUTE - VALUE - - - gio - trash - OPTION - LOCATION - - - gio - tree - OPTION - LOCATION - - - - - Description - gio is a utility that makes many of the GIO - features available from the commandline. In doing so, it provides - commands that are similar to traditional utilities, but let you - use GIO locations instead of local files: for example you can use - something like smb://server/resource/file.txt - as a location. - Plain filenames which contain a colon will be interpreted as URIs - with an unknown protocol. To avoid this, prefix them with a path such as - ./, or with the file: protocol. - - - - Commands - - - - - help - COMMAND - - - Displays a short synopsis of the available commands or provides - detailed help on a specific command. - - - - - - version - - - Prints the GLib version to which gio - belongs. - - - - - - cat - LOCATION - - - Concatenates the given files and prints them to the standard - output. - The cat command works just like the traditional cat utility. - Note: just pipe through cat if you need its formatting options - like , or other. - - - - - - copy - OPTION - SOURCE - DESTINATION - - - Copies one or more files from SOURCE - to DESTINATION. If more than one source - is specified, the destination must be a directory. - The copy command is similar to the traditional cp utility. - - Options - - - , - Don’t copy into DESTINATION even if it is a directory. - - - , - Show progress. - - - , - Prompt for confirmation before overwriting files. - - - - Preserve all attributes of copied files. - - - , - Create backups of existing destination files. - - - , - Never follow symbolic links. - - - - Use the default permissions of the current process for the destination file, rather than copying the permissions of the source file. - - - - - - - - info - OPTION - LOCATION - - - Shows information about the given locations. - The info command is similar to the traditional ls utility. - - Options - - - , - List writable attributes. - - - , - Show information about the filesystem that the given - locations reside on. - - - - The attributes to get. - Attributes can be specified with their GIO name, e.g. - standard::icon, or just by namespace, e.g. unix, or by *, - which matches all attributes. Several attributes or groups - of attributes can be specified, separated by comma. - By default, all attributes are listed. - - - , - Don’t follow symbolic links. - - - - - - - - - launch - DESKTOP-FILE - FILE-ARG - - - Launch a desktop file from any location given. - The launch command extends the behavior of the open command by allowing - any desktop file to be launched, not only those registered as file handlers. - - - - - - list - OPTION - LOCATION - - - Lists the contents of the given locations. If no location is - given, the contents of the current directory are shown. - The list command is similar to the traditional ls utility. - - Options - - - - The attributes to get. - Attributes can be specified with their GIO name, e.g. - standard::icon, or just by namespace, e.g. unix, or by *, - which matches all attributes. Several attributes or groups - of attributes can be specified, separated by comma. - By default, all attributes are listed. - - - , - Show hidden files. - - - , - Use a long listing format. - - - , - Don’t follow symbolic links. - - - , - Print display names. - - - , - Print full URIs. - - - - - - - - - mime - MIMETYPE - HANDLER - - - If no handler is given, the mime command lists the - registered and recommended applications for the mimetype. - If a handler is given, it is set as the default handler for - the mimetype. - Handlers must be specified by their desktop file name, - including the extension. Example: org.gnome.gedit.desktop. - - - - - - mkdir - OPTION - LOCATION - - - Creates directories. - The mkdir command is similar to the traditional mkdir utility. - - Options - - - , - Create parent directories when necessary. - - - - - - - - - monitor - OPTION - LOCATION - - - Monitors files or directories for changes, such as creation - deletion, content and attribute changes, and mount and unmount - operations affecting the monitored locations. - The monitor command uses the GIO file monitoring APIs to do - its job. GIO has different implementations for different platforms. - The most common implementation on Linux uses inotify. - - Options - - - , - Monitor the given location as a directory. Normally, - the file type is used to determine whether to monitor a file or directory. - - - , - Monitor the given location as a file. Normally, - the file type is used to determine whether to monitor a file or directory. - - - , - Monitor the file directly. This allows changes made via hardlinks to be captured. - - - , - Monitor the file directly, but don’t report changes. - - - , - Report moves and renames as simple deleted/created events. - - - , - Watch for mount events. - - - - - - - - - mount - OPTION - LOCATION - - - Provides commandline access to various aspects of GIO’s mounting - functionality. - Mounting refers to the traditional concept of arranging multiple - file systems and devices in a single tree, rooted at /. Classical - mounting happens in the kernel and is controlled by the mount utility. - GIO expands this concept by introducing mount daemons that can make - file systems available to GIO applications without kernel - involvement. - GIO mounts can require authentication, and the mount command - may ask for user IDs, passwords, and so on, when required. - - Options - - - , - Mount as mountable. - - - , - Mount volume with device file, or other identifier. - - - , - Unmount the location. - - - , - Eject the location. - - - , - Stop drive with device file. - - - , - Unmount all mounts with the given scheme. - - - , - Ignore outstanding file operations when unmounting or ejecting. - - - , - Use an anonymous user when authenticating. - - - , - List all GIO mounts. - - - , - Monitor mount-related events. - - - - , - Show extra information. - - - - - The numeric PIM when unlocking a VeraCrypt volume. - - - - - Mount a TCRYPT hidden volume. - - - - - Mount a TCRYPT system volume. - - - - - - - - - - move - OPTION - SOURCE - DESTINATION - - - Moves one or more files from SOURCE - to DESTINATION. If more than one source - is specified, the destination must be a directory. - The move command is similar to the traditional mv utility. - - Options - - - , - Don’t copy into DESTINATION even if it is a directory. - - - , - Show progress. - - - , - Prompt for confirmation before overwriting files. - - - , - Create backups of existing destination files. - - - , - Don’t use copy and delete fallback. - - - - - - - - - open - LOCATION - - - Opens files with the default application that is registered - to handle files of this type. - GIO obtains this information from the shared-mime-info - database, with per-user overrides stored in - $XDG_DATA_HOME/applications/mimeapps.list. - The mime command can be used to change the default handler for - a mimetype. - Environment variables will not be set on the application, as it - may be an existing process which is activated to handle the new file. - - - - - - rename - LOCATION - NAME - - - Renames a file. - The rename command is similar to the traditional rename utility. - - - - - - remove - OPTION - LOCATION - - - Deletes each given file. - This command removes files irreversibly. If you want a reversible - way to remove files, see the trash command. - Note that not all URI schemes that are supported by GIO may - allow deletion of files. - The remove command is similar to the traditional rm utility. - - Options - - - , - Ignore non-existent and non-deletable files. - - - - - - - - - save - OPTION - DESTINATION - - - Reads from standard input and saves the data to the given - location. - This is similar to just redirecting output to a file using - traditional shell syntax, but the save command allows saving to - location that GIO can write to. - - Options - - - , - Back up existing destination files. - - - , - Only create the destination if it doesn’t exist yet. - - - , - Append to the end of the file. - - - , - When creating, restrict access to the current user. - - - , - When replacing, replace as if the destination did not exist. - - - , - Print the new ETag in the end. - - - , - The ETag of the file that is overwritten. - - - - - - - - - set - LOCATION - ATTRIBUTE - VALUE - - - Sets a file attribute on a file. - File attributes can be specified with their GIO name, e.g - standard::icon. Note that not all GIO file attributes are writable. - Use the option of the info command to list - writable file attributes. - If the TYPE is unset, - VALUE does not have to be specified. - If the TYPE is stringv, multiple values can be given. - - Options - - - , - Specifies the type of the attribute. Supported - types are string, stringv, - bytestring, boolean, - uint32, int32, - uint64, int64 and unset. - If the type is not specified, string is assumed. - - - - , - Unsets an attribute (same as setting it's type to unset). - - - , - Don’t follow symbolic links. - - - - - - - - - trash - OPTION - LOCATION - - - Sends files or directories to the ‘Trashcan’ or restore them from - ‘Trashcan’. This can be a different folder depending on where the file - is located, and not all file systems support this concept. In the common - case that the file lives inside a user’s home directory, the trash folder is - $XDG_DATA_HOME/Trash. - Note that moving files to the trash does not free up space on - the file system until the ‘Trashcan’ is emptied. If you are interested - in deleting a file irreversibly, see the remove command. - Inspecting and emptying the ‘Trashcan’ is normally supported by - graphical file managers such as Nautilus, but you can also see the - trash with the command: gio trash --list or - gio list trash://. - - Options - - - , - Ignore non-existent and non-deletable files. - - - - Empty the trash. - - - - List files in the trash with their original locations - - - - Restore a file from trash to its original location. A URI beginning - with trash:// is expected here. If the original - directory doesn't exist, it will be recreated. - - - - - - - - - tree - OPTION - LOCATION - - - Lists the contents of the given locations recursively, in a - tree-like format. If no location is given, it defaults to the current - directory. - The tree command is similar to the traditional tree utility. - - Options - - - , - Show hidden files. - - - , - Follow symbolic links. - - - - - - - - - - Exit status - On success 0 is returned, a non-zero failure code otherwise. - - - - See Also - - - cat - 1 - , - - cp - 1 - , - - ls - 1 - , - - mkdir - 1 - , - - mv - 1 - , - - rm - 1 - , - - tree - 1 - . - - - diff --git a/docs/reference/gio/glib-compile-resources.rst b/docs/reference/gio/glib-compile-resources.rst new file mode 100644 index 0000000..096dc1d --- /dev/null +++ b/docs/reference/gio/glib-compile-resources.rst @@ -0,0 +1,181 @@ +.. _glib-compile-resources(1): +.. meta:: + :copyright: Copyright 2012, 2016 Red Hat, Inc. + :copyright: Copyright 2012 Christian Persch + :copyright: Copyright 2016 Sam Thursfield + :copyright: Copyright 2016 Patrick Griffis + :copyright: Copyright 2018 Ninja-Koala + :copyright: Copyright 2018, 2021 Emmanuele Bassi + :copyright: Copyright 2020 Endless OS Foundation, LLC + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2012, 2016 Red Hat, Inc. + SPDX-FileCopyrightText: 2012 Christian Persch + SPDX-FileCopyrightText: 2016 Sam Thursfield + SPDX-FileCopyrightText: 2016 Patrick Griffis + SPDX-FileCopyrightText: 2018 Ninja-Koala + SPDX-FileCopyrightText: 2018, 2021 Emmanuele Bassi + SPDX-FileCopyrightText: 2020 Endless OS Foundation, LLC + SPDX-License-Identifier: LGPL-2.1-or-later + +====================== +glib-compile-resources +====================== + +---------------------- +GLib resource compiler +---------------------- + +SYNOPSIS +-------- + +| **glib-compile-resources** [*OPTION*…] *FILE* + +DESCRIPTION +----------- + +``glib-compile-resources`` reads the resource description from ``FILE`` and the +files that it references and creates a binary resource bundle that is suitable +for use with the ``GResource`` API. The resulting bundle is then written out +as-is, or as C source for linking into an application. + +The XML resource files normally have the filename extension ``.gresource.xml``. +For a detailed description of the XML file format, see the +``GResource`` `documentation `_. + +OPTIONS +------- + +``-h``, ``--help`` + + Print help and exit. + +``--version`` + + Print program version and exit. + +``--target `` + + Store the compiled resources in the file ``TARGET``. If not specified a + filename based on the ``FILE`` basename is used. + +``--sourcedir `` + + The files referenced in ``FILE`` are loaded from this directory. If not + specified, the current directory is used. + +``--generate`` + + Write the output file in the format selected for by its filename extension: + + ``.c`` + + C source + + ``.h`` + + C header + + ``.gresource`` + + resource bundle + +``--generate-source`` + + Instead of a writing the resource bundle in binary form, create a C source + file that contains the resource bundle. This can then be compiled into an + application for easy access. + +``--generate-header`` + + Generate a header file for use with C code generated by ``--generate-source``. + +``--generate-dependencies`` + + Prints the list of files that the resource bundle references to standard + output. This can be used to track dependencies in the build system. For + example, the following make rule would mark ``test.gresource`` as depending on + all the files that ``test.gresource.xml`` includes, so that it is + automatically rebuilt if any of them change:: + + test.gresource: test.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies test.gresource.xml) + + Note that this may or may not be portable to non-GNU ``make``. + + Also see ``--dependency-file``. + +``--c-name`` + + Specify the prefix used for the C identifiers in the code generated by + ``--generate-source`` and ``--generate-header``. + +``--manual-register`` + + By default, code generated by ``--generate-source`` uses automatic + initialization of the resource. This works on most systems by using the + compiler support for constructors. However, some (uncommon) compilers may not + support this, you can then specify ``--manual-register``, + which will generate custom register and unregister functions that your code + can manually call at initialization and uninitialization time. + +``--internal`` + + By default, code generated by ``--generate-source`` declares all + initialization functions as ``extern``. So they are exported unless this is + prevented by a link script or other means. Since libraries usually want to + use the functions only internally it can be more useful to declare them as + ``G_GNUC_INTERNAL`` which is what ``--internal`` does. + +``--external-data`` + + By default, code generated by ``--generate-source`` embeds the resource data + as a string literal. When ``--external-data`` is given, the data is only + declared in the generated C file, and the data has to be linked externally. + +``--dependency-file `` + + Write dependencies in the same style as ``gcc -M -MF`` to the given file. If + ``FILE`` is ``-``, the dependencies are written to the standard output. Unlike + ``--generate-dependencies``, this option can be combined with other + ``--generate`` options to generate dependencies as a side-effect of generating + sources. + +``--generate-phony-targets`` + + When creating a dependency file with ``--dependency-file`` include phony + targets in the same style as ``gcc -MP``. This would typically be used with + ``make``. + +``--compiler `` + + Generate code that is going to target the given compiler ``NAME``. The current + two compiler modes are ``gcc``, for all GCC-compatible toolchains; and + ``msvc``, for the Microsoft Visual C Compiler. If this option isn’t set, then + the default will be taken from the ``CC`` environment variable. + +ENVIRONMENT +----------- + +``XMLLINT`` + + The full path to the ``xmllint`` executable. This is used to preprocess + resources with the ``xml-stripblanks`` preprocessing option. If this + environment variable is not set, ``xmllint`` is searched for in the ``PATH``. + +``GDK_PIXBUF_PIXDATA`` + + Deprecated since gdk-pixbuf 2.32, as ``GResource`` supports embedding + modern image formats without conversion. + + The full path to the ``gdk-pixbuf-pixdata`` executable. This is used to + preprocess resources with the ``to-pixdata`` preprocessing option. If this + environment variable is not set, ``gdk-pixbuf-pixdata`` is searched for in the + ``PATH``. + +``JSON_GLIB_FORMAT`` + + The full path to the ``json-glib-format`` executable. This is used to + preprocess resources with the ``json-stripblanks`` preprocessing option. If + this environment variable is not set, ``json-glib-format`` is searched for in + the ``PATH``. \ No newline at end of file diff --git a/docs/reference/gio/glib-compile-resources.xml b/docs/reference/gio/glib-compile-resources.xml deleted file mode 100644 index 7ab36f5..0000000 --- a/docs/reference/gio/glib-compile-resources.xml +++ /dev/null @@ -1,254 +0,0 @@ - - - - glib-compile-schemas - GIO - - - Developer - Alexander - Larsson - - - - - - glib-compile-resources - 1 - User Commands - - - - glib-compile-resources - GLib resource compiler - - - - - glib-compile-resources - OPTION - FILE - - - -Description -glib-compile-resources reads the resource description from -FILE and the files that it references -and creates a binary resource bundle that is suitable for use with the -GResource API. -The resulting bundle is then written out as-is, or as C source for linking into -an application. - - -The XML resource files normally have the filename extension .gresource.xml. -For a detailed description of the XML file format, see the -GResource documentation. - - - -Options - - - -, - -Print help and exit - - - - - - -Print program version and exit - - - - - - -Store the compiled resources in the file TARGET. -If not specified a filename based on the FILE -basename is used. - - - - - - -The files referenced in FILE are loaded from -this directory. If not specified, the current directory is used. - - - - - - -Write the output file in the format selected for by its filename extension: - - -.c -C source - - -.h -C header - - -.gresource -resource bundle - - - - - - - - -Instead of a writing the resource bundle in binary form create a C source file -that contains the resource bundle. This can then be compiled into an -application for easy access. - - - - - - -Generate a header file for use with C code generated by -. - - - - - - -Prints the list of files that the resource bundle references to standard output. -This can be used to track dependencies in the build system. For example, the -following make rule would mark test.gresource as -depending on all the files that test.gresource.xml -includes, so that is is automatically rebuilt if any of them change: - -test.gresource: test.gresource.xml $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies test.gresource.xml) - -Note that this may or may not be portable to non-GNU make. - - -Also see . - - - - - - - -Specify the prefix used for the C identifiers in the code generated by - and . - - - - - - -By default code generated by uses automatic -initialization of the resource. This works on most systems by using the -compiler support for constructors. However, some (uncommon) compilers may not -support this, you can then specify , -which will generate custom register and unregister functions that your code -can manually call at initialization and uninitialization time. - - - - - - -By default code generated by declares all -initialization functions as extern. So they are exported -unless this is prevented by a link script or other means. Since libraries -usually want to use the functions only internally it can be more useful to -declare them as -G_GNUC_INTERNAL -which is what does. - - - - - - -By default code generated by embeds the -resource data as a string literal. When -is given, the data is only declared in the generated C file, and the data -has to be linked externally. - - - - - - -Write dependencies in the same style as gcc -M -MF to the given file. -If is -, the dependencies are written to the standard -output. Unlike , this option can be -combined with other options to generate dependencies -as a side-effect of generating sources. - - - - - - -When creating a dependency file with -include phony targets in the same style as gcc -MP. This would typically -be used with make. - - - - - - -Generate code that is going to target the given compiler NAME. -The current two compiler modes are "gcc", for all GCC-compatible toolchains; and "msvc", -for the Microsoft Visual C Compiler. If this option isn't set, then the default will be -taken from the CC environment variable. - - - - - - -Environment - - - -XMLLINT - -The full path to the xmllint executable. This is used to -preprocess resources with the xml-stripblanks preprocessing -option. If this environment variable is not set, xmllint is -searched for in the PATH. - - - - -GDK_PIXBUF_PIXDATA - -Deprecated since gdk-pixbuf 2.32, as GResource supports embedding -modern image formats without conversion. - -The full path to the gdk-pixbuf-pixdata executable. This is -used to preprocess resources with the to-pixdata preprocessing -option. If this environment variable is not set, gdk-pixbuf-pixdata -is searched for in the PATH. - - - - -JSON_GLIB_FORMAT - -The full path to the json-glib-format executable. This is used -to preprocess resources with the json-stripblanks preprocessing -option. If this environment variable is not set, json-glib-format -is searched for in the PATH. - - - - - - diff --git a/docs/reference/gio/glib-compile-schemas.rst b/docs/reference/gio/glib-compile-schemas.rst new file mode 100644 index 0000000..4f42092 --- /dev/null +++ b/docs/reference/gio/glib-compile-schemas.rst @@ -0,0 +1,83 @@ +.. _glib-compile-schemas(1): +.. meta:: + :copyright: Copyright 2010, 2011, 2012, 2015 Red Hat, Inc. + :copyright: Copyright 2012 Allison Karlitskaya + :copyright: Copyright 2016 Sam Thursfield + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2010, 2011, 2012, 2015 Red Hat, Inc. + SPDX-FileCopyrightText: 2012 Allison Karlitskaya + SPDX-FileCopyrightText: 2016 Sam Thursfield + SPDX-License-Identifier: LGPL-2.1-or-later + +==================== +glib-compile-schemas +==================== + +------------------------- +GSettings schema compiler +------------------------- + +SYNOPSIS +-------- + +| **glib-compile-schemas** [*OPTION*…] *DIRECTORY* + +DESCRIPTION +----------- + +``glib-compile-schemas`` compiles all the GSettings XML schema files in +``DIRECTORY`` into a binary file with the name ``gschemas.compiled`` that can be +used by ``GSettings``. The XML schema files must have the filename extension +``.gschema.xml``. For a detailed description of the XML file format, see the +``GSettings`` documentation. + +At runtime, GSettings looks for schemas in the ``glib-2.0/schemas`` +subdirectories of all directories specified in the ``XDG_DATA_DIRS`` environment +variable. The usual location to install schema files is +``/usr/share/glib-2.0/schemas``. + +In addition to schema files, ``glib-compile-schemas`` reads ‘vendor override’ +files, which are key files that can override default values for keys in +the schemas. The group names in the key files are the schema ID, and the +values are written in serialized GVariant form. +Vendor override files must have the filename extension +``.gschema.override``. + +By convention, vendor override files begin with ``nn_`` where ``nn`` is a number +from 00 to 99. Higher numbered files have higher priority (e.g. if the same +override is made in a file numbered 10 and then again in a file numbered 20, the +override from 20 will take precedence). + +OPTIONS +------- + +``-h``, ``--help`` + + Print help and exit. + +``--version`` + + Print program version and exit. + +``--targetdir `` + + Store ``gschemas.compiled`` in the ``TARGET`` directory instead of + ``DIRECTORY``. + +``--strict`` + + Abort on any errors in schemas. Without this option, faulty schema files are + simply omitted from the resulting compiled schema. + +``--dry-run`` + + Don’t write ``gschemas.compiled``. This option can be used to check + ``.gschema.xml`` sources for errors. + +``--allow-any-name`` + + Do not enforce restrictions on key names. Note that this option is purely + to facility the transition from GConf, and will be removed at some time + in the future. \ No newline at end of file diff --git a/docs/reference/gio/glib-compile-schemas.xml b/docs/reference/gio/glib-compile-schemas.xml deleted file mode 100644 index 0796bd7..0000000 --- a/docs/reference/gio/glib-compile-schemas.xml +++ /dev/null @@ -1,118 +0,0 @@ - - - - glib-compile-schemas - GIO - - - Developer - Ryan - Lortie - - - - - - glib-compile-schemas - 1 - User Commands - - - - glib-compile-schemas - GSettings schema compiler - - - - - glib-compile-schemas - OPTION - DIRECTORY - - - -Description -glib-compile-schemas compiles all the GSettings XML -schema files in DIRECTORY into a binary file -with the name gschemas.compiled that can be used -by GSettings. The XML schema -files must have the filename extension .gschema.xml. -For a detailed description of the XML file format, see the -GSettings documentation. - - -At runtime, GSettings looks for schemas in the -glib-2.0/schemas subdirectories of all directories -specified in the XDG_DATA_DIRS environment variable. The -usual location to install schema files is -/usr/share/glib-2.0/schemas. - - -In addition to schema files, glib-compile-schemas reads 'vendor override' -files, which are key files that can override default values for keys in -the schemas. The group names in the key files are the schema id, and the -values are written in serialized GVariant form. -Vendor override files must have the filename extension -.gschema.override. - - -By convention, vendor override files begin with nn_ -where nn is a number from 00 to 99. Higher -numbered files have higher priority (eg: if the same override is made in -a file numbered 10 and then again in a file numbered 20, the override -from 20 will take precedence). - - - -Options - - - -, - -Print help and exit - - - - - - -Print program version and exit - - - - - - -Store gschemas.compiled in the TARGET directory instead of DIRECTORY. - - - - - - -Abort on any errors in schemas. Without this option, faulty schema files are -simply omitted from the resulting compiled schema. - - - - - - -Don't write gschemas.compiled. This option can be used -to check .gschema.xml sources for errors. - - - - - - -Do not enforce restrictions on key names. Note that this option is purely -to facility the transition from GConf, and will be removed at some time -in the future. - - - - - - diff --git a/docs/reference/gio/gresource.rst b/docs/reference/gio/gresource.rst new file mode 100644 index 0000000..cb65c69 --- /dev/null +++ b/docs/reference/gio/gresource.rst @@ -0,0 +1,66 @@ +.. _gresource(1): +.. meta:: + :copyright: Copyright 2012 Red Hat, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2012 Red Hat, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +========= +gresource +========= + +-------------- +GResource tool +-------------- + +SYNOPSIS +-------- + +| **gresource** [--section *SECTION*] list *FILE* [*PATH*] +| **gresource** [--section *SECTION*] details *FILE* [*PATH*] +| **gresource** [--section *SECTION*] extract *FILE* *PATH* +| **gresource** sections *FILE* +| **gresource** help [*COMMAND*] + +DESCRIPTION +----------- + +``gresource`` offers a simple commandline interface to ``GResource``. It lets +you list and extract resources that have been compiled into a resource file or +included in an ELF file (a binary or a shared library). + +The file to operate on is specified by the ``FILE`` argument. + +If an ELF file includes multiple sections with resources, it is possible to +select which one to operate on with the ``--section`` option. Use the +``sections`` command to find available sections. + +COMMANDS +-------- + +``list`` + + Lists resources. If ``SECTION`` is given, only list resources in this section. + If ``PATH`` is given, only list matching resources. + +``details`` + + Lists resources with details. If ``SECTION`` is given, only list resources in + this section. If ``PATH`` is given, only list matching resources. Details + include the section, size and compression of each resource. + +``extract`` + + Extracts the resource named by ``PATH`` to stdout. Note that resources may + contain binary data. + +``sections`` + + Lists sections containing resources. This is only interesting if ``FILE`` is + an ELF file. + +``help`` + + Prints help and exits. \ No newline at end of file diff --git a/docs/reference/gio/gresource.xml b/docs/reference/gio/gresource.xml deleted file mode 100644 index 4ada0eb..0000000 --- a/docs/reference/gio/gresource.xml +++ /dev/null @@ -1,127 +0,0 @@ - - - - gresource - GIO - - - Developer - Matthias - Clasen - - - - - - gresource - 1 - User Commands - - - - gresource - GResource tool - - - - - gresource - --section SECTION - list - FILE - PATH - - - gresource - --section SECTION - details - FILE - PATH - - - gresource - --section SECTION - extract - FILE - PATH - - - gresource - sections - FILE - - - gresource - help - COMMAND - - - -Description -gresource offers a simple commandline -interface to GResource. -It lets you list and extract resources that have been compiled -into a resource file or included in an elf file (a binary or a -shared library). - - -The file to operate on is specified by the FILE -argument. - - -If an elf file includes multiple sections with resources, it is -possible to select which one to operate on with the ---section option. Use the -sections command to find available sections. - - - -Commands - - - - - -Lists resources. If SECTION is given, only -list resources in this section. If PATH is -given, only list matching resources. - - - - - - -Lists resources with details. If SECTION -is given, only list resources in this section. If -PATH is given, only list matching resources. -Details include the section, size and compression of each resource. - - - - - - -Extracts the resource named by PATH to stdout. -Note that resources may contain binary data. - - - - - - -Lists sections containing resources. This is only interesting if -FILE is an elf file. - - - - - - -Prints help and exits. - - - - - - - diff --git a/docs/reference/gio/gsettings.rst b/docs/reference/gio/gsettings.rst new file mode 100644 index 0000000..c89aa35 --- /dev/null +++ b/docs/reference/gio/gsettings.rst @@ -0,0 +1,125 @@ +.. _gsettings(1): +.. meta:: + :copyright: Copyright 2010, 2011, 2013 Red Hat, Inc. + :copyright: Copyright 2011 Colin Walters + :copyright: Copyright 2016 Jeremy Whiting + :copyright: Copyright 2018 Arnaud Bonatti + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2010, 2011, 2013 Red Hat, Inc. + SPDX-FileCopyrightText: 2011 Colin Walters + SPDX-FileCopyrightText: 2016 Jeremy Whiting + SPDX-FileCopyrightText: 2018 Arnaud Bonatti + SPDX-License-Identifier: LGPL-2.1-or-later + +========= +gsettings +========= + +---------------------------- +GSettings configuration tool +---------------------------- + +SYNOPSIS +-------- + +| **gsettings** get *SCHEMA*[:*PATH*] *KEY* +| **gsettings** monitor *SCHEMA*[:*PATH*] *KEY* +| **gsettings** writable *SCHEMA*[:*PATH*] *KEY* +| **gsettings** range *SCHEMA*[:*PATH*] *KEY* +| **gsettings** describe *SCHEMA*[:*PATH*] *KEY* +| **gsettings** set *SCHEMA*[:*PATH*] *KEY* *VALUE* +| **gsettings** reset *SCHEMA*[:*PATH*] *KEY* +| **gsettings** reset-recursively *SCHEMA*[:*PATH*] +| **gsettings** list-schemas [--print-paths] +| **gsettings** list-relocatable-schemas +| **gsettings** list-keys *SCHEMA*[:*PATH*] +| **gsettings** list-children *SCHEMA*[:*PATH*] +| **gsettings** list-recursively [*SCHEMA*[:*PATH*]] +| **gsettings** help [*COMMAND*] + +DESCRIPTION +----------- + +``gsettings`` offers a simple commandline interface to ``GSettings``. It lets +you get, set or monitor an individual key for changes. + +The ``SCHEMA`` and ``KEY`` arguments are required for most commands to specify +the schema ID and the name of the key to operate on. The schema ID may +optionally have a ``:PATH`` suffix. Specifying the path is only needed if the +schema does not have a fixed path. + +When setting a key, you also need specify a ``VALUE``. The format for the value +is that of a serialized ``GVariant``, so e.g. a string must include explicit +quotes: ``'foo'``. This format is also used when printing out values. + +Note that ``gsettings`` needs a D-Bus session bus connection to write changes to +the dconf database. + +COMMANDS +-------- + +``get`` + + Gets the value of ``KEY``. The value is printed out as a serialized + ``GVariant``. + +``monitor`` + + Monitors ``KEY`` for changes and prints the changed values. If no ``KEY`` is + specified, all keys in the schema are monitored. Monitoring will continue + until the process is terminated. + +``writable`` + + Finds out whether ``KEY`` is writable. + +``range`` + + Queries the range of valid values for ``KEY``. + +``describe`` + + Queries the description of valid values for ``KEY``. + +``set`` + + Sets the value of ``KEY`` to ``VALUE``. The value is specified as a serialized + ``GVariant``. + +``reset`` + + Resets ``KEY`` to its default value. + +``reset-recursively`` + + Reset all keys under the given ``SCHEMA``. + +``list-schemas`` + + Lists the installed, non-relocatable schemas. See ``list-relocatable-schemas`` + if you are interested in relocatable schemas. If ``--print-paths`` is given, + the path where each schema is mapped is also printed. + +``list-relocatable-schemas`` + + Lists the installed, relocatable schemas. See ``list-schemas`` if you are + interested in non-relocatable schemas. + +``list-keys`` + + Lists the keys in ``SCHEMA``. + +``list-children`` + + Lists the children of ``SCHEMA``. + +``list-recursively`` + + Lists keys and values, recursively. If no ``SCHEMA`` is given, list keys in + all schemas. + +``help`` + + Prints help and exits. \ No newline at end of file diff --git a/docs/reference/gio/gsettings.xml b/docs/reference/gio/gsettings.xml deleted file mode 100644 index 5f720d6..0000000 --- a/docs/reference/gio/gsettings.xml +++ /dev/null @@ -1,248 +0,0 @@ - - - - gsettings - GIO - - - Developer - Ryan - Lortie - - - - - - gsettings - 1 - User Commands - - - - gsettings - GSettings configuration tool - - - - - gsettings - get - SCHEMA:PATH - KEY - - - gsettings - monitor - SCHEMA:PATH - KEY - - - gsettings - writable - SCHEMA:PATH - KEY - - - gsettings - range - SCHEMA:PATH - KEY - - - gsettings - describe - SCHEMA:PATH - KEY - - - gsettings - set - SCHEMA:PATH - KEY - VALUE - - - gsettings - reset - SCHEMA:PATH - KEY - - - gsettings - reset-recursively - SCHEMA:PATH - - - gsettings - list-schemas - --print-paths - - - gsettings - list-relocatable-schemas - - - gsettings - list-keys - SCHEMA:PATH - - - gsettings - list-children - SCHEMA:PATH - - - gsettings - list-recursively - SCHEMA:PATH - - - gsettings - help - COMMAND - - - -Description -gsettings offers a simple commandline -interface to GSettings. -It lets you get, set or monitor an individual key for changes. - - -The SCHEMA and KEY -arguments are required for most commands to specify the schema id and the -name of the key to operate on. The schema id may optionally have a -:PATH suffix. Specifying the path is only needed -if the schema does not have a fixed path. - - -When setting a key, you also need specify a VALUE -The format for the value is that of a serialized -GVariant, -so e.g. a string -must include explicit quotes: "'foo'". This format is also used when printing -out values. - - -Note that gsettings needs a D-Bus session bus connection to write changes to -the dconf database. - - - -Commands - - - - - -Gets the value of KEY. -The value is printed out as a serialized -GVariant. - - - - - - -Monitors KEY for changes and prints the changed -values. If no KEY is specified, all keys in the -schema are monitored. Monitoring will continue until the process is terminated. - - - - - - -Finds out whether KEY is writable. - - - - - - -Queries the range of valid values for KEY. - - - - - - -Queries the description of valid values for KEY. - - - - - - -Sets the value of KEY to -VALUE. The value is specified as a serialized -GVariant. - - - - - - -Resets KEY to its default value. - - - - - - -Reset all keys under the given SCHEMA. - - - - - - -Lists the installed, non-relocatable schemas. -See if you are interested in -relocatable schemas. If -is given, the path where each schema is mapped is also printed. - - - - - - -Lists the installed, relocatable schemas. -See if you are interested in -non-relocatable schemas. - - - - - - -Lists the keys in SCHEMA. - - - - - - -Lists the children of SCHEMA. - - - - - - -Lists keys and values, recursively. If no SCHEMA -is given, list keys in all schemas. - - - - - - -Prints help and exits. - - - - - - - diff --git a/docs/reference/gio/io-scheduler.md b/docs/reference/gio/io-scheduler.md new file mode 100644 index 0000000..490e07d --- /dev/null +++ b/docs/reference/gio/io-scheduler.md @@ -0,0 +1,20 @@ +Title: GIOScheduler +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007 Andrew Walton + +# GIOScheduler + +Schedules asynchronous I/O operations. `GIOScheduler` integrates +into the main event loop ([struct@GLib.MainLoop]) and uses threads. + +Deprecated: 2.36: As of GLib 2.36, `GIOScheduler` is deprecated in favor of +[struct@GLib.ThreadPool] and [class@Gio.Task]. + +The `GIOScheduler` API is: + * [type@Gio.IOSchedulerJobFunc] + * [func@Gio.io_scheduler_push_job] + * [func@Gio.io_scheduler_cancel_all_jobs] + * [type@Gio.IOSchedulerJob] + * [method@Gio.IOSchedulerJob.send_to_mainloop] + * [method@Gio.IOSchedulerJob.send_to_mainloop_async] + diff --git a/docs/reference/gio/menu-exporter.md b/docs/reference/gio/menu-exporter.md new file mode 100644 index 0000000..a440379 --- /dev/null +++ b/docs/reference/gio/menu-exporter.md @@ -0,0 +1,15 @@ +Title: GMenuModel Exporter +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2011 Matthias Clasen + +# GMenuModel Exporter + +These functions support exporting a [class@Gio.MenuModel] on D-Bus. The D-Bus +interface that is used is a private implementation detail. + + * [method@Gio.DBusConnection.export_menu_model] + * [method@Gio.DBusConnection.unexport_menu_model] + +To access an exported [class@Gio.MenuModel] remotely, use +[func@Gio.DBusMenuModel.get] to obtain a [class@Gio.DBusMenuModel]. + diff --git a/docs/reference/gio/meson.build b/docs/reference/gio/meson.build index 38696a1..b8b9322 100644 --- a/docs/reference/gio/meson.build +++ b/docs/reference/gio/meson.build @@ -1,236 +1,65 @@ -if get_option('gtk_doc') - subdir('gdbus-object-manager-example') - subdir('xml') - - ignore_headers = [ - 'gdbus-2.0', - 'inotify', - 'kqueue', - 'libasyncns', - 'tests', - 'win32', - 'xdgmime', - 'gappinfoprivate.h', - 'gapplicationimpl.h', - 'gasynchelper.h', - 'gcontenttypeprivate.h', - 'gcontextspecificgroup.h', - 'gcredentialsprivate.h', - 'gdbus-daemon-generated.h', - 'gdbusactiongroup-private.h', - 'gdbusauth.h', - 'gdbusauthmechanismanon.h', - 'gdbusauthmechanismexternal.h', - 'gdbusauthmechanism.h', - 'gdbusauthmechanismsha1.h', - 'gdbusdaemon.h', - 'gdbusprivate.h', - 'gdelayedsettingsbackend.h', - 'gdocumentportal.h', - 'gdummyfile.h', - 'gdummyproxyresolver.h', - 'gdummytlsbackend.h', - 'gfileattribute-priv.h', - 'gfileinfo-priv.h', - 'ghttpproxy.h', - 'giomodule-priv.h', - 'gioprivate.h', - 'giowin32-afunix.h', - 'giowin32-priv.h', - 'gio_probes.h', - 'gio_trace.h', - 'gio-tool.h', - 'glocaldirectorymonitor.h', - 'glocalfileenumerator.h', - 'glocalfile.h', - 'glocalfileinfo.h', - 'glocalfileinputstream.h', - 'glocalfileiostream.h', - 'glocalfilemonitor.h', - 'glocalfileoutputstream.h', - 'glocalvfs.h', - 'gmemorymonitordbus.h', - 'gmemorymonitorportal.h', - 'gmountprivate.h', - 'gnativevolumemonitor.h', - 'gnetworkingprivate.h', - 'gnetworkmonitorbase.h', - 'gnetworkmonitornetlink.h', - 'gnetworkmonitornm.h', - 'gnetworkmonitorportal.h', - 'gnotificationbackend.h', - 'gnotification-private.h', - 'gopenuriportal.h', - 'gpollfilemonitor.h', - 'gportalsupport.h', - 'gpowerprofilemonitordbus.h', - 'gpowerprofilemonitorportal.h', - 'gproxyresolverportal.h', - 'gregistrysettingsbackend.h', - 'gresourcefile.h', - 'gsandbox.h', - 'gsettingsbackendinternal.h', - 'gsettings-mapping.h', - 'gsettingsschema-internal.h', - 'gsocketinputstream.h', - 'gsocketoutputstream.h', - 'gsocks4aproxy.h', - 'gsocks4proxy.h', - 'gsocks5proxy.h', - 'gsubprocesslauncher-private.h', - 'gthreadedresolver.h', - 'gtrashportal.h', - 'gunionvolumemonitor.h', - 'gunixmount.h', - 'gunixresolver.h', - 'gunixvolume.h', - 'gunixvolumemonitor.h', - 'gwin32networkmonitor.h', - 'gwin32api-application-activation-manager.h', - 'gwin32api-iterator.h', - 'gwin32api-misc.h', - 'gwin32api-package.h', - 'gwin32api-storage.h', - 'gwin32appinfo.h', - 'gwin32file-sync-stream.h', - 'gwin32mount.h', - 'gwin32packageparser.h', - 'gwin32resolver.h', - 'gwin32volumemonitor.h', - 'thumbnail-verify.h', - 'xdp-dbus.h', - 'gio-visibility.h', - ] - - sections_files = files('gio-sections-common.txt') - - if host_system == 'windows' - ignore_headers += [ - 'gfiledescriptorbased.h', - 'gunixmounts.h', - 'gunixfdmessage.h', - 'gunixinputstream.h', - 'gunixoutputstream.h', - 'gdesktopappinfo.h', - 'gosxappinfo.h', - ] - sections_files += files('gio-sections-win32.txt') - platform_file = files('gio-docs-win32.xml') - else - if glib_have_cocoa - ignore_headers += ['gdesktopappinfo.h'] - else - ignore_headers += ['gosxappinfo.h'] - endif - - ignore_headers += [ - 'gwin32inputstream.h', - 'gwin32outputstream.h', - 'gwin32registrykey.h', - ] - platform_file = files('gio-docs-unix.xml') - endif - - ignore_sources = [ - 'kqueue', - 'tests', - 'gdbus-daemon-generated.c', - 'xdp-dbus.c', - ] - - docpath = join_paths(glib_datadir, 'gtk-doc', 'html') - version_conf = configuration_data() - version_conf.set('VERSION', meson.project_version()) - configure_file( - input: 'version.xml.in', - output: 'version.xml', - configuration: version_conf - ) - - concat_files_helper = find_program('concat-files-helper.py') - configure_file( - output : 'gio-sections.txt', - input : sections_files, - command : [concat_files_helper, '@OUTPUT@', '@INPUT@'], - ) - - configure_file( - output : 'gio-docs-platform.xml', - input : platform_file, - copy : true, - ) - - content_files = [ - 'overview.xml', - 'migrating-posix.xml', - 'migrating-gnome-vfs.xml', - 'migrating-gconf.xml', - 'migrating-gdbus.xml', - 'gio-querymodules.xml', - 'glib-compile-schemas.xml', - 'glib-compile-resources.xml', - 'gapplication.xml', - 'gsettings.xml', - 'gresource.xml', - 'gdbus.xml', - 'gdbus-codegen.xml', - ] - - content_files += [ - gdbus_example_objectmanager_xml, - gdbus_example_objectmanager_sources, - gdbus_object_manager_example_doc - ] - - gnome.gtkdoc('gio', - main_xml : 'gio-docs.xml', - namespace : 'g', - mode : 'none', - dependencies : [libgio_dep, libgobject_dep, libglib_dep], - src_dir : 'gio', - scan_args : [ - '--ignore-decorators=' + ignore_decorators.replace('GLIB', 'GIO'), - '--rebuild-types', - '--ignore-headers=' + ' '.join(ignore_headers), - ], - mkdb_args : [ - '--ignore-files=' + ' '.join(ignore_sources), - ], - content_files : content_files, - expand_content_files : [ - 'overview.xml', - 'migrating-posix.xml', - 'migrating-gnome-vfs.xml', - 'migrating-gconf.xml', - 'migrating-gdbus.xml', - 'gdbus-codegen.xml', - ], - html_assets : [ - 'gvfs-overview.png', - 'menu-example.png', - 'menu-model.png', - ], - fixxref_args: [ - '--html-dir=' + docpath, - '--extra-dir=' + join_paths('gio', '..', 'glib', 'html'), - '--extra-dir=' + join_paths('gio', '..', 'gobject', 'html'), - ], - install: true, - check: true, - ) -endif - - -if get_option('man') +if get_option('man-pages').enabled() manpages = ['gapplication', 'gio-querymodules', 'glib-compile-schemas', 'glib-compile-resources', 'gsettings', 'gresource', 'gdbus', 'gio', 'gdbus-codegen'] foreach page : manpages custom_target(page + '-man', - input: page + '.xml', + input: page + '.rst', output: page + '.1', - command: xsltproc_command, + command: [ + rst2man, + rst2man_flags, + '@INPUT@', + ], + capture: true, install: true, - install_dir: man1_dir) + install_dir: man1_dir, + install_tag: 'doc', + ) endforeach endif + +expand_content_files = [ + 'dbus-error.md', + 'dbus-introspection.md', + 'dbus-name-owning.md', + 'dbus-name-watching.md', + 'dbus-utils.md', + 'error.md', + 'file-attributes.md', + 'io-scheduler.md', + 'menu-exporter.md', + 'migrating-gconf.md', + 'migrating-gdbus.md', + 'migrating-gnome-vfs.md', + 'migrating-posix.md', + 'networking.md', + 'overview.md', + 'pollable-utils.md', + 'tls-overview.md', + 'unix-mounts.md', +] + +gio_toml = configure_file(input: 'gio.toml.in', output: 'gio.toml', configuration: toml_conf) + +custom_target('gio-docs', + input: [ gio_toml, gio_gir[0] ], + output: 'gio', + command: [ + gidocgen, + 'generate', + gidocgen_common_args, + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--content-dir=@0@'.format(meson.current_source_dir()), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gobject'), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gmodule'), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gio'), + '@INPUT1@', + ], + build_by_default: true, + depend_files: expand_content_files, + install: true, + install_dir: docs_dir, + install_tag: 'doc', +) diff --git a/docs/reference/gio/migrating-gconf.md b/docs/reference/gio/migrating-gconf.md new file mode 100644 index 0000000..6cbe725 --- /dev/null +++ b/docs/reference/gio/migrating-gconf.md @@ -0,0 +1,466 @@ +Title: Migrating from GConf to GSettings +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010, 2012 Matthias Clasen +SPDX-FileCopyrightText: 2010 Allison Lortie +SPDX-FileCopyrightText: 2011 Ray Strode + +# Migrating from GConf to GSettings + +## Before you start + +Converting individual applications and their settings from GConf to +GSettings can be done at will. But desktop-wide settings like font or theme +settings often have consumers in multiple modules. Therefore, some +consideration has to go into making sure that all users of a setting are +converted to GSettings at the same time or that the program responsible for +configuring that setting continues to update the value in both places. + +It is always a good idea to have a look at how others have handled similar +problems before. + +## Conceptual differences + +Conceptually, GConf and GSettings are fairly similar. Both have a concept of +pluggable backends. Both keep information about keys and their types in +schemas. Both have a concept of mandatory values, which lets you implement +lock-down. + +There are some differences in the approach to schemas. GConf installs the +schemas into the database and has API to handle schema information +(`gconf_client_get_default_from_schema()`, `gconf_value_get_schema()`, etc). +GSettings on the other hand assumes that an application knows its own +schemas, and does not provide API to handle schema information at runtime. +GSettings is also more strict about requiring a schema whenever you want to +read or write a key. To deal with more free-form information that would +appear in schema-less entries in GConf, GSettings allows for schemas to be +'relocatable'. + +One difference in the way applications interact with their settings is that +with GConf you interact with a tree of settings (ie the keys you pass to +functions when reading or writing values are actually paths with the actual +name of the key as the last element. With GSettings, you create a GSettings +object which has an implicit prefix that determines where the settings get +stored in the global tree of settings, but the keys you pass when reading or +writing values are just the key names, not the full path. + +## GConfClient (and GConfBridge) API conversion + +Most people use GConf via the high-level `GConfClient` API. The +corresponding API is the [class@Gio.Settings] object. While not every +`GConfClient` function has a direct GSettings equivalent, many do: + +| GConfClient | GSettings | +|-------------|-----------| +| `gconf_client_get_default()` | no direct equivalent, instead you call [`ctor@Gio.Settings.new`] for the schemas you use | +| `gconf_client_set()` | [`method@Gio.Settings.set`] | +| `gconf_client_get()` | `g_settings_get()` | +| `gconf_client_get_bool()` | `g_settings_get_boolean()` | +| `gconf_client_set_bool()` | `g_settings_set_boolean()` | +| `gconf_client_get_int()` | `g_settings_get_int()` | +| `gconf_client_set_int()` | `g_settings_set_int()` | +| `gconf_client_get_float()` | `g_settings_get_double()` | +| `gconf_client_set_float()` | `g_settings_set_double()` | +| `gconf_client_get_string()` | `g_settings_get_string()` | +| `gconf_client_set_string()` | `g_settings_set_string()` | +| `gconf_client_get_list()` | for string lists, see `g_settings_get_strv()`, else see `g_settings_get_value()` and GVariant API | +| `gconf_client_set_list()` | for string lists, see `g_settings_set_strv()`, else see `g_settings_set_value()` and GVariant API | +| `gconf_entry_get_is_writable()` | `g_settings_is_writable()` | +| `gconf_client_notify_add()` | not required, the “changed” signal is emitted automatically | +| `gconf_client_add_dir()` | not required, each GSettings instance automatically watches all keys in its path | +| `GConfChangeSet` | `g_settings_delay()`, `g_settings_apply()` | +| `gconf_client_get_default_from_schema()` | no equivalent, applications are expected to know their schema | +| `gconf_client_all_entries()` | no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries | +| `gconf_client_get_without_default()` | no equivalent | +| `gconf_bridge_bind_property()` | `g_settings_bind()` | +| `gconf_bridge_bind_property_full()` | `g_settings_bind_with_mapping()` | + +GConfBridge was a third-party library that used GConf to bind an object +property to a particular configuration key. GSettings offers this service +itself. + +There is a pattern that is sometimes used for GConf, where a setting can +have explicit 'value A', explicit 'value B' or 'use the system default'. +With GConf, 'use the system default' is sometimes implemented by unsetting +the user value. This is not possible in GSettings, since it does not have +API to determine if a value is the default and does not let you unset +values. The recommended way (and much clearer) way in which this can be +implemented in GSettings is to have a separate 'use-system-default' boolean +setting. + +## Change notification + +GConf requires you to call `gconf_client_add_dir()` and +`gconf_client_notify_add()` to get change notification. With GSettings, this +is not necessary; signals get emitted automatically for every change. + +The [signal@Gio.Settings::changed] signal is emitted for each changed key. +There is also a [`signal@Gio.Settings::change-event`] signal that you can +handle if you need to see groups of keys that get changed at the same time. + +GSettings also notifies you about changes in writability of keys, with the +[signal@Gio.Settings::writable-changed] signal (and the +[signal@Gio.Settings::writable-change-event] signal). + +## Change sets + +GConf has a concept of a set of changes which can be applied or reverted at +once: `GConfChangeSet` (GConf doesn't actually apply changes atomically, +which is one of its shortcomings). + +Instead of a separate object to represent a change set, GSettings has a +'delayed-apply' mode, which can be turned on for a [class@Gio.Settings] +object by calling [method@Gio.Settings.delay]. In this mode, changes done to +the GSettings object are not applied - they are still visible when calling +[method@Gio.Settings.get] on the same object, but not to other GSettings +instances or even other processes. + +To apply the pending changes all at once (GSettings does atomicity here), +call [method@Gio.Settings.apply]. To revert the pending changes, call +[method@Gio.Settings.revert] or just drop the reference to the GSettings +object. + +## Schema conversion + +If you are porting your application from GConf, most likely you already have +a GConf schema. GConf comes with a commandline tool +`gsettings-schema-convert` that can help with the task of converting a GConf +schema into an equivalent GSettings schema. The tool is not perfect and may +need assistance in some cases. + +### An example for using gsettings-schema-convert + +Running `gsettings-schema-convert --gconf --xml --schema-id +"org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml +destop_gnome_font_rendering.schemas` on the following +`desktop_gnome_font_rendering.schemas` file: + +```xml + + + + + /schemas/desktop/gnome/font_rendering/dpi + /desktop/gnome/font_rendering/dpi + gnome + int + 96 + + DPI + The resolution used for converting font sizes to pixel sizes, in dots per inch. + + + + +``` + +produces an `org.gnome.font-rendering.gschema.xml` file with the following content: + +```xml + + + + 96 + DPI + The resolution used for converting font sizes to pixel sizes, in dots per inch. + + + +``` + +GSettings schemas are identified at runtime by their id (as specified in the +XML source file). It is recommended to use a dotted name as schema id, +similar in style to a D-Bus bus name, e.g. "org.gnome.SessionManager". In +cases where the settings are general and not specific to one application, +the id should not use StudlyCaps, e.g. "org.gnome.font-rendering". The +filename used for the XML schema source is immaterial, but schema compiler +expects the files to have the extension `.gschema.xml`. It is recommended to +simply use the schema id as the filename, followed by this extension, e.g. +`org.gnome.SessionManager.gschema.xml`. + +The XML source file for your GSettings schema needs to get installed into +`$datadir/glib-2.0/schemas`, and needs to be compiled into a binary form. At +runtime, GSettings looks for compiled schemas in the `glib-2.0/schemas` +subdirectories of all `XDG_DATA_DIRS` directories, so if you install your +schema in a different location, you need to set the `XDG_DATA_DIRS` +environment variable appropriately. + +Schemas are compiled into binary form by the `glib-compile-schemas` utility. +GIO provides a `glib_compile_schemas` variable in its pkg-config file +pointing to the schema compiler binary. + +### Using schemas with Meson + +You should use `install_data()` to install the `.gschema.xml` file in the +correct directory, e.g. + +``` +install_data('my.app.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0/schemas') +``` + +Schema compilation is done at installation time; if you are using Meson 0.57 or newer, you can use the `gnome.post_install()` function from the GNOME module: + +``` +gnome.post_install(glib_compile_schemas: true) +``` + +Alternatively, you can use `meson.add_install_script()` and the following +Python script: + +```py +#!/usr/bin/env python3 +# build-aux/compile-schemas.py + +import os +import subprocess + +install_prefix = os.environ['MESON_INSTALL_PREFIX'] +schemadir = os.path.join(install_prefix, 'share', 'glib-2.0', 'schemas') + +if not os.environ.get('DESTDIR'): + print('Compiling gsettings schemas...') + subprocess.call(['glib-compile-schemas', schemadir]) +``` + +``` +meson.add_install_script('build-aux/compile-schemas.py') +``` + +### Using schemas with Autotools + +GLib provides m4 macros for hiding the various complexities and reduce the +chances of getting things wrong. + +To handle schemas in your Autotools build, start by adding this to your +`configure.ac`: + +``` +GLIB_GSETTINGS +``` + +Then add this fragment to your `Makefile.am`: + +``` +# gsettings_SCHEMAS is a list of all the schemas you want to install +gsettings_SCHEMAS = my.app.gschema.xml + +# include the appropriate makefile rules for schema handling +@GSETTINGS_RULES@ +``` + +This is not sufficient on its own. You need to mention what the source of +the `my.app.gschema.xml` file is. If the schema file is distributed directly +with your project's tarball then a mention in `EXTRA_DIST` is appropriate. If +the schema file is generated from another source then you will need the +appropriate rule for that, plus probably an item in `EXTRA_DIST` for the +source files used by that rule. + +One possible pitfall in doing schema conversion is that the default values +in GSettings schemas are parsed by the GVariant parser. This means that +strings need to include quotes in the XML. Also note that the types are now +specified as GVariant type strings. + +```xml +string +rgb +``` + +becomes + +```xml + + 'rgb' + +``` + +Another possible complication is that GConf specifies full paths for each +key, while a GSettings schema has a 'path' attribute that contains the +prefix for all the keys in the schema, and individual keys just have a +simple name. So + +```xml +/schemas/desktop/gnome/font_rendering/antialiasing +``` + +becomes + +```xml + + +``` + + +Default values can be localized in both GConf and GSettings schemas, but +GSettings uses gettext for the localization. You can specify the gettext +domain to use in the gettext-domain attribute. Therefore, when converting +localized defaults in GConf, + +```xml +/schemas/apps/my_app/font_size + + 18 + + + 24 + + +``` + +becomes + +```xml + + ... + + 18 + +``` + +GSettings uses gettext for translation of default values. The string that is +translated is exactly the string that appears inside of the `` +element. This includes the quotation marks that appear around strings. +Default values must be marked with the l10n attribute in the `` tag, +which should be set as equal to 'messages' or 'time' depending on the +desired category. An optional translation context can also be specified with +the context attribute, as in the example. This is usually recommended, since +the string "18" is not particularly easy to translate without context. The +translated version of the default value should be stored in the specified +gettext-domain. Care must be taken during translation to ensure that all +translated values remain syntactically valid; mistakes here will cause +runtime errors. + +GSettings schemas have optional `` and `` elements for +each key which correspond to the `` and `` elements in the +GConf schema and can be used in the same way by a GUI editor, so you should +use the same conventions for them: The summary is just a short label with no +punctuation, the description can be one or more complete sentences. If +multiple paragraphs are desired for the description, the paragraphs should +be separated by a completely empty line. + +Translations for these strings will also be handled via gettext, so you +should arrange for these strings to be extracted into your gettext catalog. +Gettext supports GSettings schemas natively since version 0.19, so all you +have to do is add the XML schema file to the list of translatable files +inside your `POTFILES.in`. + +GSettings is a bit more restrictive about key names than GConf. Key names in +GSettings can be at most 32 characters long, and must only consist of +lowercase characters, numbers and dashes, with no consecutive dashes. The +first character must not be a number or dash, and the last character cannot +be '-'. + +If you are using the GConf backend for GSettings during the transition, you +may want to keep your key names the same they were in GConf, so that +existing settings in the users GConf database are preserved. You can achieve +this by using the `--allow-any-name` with the `glib-compile-schemas` schema +compiler. Note that this option is only meant to ease the process of porting +your application, allowing parts of your application to continue to access +GConf and parts to use GSettings. By the time you have finished porting your +application you must ensure that all key names are valid. + +## Data conversion + +GConf comes with a GSettings backend that can be used to facility the +transition to the GSettings API until you are ready to make the jump to a +different backend (most likely dconf). To use it, you need to set the +`GSETTINGS_BACKEND` to 'gconf', e.g. by using + +```c +g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE); +``` + +early on in your program. Note that this backend is meant purely as a +transition tool, and should not be used in production. + +GConf also comes with a utility called `gsettings-data-convert`, which is +designed to help with the task of migrating user settings from GConf into +another GSettings backend. It can be run manually, but it is designed to be +executed automatically, every time a user logs in. It keeps track of the +data migrations that it has already done, and it is harmless to run it more +than once. + +To make use of this utility, you must install a keyfile in the directory +`/usr/share/GConf/gsettings` which lists the GSettings keys and GConf paths +to map to each other, for each schema that you want to migrate user data +for. + +Here is an example: + +``` +[org.gnome.fonts] +antialiasing = /desktop/gnome/font_rendering/antialiasing +dpi = /desktop/gnome/font_rendering/dpi +hinting = /desktop/gnome/font_rendering/hinting +rgba-order = /desktop/gnome/font_rendering/rgba_order + +[apps.myapp:/path/to/myapps/] +some-odd-key1 = /apps/myapp/some_ODD-key1 +``` + +The last key demonstrates that it may be necessary to modify the key name to +comply with stricter GSettings key name rules. Of course, that means your +application must use the new key names when looking up settings in +GSettings. + +The last group in the example also shows how to handle the case of +'relocatable' schemas, which don't have a fixed path. You can specify the +path to use in the group name, separated by a colon. + +There are some limitations: `gsettings-data-convert` does not do any +transformation of the values. And it does not handle complex GConf types +other than lists of strings or integers. + +**Don't forget to require GConf 2.31.1 or newer in your configure script if +you are making use of the GConf backend or the conversion utility.** + +If, as an application developer, you are interested in manually ensuring +that `gsettings-data-convert` has been invoked (for example, to deal with the +case where the user is logged in during a distribution upgrade or for +non-XDG desktop environments which do not run the command as an autostart) +you may invoke it manually during your program initialisation. This is not +recommended for all application authors -- it is your choice if this use +case concerns you enough. + +Internally, `gsettings-data-convert` uses a keyfile to track which settings +have been migrated. The following code fragment will check that keyfile to +see if your data conversion script has been run yet and, if not, will +attempt to invoke the tool to run it. You should adapt it to your +application as you see fit. + +```c +static void +ensure_migrated (const gchar *name) +{ + gboolean needed = TRUE; + GKeyFile *kf; + gchar **list; + gsize i, n; + + kf = g_key_file_new (); + + g_key_file_load_from_data_dirs (kf, "gsettings-data-convert", + NULL, G_KEY_FILE_NONE, NULL); + list = g_key_file_get_string_list (kf, "State", "converted", &n, NULL); + + if (list) + { + for (i = 0; i < n; i++) + if (strcmp (list[i], name) == 0) + { + needed = FALSE; + break; + } + + g_strfreev (list); + } + + g_key_file_free (kf); + + if (needed) + g_spawn_command_line_sync ("gsettings-data-convert", + NULL, NULL, NULL, NULL); +} +``` + +Although there is the possibility that the `gsettings-data-convert` script +will end up running multiple times concurrently with this approach, it is +believed that this is safe. diff --git a/docs/reference/gio/migrating-gconf.xml b/docs/reference/gio/migrating-gconf.xml deleted file mode 100644 index d9fd064..0000000 --- a/docs/reference/gio/migrating-gconf.xml +++ /dev/null @@ -1,515 +0,0 @@ - - Migrating from GConf to GSettings - -
- Before you start - - - Converting individual applications and their settings from GConf to - GSettings can be done at will. But desktop-wide settings like font or - theme settings often have consumers in multiple modules. Therefore, - some consideration has to go into making sure that all users of a setting - are converted to GSettings at the same time or that the program - responsible for configuring that setting continues to update the value in - both places. - - - It is always a good idea to have a look at how others have handled - similar problems before. - -
- -
- Conceptual differences - - - Conceptually, GConf and GSettings are fairly similar. Both - have a concept of pluggable backends. Both keep information - about keys and their types in schemas. Both have a concept of - mandatory values, which lets you implement lock-down. - - - There are some differences in the approach to schemas. GConf - installs the schemas into the database and has API to handle - schema information (gconf_client_get_default_from_schema(), - gconf_value_get_schema(), etc). GSettings on the other hand - assumes that an application knows its own schemas, and does - not provide API to handle schema information at runtime. - GSettings is also more strict about requiring a schema whenever - you want to read or write a key. To deal with more free-form - information that would appear in schema-less entries in GConf, - GSettings allows for schemas to be 'relocatable'. - - - One difference in the way applications interact with their - settings is that with GConf you interact with a tree of - settings (ie the keys you pass to functions when reading - or writing values are actually paths with the actual name - of the key as the last element. With GSettings, you create - a GSettings object which has an implicit prefix that determines - where the settings get stored in the global tree of settings, - but the keys you pass when reading or writing values are just - the key names, not the full path. - -
- -
- GConfClient (and GConfBridge) API conversion - - - Most people use GConf via the high-level #GConfClient API. - The corresponding API is the #GSettings object. While not - every GConfClient function has a direct GSettings equivalent, - many do: - - - - GConfClientGSettings - - - gconf_client_get_default()no direct equivalent, - instead you call g_settings_new() for the schemas you use - gconf_client_set()g_settings_set() - gconf_client_get()g_settings_get() - gconf_client_get_bool()g_settings_get_boolean() - gconf_client_set_bool()g_settings_set_boolean() - gconf_client_get_int()g_settings_get_int() - gconf_client_set_int()g_settings_set_int() - gconf_client_get_float()g_settings_get_double() - gconf_client_set_float()g_settings_set_double() - gconf_client_get_string()g_settings_get_string() - gconf_client_set_string()g_settings_set_string() - gconf_client_get_list()for string lists, see g_settings_get_strv(), else see g_settings_get_value() and #GVariant API - gconf_client_set_list()for string lists, see g_settings_set_strv(), else see g_settings_set_value() and #GVariant API - gconf_entry_get_is_writable()g_settings_is_writable() - gconf_client_notify_add()not required, the #GSettings::changed signal is emitted automatically - gconf_client_add_dir()not required, each GSettings instance automatically watches all keys in its path - #GConfChangeSetg_settings_delay(), g_settings_apply() - gconf_client_get_default_from_schema()no equivalent, applications are expected to know their schema - gconf_client_all_entries()no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries - gconf_client_get_without_default()no equivalent - gconf_bridge_bind_property()g_settings_bind() - gconf_bridge_bind_property_full()g_settings_bind_with_mapping() - - -
-
- - GConfBridge was a third-party library that used GConf to bind an object property - to a particular configuration key. GSettings offers this service itself. - - - There is a pattern that is sometimes used for GConf, where a setting can have - explicit 'value A', explicit 'value B' or 'use the system default'. With GConf, - 'use the system default' is sometimes implemented by unsetting the user value. - - - This is not possible in GSettings, since it does not have API to determine if a value - is the default and does not let you unset values. The recommended way (and much - clearer) way in which this can be implemented in GSettings is to have a separate - 'use-system-default' boolean setting. - -
- -
- Change notification - - - GConf requires you to call gconf_client_add_dir() and - gconf_client_notify_add() to get change notification. With - GSettings, this is not necessary; signals get emitted automatically - for every change. - - - The #GSettings::changed signal is emitted for each changed key. - There is also a #GSettings::change-event signal that you can handle - if you need to see groups of keys that get changed at the same time. - - - GSettings also notifies you about changes in writability of keys, - with the #GSettings::writable-changed signal (and the - #GSettings::writable-change-event signal). - -
- -
Change sets - - GConf has a concept of a set of changes which can be applied or reverted - at once: #GConfChangeSet (GConf doesn't actually apply changes atomically, - which is one of its shortcomings). - - - Instead of a separate object to represent a change set, GSettings has a - 'delayed-apply' mode, which can be turned on for a GSettings object by - calling g_settings_delay(). In this mode, changes done to the GSettings - object are not applied - they are still visible when calling g_settings_get() - on the same object, but not to other GSettings instances - or even other processes. - - - To apply the pending changes all at once (GSettings does - atomicity here), call g_settings_apply(). To revert the pending changes, - call g_settings_revert() or just drop the reference to the #GSettings object. - -
- -
- Schema conversion - - - If you are porting your application from GConf, most likely you already - have a GConf schema. GConf comes with a commandline tool - gsettings-schema-convert that can help with the task of converting - a GConf schema into an equivalent GSettings schema. The tool is not - perfect and may need assistance in some cases. - - An example for using gsettings-schema-convert - Running gsettings-schema-convert --gconf --xml --schema-id "org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml destop_gnome_font_rendering.schemas on the following desktop_gnome_font_rendering.schemas file: - - - - - - /schemas/desktop/gnome/font_rendering/dpi - /desktop/gnome/font_rendering/dpi - gnome - int - 96 - - DPI - The resolution used for converting font sizes to pixel sizes, in dots per inch. - - - - -]]> - -produces a org.gnome.font-rendering.gschema.xml file with the following content: - - - - - 96 - DPI - The resolution used for converting font sizes to pixel sizes, in dots per inch. - - - -]]> - - - - - - GSettings schemas are identified at runtime by their id (as specified - in the XML source file). It is recommended to use a dotted name as schema - id, similar in style to a D-Bus bus name, e.g. "org.gnome.SessionManager". - In cases where the settings are general and not specific to one application, - the id should not use StudlyCaps, e.g. "org.gnome.font-rendering". - The filename used for the XML schema source is immaterial, but - schema compiler expects the files to have the extension - .gschema.xml. It is recommended to simply - use the schema id as the filename, followed by this extension, - e.g. org.gnome.SessionManager.gschema.xml. - - - - The XML source file for your GSettings schema needs to get installed - into $datadir/glib-2.0/schemas, and needs to be - compiled into a binary form. At runtime, GSettings looks for compiled - schemas in the glib-2.0/schemas subdirectories - of all XDG_DATA_DIRS directories, so if you install - your schema in a different location, you need to set the - XDG_DATA_DIRS environment variable appropriately. - - - Schemas are compiled into binary form by the - glib-compile-schemas utility. - GIO provides a glib_compile_schemas - variable for the schema compiler. - - - You can ignore all of this by using the provided m4 macros. To - do this, add to your configure.ac: - -GLIB_GSETTINGS - - The corresponding Makefile.am fragment looks like - this: - -# gsettings_SCHEMAS is a list of all the schemas you want to install -gsettings_SCHEMAS = my.app.gschema.xml - -# include the appropriate makefile rules for schema handling -@GSETTINGS_RULES@ - - - - - This is not sufficient on its own. You need to mention what the source - of the my.app.gschema.xml file is. If the schema - file is distributed directly with your project's tarball then a mention - in EXTRA_DIST is appropriate. If the schema file is - generated from another source then you will need the appropriate rule - for that, plus probably an item in EXTRA_DIST for the - source files used by that rule. - - - - One possible pitfall in doing schema conversion is that the default - values in GSettings schemas are parsed by the #GVariant parser. - This means that strings need to include quotes in the XML. Also note - that the types are now specified as #GVariant type strings. - -string -rgb -]]> - - becomes - - - 'rgb' - -]]> - - - - Another possible complication is that GConf specifies full paths - for each key, while a GSettings schema has a 'path' attribute that - contains the prefix for all the keys in the schema, and individual - keys just have a simple name. So - -/schemas/desktop/gnome/font_rendering/antialiasing -]]> - - becomes - - - -]]> - - - - Default values can be localized in both GConf and GSettings schemas, - but GSettings uses gettext for the localization. You can specify - the gettext domain to use in the gettext-domain - attribute. Therefore, when converting localized defaults in GConf, - -/schemas/apps/my_app/font_size - - 18 - - - 24 - - -]]> - - becomes - - - ... - - 18 - -]]> - - - - GSettings uses gettext for translation of default values. - The string that is translated is exactly the string that appears - inside of the default element. This - includes the quotation marks that appear around strings. - Default values must be marked with the l10n - attribute in the default tag, which - should be set as equal to 'messages' or - 'time' depending on the desired category. An - optional translation context can also be specified with the - context attribute, as in the example. This - is usually recommended, since the string "18" - is not particularly easy to translate without context. The - translated version of the default value should be stored in the - specified gettext-domain. Care must be taken - during translation to ensure that all translated values remain - syntactically valid; mistakes here will cause runtime errors. - - - GSettings schemas have optional summary and - description elements for each key which - correspond to the short and - long elements in the GConf schema and - will be used in similar ways by a future gsettings-editor, so you - should use the same conventions for them: The summary is just a short - label with no punctuation, the description can be one or more complete - sentences. If multiple paragraphs are desired for the description, the - paragraphs should be separated by a completely empty line. - - - Translations for these strings will also be handled - via gettext, so you should arrange for these strings to be - extracted into your gettext catalog. One way to do that is to use - intltool. Since intltool 0.50.1, schema files are - supported, so all you have to do is to add your .gschema.xml - files to POTFILES.in with a line like - - [type: gettext/gsettings]data/org.foo.MyApp.gschema.xml - - - - GSettings is a bit more restrictive about key names than GConf. Key - names in GSettings can be at most 32 characters long, and must only - consist of lowercase characters, numbers and dashes, with no - consecutive dashes. The first character must not be a number or dash, - and the last character cannot be '-'. - - - If you are using the GConf backend for GSettings during the - transition, you may want to keep your key names the same they - were in GConf, so that existing settings in the users GConf - database are preserved. You can achieve this by using the - with the - glib-compile-schemas schema - compiler. Note that this option is only meant - to ease the process of porting your application, allowing parts - of your application to continue to access GConf and parts to use - GSettings. By the time you have finished porting your application - you must ensure that all key names are valid. - -
- -
Data conversion - - GConf comes with a GSettings backend that can be used to - facility the transition to the GSettings API until you are - ready to make the jump to a different backend (most likely - dconf). To use it, you need to set the GSETTINGS_BACKEND - to 'gconf', e.g. by using - - g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE); - - early on in your program. Note that this backend is meant purely - as a transition tool, and should not be used in production. - - - GConf also comes with a utility called - gsettings-data-convert, which is designed to help - with the task of migrating user settings from GConf into another - GSettings backend. It can be run manually, but it is designed to be - executed automatically, every time a user logs in. It keeps track of - the data migrations that it has already done, and it is harmless to - run it more than once. - - - To make use of this utility, you must install a keyfile in the - directory /usr/share/GConf/gsettings which - lists the GSettings keys and GConf paths to map to each other, for - each schema that you want to migrate user data for. - - - Here is an example: - - - - The last key demonstrates that it may be necessary to modify the key - name to comply with stricter GSettings key name rules. Of course, - that means your application must use the new key names when looking - up settings in GSettings. - - - The last group in the example also shows how to handle the case - of 'relocatable' schemas, which don't have a fixed path. You can - specify the path to use in the group name, separated by a colon. - - - There are some limitations: gsettings-data-convert - does not do any transformation of the values. And it does not handle - complex GConf types other than lists of strings or integers. - - - Don't forget to require GConf 2.31.1 or newer in your configure - script if you are making use of the GConf backend or the conversion - utility. - - - - If, as an application developer, you are interested in manually - ensuring that gsettings-data-convert has been - invoked (for example, to deal with the case where the user is - logged in during a distribution upgrade or for non-XDG desktop - environments which do not run the command as an autostart) you - may invoke it manually during your program initialisation. This - is not recommended for all application authors -- it is your - choice if this use case concerns you enough. - - - Internally, gsettings-data-convert uses a - keyfile to track which settings have been migrated. The - following code fragment will check that keyfile to see if your - data conversion script has been run yet and, if not, will - attempt to invoke the tool to run it. You should adapt it to - your application as you see fit. - - - - - - - - Although there is the possibility that the - gsettings-data-convert script will end up - running multiple times concurrently with this approach, it is - believed that this is safe. - -
-
diff --git a/docs/reference/gio/migrating-gdbus.md b/docs/reference/gio/migrating-gdbus.md new file mode 100644 index 0000000..c2c3355 --- /dev/null +++ b/docs/reference/gio/migrating-gdbus.md @@ -0,0 +1,633 @@ +Title: Migrating to GDBus +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Matthias Clasen +SPDX-FileCopyrightText: 2010, 2011 David Zeuthen + +# Migrating to GDBus + +## Conceptual differences + +The central concepts of D-Bus are modelled in a very similar way in +dbus-glib and GDBus. Both have objects representing connections, proxies and +method invocations. But there are some important differences: + +- dbus-glib uses the libdbus reference implementation, GDBus doesn't. + Instead, it relies on GIO streams as transport layer, and has its own + implementation for the D-Bus connection setup and authentication. Apart + from using streams as transport, avoiding libdbus also lets GDBus avoid + some thorny multithreading issues. +- dbus-glib uses the GObject type system for method arguments and return + values, including a homegrown container specialization mechanism. GDBus + relies on the GVariant type system which is explicitly designed to match + D-Bus types. +- dbus-glib models only D-Bus interfaces and does not provide any types for + objects. GDBus models both D-Bus interfaces (via the GDBusInterface, + GDBusProxy and GDBusInterfaceSkeleton types) and objects (via the + GDBusObject, GDBusObjectSkeleton and GDBusObjectProxy types). +- GDBus includes native support for the org.freedesktop.DBus.Properties (via + the GDBusProxy type) and org.freedesktop.DBus.ObjectManager D-Bus + interfaces, dbus-glib doesn't. +- The typical way to export an object in dbus-glib involves generating glue + code from XML introspection data using dbus-binding-tool. GDBus provides a + similar tool called gdbus-codegen that can also generate Docbook D-Bus + interface documentation. +- dbus-glib doesn't provide any convenience API for owning and watching bus + names, GDBus provides the `g_bus_own_name()` and `g_bus_watch_name()` + family of convenience functions. +- GDBus provides API to parse, generate and work with Introspection XML, + dbus-glib doesn't. +- GTestDBus provides API to create isolated unit tests + +## API comparison + +| dbus-glib | GDBus | +|-----------|-------| +| `DBusGConnection` | `GDBusConnection` | +| `DBusGProxy` | `GDBusProxy`, `GDBusInterface` - also see `GDBusObjectProxy` | +| `DBusGObject` | `GDBusInterfaceSkeleton`, `GDBusInterface` - also see `GDBusObjectSkeleton` | +| `DBusGMethodInvocation` | `GDBusMethodInvocation` | +| `dbus_g_bus_get()` | `g_bus_get_sync()`, also see `g_bus_get()` | +| `dbus_g_proxy_new_for_name()` | `g_dbus_proxy_new_sync()` and `g_dbus_proxy_new_for_bus_sync()`, also see `g_dbus_proxy_new()` | +| `dbus_g_proxy_add_signal()` | not needed, use the generic “g-signal” | +| `dbus_g_proxy_connect_signal()` | use `g_signal_connect()` with “g-signal” | +| `dbus_g_connection_register_g_object()` | `g_dbus_connection_register_object()` - also see `g_dbus_object_manager_server_export()` | +| `dbus_g_connection_unregister_g_object()` | `g_dbus_connection_unregister_object()` - also see `g_dbus_object_manager_server_unexport()` | +| `dbus_g_object_type_install_info()` | introspection data is installed while registering an object, see `g_dbus_connection_register_object()` | +| `dbus_g_proxy_begin_call()` | `g_dbus_proxy_call()` | +| `dbus_g_proxy_end_call()` | `g_dbus_proxy_call_finish()` | +| `dbus_g_proxy_call()` | `g_dbus_proxy_call_sync()` | +| `dbus_g_error_domain_register()` | `g_dbus_error_register_error_domain()` | +| `dbus_g_error_has_name()` | no direct equivalent, see `g_dbus_error_get_remote_error()` | +| `dbus_g_method_return()` | `g_dbus_method_invocation_return_value()` | +| `dbus_g_method_return_error()` | `g_dbus_method_invocation_return_error()` and variants | +| `dbus_g_method_get_sender()` | `g_dbus_method_invocation_get_sender()` | + +## Owning bus names + +Using dbus-glib, you typically call RequestName manually to own a name, like in the following excerpt: + +```c +error = NULL; +res = dbus_g_proxy_call (system_bus_proxy, + "RequestName", + &error, + G_TYPE_STRING, NAME_TO_CLAIM, + G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT, + G_TYPE_INVALID, + G_TYPE_UINT, &result, + G_TYPE_INVALID); +if (!res) + { + if (error != NULL) + { + g_warning ("Failed to acquire %s: %s", + NAME_TO_CLAIM, error->message); + g_error_free (error); + } + else + { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + goto out; + } + +if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) + { + if (error != NULL) + { + g_warning ("Failed to acquire %s: %s", + NAME_TO_CLAIM, error->message); + g_error_free (error); + } + else + { + g_warning ("Failed to acquire %s", NAME_TO_CLAIM); + } + exit (1); + } + +dbus_g_proxy_add_signal (system_bus_proxy, "NameLost", + G_TYPE_STRING, G_TYPE_INVALID); +dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost", + G_CALLBACK (on_name_lost), NULL, NULL); + +/* further setup ... */ +``` + +While you can do things this way with GDBus too, using +`g_dbus_proxy_call_sync()`, it is much nicer to use the high-level API for +this: + +```c +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + /* further setup ... */ +} + +/* ... */ + + owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM, + NAME_TO_CLAIM, + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, + on_bus_acquired, + on_name_acquired, + on_name_lost, + NULL, + NULL); + + g_main_loop_run (loop); + + g_bus_unown_name (owner_id); +``` + +Note that `g_bus_own_name()` works asynchronously and requires you to enter +your mainloop to await the `on_name_aquired()` callback. Also note that in +order to avoid race conditions (e.g. when your service is activated by a +method call), you have to export your manager object before acquiring the +name. The `on_bus_acquired()` callback is the right place to do such +preparations. + +## Creating proxies for well-known names + +dbus-glib lets you create proxy objects for well-known names, like the following example: + +```c +proxy = dbus_g_proxy_new_for_name (system_bus_connection, + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts"); +``` + +For a DBusGProxy constructed like this, method calls will be sent to the current owner of the name, and that owner can change over time. + +The same can be achieved with GDBusProxy: + +```c +error = NULL; +proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM, + G_DBUS_PROXY_FLAGS_NONE, + NULL, /* GDBusInterfaceInfo */ + "org.freedesktop.Accounts", + "/org/freedesktop/Accounts", + "org.freedesktop.Accounts", + NULL, /* GCancellable */ + &error); +``` + +For an added layer of safety, you can specify what D-Bus interface the proxy +is expected to conform to by using the GDBusInterfaceInfo type. +Additionally, GDBusProxy loads, caches and tracks changes to the D-Bus +properties on the remote object. It also sets up match rules so D-Bus +signals from the remote object are delivered locally. + +The GDBusProxy type normally isn't used directly - instead proxies +subclassing GDBusProxy generated by `gdbus-codegen` is used, see the section +called “Using gdbus-codegen”. + +## Generating code and docs + +### Using gdbus-codegen + +dbus-glib comes with dbus-binding-tool, which can produce somewhat nice +client- and server-side wrappers for a D-Bus interface. With GDBus, +gdbus-codegen is used and like its counterpart, it also takes D-Bus +Introspection XML as input: + +#### Example D-Bus Introspection XML + +```xml + + + + + + + + + + + + + + + + + + + + + + + + + + + + +``` + +If this XML is processed like this + +``` +gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \ + --generate-c-code generated-code \ + --c-namespace Example \ + --c-generate-object-manager \ + --generate-docbook generated-docs \ + gdbus-example-objectmanager.xml +``` + +then two files generated-code.h and generated-code.c are generated. +Additionally, two XML files +generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal and +generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat with Docbook XML are +generated. + +While the contents of `generated-code.h` and `generated-code.c` are best described by the `gdbus-codegen` manual page, here's a brief example of how this generated code can be used: + +```c +#include "gdbus-object-manager-example/objectmanager-gen.h" + +/* ---------------------------------------------------------------------------------------------------- */ + +static GDBusObjectManagerServer *manager = NULL; + +static gboolean +on_animal_poke (ExampleAnimal *animal, + GDBusMethodInvocation *invocation, + gboolean make_sad, + gboolean make_happy, + gpointer user_data) +{ + if ((make_sad && make_happy) || (!make_sad && !make_happy)) + { + g_dbus_method_invocation_return_dbus_error (invocation, + "org.gtk.GDBus.Examples.ObjectManager.Error.Failed", + "Exactly one of make_sad or make_happy must be TRUE"); + goto out; + } + + if (make_sad) + { + if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0) + { + g_dbus_method_invocation_return_dbus_error (invocation, + "org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad", + "Sad animal is already sad"); + goto out; + } + + example_animal_set_mood (animal, "Sad"); + example_animal_complete_poke (animal, invocation); + goto out; + } + + if (make_happy) + { + if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0) + { + g_dbus_method_invocation_return_dbus_error (invocation, + "org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy", + "Happy animal is already happy"); + goto out; + } + + example_animal_set_mood (animal, "Happy"); + example_animal_complete_poke (animal, invocation); + goto out; + } + + g_assert_not_reached (); + + out: + return G_DBUS_METHOD_INVOCATION_HANDLED; +} + + +static void +on_bus_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + ExampleObjectSkeleton *object; + guint n; + + g_print ("Acquired a message bus connection\n"); + + /* Create a new org.freedesktop.DBus.ObjectManager rooted at /example/Animals */ + manager = g_dbus_object_manager_server_new ("/example/Animals"); + + for (n = 0; n < 10; n++) + { + gchar *s; + ExampleAnimal *animal; + + /* Create a new D-Bus object at the path /example/Animals/N where N is 000..009 */ + s = g_strdup_printf ("/example/Animals/%03d", n); + object = example_object_skeleton_new (s); + g_free (s); + + /* Make the newly created object export the interface + * org.gtk.GDBus.Example.ObjectManager.Animal (note + * that @object takes its own reference to @animal). + */ + animal = example_animal_skeleton_new (); + example_animal_set_mood (animal, "Happy"); + example_object_skeleton_set_animal (object, animal); + g_object_unref (animal); + + /* Cats are odd animals - so some of our objects implement the + * org.gtk.GDBus.Example.ObjectManager.Cat interface in addition + * to the .Animal interface + */ + if (n % 2 == 1) + { + ExampleCat *cat; + cat = example_cat_skeleton_new (); + example_object_skeleton_set_cat (object, cat); + g_object_unref (cat); + } + + /* Handle Poke() D-Bus method invocations on the .Animal interface */ + g_signal_connect (animal, + "handle-poke", + G_CALLBACK (on_animal_poke), + NULL); /* user_data */ + + /* Export the object (@manager takes its own reference to @object) */ + g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object)); + g_object_unref (object); + } + + /* Export all objects */ + g_dbus_object_manager_server_set_connection (manager, connection); +} + +static void +on_name_acquired (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_print ("Acquired the name %s\n", name); +} + +static void +on_name_lost (GDBusConnection *connection, + const gchar *name, + gpointer user_data) +{ + g_print ("Lost the name %s\n", name); +} + + +gint +main (gint argc, gchar *argv[]) +{ + GMainLoop *loop; + guint id; + + loop = g_main_loop_new (NULL, FALSE); + + id = g_bus_own_name (G_BUS_TYPE_SESSION, + "org.gtk.GDBus.Examples.ObjectManager", + G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | + G_BUS_NAME_OWNER_FLAGS_REPLACE, + on_bus_acquired, + on_name_acquired, + on_name_lost, + loop, + NULL); + + g_main_loop_run (loop); + + g_bus_unown_name (id); + g_main_loop_unref (loop); + + return 0; +} +``` + +This, on the other hand, is a client-side application using generated code: + +```c +#include "gdbus-object-manager-example/objectmanager-gen.h" + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +print_objects (GDBusObjectManager *manager) +{ + GList *objects; + GList *l; + + g_print ("Object manager at %s\n", g_dbus_object_manager_get_object_path (manager)); + objects = g_dbus_object_manager_get_objects (manager); + for (l = objects; l != NULL; l = l->next) + { + ExampleObject *object = EXAMPLE_OBJECT (l->data); + GList *interfaces; + GList *ll; + g_print (" - Object at %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object))); + + interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object)); + for (ll = interfaces; ll != NULL; ll = ll->next) + { + GDBusInterface *interface = G_DBUS_INTERFACE (ll->data); + g_print (" - Interface %s\n", g_dbus_interface_get_info (interface)->name); + + /* Note that @interface is really a GDBusProxy instance - and additionally also + * an ExampleAnimal or ExampleCat instance - either of these can be used to + * invoke methods on the remote object. For example, the generated function + * + * void example_animal_call_poke_sync (ExampleAnimal *proxy, + * gboolean make_sad, + * gboolean make_happy, + * GCancellable *cancellable, + * GError **error); + * + * can be used to call the Poke() D-Bus method on the .Animal interface. + * Additionally, the generated function + * + * const gchar *example_animal_get_mood (ExampleAnimal *object); + * + * can be used to get the value of the :Mood property. + */ + } + g_list_free_full (interfaces, g_object_unref); + } + g_list_free_full (objects, g_object_unref); +} + +static void +on_object_added (GDBusObjectManager *manager, + GDBusObject *object, + gpointer user_data) +{ + gchar *owner; + owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); + g_print ("Added object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner); + g_free (owner); +} + +static void +on_object_removed (GDBusObjectManager *manager, + GDBusObject *object, + gpointer user_data) +{ + gchar *owner; + owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); + g_print ("Removed object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner); + g_free (owner); +} + +static void +on_notify_name_owner (GObject *object, + GParamSpec *pspec, + gpointer user_data) +{ + GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object); + gchar *name_owner; + + name_owner = g_dbus_object_manager_client_get_name_owner (manager); + g_print ("name-owner: %s\n", name_owner); + g_free (name_owner); +} + +static void +on_interface_proxy_properties_changed (GDBusObjectManagerClient *manager, + GDBusObjectProxy *object_proxy, + GDBusProxy *interface_proxy, + GVariant *changed_properties, + const gchar *const *invalidated_properties, + gpointer user_data) +{ + GVariantIter iter; + const gchar *key; + GVariant *value; + gchar *s; + + g_print ("Properties Changed on %s:\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy))); + g_variant_iter_init (&iter, changed_properties); + while (g_variant_iter_next (&iter, "{&sv}", &key, &value)) + { + s = g_variant_print (value, TRUE); + g_print (" %s -> %s\n", key, s); + g_variant_unref (value); + g_free (s); + } +} + +gint +main (gint argc, gchar *argv[]) +{ + GDBusObjectManager *manager; + GMainLoop *loop; + GError *error; + gchar *name_owner; + + manager = NULL; + loop = NULL; + + loop = g_main_loop_new (NULL, FALSE); + + error = NULL; + manager = example_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, + "org.gtk.GDBus.Examples.ObjectManager", + "/example/Animals", + NULL, /* GCancellable */ + &error); + if (manager == NULL) + { + g_printerr ("Error getting object manager client: %s", error->message); + g_error_free (error); + goto out; + } + + name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager)); + g_print ("name-owner: %s\n", name_owner); + g_free (name_owner); + + print_objects (manager); + + g_signal_connect (manager, + "notify::name-owner", + G_CALLBACK (on_notify_name_owner), + NULL); + g_signal_connect (manager, + "object-added", + G_CALLBACK (on_object_added), + NULL); + g_signal_connect (manager, + "object-removed", + G_CALLBACK (on_object_removed), + NULL); + g_signal_connect (manager, + "interface-proxy-properties-changed", + G_CALLBACK (on_interface_proxy_properties_changed), + NULL); + + g_main_loop_run (loop); + + out: + if (manager != NULL) + g_object_unref (manager); + if (loop != NULL) + g_main_loop_unref (loop); + + return 0; +} +``` diff --git a/docs/reference/gio/migrating-gdbus.xml b/docs/reference/gio/migrating-gdbus.xml deleted file mode 100644 index dc4ee75..0000000 --- a/docs/reference/gio/migrating-gdbus.xml +++ /dev/null @@ -1,310 +0,0 @@ - - - -]> - - Migrating to GDBus - -
- Conceptual differences - - - The central concepts of D-Bus are modelled in a very similar way - in dbus-glib and GDBus. Both have objects representing connections, - proxies and method invocations. But there are some important - differences: - - - dbus-glib uses the libdbus - reference implementation, GDBus doesn't. Instead, it - relies on GIO streams as transport layer, and has its own - implementation for the D-Bus connection setup and - authentication. Apart from using streams as transport, - avoiding libdbus also lets GDBus avoid some thorny - multithreading issues. - - - dbus-glib uses the GObject type system for method arguments and - return values, including a homegrown container specialization - mechanism. GDBus relies on the #GVariant type system which is - explicitly designed to match D-Bus types. - - - dbus-glib models only D-Bus interfaces and does not provide - any types for objects. GDBus models both D-Bus interfaces - (via the #GDBusInterface, #GDBusProxy and - #GDBusInterfaceSkeleton types) and objects (via the - #GDBusObject, #GDBusObjectSkeleton and #GDBusObjectProxy types). - - - GDBus includes native support for the org.freedesktop.DBus.Properties (via the #GDBusProxy type) and org.freedesktop.DBus.ObjectManager D-Bus interfaces, dbus-glib doesn't. - - - The typical way to export an object in dbus-glib involves - generating glue code from XML introspection data using - dbus-binding-tool. GDBus provides a - similar tool called gdbus-codegen that - can also generate Docbook D-Bus interface documentation. - - - dbus-glib doesn't provide any convenience API for owning and - watching bus names, GDBus provides the g_bus_own_name() and - g_bus_watch_name() family of convenience functions. - - - GDBus provides API to parse, generate and work with Introspection - XML, dbus-glib doesn't. - - - GTestDBus provides API to create isolated unit tests GDBus Test Scaffolding. - - - -
- -
- API comparison - - - dbus-glib APIs and their GDBus counterparts - - - dbus-glibGDBus - - - #DBusGConnection#GDBusConnection - #DBusGProxy#GDBusProxy, #GDBusInterface - also see #GDBusObjectProxy - #DBusGObject#GDBusInterfaceSkeleton, #GDBusInterface - also see #GDBusObjectSkeleton - #DBusGMethodInvocation#GDBusMethodInvocation - dbus_g_bus_get()g_bus_get_sync(), also see - g_bus_get() - dbus_g_proxy_new_for_name()g_dbus_proxy_new_sync() and - g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new() - dbus_g_proxy_add_signal()not needed, use the generic #GDBusProxy::g-signal - dbus_g_proxy_connect_signal()use g_signal_connect() with #GDBusProxy::g-signal - dbus_g_connection_register_g_object()g_dbus_connection_register_object() - also see g_dbus_object_manager_server_export() - dbus_g_connection_unregister_g_object()g_dbus_connection_unregister_object() - also see g_dbus_object_manager_server_unexport() - dbus_g_object_type_install_info()introspection data is installed while registering - an object, see g_dbus_connection_register_object() - dbus_g_proxy_begin_call()g_dbus_proxy_call() - dbus_g_proxy_end_call()g_dbus_proxy_call_finish() - dbus_g_proxy_call()g_dbus_proxy_call_sync() - dbus_g_error_domain_register()g_dbus_error_register_error_domain() - dbus_g_error_has_name()no direct equivalent, see g_dbus_error_get_remote_error() - dbus_g_method_return()g_dbus_method_invocation_return_value() - dbus_g_method_return_error()g_dbus_method_invocation_return_error() and variants - dbus_g_method_get_sender()g_dbus_method_invocation_get_sender() - - -
-
- -
- Owning bus names - - Using dbus-glib, you typically call RequestName manually - to own a name, like in the following excerpt: - message); - g_error_free (error); - } - else - { - g_warning ("Failed to acquire %s", NAME_TO_CLAIM); - } - goto out; - } - - if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) - { - if (error != NULL) - { - g_warning ("Failed to acquire %s: %s", - NAME_TO_CLAIM, error->message); - g_error_free (error); - } - else - { - g_warning ("Failed to acquire %s", NAME_TO_CLAIM); - } - exit (1); - } - - dbus_g_proxy_add_signal (system_bus_proxy, "NameLost", - G_TYPE_STRING, G_TYPE_INVALID); - dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost", - G_CALLBACK (on_name_lost), NULL, NULL); - - /* further setup ... */ -]]> - - - - While you can do things this way with GDBus too, using - g_dbus_proxy_call_sync(), it is much nicer to use the high-level API - for this: - - - Note that g_bus_own_name() works asynchronously and requires - you to enter your mainloop to await the on_name_aquired() - callback. Also note that in order to avoid race conditions (e.g. - when your service is activated by a method call), you have to export - your manager object before acquiring the - name. The on_bus_acquired() callback is the right place to do - such preparations. - -
- -
- Creating proxies for well-known names - - dbus-glib lets you create proxy objects for well-known names, like the - following example: - - - For a #DBusGProxy constructed like this, method calls will be sent to - the current owner of the name, and that owner can change over time. - - - The same can be achieved with #GDBusProxy: - - - For an added layer of safety, you can specify what D-Bus - interface the proxy is expected to conform to by using the - #GDBusInterfaceInfo type. Additionally, #GDBusProxy loads, - caches and tracks changes to the D-Bus properties on the remote - object. It also sets up match rules so D-Bus signals from the - remote object are delivered locally. - - - The #GDBusProxy type normally isn't used directly - instead - proxies subclassing #GDBusProxy generated by gdbus-codegen is used, see - -
- -
- Generating code and docs - -
- Using gdbus-codegen - - - dbus-glib comes with dbus-binding-tool, which - can produce somewhat nice client- and server-side wrappers for a D-Bus interface. - With GDBus, gdbus-codegen is used and like - its counterpart, it also takes D-Bus Introspection XML as input: - - Example D-Bus Introspection XMLFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager.xml - - If this XML is processed like this - - then two files generated-code.h and - generated-code.c are - generated. Additionally, two XML files - generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal and - generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat - with Docbook XML are generated. For an example of what the docs look - like see the Animal D-Bus interface documentation. - and - the Cat D-Bus interface documentation. - - - While the contents of generated-code.h and - generated-code.c are best described by the - gdbus-codegen manual - page, brief examples of how this generated code can be used can be found in - - and . Additionally, since - the generated code has 100% gtk-doc coverage, see - #ExampleAnimal, #ExampleCat, #ExampleObject and - #ExampleObjectManagerClient pages for documentation. - - - Server-side application using generated codeFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-server.c - - Client-side application using generated codeFIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-client.c - -
- - - FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml - FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleAnimal.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleCat.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleObject.xml - FIXME: MISSING XINCLUDE CONTENT: ExampleObjectManagerClient.xml - -
- -
diff --git a/docs/reference/gio/migrating-gnome-vfs.md b/docs/reference/gio/migrating-gnome-vfs.md new file mode 100644 index 0000000..6c3a8cd --- /dev/null +++ b/docs/reference/gio/migrating-gnome-vfs.md @@ -0,0 +1,109 @@ +Title: Migrating from GnomeVFS to GIO +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Matthias Clasen + +# Migrating from GnomeVFS to GIO + +## Comparison of GnomeVFS and GIO concepts + +| GnomeVFS | GIO | +|----------|-----| +| `GnomeVFSURI` | [iface@Gio.File] | +| `GnomeVFSFileInfo` | [class@Gio.FileInfo] | +| `GnomeVFSResult` | [struct@GLib.Error], with `G_IO_ERROR` values | +| `GnomeVFSHandle` & `GnomeVFSAsyncHandle` | [class@Gio.InputStream] or [class@Gio.OutputStream] | +| `GnomeVFSDirectoryHandle` | [class@Gio.FileEnumerator] | +| MIME type | content type | +| `GnomeVFSMonitor` | [class@Gio.FileMonitor] | +| `GnomeVFSVolumeMonitor` | [class@Gio.VolumeMonitor] | +| `GnomeVFSVolume` | [iface@Gio.Mount] | +| `GnomeVFSDrive` | [iface@Gio.Volume] | +| - | [iface@Gio.Drive] | +| `GnomeVFSContext` | [class@Gio.Cancellable] | +| `gnome_vfs_async_cancel()` | [method@Gio.Cancellable.cancel] | + +## Trash handling + +The handling of trashed files has been changed in GIO, compared to +gnome-vfs. gnome-vfs has a home-grown trash implementation that predates the +freedesktop.org [Desktop Trash +Can](http://www.freedesktop.org/wiki/Specifications/trash-spec) +specification that is implemented in GIO. The location for storing trashed +files has changed from `$HOME/.Trash` to `$HOME/.local/share/Trash` (or more +correctly `$XDG_DATA_HOME/Trash`), which means that there is a need for +migrating files that have been trashed by gnome-vfs to the new location. + +In gnome-vfs, the `trash://` scheme offering a merged view of all trash +directories was implemented in Nautilus, and trash-handling applications had +to find and monitor all trash directories themselves. With GIO, the +`trash://` implementation has been moved to gvfs and applications can simply +monitor that location: + +```c +static void +file_changed (GFileMonitor *file_monitor, + GFile *child, + GFile *other_file, + GFileMonitorEvent event_type, + gpointer user_data) +{ + switch (event_type) + { + case G_FILE_MONITOR_EVENT_DELETED: + g_print ("'%s' removed from trash\n", g_file_get_basename (child)); + break; + case G_FILE_MONITOR_EVENT_CREATED: + g_print ("'%s' added to trash\n", g_file_get_basename (child)); + break; + default: ; + } +} + +static void +start_monitoring_trash (void) +{ + GFile *file; + GFileMonitor *monitor; + + file = g_file_new_for_uri ("trash://"); + monitor = g_file_monitor_directory (file, 0, NULL, NULL); + g_object_unref (file); + + g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL); + + /* ... */ + +} +``` + +GIO exposes some useful metadata about trashed files. There are +`trash::orig-path` and `trash::deletion-date` attributes. The +`standard::icon` attribute of the `trash://` itself provides a suitable icon +for displaying the trash can on the desktop. If you are using this icon, +make sure to monitor this attribute for changes, since the icon may be +updated to reflect that state of the trash can. + +Moving a file to the trash is much simpler with GIO. Instead of using +`gnome_vfs_find_directory()` with `GNOME_VFS_DIRECTORY_KIND_TRASH` to find +out where to move the trashed file, just use the [`method@Gio.File.trash`] +method. + +## Operations on multiple files + +gnome-vfs has the dreaded `gnome_vfs_xfer_uri_list()` function which has +tons of options and offers the equivalent of `cp`, `mv`, `ln`, `mkdir` and +`rm` at the same time. + +GIO offers a much simpler asynchronous task functionality instead, that lets +you schedule a function to be called in a separate thread, making sure that +updates are scheduled within the main context that created the task, so you +can update your user interface. See: [`class@Gio.Task`]. + +## Mime monitoring + +gnome-vfs offered a way to monitor the association between mime types and +default handlers for changes, with the `GnomeVFSMIMEMonitor` object. GIO +does not offer a replacement for this functionality at this time, since we +have not found a compelling use case where `GnomeVFSMIMEMonitor` was used. +If you think you have such a use case, please [open an issue on the GLib +issue tracker](https://gitlab.gnome.org/GNOME/glib/issues/new). diff --git a/docs/reference/gio/migrating-gnome-vfs.xml b/docs/reference/gio/migrating-gnome-vfs.xml deleted file mode 100644 index 27194aa..0000000 --- a/docs/reference/gio/migrating-gnome-vfs.xml +++ /dev/null @@ -1,133 +0,0 @@ - - Migrating from GnomeVFS to GIO - - - Comparison of GnomeVFS and GIO concepts - - - GnomeVFSGIO - - - GnomeVFSURIGFile - GnomeVFSFileInfoGFileInfo - GnomeVFSResultGError, with G_IO_ERROR values - GnomeVFSHandle & GnomeVFSAsyncHandleGInputStream or GOutputStream - GnomeVFSDirectoryHandleGFileEnumerator - mime typecontent type - GnomeVFSMonitorGFileMonitor - GnomeVFSVolumeMonitorGVolumeMonitor - GnomeVFSVolumeGMount - GnomeVFSDriveGVolume - -GDrive - GnomeVFSContextGCancellable - gnome_vfs_async_cancelg_cancellable_cancel - - -
- -
- Trash handling - - - The handling of trashed files has been changed in GIO, compared - to gnome-vfs. gnome-vfs has a home-grown trash implementation that - predates the freedesktop.org Desktop Trash Can specification - that is implemented in GIO. The location for storing trashed files - has changed from $HOME/.Trash to - $HOME/.local/share/Trash (or more correctly - $XDG_DATA_HOME/Trash), which means that - there is a need for migrating files that have been trashed by - gnome-vfs to the new location. - - - In gnome-vfs, the trash:// scheme offering a - merged view of all trash directories was implemented in nautilus, - and trash-handling applications had to find and monitor all trash - directories themselves. With GIO, the trash:// - implementation has been moved to gvfs and applications can simply - monitor that location: - - -static void -file_changed (GFileMonitor *file_monitor, - GFile *child, - GFile *other_file, - GFileMonitorEvent event_type, - gpointer user_data) -{ - switch (event_type) - { - case G_FILE_MONITOR_EVENT_DELETED: - g_print ("'%s' removed from trash\n", g_file_get_basename (child)); - break; - case G_FILE_MONITOR_EVENT_CREATED: - g_print ("'%s' added to trash\n", g_file_get_basename (child)); - break; - default: ; - } -} - -static void -start_monitoring_trash (void) -{ - GFile *file; - GFileMonitor *monitor; - - file = g_file_new_for_uri ("trash://"); - monitor = g_file_monitor_directory (file, 0, NULL, NULL); - g_object_unref (file); - - g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL); - - /* ... */ - -} - - - GIO exposes some useful metadata about trashed files. There are - trash::orig-path and trash::deletion-date attributes. The - standard::icon attribute of the trash:// - itself provides a suitable icon for displaying the trash can on - the desktop. If you are using this icon, make sure to monitor - this attribute for changes, since the icon may be updated to - reflect that state of the trash can. - - - Moving a file to the trash is much simpler with GIO. Instead of - using gnome_vfs_find_directory() with %GNOME_VFS_DIRECTORY_KIND_TRASH - to find out where to move the trashed file, just use the g_file_trash() - function. - -
- -
- Operations on multiple files - - - gnome-vfs has the dreaded gnome_vfs_xfer_uri_list() function which - has tons of options and offers the equivalent of cp, mv, ln, mkdir - and rm at the same time. - - - GIO offers a much simpler I/O scheduler functionality instead, that - lets you schedule a function to be called in a separate thread, or - if threads are not available, as an idle in the mainloop. - See g_io_scheduler_push_job(). - - -
- -
- Mime monitoring - - - gnome-vfs offered a way to monitor the association between mime types - and default handlers for changes, with the #GnomeVFSMIMEMonitor object. - GIO does not offer a replacement for this functionality at this time, - since we have not found a compelling use case where - #GnomeVFSMIMEMonitor was used. If you think you have such a use - case, please report it at - https://gitlab.gnome.org/GNOME/glib/issues/new. - -
-
diff --git a/docs/reference/gio/migrating-posix.md b/docs/reference/gio/migrating-posix.md new file mode 100644 index 0000000..14efa1e --- /dev/null +++ b/docs/reference/gio/migrating-posix.md @@ -0,0 +1,17 @@ +Title: Migrating from POSIX to GIO +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007 Matthias Clasen + +# Migrating from POSIX to GIO + +## Comparison of POSIX and GIO concepts + +| POSIX | GIO | +|-----------------------|-----------------------------------------------------| +| `char *path` | [iface@Gio.File] | +| `struct stat *buf` | [class@Gio.FileInfo] | +| `struct statvfs *buf` | [class@Gio.FileInfo] | +| `int fd` | [class@Gio.InputStream] or [class@Gio.OutputStream] | +| `DIR *` | [class@Gio.FileEnumerator] | +| `fstab entry` | [struct@Gio.UnixMountPoint] | +| `mtab entry` | [struct@Gio.UnixMountEntry] | diff --git a/docs/reference/gio/migrating-posix.xml b/docs/reference/gio/migrating-posix.xml deleted file mode 100644 index e7dc9f4..0000000 --- a/docs/reference/gio/migrating-posix.xml +++ /dev/null @@ -1,27 +0,0 @@ - - Migrating to GIO - - - Migrating from POSIX to GIO - - - Comparison of POSIX and GIO concepts - - - POSIXGIO - - - char *pathGFile *file - struct stat *bufGFileInfo *info - struct statvfs *bufGFileInfo *info - int fdGInputStream *in - GOutputStream *out - DIR *GFileEnumerator *enum - fstab entryGUnixMountPoint *mount_point - mtab entryGUnixMountEntry *mount_entry - - -
- -
-
diff --git a/docs/reference/gio/networking.md b/docs/reference/gio/networking.md new file mode 100644 index 0000000..d3da5f5 --- /dev/null +++ b/docs/reference/gio/networking.md @@ -0,0 +1,29 @@ +Title: gnetworking.h +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Dan Winship + +# gnetworking.h + +The `` header can be included to get +various low-level networking-related system headers, automatically +taking care of certain portability issues for you. + +This can be used, for example, if you want to call +[`setsockopt()`](man:setsockopt(2)) on a [class@Gio.Socket]. + +Note that while WinSock has many of the same APIs as the +traditional UNIX socket API, most of them behave at least slightly +differently (particularly with respect to error handling). If you +want your code to work under both UNIX and Windows, you will need +to take these differences into account. + +Also, under GNU libc, certain non-portable functions are only visible +in the headers if you define `_GNU_SOURCE` before including them. Note +that this symbol must be defined before including any headers, or it +may not take effect. + +There is one function provided specifically for initialising the networking +APIs, which needs to be called only if they are being used before GLib +initialises itself: + + * [func@Gio.networking_init] diff --git a/docs/reference/gio/overview.md b/docs/reference/gio/overview.md new file mode 100644 index 0000000..2e496e6 --- /dev/null +++ b/docs/reference/gio/overview.md @@ -0,0 +1,406 @@ +Title: Overview +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007, 2008, 2010, 2011, 2012, 2013 Matthias Clasen +SPDX-FileCopyrightText: 2007, 2009 Alexander Larsson +SPDX-FileCopyrightText: 2008 A. Walton +SPDX-FileCopyrightText: 2010 David Zeuthen +SPDX-FileCopyrightText: 2013 Stef Walter +SPDX-FileCopyrightText: 2015 Collabora, Ltd. +SPDX-FileCopyrightText: 2016 Colin Walters +SPDX-FileCopyrightText: 2020 Wouter Bolsterlee +SPDX-FileCopyrightText: 2022 Endless OS Foundation, LLC + +# Overview + +GIO is striving to provide a modern, easy-to-use VFS API that sits at the +right level in the library stack, as well as other generally useful APIs +for desktop applications (such as networking and D-Bus support). The goal +is to overcome the shortcomings of GnomeVFS and provide an API that is so +good that developers prefer it over raw POSIX calls. Among other things +that means using GObject. It also means not cloning the POSIX API, but +providing higher-level, document-centric interfaces. + +The abstract file system model of GIO consists of a number of interfaces and +base classes for I/O and files: + +[iface@Gio.File] +: reference to a file + +[class@Gio.FileInfo] +: information about a file or filesystem + +[class@Gio.FileEnumerator] +: list files in directories + +[iface@Gio.Drive] +: represents a drive + +[iface@Gio.Volume] +: represents a file system in an abstract way + +[iface@Gio.Mount] +: represents a mounted file system + +Then there is a number of stream classes, similar to the input and output +stream hierarchies that can be found in frameworks like Java: + +[class@Gio.InputStream] +: read data + +[class@Gio.OutputStream] +: write data + +[class@Gio.IOStream] +: read and write data + +[iface@Gio.Seekable] +: interface optionally implemented by streams to support seeking + +There are interfaces related to applications and the types of files they +handle: + +[iface@Gio.AppInfo] +: information about an installed application + +[iface@Gio.Icon] +: abstract type for file and application icons + +There is a framework for storing and retrieving application settings: + +[class@Gio.Settings] +: stores and retrieves application settings + +There is support for network programming, including connectivity monitoring, +name resolution, lowlevel socket APIs and highlevel client and server helper +classes: + +[class@Gio.Socket] +: lowlevel platform independent socket object + +[class@Gio.Resolver] +: asynchronous and cancellable DNS resolver + +[class@Gio.SocketClient] +: high-level network client helper + +[class@Gio.SocketService] +: high-level network server helper + +[class@Gio.SocketConnection] +: network connection stream + +[iface@Gio.NetworkMonitor] +: network connectivity monitoring + +There is support for connecting to +[D-Bus](https://www.freedesktop.org/wiki/Software/dbus/), sending and receiving +messages, owning and watching bus names, and making objects available on the bus: + +[class@Gio.DBusConnection] +: a D-Bus connection + +[class@Gio.DBusMethodInvocation] +: for handling remote calls + +[class@Gio.DBusServer] +: helper for accepting connections + +[class@Gio.DBusProxy] +: proxy to access D-Bus interfaces on a remote object + +Beyond these, GIO provides facilities for file monitoring, asynchronous I/O +and filename completion. In addition to the interfaces, GIO provides +implementations for the local case. Implementations for various network file +systems are provided by the GVFS package as loadable modules. + +Other design choices which consciously break with the GnomeVFS design are to +move backends out-of-process, which minimizes the dependency bloat and makes +the whole system more robust. The backends are not included in GIO, but in +the separate GVFS package. The GVFS package also contains the GVFS daemon, +which spawn further mount daemons for each individual connection. + +![GIO in the GTK library stack](./gvfs-overview.png) + +The GIO model of I/O is stateful: if an application establishes e.g. a SFTP +connection to a server, it becomes available to all applications in the +session; the user does not have to enter his password over and over again. + +One of the big advantages of putting the VFS in the GLib layer is that GTK +can directly use it, e.g. in the filechooser. + +## Writing GIO applications + +The information in the GLib documentation about writing GLib applications is +generally applicable when writing GIO applications. + +### Threads + +GDBus has its own private worker thread, so applications using GDBus have at +least 3 threads. GIO makes heavy use of the concept of a thread-default main +context to execute callbacks of asynchronous methods in the same context in +which the operation was started. + +### Asynchronous Programming + +Many GIO functions come in two versions: synchronous and asynchronous, +denoted by an `_async` suffix. It is important to use these appropriately: +synchronous calls should not be used from within a main loop which is shared +with other code, such as one in the application’s main thread. Synchronous +calls block until they complete, and I/O operations can take noticeable +amounts of time (even on ‘fast’ SSDs). Blocking a main loop iteration while +waiting for I/O means that other sources in the main loop will not be +dispatched, such as input and redraw handlers for the application’s UI. This +can cause the application to ‘freeze’ until I/O completes. + +A few self-contained groups of functions, such as code generated by +gdbus-codegen, use a different convention: functions are asynchronous +default, and it is the synchronous version which has a `_sync` suffix. Aside +from naming differences, they should be treated the same way as functions +following the normal convention above. + +The asynchronous (`_async`) versions of functions return control to the +caller immediately, after scheduling the I/O in the kernel and adding a +callback for it to the main loop. This callback will be invoked when the +operation has completed. From the callback, the paired `_finish` function +should be called to retrieve the return value of the I/O operation, and any +errors which occurred. For more information on using and implementing +asynchronous functions, see [iface@Gio.AsyncResult] and [class@Gio.Task]. + +By starting multiple asynchronous operations in succession, they will be +executed in parallel (up to an arbitrary limit imposed by GIO’s internal +worker thread pool). + +The synchronous versions of functions can be used early in application +startup when there is no main loop to block, for example to load initial +configuration files. They can also be used for I/O on files which are +guaranteed to be small and on the local disk. Note that the user’s home +directory is not guaranteed to be on the local disk. Security + +When your program needs to carry out some privileged operation (say, create +a new user account), there are various ways in which you can go about this: + +- Implement a daemon that offers the privileged operation. A convenient way + to do this is as a D-Bus system-bus service. The daemon will probably need + ways to check the identity and authorization of the caller before + executing the operation. + [polkit](https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html) + is a framework that allows this. +- Use a small helper that is executed with elevated privileges via pkexec. + [`pkexec`](https://www.freedesktop.org/software/polkit/docs/latest/pkexec.1.html) + is a small program launcher that is part of polkit. +- Use a small helper that is executed with elevated privileges by being suid + root. + +None of these approaches is the clear winner, they all have their advantages +and disadvantages. + +When writing code that runs with elevated privileges, it is important to +follow some basic rules of secure programming. David Wheeler has an +excellent book on this topic, +[Secure Programming for Linux and Unix HOWTO](https://dwheeler.com/secure-programs/Secure-Programs-HOWTO/index.html). + +When using GIO in code that runs with elevated privileges, you have to be +careful. GIO has extension points whose implementations get loaded from +modules (executable code in shared objects), which could allow an attacker +to sneak his own code into your application by tricking it into loading the +code as a module. However, GIO will never load modules from your home +directory except when explicitly asked to do so via an environment variable. + +In most cases, your helper program should be so small that you don't need +GIO, whose APIs are largely designed to support full-blown desktop +applications. If you can't resist the convenience of these APIs, here are +some steps you should take: + +- Clear the environment, e.g. using the `clearenv()` function. David Wheeler + has a good + [explanation](https://dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html) + for why it is important to sanitize the environment. See the section on + running GIO applications for a list of all environment variables affecting + GIO. In particular, `PATH` (used to locate binaries), `GIO_EXTRA_MODULES` + (used to locate loadable modules) and `DBUS_{SYSTEM,SESSION}_BUS_ADDRESS` + (used to locate the D-Bus system and session bus) are important. +- Don't use GVfs, by setting `GIO_USE_VFS=local` in the environment. The + reason to avoid GVfs in security-sensitive programs is that it uses many + libraries which have not necessarily been audited for security problems. + Gvfs is also heavily distributed and relies on a session bus to be + present. + +## Compiling GIO applications + +GIO comes with a `gio-2.0.pc` file that you should use together with +pkg-config to obtain the necessary information about header files and +libraries. See the pkg-config man page or the GLib documentation for more +information on how to use pkg-config to compile your application. + +If you are using GIO on UNIX-like systems, you may want to use UNIX-specific +GIO interfaces such as `GUnixInputStream`, `GUnixOutputStream`, `GUnixMount` +or `GDesktopAppInfo`. To do so, use the `gio-unix-2.0.pc` file instead of +`gio-2.0.pc`. + +## Running GIO applications + +GIO inspects a few environment variables in addition to the ones used by GLib. + +- `XDG_DATA_HOME`, `XDG_DATA_DIRS`. GIO uses these environment variables to + locate MIME information. For more information, see the + [Shared MIME-info Database](https://specifications.freedesktop.org/shared-mime-info-spec/latest/) + and the [Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/). +- `GVFS_DISABLE_FUSE`. This variable can be set to keep Gvfs from starting + the fuse backend, which may be unwanted or unnecessary in certain + situations. +- `GIO_USE_VFS`. This environment variable can be set to the name of a GVfs + implementation to override the default for debugging purposes. The GVfs + implementation for local files that is included in GIO has the name + "local", the implementation in the gvfs module has the name "gvfs". Most + commonly, system software will set this to "local" to avoid having `GFile` + APIs perform unnecessary D-Bus calls. The special value help can be used + to print a list of available implementations to standard output. + +The following environment variables are only useful for debugging GIO itself +or modules that it loads. They should not be set in a production +environment. + +- `GIO_USE_FILE_MONITOR`. This variable can be set to the name of a + GFileMonitor implementation to override the default for debugging + purposes. The GFileMonitor implementation for local files that is included + in GIO on Linux has the name "inotify", others that are built are built as + modules (depending on the platform) are called "fam" and "fen". The + special value help can be used to print a list of available + implementations to standard output. +- `GIO_USE_VOLUME_MONITOR`. This variable can be set to the name of a + GVolumeMonitor implementation to override the default for debugging + purposes. The GVolumeMonitor implementation for local files that is + included in GIO has the name "unix", the udisks2-based implementation in + the gvfs module has the name "udisks2". The special value help can be used + to print a list of available implementations to standard output. +- `GIO_USE_TLS`. This variable can be set to the name of a GTlsBackend + implementation to override the default for debugging purposes. GIO does + not include a GTlsBackend implementation, the gnutls-based implementation + in the glib-networking module has the name "gnutls". The special value + help can be used to print a list of available implementations to standard + output. +- `GIO_USE_PORTALS`. This variable can be set to override detection of portals + and force them to be used to provide various bits of GIO functionality, for + testing and debugging. This variable is not intended to be used in production. +- `GIO_MODULE_DIR`. When this environment variable is set to a path, GIO + will load modules from this alternate directory instead of the directory + built into GIO. This is useful when running tests, for example. This + environment variable is ignored when running in a setuid program. +- `GIO_EXTRA_MODULES`. When this environment variable is set to a path, or + a set of paths separated by a colon, GIO will attempt to load additional + modules from within the path. This environment variable is ignored when + running in a setuid program. +- `GSETTINGS_BACKEND`. This variable can be set to the name of a + GSettingsBackend implementation to override the default for debugging + purposes. The memory-based implementation that is included in GIO has the + name "memory", the one in dconf has the name "dconf". The special value + help can be used to print a list of available implementations to standard + output. +- `GSETTINGS_SCHEMA_DIR`. This variable can be set to the names of + directories to consider when looking for compiled schemas for GSettings, + in addition to the `glib-2.0/schemas` subdirectories of the XDG system + data dirs. To specify multiple directories, use `G_SEARCHPATH_SEPARATOR_S` + as a separator. +- `DBUS_SYSTEM_BUS_ADDRESS`. This variable is consulted to find the address + of the D-Bus system bus. For the format of D-Bus addresses, see the + [D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses). + Setting this variable overrides platform-specific ways of determining the + system bus address. +- `DBUS_SESSION_BUS_ADDRESS`. This variable is consulted to find the + address of the D-Bus session bus. Setting this variable overrides + platform-specific ways of determining the session bus address. +- `DBUS_STARTER_BUS_TYPE`. This variable is consulted to find out the + 'starter' bus for an application that has been started via D-Bus + activation. The possible values are 'system' or 'session'. +- `G_DBUS_DEBUG`. This variable can be set to a list of debug options, + which cause GLib to print out different types of debugging information + when using the D-Bus routines. + - `transport`: Show IO activity (e.g. reads and writes) + - `message`: Show all sent and received D-Bus messages + - `payload`: Show payload for all sent and received D-Bus messages (implies + message) + - `call`: Trace `g_dbus_connection_call()` and + `g_dbus_connection_call_sync()` API usage + - `signal`: Show when a D-Bus signal is received + - `incoming`: Show when an incoming D-Bus method call is received + - `return`: Show when a reply is returned via the GDBusMethodInvocation API + - `emission`: Trace `g_dbus_connection_emit_signal()` API usage + - `authentication`: Show information about connection authentication + - `address`: Show information about D-Bus address lookups and autolaunching + - `all`: Turn on all debug options + - `help`: Print a list of supported options to the standard output +- `G_DBUS_COOKIE_SHA1_KEYRING_DIR`. Can be used to override the directory + used to store the keyring used in the `DBUS_COOKIE_SHA1` authentication + mechanism. Normally the directory used is `.dbus-keyrings` in the user's + home directory. +- `G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION`. If set, the + permissions of the directory used to store the keyring used in the + `DBUS_COOKIE_SHA1` authentication mechanism won't be checked. Normally the + directory must be readable only by the user. + +## Extending GIO + +A lot of the functionality that is accessible through GIO is implemented in +loadable modules, and modules provide a convenient way to extend GIO. In +addition to the [`class@Gio.IOModule`] API which supports writing such modules, GIO has a +mechanism to define extension points, and register implementations thereof, +see [`struct@Gio.IOExtensionPoint`]. + +The following extension points are currently defined by GIO: + +- `G_VFS_EXTENSION_POINT_NAME`. Allows to override the functionality of the + GVfs class. Implementations of this extension point must be derived from + GVfs. GIO uses the implementation with the highest priority that is + active, see `g_vfs_is_active()`. GIO implements this extension point for + local files, gvfs contains an implementation that supports all the + backends in gvfs. +- `G_VOLUME_MONITOR_EXTENSION_POINT_NAME`. Allows to add more volume + monitors. Implementations of this extension point must be derived from + GVolumeMonitor. GIO uses all registered extensions. gvfs contains an + implementation that works together with the GVfs implementation in gvfs. +- `G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME`. Allows to override the + 'native' volume monitor. Implementations of this extension point must be + derived from GNativeVolumeMonitor. GIO uses the implementation with the + highest priority that is supported, as determined by the `is_supported()` + vfunc in GVolumeMonitorClass. GIO implements this extension point for + local mounts, gvfs contains a udisks2-based implementation. +- `G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME`. Allows to override the file + monitor implementation for local files. Implementations of this extension + point must be derived from GLocalFileMonitor. GIO uses the implementation + with the highest priority that is supported, as determined by the + `is_supported()` vfunc in GLocalFileMonitorClass. GIO uses this extension + point internally, to switch between its fam-based and inotify-based file + monitoring implementations. +- `G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME`. Allows to override the + directory monitor implementation for local files. Implementations of this + extension point must be derived from GLocalDirectoryMonitor. GIO uses the + implementation with the highest priority that is supported, as determined + by the `is_supported()` vfunc in GLocalDirectoryMonitorClass. GIO uses + this extension point internally, to switch between its fam-based and + inotify-based directory monitoring implementations. +- `G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME`. Unix-only. Allows to + provide a way to associate default handlers with URI schemes. + Implementations of this extension point must implement the + GDesktopAppInfoLookup interface. GIO uses the implementation with the + highest priority. This extension point has been discontinued in GLib 2.28. + It is still available to keep API and ABI stability, but GIO is no longer + using it for default handlers. Instead, the mime handler mechanism is + used, together with x-scheme-handler pseudo-mimetypes. +- `G_SETTINGS_BACKEND_EXTENSION_POINT_NAME`. Allows to provide an + alternative storage for GSettings. Implementations of this extension point + must derive from the GSettingsBackend type. GIO contains a keyfile-based + implementation of this extension point, another one is provided by dconf. +- `G_PROXY_EXTENSION_POINT_NAME`. Allows to provide implementations for + network proxying. Implementations of this extension point must provide the + GProxy interface, and must be named after the network protocol they are + proxying. glib-networking contains an implementation of this extension + point based on libproxy. +- `G_TLS_BACKEND_EXTENSION_POINT_NAME`. Allows to provide implementations + for TLS support. Implementations of this extension point must implement + the GTlsBackend interface. glib-networking contains an implementation of + this extension point. +- `G_NETWORK_MONITOR_EXTENSION_POINT_NAME`. Allows to provide + implementations for network connectivity monitoring. Implementations of + this extension point must implement the GNetworkMonitorInterface + interface. GIO contains an implementation of this extension point that is + using the netlink interface of the Linux kernel. diff --git a/docs/reference/gio/overview.xml b/docs/reference/gio/overview.xml deleted file mode 100644 index b93a17a..0000000 --- a/docs/reference/gio/overview.xml +++ /dev/null @@ -1,745 +0,0 @@ - - GIO Overview - - - Introduction - - - GIO is striving to provide a modern, easy-to-use VFS API that sits - at the right level in the library stack, as well as other generally - useful APIs for desktop applications (such as networking and - D-Bus support). The goal is to overcome the shortcomings of GnomeVFS - and provide an API that is so good that developers prefer it over raw - POSIX calls. Among other things that means using GObject. It also means - not cloning the POSIX API, but providing higher-level, document-centric - interfaces. - - - - The abstract file system model of GIO consists of a number of - interfaces and base classes for I/O and files: - - - GFile - reference to a file - - - GFileInfo - information about a file or filesystem - - - GFileEnumerator - list files in directories - - - GDrive - represents a drive - - - GVolume - represents a file system in an abstract way - - - GMount - represents a mounted file system - - - Then there is a number of stream classes, similar to the input and - output stream hierarchies that can be found in frameworks like Java: - - - GInputStream - read data - - - GOutputStream - write data - - - GIOStream - read and write data - - - GSeekable - interface optionally implemented by streams to support seeking - - - There are interfaces related to applications and the types - of files they handle: - - - GAppInfo - information about an installed application - - - GIcon - abstract type for file and application icons - - - There is a framework for storing and retrieving application settings: - - - GSettings - stores and retrieves application settings - - - There is support for network programming, including connectivity monitoring, - name resolution, lowlevel socket APIs and highlevel client and server - helper classes: - - - GSocket - lowlevel platform independent socket object - - - GResolver - asynchronous and cancellable DNS resolver - - - GSocketClient - high-level network client helper - - - GSocketService - high-level network server helper - - - GSocketConnection - network connection stream - - - GNetworkMonitor - network connectivity monitoring - - - There is support for connecting to D-Bus, - sending and receiving messages, owning and watching bus names, - and making objects available on the bus: - - - GDBusConnection - a D-Bus connection - - - - GDBusMethodInvocation - for handling remote calls - - - - GDBusServer - helper for accepting connections - - - - GDBusProxy - proxy to access D-Bus interfaces on a remote object - - - - Beyond these, GIO provides facilities for file monitoring, - asynchronous I/O and filename completion. In addition to the - interfaces, GIO provides implementations for the local case. - Implementations for various network file systems are provided - by the GVFS package as loadable modules. - - - - Other design choices which consciously break with the GnomeVFS - design are to move backends out-of-process, which minimizes the - dependency bloat and makes the whole system more robust. The backends - are not included in GIO, but in the separate GVFS package. The GVFS - package also contains the GVFS daemon, which spawn further mount - daemons for each individual connection. - - -
- GIO in the GTK library stack - -
- - - The GIO model of I/O is stateful: if an application establishes e.g. - a SFTP connection to a server, it becomes available to all applications - in the session; the user does not have to enter their password over - and over again. - - - One of the big advantages of putting the VFS in the GLib layer - is that GTK can directly use it, e.g. in the filechooser. - -
- - - Writing GIO applications - - - The information in the GLib documentation about writing GLib - applications is generally applicable when writing GIO applications. - - - Threads - - - GDBus has its own private worker thread, so applications using - GDBus have at least 3 threads. GIO makes heavy use of the concept - of a thread-default - main context to execute callbacks of asynchronous - methods in the same context in which the operation was started. - - - - - Asynchronous Programming - - - Many GIO functions come in two versions: synchronous and asynchronous, - denoted by an _async suffix. It is important to use these - appropriately: synchronous calls should not be used from - within a main loop which is shared with other code, such as one in the - application’s main thread. Synchronous calls block until they complete, - and I/O operations can take noticeable amounts of time (even on ‘fast’ - SSDs). Blocking a main loop iteration while waiting for I/O means that - other sources in the main loop will not be dispatched, such as input and - redraw handlers for the application’s UI. This can cause the application - to ‘freeze’ until I/O completes. - - - - A few self-contained groups of functions, such as code generated by - gdbus-codegen, - use a different convention: functions are asynchronous default, and it is - the synchronous version which has a - _sync - suffix. Aside from naming differences, they should be treated the same - way as functions following the normal convention above. - - - - The asynchronous (_async) versions of functions return - control to the caller immediately, after scheduling the I/O in the kernel - and adding a callback for it to the main loop. This callback will be - invoked when the operation has completed. From the callback, the paired - _finish function should be called to retrieve the return - value of the I/O operation, and any errors which occurred. For more - information on using and implementing asynchronous functions, see - GAsyncResult - and GTask. - - - - By starting multiple asynchronous operations in succession, they will be - executed in parallel (up to an arbitrary limit imposed by GIO’s internal - worker thread pool). - - - - The synchronous versions of functions can be used early in application - startup when there is no main loop to block, for example to load initial - configuration files. They can also be used for I/O on files which are - guaranteed to be small and on the local disk. Note that the user’s home - directory is not guaranteed to be on the local disk. - - - - Security - - -When your program needs to carry out some privileged operation (say, -create a new user account), there are various ways in which you can go -about this: - - -Implement a daemon that offers the privileged operation. A convenient -way to do this is as a D-Bus system-bus service. The daemon will probably -need ways to check the identity and authorization of the caller before -executing the operation. polkit is a framework that allows this. - - -Use a small helper that is executed with elevated privileges via -pkexec. pkexec is a small program launcher that is part of polkit. - - -Use a small helper that is executed with elevated privileges by -being suid root. - - -None of these approaches is the clear winner, they all have their -advantages and disadvantages. - - - -When writing code that runs with elevated privileges, it is important -to follow some basic rules of secure programming. David Wheeler has an -excellent book on this topic, -Secure Programming for Linux and Unix HOWTO. - - - -When using GIO in code that runs with elevated privileges, you have to -be careful. GIO has extension points whose implementations get loaded -from modules (executable code in shared objects), which could allow -an attacker to sneak their own code into your application by tricking it -into loading the code as a module. However, GIO will never load modules -from your home directory except when explicitly asked to do so via an -environment variable. - - - -In most cases, your helper program should be so small that you don't -need GIO, whose APIs are largely designed to support full-blown desktop -applications. If you can't resist the convenience of these APIs, here -are some steps you should take: - - -Clear the environment, e.g. using the clearenv() -function. -David Wheeler has a good explanation for why it is -important to sanitize the environment. -See -for a list of all environment variables affecting GIO. In particular, -PATH (used to locate binaries), GIO_EXTRA_MODULES (used to locate loadable modules) and DBUS_{SYSTEM,SESSION}_BUS_ADDRESS (used to locate the D-Bus system and session bus) are important. - - -Don't use GVfs, by setting GIO_USE_VFS=local in the environment. -The reason to avoid GVfs in security-sensitive programs is that it uses -many libraries which have not necessarily been audited for security problems. -Gvfs is also heavily distributed and relies on a session bus to be present. - - - - - - - - - - Compiling GIO applications - - - GIO comes with a gio-2.0.pc file that you - should use together with pkg-config to obtain - the necessary information about header files and libraries. See - the pkg-config man page or the GLib documentation - for more information on how to use pkg-config - to compile your application. - - - - If you are using GIO on UNIX-like systems, you may want to use - UNIX-specific GIO interfaces such as #GUnixInputStream, - #GUnixOutputStream, #GUnixMount or #GDesktopAppInfo. - To do so, use the gio-unix-2.0.pc file - instead of gio-2.0.pc - - - - - Running GIO applications - - - GIO inspects a few environment variables in addition to the - ones used by GLib. - - - - <envar>XDG_DATA_HOME</envar>, <envar>XDG_DATA_DIRS</envar> - - - GIO uses these environment variables to locate MIME information. - For more information, see the Shared MIME-info Database - and the Base Directory Specification. - - - - - <envar>GVFS_DISABLE_FUSE</envar> - - - This variable can be set to keep #Gvfs from starting the fuse backend, - which may be unwanted or unnecessary in certain situations. - - - - - <envar>GIO_USE_VFS</envar> - - - This environment variable can be set to the name of a #GVfs - implementation to override the default for debugging purposes. - The #GVfs implementation for local files that is included in GIO - has the name "local", the implementation in the gvfs module has - the name "gvfs". Most commonly, system software will set this to "local" - to avoid having `GFile` APIs perform unnecessary D-Bus calls. - - The special value help can be used to print a list of - available implementations to standard output. - - - - - The following environment variables are only useful for debugging - GIO itself or modules that it loads. They should not be set in a - production environment. - - - - <envar>GIO_USE_FILE_MONITOR</envar> - - - This variable can be set to the name of a #GFileMonitor - implementation to override the default for debugging purposes. - The #GFileMonitor implementation for local files that is included - in GIO on Linux has the name inotify, others that are built - are built as modules (depending on the platform) are called - kqueue and win32filemonitor. - - The special value help can be used to print a list of - available implementations to standard output. - - - - - <envar>GIO_USE_VOLUME_MONITOR</envar> - - - This variable can be set to the name of a #GVolumeMonitor - implementation to override the default for debugging purposes. - The #GVolumeMonitor implementation for local files that is included - in GIO has the name "unix", the udisks2-based implementation in the - gvfs module has the name "udisks2". - - The special value help can be used to print a list of - available implementations to standard output. - - - - - <envar>GIO_USE_TLS</envar> - - - This variable can be set to the name of a #GTlsBackend - implementation to override the default for debugging purposes. - GIO does not include a #GTlsBackend implementation, the gnutls-based - implementation in the glib-networking module has the name "gnutls". - - The special value help can be used to print a list of - available implementations to standard output. - - - - - <envar>GIO_MODULE_DIR</envar> - - - When this environment variable is set to a path, GIO will load - modules from this alternate directory instead of the directory - built into GIO. This is useful when running tests, for example. - - - This environment variable is ignored when running in a setuid program. - - - - - <envar>GIO_EXTRA_MODULES</envar> - - - When this environment variable is set to a path, or a set of - paths separated by a colon, GIO will attempt to load - additional modules from within the path. - - - This environment variable is ignored when running in a setuid program. - - - - - <envar>GSETTINGS_BACKEND</envar> - - - This variable can be set to the name of a #GSettingsBackend - implementation to override the default for debugging purposes. - The memory-based implementation that is included in GIO has - the name "memory", the one in dconf has the name "dconf". - - The special value help can be used to print a list of - available implementations to standard output. - - - - - <envar>GSETTINGS_SCHEMA_DIR</envar> - - - This variable can be set to the names of directories to consider when looking for compiled schemas for #GSettings, - in addition to the glib-2.0/schemas - subdirectories of the XDG system data dirs. To specify multiple directories, use G_SEARCHPATH_SEPARATOR_S as a separator. - - - - - <envar>DBUS_SYSTEM_BUS_ADDRESS</envar> - - - This variable is consulted to find the address of the D-Bus system - bus. For the format of D-Bus addresses, see the D-Bus - specification. - - - Setting this variable overrides platform-specific ways of determining - the system bus address. - - - - - <envar>DBUS_SESSION_BUS_ADDRESS</envar> - - - This variable is consulted to find the address of the D-Bus session bus. - - - Setting this variable overrides platform-specific ways of determining - the session bus address. - - - - - <envar>DBUS_STARTER_BUS_TYPE</envar> - - - This variable is consulted to find out the 'starter' bus for an - application that has been started via D-Bus activation. The possible - values are 'system' or 'session'. - - - - - <envar>G_DBUS_DEBUG</envar> - - - This variable can be set to a list of debug options, which - cause GLib to print out different types of debugging - information when using the D-Bus routines. - - - transport - Show IO activity (e.g. reads and writes) - - - message - Show all sent and received D-Bus messages - - - payload - Show payload for all sent and received D-Bus messages (implies message) - - - call - Trace g_dbus_connection_call() and g_dbus_connection_call_sync() API usage - - - signal - Show when a D-Bus signal is received - - - incoming - Show when an incoming D-Bus method call is received - - - return - Show when a reply is returned via the #GDBusMethodInvocation API - - - emission - Trace g_dbus_connection_emit_signal() API usage - - - authentication - Show information about connection authentication - - - address - Show information about D-Bus address lookups and autolaunching - - - The special value all can be used to turn - on all debug options. The special value - help can be used to print a list of - supported options to standard output. - - - - - <envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR</envar> - - - Can be used to override the directory used to store the - keyring used in the DBUS_COOKIE_SHA1 - authentication mechanism. Normally the directory used is - .dbus-keyrings in the user's home - directory. - - - - - <envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION</envar> - - - If set, the permissions of the directory used to store the - keyring used in the DBUS_COOKIE_SHA1 - authentication mechanism won't be checked. Normally the - directory must be readable only by the user. - - - - - - Extending GIO - - - A lot of the functionality that is accessible through GIO - is implemented in loadable modules, and modules provide a convenient - way to extend GIO. In addition to the #GIOModule API which supports - writing such modules, GIO has a mechanism to define extension points, - and register implementations thereof, see #GIOExtensionPoint. - - - The following extension points are currently defined by GIO: - - - - G_VFS_EXTENSION_POINT_NAME - - - Allows to override the functionality of the #GVfs class. - Implementations of this extension point must be derived from #GVfs. - GIO uses the implementation with the highest priority that is active, - see g_vfs_is_active(). - - - GIO implements this extension point for local files, gvfs contains - an implementation that supports all the backends in gvfs. - - - - - G_VOLUME_MONITOR_EXTENSION_POINT_NAME - - - Allows to add more volume monitors. - Implementations of this extension point must be derived from - #GVolumeMonitor. GIO uses all registered extensions. - - - gvfs contains an implementation that works together with the #GVfs - implementation in gvfs. - - - - - G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME - - - Allows to override the 'native' volume monitor. - Implementations of this extension point must be derived from - #GNativeVolumeMonitor. GIO uses the implementation with - the highest priority that is supported, as determined by the - is_supported() vfunc in #GVolumeMonitorClass. - - - GIO implements this extension point for local mounts, - gvfs contains a udisks2-based implementation. - - - - - G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME - - - Allows to override the file monitor implementation for - local files. Implementations of this extension point must - be derived from #GLocalFileMonitor. GIO uses the implementation - with the highest priority that is supported, as determined by the - is_supported() vfunc in #GLocalFileMonitorClass. - - - GIO uses this extension point internally, to switch between - its kqueue-based and inotify-based file monitoring implementations. - - - - - G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME - - - Unix-only. Allows to provide a way to associate default handlers - with URI schemes. Implementations of this extension point must - implement the #GDesktopAppInfoLookup interface. GIO uses the - implementation with the highest priority. - - - This extension point has been discontinued in GLib 2.28. It is - still available to keep API and ABI stability, but GIO is no - longer using it for default handlers. Instead, the mime handler - mechanism is used, together with x-scheme-handler pseudo-mimetypes. - - - - - G_SETTINGS_BACKEND_EXTENSION_POINT_NAME - - - Allows to provide an alternative storage for #GSettings. - Implementations of this extension point must derive from the - #GSettingsBackend type. GIO contains a keyfile-based - implementation of this extension point, another one is provided - by dconf. - - - - - G_PROXY_EXTENSION_POINT_NAME - - - Allows to provide implementations for network proxying. - Implementations of this extension point must provide the - #GProxy interface, and must be named after the network - protocol they are proxying. - - - glib-networking contains an implementation of this extension - point based on libproxy. - - - - G_TLS_BACKEND_EXTENSION_POINT_NAME - - - Allows to provide implementations for TLS support. - Implementations of this extension point must implement - the #GTlsBackend interface. - - - glib-networking contains an implementation of this extension - point. - - - - - G_NETWORK_MONITOR_EXTENSION_POINT_NAME - - - Allows to provide implementations for network connectivity - monitoring. - Implementations of this extension point must implement - the #GNetworkMonitorInterface interface. - - - GIO contains an implementation of this extension point - that is using the netlink interface of the Linux kernel. - - - -
- diff --git a/docs/reference/gio/pollable-utils.md b/docs/reference/gio/pollable-utils.md new file mode 100644 index 0000000..c026dd9 --- /dev/null +++ b/docs/reference/gio/pollable-utils.md @@ -0,0 +1,15 @@ +Title: Pollable Utility Functions +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2012 Dan Winship + +# Pollable Utility Functions + +Utility functions for [iface@Gio.PollableInputStream] and +[iface@Gio.PollableOutputStream] implementations. + + * [func@Gio.pollable_source_new] + * [func@Gio.pollable_source_new_full] + * [func@Gio.pollable_stream_read] + * [func@Gio.pollable_stream_write] + * [func@Gio.pollable_stream_write_all] + diff --git a/docs/reference/gio/tls-overview.md b/docs/reference/gio/tls-overview.md new file mode 100644 index 0000000..453c57e --- /dev/null +++ b/docs/reference/gio/tls-overview.md @@ -0,0 +1,37 @@ +Title: TLS Overview +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Dan Winship +SPDX-FileCopyrightText: 2015 Collabora, Ltd. + +# TLS Overview + +[class@Gio.TlsConnection] and related classes provide TLS (Transport Layer +Security, previously known as SSL, Secure Sockets Layer) support for GIO-based +network streams. + +[iface@Gio.DtlsConnection] and related classes provide DTLS (Datagram TLS) +support for GIO-based network sockets, using the [iface@Gio.DatagramBased] +interface. The TLS and DTLS APIs are almost identical, except TLS is +stream-based and DTLS is datagram-based. They share certificate and backend +infrastructure. + +In the simplest case, for a client TLS connection, you can just set the +[property@Gio.SocketClient:tls] flag on a [class@Gio.SocketClient], and then any +connections created by that client will have TLS negotiated automatically, using +appropriate default settings, and rejecting any invalid or self-signed +certificates (unless you change that default by setting the +[property@Gio.SocketClient:tls-validation-flags] property). The returned object +will be a [class@Gio.TcpWrapperConnection], which wraps the underlying +[iface@Gio.TlsClientConnection]. + +For greater control, you can create your own [iface@Gio.TlsClientConnection], +wrapping a [class@Gio.SocketConnection] (or an arbitrary [class@Gio.IOStream] +with pollable input and output streams) and then connect to its signals, +such as [signal@Gio.TlsConnection::accept-certificate], before starting the +handshake. + +Server-side TLS is similar, using [iface@Gio.TlsServerConnection]. At the +moment, there is no support for automatically wrapping server-side +connections in the way [class@Gio.SocketClient] does for client-side +connections. + diff --git a/docs/reference/gio/unix-mounts.md b/docs/reference/gio/unix-mounts.md new file mode 100644 index 0000000..dc45010 --- /dev/null +++ b/docs/reference/gio/unix-mounts.md @@ -0,0 +1,35 @@ +Title: UNIX Mounts +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2007 Andrew Walton +SPDX-FileCopyrightText: 2008 Matthias Clasen + +# UNIX Mounts + +Routines for managing mounted UNIX mount points and paths. + +Note that `` belongs to the UNIX-specific GIO +interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config +file when using it. + +There are three main classes: + + * [struct@Gio.UnixMountEntry] + * [struct@Gio.UnixMountPoint] + * [class@Gio.UnixMountMonitor] + +Various helper functions for querying mounts: + + * [func@Gio.unix_mount_points_get] + * [func@Gio.UnixMountPoint.at] + * [func@Gio.unix_mounts_get] + * [func@Gio.unix_mount_at] + * [func@Gio.unix_mount_for] + * [func@Gio.unix_mounts_changed_since] + * [func@Gio.unix_mount_points_changed_since] + +And several helper functions for checking the type of a mount or path: + + * [func@Gio.unix_is_mount_path_system_internal] + * [func@Gio.unix_is_system_fs_type] + * [func@Gio.unix_is_system_device_path] + diff --git a/docs/reference/gio/urlmap.js b/docs/reference/gio/urlmap.js new file mode 100644 index 0000000..3224300 --- /dev/null +++ b/docs/reference/gio/urlmap.js @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Matthias Clasen +var baseURLs = [ + [ 'GdkPixbuf', 'https://docs.gtk.org/gdk-pixbuf/' ], + [ 'GLib', 'https://docs.gtk.org/glib/' ], + [ 'GModule', 'https://docs.gtk.org/gmodule/' ], + [ 'GObject', 'https://docs.gtk.org/gobject/' ], + [ 'Gio', 'https://docs.gtk.org/gio/' ], + [ 'Gtk', 'https://docs.gtk.org/gtk4/' ], +]; diff --git a/docs/reference/gio/version.xml.in b/docs/reference/gio/version.xml.in deleted file mode 100644 index d78bda9..0000000 --- a/docs/reference/gio/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@VERSION@ diff --git a/docs/reference/gio/xml/gtkdocentities.ent.in b/docs/reference/gio/xml/gtkdocentities.ent.in deleted file mode 100644 index f12c9ff..0000000 --- a/docs/reference/gio/xml/gtkdocentities.ent.in +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/reference/gio/xml/meson.build b/docs/reference/gio/xml/meson.build deleted file mode 100644 index 6aeb745..0000000 --- a/docs/reference/gio/xml/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -ent_conf = configuration_data() -ent_conf.set('PACKAGE', 'glib') -ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.gnome.org/GNOME/glib/issues/new') -ent_conf.set('PACKAGE_NAME', 'glib') -ent_conf.set('PACKAGE_STRING', 'glib') -ent_conf.set('PACKAGE_TARNAME', 'glib') -ent_conf.set('PACKAGE_URL', 'FIXME') -ent_conf.set('PACKAGE_VERSION', glib_version) -ent_conf.set('PACKAGE_API_VERSION', glib_api_version) -configure_file( - input: 'gtkdocentities.ent.in', - output: 'gtkdocentities.ent', - configuration: ent_conf -) diff --git a/docs/reference/girepository/girepository.toml.in b/docs/reference/girepository/girepository.toml.in new file mode 100644 index 0000000..a8102e3 --- /dev/null +++ b/docs/reference/girepository/girepository.toml.in @@ -0,0 +1,50 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2023 Matthias Clasen +# Copyright 2023 Philip Withnall + +[library] +name = "Girepository" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/glib/" +repository_url = "https://gitlab.gnome.org/GNOME/glib.git" +website_url = "https://www.gtk.org" +docs_urls = "https://docs.gtk.org/girepository/" +authors = "GLib Development Team" +license = "LGPL-2.1-or-later" +description = "GIRepository is a library providing access to typelibs and introspection data which describes C APIs" +dependencies = [ "GLib-2.0", "GModule-2.0", "GObject-2.0", "Gio-2.0" ] +devhelp = true +search_index = true + + [dependencies."GLib-2.0"] + name = "GLib" + description = "The base utility library" + docs_url = "https://docs.gtk.org/glib/" + + [dependencies."GModule-2.0"] + name = "GModule" + description = "Portable API for dynamically loading modules" + docs_url = "https://docs.gtk.org/gmodule/" + + [dependencies."GObject-2.0"] + name = "GObject" + description = "The base type system library" + docs_url = "https://docs.gtk.org/gobject/" + + [dependencies."Gio-2.0"] + name = "Gio" + description = "Useful classes for general purpose I/O, networking, IPC, settings, etc." + docs_url = "https://docs.gtk.org/gio/" + +[theme] +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +[extra] +urlmap_file = "urlmap.js" +# The same order will be used when generating the index +content_files = [ +] +content_images = [ +] diff --git a/docs/reference/girepository/meson.build b/docs/reference/girepository/meson.build new file mode 100644 index 0000000..f5e8e6d --- /dev/null +++ b/docs/reference/girepository/meson.build @@ -0,0 +1,23 @@ +girepository_toml = configure_file( + input: 'girepository.toml.in', + output: 'girepository.toml', + configuration: toml_conf, +) + +custom_target('girepository-docs', + input: [ girepository_toml, girepository_gir[0] ], + output: 'girepository', + command: [ + gidocgen, + 'generate', + gidocgen_common_args, + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--content-dir=@0@'.format(meson.current_source_dir()), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gobject'), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gmodule'), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gio'), + '@INPUT1@', + ], + build_by_default: true, +) diff --git a/docs/reference/girepository/urlmap.js b/docs/reference/girepository/urlmap.js new file mode 100644 index 0000000..3224300 --- /dev/null +++ b/docs/reference/girepository/urlmap.js @@ -0,0 +1,10 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Matthias Clasen +var baseURLs = [ + [ 'GdkPixbuf', 'https://docs.gtk.org/gdk-pixbuf/' ], + [ 'GLib', 'https://docs.gtk.org/glib/' ], + [ 'GModule', 'https://docs.gtk.org/gmodule/' ], + [ 'GObject', 'https://docs.gtk.org/gobject/' ], + [ 'Gio', 'https://docs.gtk.org/gio/' ], + [ 'Gtk', 'https://docs.gtk.org/gtk4/' ], +]; diff --git a/docs/reference/glib/atomic.md b/docs/reference/glib/atomic.md new file mode 100644 index 0000000..65337fe --- /dev/null +++ b/docs/reference/glib/atomic.md @@ -0,0 +1,75 @@ +Title: Atomic Operations +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2012 Dan Winship + +# Atomic Operations + +The following is a collection of compiler macros to provide atomic +access to integer and pointer-sized values. + +The macros that have ‘int’ in the name will operate on pointers to `gint` and +`guint`. The macros with ‘pointer’ in the name will operate on pointers to any +pointer-sized value, including `guintptr`. + +There is no support for 64-bit operations on platforms with 32-bit pointers +because it is not generally possible to perform these operations atomically. + +The get, set and exchange operations for integers and pointers +nominally operate on `gint` and `gpointer`, respectively. Of the +arithmetic operations, the ‘add’ operation operates on (and returns) +signed integer values (`gint` and `gssize`) and the ‘and’, ‘or’, and +‘xor’ operations operate on (and return) unsigned integer values +(`guint` and `gsize`). + +All of the operations act as a full compiler and (where appropriate) +hardware memory barrier. Acquire and release or producer and +consumer barrier semantics are not available through this API. + +It is very important that all accesses to a particular integer or +pointer be performed using only this API and that different sizes of +operation are not mixed or used on overlapping memory regions. Never +read or assign directly from or to a value — always use this API. + +For simple reference counting purposes you should use `gatomicrefcount` +(see [func@GLib.atomic_ref_count_init]) rather than [func@GLib.atomic_int_inc] +and [func@GLib.atomic_int_dec_and_test]. + +Uses of [func@GLib.atomic_int_inc] and [func@GLib.atomic_int_dec_and_test] +that fall outside of simple counting patterns are prone to +subtle bugs and occasionally undefined behaviour. It is also worth +noting that since all of these operations require global +synchronisation of the entire machine, they can be quite slow. In +the case of performing multiple atomic operations it can often be +faster to simply acquire a mutex lock around the critical area, +perform the operations normally and then release the lock. + +## Atomic Integer Operations + + * [func@GLib.atomic_int_get] + * [func@GLib.atomic_int_set] + * [func@GLib.atomic_int_inc] + * [func@GLib.atomic_int_dec_and_test] + * [func@GLib.atomic_int_compare_and_exchange] + * [func@GLib.atomic_int_compare_and_exchange_full] + * [func@GLib.atomic_int_exchange] + * [func@GLib.atomic_int_add] + * [func@GLib.atomic_int_and] + * [func@GLib.atomic_int_or] + * [func@GLib.atomic_int_xor] + +## Atomic Pointer Operations + + * [func@GLib.atomic_pointer_get] + * [func@GLib.atomic_pointer_set] + * [func@GLib.atomic_pointer_compare_and_exchange] + * [func@GLib.atomic_pointer_compare_and_exchange_full] + * [func@GLib.atomic_pointer_exchange] + * [func@GLib.atomic_pointer_add] + * [func@GLib.atomic_pointer_and] + * [func@GLib.atomic_pointer_or] + * [func@GLib.atomic_pointer_xor] + +## Deprecated API + + * [func@GLib.atomic_int_exchange_and_add] + diff --git a/docs/reference/glib/auto-cleanup.md b/docs/reference/glib/auto-cleanup.md new file mode 100644 index 0000000..f286bfe --- /dev/null +++ b/docs/reference/glib/auto-cleanup.md @@ -0,0 +1,291 @@ +Title: Automatic Cleanup +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2023 Matthias Clasen + +# Automatic Cleanup + +GLib provides a set of macros that wrap the GCC extension for automatic +cleanup of variables when they go out of scope. + +These macros can only be used with GCC and GCC-compatible C compilers. + +## Variable declaration + +`g_auto(TypeName)` + +: Helper to declare a variable with automatic cleanup. + + The variable is cleaned up in a way appropriate to its type when the + variable goes out of scope. The `TypeName` of the variable must support + this. + + The way to clean up the type must have been defined using one of the macros + `G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC()` or `G_DEFINE_AUTO_CLEANUP_FREE_FUNC()`. + + This feature is only supported on GCC and clang. This macro is not + defined on other compilers and should not be used in programs that + are intended to be portable to those compilers. + + This macro meant to be used with stack-allocated structures and + non-pointer types. For the (more commonly used) pointer version, see + `g_autoptr()`. + + This macro can be used to avoid having to do explicit cleanups of + local variables when exiting functions. It often vastly simplifies + handling of error conditions, removing the need for various tricks + such as `goto out` or repeating of cleanup code. It is also helpful + for non-error cases. + + Consider the following example: + + GVariant * + my_func(void) + { + g_auto(GQueue) queue = G_QUEUE_INIT; + g_auto(GVariantBuilder) builder; + g_auto(GStrv) strv; + + g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT); + strv = g_strsplit("a:b:c", ":", -1); + + // ... + + if (error_condition) + return NULL; + + // ... + + return g_variant_builder_end (&builder); + } + + You must initialize the variable in some way — either by use of an + initialiser or by ensuring that an `_init` function will be called on + it unconditionally before it goes out of scope. + + Since: 2.44 + + +`g_autoptr(TypeName)` +: Helper to declare a pointer variable with automatic cleanup. + + The variable is cleaned up in a way appropriate to its type when the + variable goes out of scope. The `TypeName` of the variable must support this. + The way to clean up the type must have been defined using the macro + `G_DEFINE_AUTOPTR_CLEANUP_FUNC()`. + + This feature is only supported on GCC and clang. This macro is not + defined on other compilers and should not be used in programs that + are intended to be portable to those compilers. + + This is meant to be used to declare pointers to types with cleanup + functions. The type of the variable is a pointer to `TypeName`. You + must not add your own `*`. + + This macro can be used to avoid having to do explicit cleanups of + local variables when exiting functions. It often vastly simplifies + handling of error conditions, removing the need for various tricks + such as `goto out` or repeating of cleanup code. It is also helpful + for non-error cases. + + Consider the following example: + + gboolean + check_exists(GVariant *dict) + { + g_autoptr(GVariant) dirname, basename = NULL; + g_autofree gchar *path = NULL; + + dirname = g_variant_lookup_value (dict, "dirname", G_VARIANT_TYPE_STRING); + if (dirname == NULL) + return FALSE; + + basename = g_variant_lookup_value (dict, "basename", G_VARIANT_TYPE_STRING); + if (basename == NULL) + return FALSE; + + path = g_build_filename (g_variant_get_string (dirname, NULL), + g_variant_get_string (basename, NULL), + NULL); + + return g_access (path, R_OK) == 0; + } + + You must initialise the variable in some way — either by use of an + initialiser or by ensuring that it is assigned to unconditionally + before it goes out of scope. + + See also: `g_auto()`, `g_autofree()` and `g_steal_pointer()`. + + Since: 2.44 + + +`g_autofree` + +: Macro to add an attribute to pointer variable to ensure automatic + cleanup using `g_free()`. + + This macro differs from `g_autoptr()` in that it is an attribute supplied + before the type name, rather than wrapping the type definition. Instead + of using a type-specific lookup, this macro always calls `g_free()` directly. + + This means it's useful for any type that is returned from `g_malloc()`. + + Otherwise, this macro has similar constraints as `g_autoptr()`: only + supported on GCC and clang, the variable must be initialized, etc. + + gboolean + operate_on_malloc_buf (void) + { + g_autofree guint8* membuf = NULL; + + membuf = g_malloc (8192); + + // Some computation on membuf + + // membuf will be automatically freed here + return TRUE; + } + + Since: 2.44 + + +`g_autolist(TypeName)` + +: Helper to declare a list variable with automatic deep cleanup. + + The list is deeply freed, in a way appropriate to the specified type, when the + variable goes out of scope. The type must support this. + + This feature is only supported on GCC and clang. This macro is not + defined on other compilers and should not be used in programs that + are intended to be portable to those compilers. + + This is meant to be used to declare lists of a type with a cleanup + function. The type of the variable is a `GList *`. You + must not add your own `*`. + + This macro can be used to avoid having to do explicit cleanups of + local variables when exiting functions. It often vastly simplifies + handling of error conditions, removing the need for various tricks + such as `goto out` or repeating of cleanup code. It is also helpful + for non-error cases. + + See also: `g_autoslist()`, `g_autoptr()` and `g_steal_pointer()`. + + Since: 2.56 + + +`g_autoslist(TypeName)` + +: Helper to declare a singly linked list variable with automatic deep cleanup. + + The list is deeply freed, in a way appropriate to the specified type, when the + variable goes out of scope. The type must support this. + + This feature is only supported on GCC and clang. This macro is not + defined on other compilers and should not be used in programs that + are intended to be portable to those compilers. + + This is meant to be used to declare lists of a type with a cleanup + function. The type of the variable is a `GSList *`. You + must not add your own `*`. + + This macro can be used to avoid having to do explicit cleanups of + local variables when exiting functions. It often vastly simplifies + handling of error conditions, removing the need for various tricks + such as `goto out` or repeating of cleanup code. It is also helpful + for non-error cases. + + See also: `g_autolist()`, `g_autoptr()` and `g_steal_pointer()`. + + Since: 2.56 + + +`g_autoqueue(TypeName)` + +: Helper to declare a double-ended queue variable with automatic deep cleanup. + + The queue is deeply freed, in a way appropriate to the specified type, when the + variable goes out of scope. The type must support this. + + This feature is only supported on GCC and clang. This macro is not + defined on other compilers and should not be used in programs that + are intended to be portable to those compilers. + + This is meant to be used to declare queues of a type with a cleanup + function. The type of the variable is a `GQueue *`. You + must not add your own `*`. + + This macro can be used to avoid having to do explicit cleanups of + local variables when exiting functions. It often vastly simplifies + handling of error conditions, removing the need for various tricks + such as `goto out` or repeating of cleanup code. It is also helpful + for non-error cases. + + See also: `g_autolist()`, `g_autoptr()` and `g_steal_pointer()`. + + Since: 2.62 + + +## Type definition + +`G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func)` + +: Defines the appropriate cleanup function for a pointer type. + + The function will not be called if the variable to be cleaned up + contains `NULL`. + + This will typically be the `_free()` or `_unref()` function for the given + type. + + With this definition, it will be possible to use `g_autoptr()` with + the given `TypeName`. + + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GObject, g_object_unref) + + This macro should be used unconditionally; it is a no-op on compilers + where cleanup is not supported. + + Since: 2.44 + + +`G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func)` + +: Defines the appropriate cleanup function for a type. + + This will typically be the `_clear()` function for the given type. + + With this definition, it will be possible to use `g_auto()` with + the given `TypeName`. + + G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear) + + This macro should be used unconditionally; it is a no-op on compilers + where cleanup is not supported. + + Since: 2.44 + + +`G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none_value)` + +: Defines the appropriate cleanup function for a type. + + With this definition, it will be possible to use `g_auto()` with the + given `TypeName`. + + This function will be rarely used. It is used with pointer-based + typedefs and non-pointer types where the value of the variable + represents a resource that must be freed. Two examples are `GStrv` + and file descriptors. + + `none_value` specifies the "none" value for the type in question. It + is probably something like `NULL` or `-1`.If the variable is found to + contain this value then the free function will not be called. + + G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL) + + This macro should be used unconditionally; it is a no-op on compilers + where cleanup is not supported. + + Since: 2.44 diff --git a/docs/reference/glib/base64.md b/docs/reference/glib/base64.md new file mode 100644 index 0000000..d4d57bd --- /dev/null +++ b/docs/reference/glib/base64.md @@ -0,0 +1,20 @@ +Title: Base64 Encoding +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2006, 2009 Matthias Clasen + +# Base64 Encoding + +Base64 is an encoding that allows a sequence of arbitrary bytes to be +encoded as a sequence of printable ASCII characters. For the definition +of Base64, see [RFC 1421](http://www.ietf.org/rfc/rfc1421.txt) or +[RFC 2045](http://www.ietf.org/rfc/rfc2045.txt). +Base64 is most commonly used as a MIME transfer encoding for email. + +GLib supports incremental encoding using [func@GLib.base64_encode_step] and +[func@GLib.base64_encode_close]. Incremental decoding can be done with +[func@GLib.base64_decode_step]. To encode or decode data in one go, use +[func@GLib.base64_encode] or [func@GLib.base64_decode]. To avoid memory +allocation when decoding, you can use [func@GLib.base64_decode_inplace]. + +Support for Base64 encoding was added in GLib 2.12. + diff --git a/docs/reference/glib/building.md b/docs/reference/glib/building.md new file mode 100644 index 0000000..1a59c69 --- /dev/null +++ b/docs/reference/glib/building.md @@ -0,0 +1,180 @@ +Title: Building GLib + +# Building GLib + +GLib uses the [Meson build system](https://mesonbuild.com). The normal +sequence for compiling and installing the GLib library is thus: + + $ meson setup _build + $ meson compile -C _build + $ meson install -C _build + +On FreeBSD, you will need something more complex: + + $ env CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib -Wl,--disable-new-dtags" \ + > meson setup \ + > -Dxattr=false \ + > -Dinstalled_tests=true \ + > -Db_lundef=false \ + > _build + $ meson compile -C _build + +The standard options provided by Meson may be passed to the `meson` command. Please see the Meson documentation or run: + + meson configure --help + +for information about the standard options. + +GLib is compiled with +[strict aliasing](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fstrict-aliasing) +disabled. It is strongly recommended that this is not re-enabled by overriding +the compiler flags, as GLib has not been tested with strict aliasing and cannot +be guaranteed to work. + +## Dependencies + +Before you can compile the GLib library, you need to have various other +tools and libraries installed on your system. If you are building from a +release archive, you will need a [compliant C +toolchain](https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/toolchain-requirements.md), +Meson, and pkg-config; the requirements are the same when building from a +Git repository clone of GLib. + +- [`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/) is a + tool for tracking the compilation flags needed for libraries that are used + by the GLib library. (For each library, a small `.pc` text file is + installed in a standard location that contains the compilation flags + needed for that library along with version number information). + +A UNIX build of GLib requires that the system implements at least the +original 1990 version of POSIX. Beyond this, it depends on a number of other +libraries. + +- The [GNU libiconv library](http://www.gnu.org/software/libiconv/) is + needed to build GLib if your system doesn't have the `iconv()` function + for doing conversion between character encodings. Most modern systems + should have `iconv()`, however many older systems lack an `iconv()` + implementation. On such systems, you must install the libiconv library. + This can be found at: http://www.gnu.org/software/libiconv. + + If your system has an `iconv()` implementation but you want to use libiconv + instead, make sure it is installed to the default compiler header/library + search path (for instance, in `/usr/local/`). The `iconv.h` that libiconv + installs hides the system iconv. Meson then detects this, recognizes that the + system iconv is unusable and the external one is mandatory, and automatically + forces it to be used. + + If you are using the native iconv implementation on Solaris instead of + libiconv, you'll need to make sure that you have the converters between + locale encodings and UTF-8 installed. At a minimum you'll need the + SUNWuiu8 package. You probably should also install the SUNWciu8, SUNWhiu8, + SUNWjiu8, and SUNWkiu8 packages. + + The native iconv on Compaq Tru64 doesn't contain support for UTF-8, so + you'll need to use GNU libiconv instead. (When using GNU libiconv for + GLib, you'll need to use GNU libiconv for GNU gettext as well.) This + probably applies to related operating systems as well. + +- Python 3.5 or newer is required. Your system Python must conform to + [PEP 394](https://www.python.org/dev/peps/pep-0394/) For FreeBSD, this means + that the `lang/python3` port must be installed. + +- The libintl library from the [GNU + gettext](http://www.gnu.org/software/gettext) package is needed if your + system doesn't have the `gettext()` functionality for handling message + translation databases. + +- A thread implementation is needed. The thread support in GLib can be based + upon POSIX threads or win32 threads. + +- GRegex uses the [PCRE library](http://www.pcre.org/) for regular + expression matching. The system version of PCRE is used, unless not available + (which is the case on Android), in which case a fallback subproject is used. + +- The optional extended attribute support in GIO requires the `getxattr()` + family of functions that may be provided by the C library or by the + standalone libattr library. To build GLib without extended attribute + support, use the `-Dxattr=false` option. + +- The optional SELinux support in GIO requires libselinux. To build GLib + without SELinux support, use the `-Dselinux=disabled` option. + +- The optional support for DTrace requires the `sys/sdt.h` header, which is + provided by SystemTap on Linux. To build GLib without DTrace, use the + `-Ddtrace=false` option. + +- The optional support for SystemTap can be disabled with the + `-Dsystemtap=false` option. Additionally, you can control the location + where GLib installs the SystemTap probes, using the + `-Dtapset_install_dir=DIR` option. + +- [gobject-introspection](https://gitlab.gnome.org/GNOME/gobject-introspection/) + is needed to generate introspection data for consumption by other projects, + and to generate the GLib documentation via + [gi-docgen](https://gitlab.gnome.org/GNOME/gi-docgen). There is a dependency + cycle between GLib and gobject-introspection. This can be broken by building + GLib first with `-Dintrospection=disabled`, then building + gobject-introspection against this copy of GLib, then re-building GLib against + the new gobject-introspection with `-Dintrospection=enabled`. The GLib API + documentation can be built during this second build process if + `-Ddocumentation=true` is also set. + +## Extra Configuration Options + +In addition to the normal options, these additional ones are supported when +configuring the GLib library: + +`--buildtype` +: This is a standard Meson option which specifies how much debugging and + optimization to enable. If the build type is `debug`, `G_ENABLE_DEBUG` will be + defined and GLib will be built with additional debug code enabled. You can + override this behavior using `-Dglib_debug`. + +`-Dforce_posix_threads=true` +: Normally, Meson should be able to work out the correct thread implementation + to use. This option forces POSIX threads to be used even if the platform + provides another threading API (for example, on Windows). + +`-Dbsymbolic_functions=false` and `-Dbsymbolic_functions=true` +: By default, GLib uses the `-Bsymbolic-functions` linker flag to avoid + intra-library PLT jumps. A side-effect of this is that it is no longer + possible to override internal uses of GLib functions with `LD_PRELOAD`. + Therefore, it may make sense to turn this feature off in some + situations. The `-Dbsymbolic_functions=false` option allows to do that. + +`-Ddocumentation=false` and `-Ddocumentation=true` +: By default, GLib will not build documentation for the library and tools. This + option can be used to enable building the documentation. + +`-Dman-pages=disabled` and `-Dman-pages=enabled` +: By default, GLib will detect whether `rst2man` and the necessary DocBook + stylesheets are installed. If they are, then it will use them to build + the included man pages from the reStructuredText sources. These options can be + used to explicitly control whether man pages should be built and used. + +`-Dxattr=false` and `-Dxattr=true` +: By default, GLib will detect whether the `getxattr()` family of functions is + available. If it is, then extended attribute support will be included in + GIO. These options can be used to explicitly control whether extended + attribute support should be included or not. `getxattr()` and friends can be + provided by glibc or by the standalone libattr library. + +`-Dselinux=auto`, `-Dselinux=enabled` or `-Dselinux=disabled` +: By default, GLib will detect if libselinux is available and include SELinux + support in GIO if it is. These options can be used to explicitly control + whether SELinux support should be included. + +`-Ddtrace=false` and `-Ddtrace=true` +: By default, GLib will detect if DTrace support is available, and use it. + These options can be used to explicitly control whether DTrace support is + compiled into GLib. + +`-Dsystemtap=false` and `-Dsystemtap=true` +: This option requires DTrace support. If it is available, then GLib will also + check for the presence of SystemTap. + +`-Db_coverage=true` and `-Db_coverage=false` +: Enable the generation of coverage reports for the GLib tests. This requires + the lcov frontend to gcov from the Linux Test Project. To generate a + coverage report, use `ninja coverage-html`. The report is placed in the + `meson-logs` directory. diff --git a/docs/reference/glib/building.xml b/docs/reference/glib/building.xml deleted file mode 100644 index edfdfbe..0000000 --- a/docs/reference/glib/building.xml +++ /dev/null @@ -1,339 +0,0 @@ - - - - - Compiling the GLib package - 3 - GLib Library - - - - Compiling the GLib Package - How to compile GLib itself - - - - Building the Library on UNIX - - On UNIX, GLib uses the standard Meson build - system. The normal sequence for compiling and installing the GLib library - is thus: - - - meson setup _build - meson compile -C _build - meson install -C _build - - - On FreeBSD: - - env CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib -Wl,--disable-new-dtags" meson setup -Dxattr=false -Dinstalled_tests=true -Db_lundef=false _build - meson compile -C _build - - - - - The standard options provided by Meson may be - passed to the meson command. Please see the - Meson documentation or run - meson configure --help for information about - the standard options. - - - GLib is compiled with - strict aliasing - disabled. It is strongly recommended that this is not re-enabled by - overriding the compiler flags, as GLib has not been tested with strict - aliasing and cannot be guaranteed to work. - - - The GTK documentation contains - further details - about the build process and ways to influence it. - - - - Dependencies - - Before you can compile the GLib library, you need to have - various other tools and libraries installed on your system. - If you are building from a release archive, you will need - a compliant C toolchain, - Meson, and pkg-config; - the requirements are the same when building from a Git repository clone - of GLib. - - - - - pkg-config - is a tool for tracking the compilation flags needed for - libraries that are used by the GLib library. (For each - library, a small .pc text file is - installed in a standard location that contains the compilation - flags needed for that library along with version number - information). - - - - - A UNIX build of GLib requires that the system implements at - least the original 1990 version of POSIX. Beyond this, it - depends on a number of other libraries. - - - - - The GNU - libiconv library is needed to build GLib if your - system doesn't have the iconv() - function for doing conversion between character - encodings. Most modern systems should have - iconv(), however many older systems lack - an iconv() implementation. On such systems, - you must install the libiconv library. This can be found at: - http://www.gnu.org/software/libiconv. - - - If your system has an iconv() implementation but - you want to use libiconv instead, make sure it is installed to the - default compiler header/library search path (for instance, in - /usr/local/). The iconv.h - that libiconv installs hides the system iconv. Meson then detects - this, recognizes that the system iconv is unusable and the external - one is mandatory, and automatically forces it to be used. - - - If you are using the native iconv implementation on Solaris - instead of libiconv, you'll need to make sure that you have - the converters between locale encodings and UTF-8 installed. - At a minimum you'll need the SUNWuiu8 package. You probably - should also install the SUNWciu8, SUNWhiu8, SUNWjiu8, and - SUNWkiu8 packages. - - - The native iconv on Compaq Tru64 doesn't contain support for - UTF-8, so you'll need to use GNU libiconv instead. (When - using GNU libiconv for GLib, you'll need to use GNU libiconv - for GNU gettext as well.) This probably applies to related - operating systems as well. - - - - - Python 3.5 or newer is required. Your system Python must - conform to PEP 394 - - For FreeBSD, this means that the - lang/python3 port must be installed. - - - - - The libintl library from the GNU gettext - package is needed if your system doesn't have the - gettext() functionality for handling - message translation databases. - - - - - A thread implementation is needed. The thread support in GLib - can be based upon POSIX threads or win32 threads. - - - - - GRegex uses the PCRE library - for regular expression matching. The system version of PCRE is used, - unless not available (which is the case on Android), in which case a - fallback subproject is used. - - - - - The optional extended attribute support in GIO requires the - getxattr() family of functions that may be - provided by the C library or by the standalone libattr library. To - build GLib without extended attribute support, use the - option. - - - - - The optional SELinux support in GIO requires libselinux. - To build GLib without SELinux support, use the - option. - - - - - The optional support for DTrace requires the - sys/sdt.h header, which is provided - by SystemTap on Linux. To build GLib without DTrace, use - the option. - - - - - The optional support for - SystemTap - can be disabled with the - option. Additionally, you can control the location - where GLib installs the SystemTap probes, using the - option. - - - - - - - Extra Configuration Options - - - In addition to the normal options, these additional ones are supported - when configuring the GLib library: - - - - <option>--buildtype</option> - - - This is a standard Meson option which - specifies how much debugging and optimization to enable. If the build - type is debug, - G_ENABLE_DEBUG will be defined and GLib will be built - with additional debug code enabled. You can override this behavior using - . - - - - - <option>-Dforce_posix_threads=true</option> - - - Normally, Meson should be able to work out - the correct thread implementation to use. This option forces POSIX - threads to be used even if the platform provides another threading API - (for example, on Windows). - - - - - <option>-Dbsymbolic_functions=false</option> and - <option>-Dbsymbolic_functions=true</option> - - - By default, GLib uses the - linker flag to avoid intra-library PLT jumps. A side-effect - of this is that it is no longer possible to override - internal uses of GLib functions with - LD_PRELOAD. Therefore, it may make - sense to turn this feature off in some situations. - The option allows - to do that. - - - - - <option>-Dgtk_doc=false</option> and - <option>-Dgtk_doc=true</option> - - - By default, GLib will detect whether the - gtk-doc package is installed. - If it is, then it will use it to extract and build the - documentation for the GLib library. These options - can be used to explicitly control whether - gtk-doc should be - used or not. If it is not used, the distributed, - pre-generated HTML files will be installed instead of - building them on your machine. - - - - - <option>-Dman=false</option> and - <option>-Dman=true</option> - - - By default, GLib will detect whether xsltproc - and the necessary DocBook stylesheets are installed. - If they are, then it will use them to rebuild the included - man pages from the XML sources. These options can be used - to explicitly control whether man pages should be rebuilt - used or not. The distribution includes pre-generated man - pages. - - - - - <option>-Dxattr=false</option> and - <option>-Dxattr=true</option> - - - By default, GLib will detect whether the - getxattr() - family of functions is available. If it is, then extended - attribute support will be included in GIO. These options can - be used to explicitly control whether extended attribute - support should be included or not. getxattr() - and friends can be provided by glibc or by the standalone - libattr library. - - - - - <option>-Dselinux=auto</option>, - <option>-Dselinux=enabled</option> or - <option>-Dselinux=disabled</option> - - - By default, GLib will detect if libselinux is available and - include SELinux support in GIO if it is. These options can be - used to explicitly control whether SELinux support should - be included. - - - - - <option>-Ddtrace=false</option> and - <option>-Ddtrace=true</option> - - - By default, GLib will detect if DTrace support is available, and use it. - These options can be used to explicitly control whether DTrace support - is compiled into GLib. - - - - - <option>-Dsystemtap=false</option> and - <option>-Dsystemtap=true</option> - - - This option requires DTrace support. If it is available, then - GLib will also check for the presence of SystemTap. - - - - - <option>-Db_coverage=true</option> and - <option>-Db_coverage=false</option> - - - Enable the generation of coverage reports for the GLib tests. - This requires the lcov frontend to gcov from the - Linux Test Project. - To generate a coverage report, use - ninja coverage-html. The report is placed in the - meson-logs directory. - - - - - diff --git a/docs/reference/glib/changes.xml b/docs/reference/glib/changes.xml deleted file mode 100644 index 9b4aa74..0000000 --- a/docs/reference/glib/changes.xml +++ /dev/null @@ -1,174 +0,0 @@ - - - - -Changes to GLib -3 -Changes to GLib - - - -Changes to GLib - -Incompatible changes made between successive versions of GLib - - - - - -Incompatible changes from 2.0 to 2.2 - - - - - -GLib changed the seeding algorithm for the pseudo-random number -generator Mersenne Twister, as used by GRand -and GRandom. This was necessary, because some -seeds would yield very bad pseudo-random streams. Also the -pseudo-random integers generated by -g_rand*_int_range() will have a -slightly better equal distribution with the new version of GLib. - - - -Further information can be found at the website of the Mersenne -Twister random number generator at http://www.math.keio.ac.jp/~matumoto/emt.html. - - - -The original seeding and generation algorithms, as found in GLib -2.0.x, can be used instead of the new ones by setting the environment -variable G_RANDOM_VERSION to the value of '2.0'. Use -the GLib-2.0 algorithms only if you have sequences of numbers generated -with Glib-2.0 that you need to reproduce exactly. - - - - - - - - - -Incompatible changes from 1.2 to 2.0 - - - - - -The event loop functionality GMain has extensively -been revised to support multiple separate main loops in separate threads. -All sources (timeouts, idle functions, etc.) are associated with a -GMainContext. - - - -Compatibility functions exist so that most application code dealing with -the main loop will continue to work. However, code that creates new custom -types of sources will require modification. - - - -The main changes here are: - - - - - - Sources are now exposed as GSource *, rather than simply as - numeric ids. - - - - - - New types of sources are created by structure "derivation" from - GSource, so the source_data - parameter to the GSource virtual functions has been - replaced with a GSource *. - - - - - - Sources are first created, then later added to a specific - GMainContext. - - - - - - Dispatching has been modified so both the callback and data are passed - in to the dispatch() virtual function. - - - - - To go along with this change, the vtable for - GIOChannel has changed and - add_watch() has been replaced by - create_watch(). - - - - - -g_list_foreach() and -g_slist_foreach() have been changed so they -are now safe against removal of the current item, not the next item. - - - -It's not recommended to mutate the list in the callback to these -functions in any case. - - - - - -GDate now works in UTF-8, not in the current locale. -If you want to use it with the encoding of the locale, you need to convert -strings using g_locale_to_utf8() first. - - - - - -g_strsplit() has been fixed to: - - - - - include trailing empty tokens, rather than stripping them - - - - - split into a maximum of max_tokens tokens, rather - than max_tokens + 1 - - - - - Code depending on either of these bugs will need to be fixed. - - - - - -Deprecated functions that got removed: -g_set_error_handler(), -g_set_warning_handler(), -g_set_message_handler(), use -g_log_set_handler() instead. - - - - - - - diff --git a/docs/reference/glib/character-set.md b/docs/reference/glib/character-set.md new file mode 100644 index 0000000..f1726bd --- /dev/null +++ b/docs/reference/glib/character-set.md @@ -0,0 +1,91 @@ +Title: Character Set Conversions +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010, 2012, 2014 Matthias Clasen + +# Character Set Conversions + +The [`func@GLib.convert`] family of function wraps the functionality of +iconv(). In addition to pure character set conversions, GLib has functions +to deal with the extra complications of encodings for file names. + +## File Name Encodings + +Historically, UNIX has not had a defined encoding for file names: a file +name is valid as long as it does not have path separators in it ("/"). +However, displaying file names may require conversion: from the character +set in which they were created, to the character set in which the +application operates. Consider the Spanish file name "Presentación.sxi". If +the application which created it uses ISO-8859-1 for its encoding, + +``` +Character: P r e s e n t a c i ó n . s x i +Hex code: 50 72 65 73 65 6e 74 61 63 69 f3 6e 2e 73 78 69 +``` + +However, if the application use UTF-8, the actual file name on disk would +look like this: + +``` +Character: P r e s e n t a c i ó n . s x i +Hex code: 50 72 65 73 65 6e 74 61 63 69 c3 b3 6e 2e 73 78 69 +``` + +Glib uses UTF-8 for its strings, and GUI toolkits like GTK that use GLib do +the same thing. If you get a file name from the file system, for example, +from `readdir()` or from [`method@GLib.Dir.read_name`], and you wish to +display the file name to the user, you will need to convert it into UTF-8. +The opposite case is when the user types the name of a file they wish to +save: the toolkit will give you that string in UTF-8 encoding, and you will +need to convert it to the character set used for file names before you can +create the file with `open()` or `fopen()`. + +By default, GLib assumes that file names on disk are in UTF-8 encoding. This +is a valid assumption for file systems which were created relatively +recently: most applications use UTF-8 encoding for their strings, and that +is also what they use for the file names they create. However, older file +systems may still contain file names created in "older" encodings, such as +ISO-8859-1. In this case, for compatibility reasons, you may want to +instruct GLib to use that particular encoding for file names rather than +UTF-8. You can do this by specifying the encoding for file names in the +`G_FILENAME_ENCODING` environment variable. For example, if your installation +uses ISO-8859-1 for file names, you can put this in your `~/.profile`: + + export G_FILENAME_ENCODING=ISO-8859-1 + +GLib provides the functions [`func@GLib.filename_to_utf8`] and +[`func@GLib.filename_from_utf8`] to perform the necessary conversions. These +functions convert file names from the encoding specified in +`G_FILENAME_ENCODING` to UTF-8 and vice-versa. This diagram illustrates how +these functions are used to convert between UTF-8 and the encoding for file +names in the file system. + +## Conversion between file name encodings + +![](file-name-encodings.png) + +## Checklist for Application Writers + +This section is a practical summary of the detailed things to do to make +sure your applications process file name encodings correctly. + +1. If you get a file name from the file system from a function such as + `readdir()` or `gtk_file_chooser_get_filename()`, you do not need to do + any conversion to pass that file name to functions like `open()`, + `rename()`, or `fopen()` -- those are "raw" file names which the file + system understands. +2. If you need to display a file name, convert it to UTF-8 first by using + [`func@GLib.filename_to_utf8`]. If conversion fails, display a string + like "Unknown file name". Do not convert this string back into the + encoding used for file names if you wish to pass it to the file system; + use the original file name instead. +3. For example, the document window of a word processor could display + "Unknown file name" in its title bar but still let the user save the + file, as it would keep the raw file name internally. This can happen if + the user has not set the `G_FILENAME_ENCODING` environment variable even + though he has files whose names are not encoded in UTF-8. +4. If your user interface lets the user type a file name for saving or + renaming, convert it to the encoding used for file names in the file + system by using [`func@GLib.filename_from_utf8`]. Pass the converted file + name to functions like `fopen()`. If conversion fails, ask the user to + enter a different file name. This can happen if the user types Japanese + characters when `G_FILENAME_ENCODING` is set to ISO-8859-1, for example. diff --git a/docs/reference/glib/checked-math.md b/docs/reference/glib/checked-math.md new file mode 100644 index 0000000..b16a4a2 --- /dev/null +++ b/docs/reference/glib/checked-math.md @@ -0,0 +1,30 @@ +Title: Bounds-checking Integer Arithmetic +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2015 Allison Lortie + +# Bounds-checking Integer Arithmetic + +GLib offers a set of macros for doing additions and multiplications +of unsigned integers, with checks for overflows. + +The helpers all have three arguments. A pointer to the destination +is always the first argument and the operands to the operation are +the other two. + +Following standard GLib convention, the helpers return true in case +of success (ie: no overflow). + +The helpers may be macros, normal functions or inlines. They may be +implemented with inline assembly or compiler intrinsics where +available. + +Since: 2.48 + +The APIs are: + + * [func@GLib.uint_checked_add] + * [func@GLib.uint_checked_mul] + * [func@GLib.uint64_checked_add] + * [func@GLib.uint64_checked_mul] + * [func@GLib.size_checked_add] + * [func@GLib.size_checked_mul] diff --git a/docs/reference/glib/compiling.md b/docs/reference/glib/compiling.md new file mode 100644 index 0000000..38f1517 --- /dev/null +++ b/docs/reference/glib/compiling.md @@ -0,0 +1,71 @@ +Title: Compiling GLib Applications + +# Compiling GLib Applications + +To compile a GLib application, you need to tell the compiler where to find +the GLib header files and libraries. This is done with the +[`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/) +utility. + +The following interactive shell session demonstrates how pkg-config is used +(the actual output on your system may be different): + + $ pkg-config --cflags glib-2.0 + -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include + $ pkg-config --libs glib-2.0 + -L/usr/lib -lm -lglib-2.0 + +See the `pkg-config` website for more information about `pkg-config`. + +If your application uses or GObject features, it must be compiled and linked +with the options returned by the following `pkg-config` invocation: + + $ pkg-config --cflags --libs gobject-2.0 + +If your application uses modules, it must be compiled and linked with the +options returned by one of the following pkg-config invocations: + + $ pkg-config --cflags --libs gmodule-no-export-2.0 + $ pkg-config --cflags --libs gmodule-2.0 + +The difference between the two is that `gmodule-2.0` adds `--export-dynamic` +to the linker flags, which is often not needed. + +The simplest way to compile a program is to use the "backticks" feature of +the shell. If you enclose a command in backticks (not single quotes), then +its output will be substituted into the command line before execution. So to +compile a GLib Hello, World, you would type the following: + + $ cc `pkg-config --cflags glib-2.0` hello.c -o hello `pkg-config --libs glib-2.0` + +Deprecated GLib functions are annotated to make the compiler emit warnings +when they are used (e.g. with GCC, you need to use the +`-Wdeprecated-declarations option`). If these warnings are problematic, they +can be turned off by defining the preprocessor symbol +`GLIB_DISABLE_DEPRECATION_WARNINGS` by using the commandline option +`-DGLIB_DISABLE_DEPRECATION_WARNINGS` + +GLib deprecation annotations are versioned; by defining the macros +`GLIB_VERSION_MIN_REQUIRED` and `GLIB_VERSION_MAX_ALLOWED`, you can specify the +range of GLib versions whose API you want to use. APIs that were deprecated +before or introduced after this range will trigger compiler warnings. + +Since GLib 2.62, the older deprecation mechanism of hiding deprecated +interfaces entirely from the compiler by using the preprocessor symbol +`G_DISABLE_DEPRECATED` has been removed. All deprecations are now handled +using the above mechanism. + +The recommended way of using GLib has always been to only include the +toplevel headers `glib.h`, `glib-object.h`, `gio.h`. Starting with 2.32, GLib +enforces this by generating an error when individual headers are directly +included. + +Still, there are some exceptions; these headers have to be included +separately: + +- `gmodule.h` +- `glib-unix.h` +- `glib/gi18n-lib.h` or `glib/gi18n.h` (see the section on + [Internationalization](i18n.html)) +- `glib/gprintf.h` and `glib/gstdio.h` (we don't want to pull in all of + stdio) diff --git a/docs/reference/glib/compiling.xml b/docs/reference/glib/compiling.xml deleted file mode 100644 index c7a058c..0000000 --- a/docs/reference/glib/compiling.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - -Compiling GLib Applications -3 -GLib Library - - - -Compiling GLib Applications - -How to compile your GLib application - - - - -Compiling GLib Applications on UNIX - - -To compile a GLib application, you need to tell the compiler where to -find the GLib header files and libraries. This is done with the -pkg-config utility. - - -The following interactive shell session demonstrates how -pkg-config is used (the actual output on -your system may be different): - -$ pkg-config --cflags glib-2.0 - -I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include -$ pkg-config --libs glib-2.0 - -L/usr/lib -lm -lglib-2.0 - - - -See the pkg-config website -for more information about pkg-config. - - -If your application uses or GObject -features, it must be compiled and linked with the options returned -by the following pkg-config invocation: - -$ pkg-config --cflags --libs gobject-2.0 - - - -If your application uses modules, it must be compiled and linked -with the options returned by one of the following -pkg-config invocations: - -$ pkg-config --cflags --libs gmodule-no-export-2.0 -$ pkg-config --cflags --libs gmodule-2.0 - -The difference between the two is that gmodule-2.0 adds - to the linker flags, -which is often not needed. - - -The simplest way to compile a program is to use command substitution -feature of a shell. A command written in the format -$(command) gets substituted into the command line -before execution. So to compile a GLib Hello, World, you would type -the following: - -$ cc hello.c $(pkg-config --cflags --libs glib-2.0) -o hello - - - -Note that the name of the file must come before the other options -(such as pkg-config), or else you may get an -error from the linker. - - - -Deprecated GLib functions are annotated to make the compiler -emit warnings when they are used (e.g. with gcc, you need to use -the -Wdeprecated-declarations option). If these warnings are -problematic, they can be turned off by defining the preprocessor -symbol %GLIB_DISABLE_DEPRECATION_WARNINGS by using the commandline -option -DGLIB_DISABLE_DEPRECATION_WARNINGS - - - -GLib deprecation annotations are versioned; by defining the -macros %GLIB_VERSION_MIN_REQUIRED and %GLIB_VERSION_MAX_ALLOWED, -you can specify the range of GLib versions whose API you want -to use. APIs that were deprecated before or introduced after -this range will trigger compiler warnings. - - - -Since GLib 2.62, the older deprecation mechanism of hiding deprecated interfaces -entirely from the compiler by using the preprocessor symbol -G_DISABLE_DEPRECATED has been removed. All deprecations -are now handled using the above mechanism. - - - -The recommended way of using GLib has always been to only include the -toplevel headers glib.h, -glib-object.h, gio.h. -Starting with 2.32, GLib enforces this by generating an error -when individual headers are directly included. - - - -Still, there are some exceptions; these headers have to be included -separately: -gmodule.h, -glib-unix.h, -glib/gi18n-lib.h or -glib/gi18n.h (see -the Internationalization section), -glib/gprintf.h and -glib/gstdio.h -(we don't want to pull in all of stdio). - - - - - diff --git a/docs/reference/glib/conversion-macros.md b/docs/reference/glib/conversion-macros.md new file mode 100644 index 0000000..c27504c --- /dev/null +++ b/docs/reference/glib/conversion-macros.md @@ -0,0 +1,281 @@ +Title: Conversion Macros + +# Conversion Macros + +## Type Conversion + +Many times GLib, GTK, and other libraries allow you to pass "user data" to a +callback, in the form of a void pointer. From time to time you want to pass +an integer instead of a pointer. You could allocate an integer, with +something like: + +```c +int *ip = g_new (int, 1); +*ip = 42; +``` + +But this is inconvenient, and it's annoying to have to free the memory at +some later time. + +Pointers are always at least 32 bits in size (on all platforms GLib intends +to support). Thus you can store at least 32-bit integer values in a pointer +value. Naively, you might try this, but it's incorrect: + +```c +gpointer p; +int i; +p = (void*) 42; +i = (int) p; +``` + +Again, that example was not correct, don't copy it. + +The problem is that on some systems you need to do this: + +```c +gpointer p; +int i; +p = (void*) (long) 42; +i = (int) (long) p; +``` + +The GLib macros `GPOINTER_TO_INT()`, `GINT_TO_POINTER()`, etc. take care to +do the right thing on every platform. + +**Warning**: You may not store pointers in integers. This is not portable in +any way, shape or form. These macros only allow storing integers in +pointers, and only preserve 32 bits of the integer; values outside the range +of a 32-bit integer will be mangled. + + +``GINT_TO_POINTER(value)``, ``GPOINTER_TO_INT(value)`` +: Stuffs an integer into a pointer type, and vice versa. Remember, you may not + store pointers in integers. This is not portable in any way, shape or form. + These macros only allow storing integers in pointers, and only preserve 32 + bits of the integer; values outside the range of a 32-bit integer will be + mangled. + +``GUINT_TO_POINTER(value)``, ``GPOINTER_TO_UINT(value)`` +: Stuffs an unsigned integer into a pointer type, and vice versa. + +``GSIZE_TO_POINTER(value)``, ``GPOINTER_TO_SIZE(value)`` +: Stuffs a `size_t` into a pointer type, and vice versa. + +## Byte Order Conversion + +These macros provide a portable way to determine the host byte order and to +convert values between different byte orders. + +The byte order is the order in which bytes are stored to create larger data +types such as the #gint and #glong values. The host byte order is the byte +order used on the current machine. + +Some processors store the most significant bytes (i.e. the bytes that hold +the largest part of the value) first. These are known as big-endian +processors. Other processors (notably the x86 family) store the most +significant byte last. These are known as little-endian processors. + +Finally, to complicate matters, some other processors store the bytes in a +rather curious order known as PDP-endian. For a 4-byte word, the 3rd most +significant byte is stored first, then the 4th, then the 1st and finally the +2nd. + +Obviously there is a problem when these different processors communicate +with each other, for example over networks or by using binary file formats. +This is where these macros come in. They are typically used to convert +values into a byte order which has been agreed on for use when communicating +between different processors. The Internet uses what is known as 'network +byte order' as the standard byte order (which is in fact the big-endian byte +order). + +Note that the byte order conversion macros may evaluate their arguments +multiple times, thus you should not use them with arguments which have +side-effects. + +`G_BYTE_ORDER` +: The host byte order. This can be either `G_LITTLE_ENDIAN` or `G_BIG_ENDIAN`. + +`G_LITTLE_ENDIAN` +: Specifies the little endian byte order. + +`G_BIG_ENDIAN` +: Specifies the big endian byte order. + +`G_PDP_ENDIAN` +: Specifies the PDP endian byte order. + +### Signed + +`GINT_FROM_BE(value)` +: Converts an `int` value from big-endian to host byte order. + +`GINT_FROM_LE(value)` +: Converts an `int` value from little-endian to host byte order. + +`GINT_TO_BE(value)` +: Converts an `int` value from host byte order to big-endian. + +`GINT_TO_LE(value)` +: Converts an `int` value from host byte order to little-endian. + +`GLONG_FROM_BE(value)` +: Converts a `long` value from big-endian to the host byte order. + +`GLONG_FROM_LE(value)` +: Converts a `long` value from little-endian to host byte order. + +`GLONG_TO_BE(value)` +: Converts a `long` value from host byte order to big-endian. + +`GLONG_TO_LE(value)` +: Converts a `long` value from host byte order to little-endian. + +`GSSIZE_FROM_BE(value)` +: Converts a `ssize_t` value from big-endian to host byte order. + +`GSSIZE_FROM_LE(value)` +: Converts a `ssize_t` value from little-endian to host byte order. + +`GSSIZE_TO_BE(value)` +: Converts a `ssize_t` value from host byte order to big-endian. + +`GSSIZE_TO_LE(value)` +: Converts a `ssize_t` value from host byte order to little-endian. + +`GINT16_FROM_BE(value)` +: Converts an `int16_t` value from big-endian to host byte order. + +`GINT16_FROM_LE(value)` +: Converts an `int16_t` value from little-endian to host byte order. + +`GINT16_TO_BE(value)` +: Converts an `int16_t` value from host byte order to big-endian. + +`GINT16_TO_LE(value)` +: Converts an `int16_t` value from host byte order to little-endian. + +`GINT32_FROM_BE(value)` +: Converts an `int32_t` value from big-endian to host byte order. + +`GINT32_FROM_LE(value)` +: Converts an `int32_t` value from little-endian to host byte order. + +`GINT32_TO_BE(value)` +: Converts an `int32_t` value from host byte order to big-endian. + +`GINT32_TO_LE(value)` +: Converts an `int32_t` value from host byte order to little-endian. + +`GINT64_FROM_BE(value)` +: Converts an `int64_t` value from big-endian to host byte order. + +`GINT64_FROM_LE(value)` +: Converts an `int64_t` value from little-endian to host byte order. + +`GINT64_TO_BE(value)` +: Converts an `int64_t` value from host byte order to big-endian. + +`GINT64_TO_LE(value)` +: Converts an `int64_t` value from host byte order to little-endian. + +### Unsigned + +`GUINT_FROM_BE(value)` +: Converts an `unsigned int` value from big-endian to host byte order. + +`GUINT_FROM_LE(value)` +: Converts an `unsigned int` value from little-endian to host byte order. + +`GUINT_TO_BE(value)` +: Converts an `unsigned int` value from host byte order to big-endian. + +`GUINT_TO_LE(value)` +: Converts an `unsigned int` value from host byte order to little-endian. + +`GULONG_FROM_BE(value)` +: Converts an `unsigned long` value from big-endian to host byte order. + +`GULONG_FROM_LE(value)` +: Converts an `unsigned long` value from little-endian to host byte order. + +`GULONG_TO_BE(value)` +: Converts an `unsigned long` value from host byte order to big-endian. + +`GULONG_TO_LE(value)` +: Converts an `unsigned long` value from host byte order to little-endian. + +`GSIZE_FROM_BE(value)` +: Converts a `size_t` value from big-endian to the host byte order. + +`GSIZE_FROM_LE(value)` +: Converts a `size_t` value from little-endian to host byte order. + +`GSIZE_TO_BE(value)` +: Converts a `size_t` value from host byte order to big-endian. + +`GSIZE_TO_LE(value)` +: Converts a `size_t` value from host byte order to little-endian. + +`GUINT16_FROM_BE(value)` +: Converts an `uint16_t` value from big-endian to host byte order. + +`GUINT16_FROM_LE(value)` +: Converts an `uint16_t` value from little-endian to host byte order. + +`GUINT16_TO_BE(value)` +: Converts an `uint16_t` value from host byte order to big-endian. + +`GUINT16_TO_LE(value)` +: Converts an `uint16_t` value from host byte order to little-endian. + +`GUINT32_FROM_BE(value)` +: Converts an `uint32_t` value from big-endian to host byte order. + +`GUINT32_FROM_LE(value)` +: Converts an `uint32_t` value from little-endian to host byte order. + +`GUINT32_TO_BE(value)` +: Converts an `uint32_t` value from host byte order to big-endian. + +`GUINT32_TO_LE(value)` +: Converts an `uint32_t` value from host byte order to little-endian. + +`GUINT64_FROM_BE(value)` +: Converts an `uint64_t` value from big-endian to host byte order. + +`GUINT64_FROM_LE(value)` +: Converts an `uint64_t` value from little-endian to host byte order. + +`GUINT64_TO_BE(value)` +: Converts an `uint64_t` value from host byte order to big-endian. + +`GUINT64_TO_LE(value)` +: Converts an `uint64_t` value from host byte order to little-endian. + +`GUINT16_SWAP_BE_PDP(value)` +: Converts an `uint16_t` value between big-endian and pdp-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT16_SWAP_LE_BE(value)` +: Converts an `uint16_t` value between little-endian and big-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT16_SWAP_LE_PDP(value)` +: Converts an `uint16_t` value between little-endian and pdp-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT32_SWAP_BE_PDP(value)` +: Converts an `uint32_t` value between big-endian and pdp-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT32_SWAP_LE_BE(value)` +: Converts an `uint32_t` value between little-endian and big-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT32_SWAP_LE_PDP(value)` +: Converts an `uint32_t` value between little-endian and pdp-endian byte order. + The conversion is symmetric so it can be used both ways. + +`GUINT64_SWAP_LE_BE(value)` +: Converts a `uint64_t` value between little-endian and big-endian byte order. + The conversion is symmetric so it can be used both ways. diff --git a/docs/reference/glib/cross-compiling.md b/docs/reference/glib/cross-compiling.md new file mode 100644 index 0000000..4d91caa --- /dev/null +++ b/docs/reference/glib/cross-compiling.md @@ -0,0 +1,88 @@ +Title: Cross-compiling the GLib package + +# Cross-compiling the GLib Package + +## Building the Library for a different architecture + +Cross-compilation is the process of compiling a program or library on a +different architecture or operating system then it will be run upon. GLib is +slightly more difficult to cross-compile than many packages because much of +GLib is about hiding differences between different systems. + +These notes cover things specific to cross-compiling GLib; for general +information about cross-compilation, see the [Meson +documentation](http://mesonbuild.com/Cross-compilation.html). + +GLib tries to detect as much information as possible about the target system +by compiling and linking programs without actually running anything; +however, some information GLib needs is not available this way. This +information needs to be provided to meson via a ‘cross file’. + +As an example of using a cross file, to cross compile for the ‘MingW32’ +Win64 runtime environment on a Linux system, create a file `cross_file.txt` +with the following contents: + +``` +[host_machine] +system = 'windows' +cpu_family = 'x86_64' +cpu = 'x86_64' +endian = 'little' + +[properties] +c_args = [] +c_link_args = [] + +[binaries] +c = 'x86_64-w64-mingw32-gcc' +cpp = 'x86_64-w64-mingw32-g++' +ar = 'x86_64-w64-mingw32-ar' +ld = 'x86_64-w64-mingw32-ld' +objcopy = 'x86_64-w64-mingw32-objcopy' +strip = 'x86_64-w64-mingw32-strip' +pkgconfig = 'x86_64-w64-mingw32-pkg-config' +windres = 'x86_64-w64-mingw32-windres' +``` + +Then execute the following commands: + + meson setup --cross-file cross_file.txt builddir + +The complete list of cross properties follows. Most of these won't need to +be set in most cases. + +## Cross properties + +`have_[function]` +: When meson checks if a function is supported, the test can be overridden by + setting the `have_function` property to `true` or `false`. For example: + + Checking for function "fsync" : YES + + can be overridden by setting + + have_fsync = false + +`growing_stack=[true/false]` +: Whether the stack grows up or down. Most places will want `false`. A few + architectures, such as PA-RISC need `true`. + +`have_strlcpy=[true/false]` +: Whether you have `strlcpy()` that matches OpenBSD. Defaults to `false`, + which is safe, since GLib uses a built-in version in that case. + +`va_val_copy=[true/false]` +: Whether `va_list` can be copied as a pointer. If set to `false`, then + `memcopy()` will be used. Only matters if you don't have `va_copy()` or + `__va_copy()`. (So, doesn't matter for GCC.) Defaults to `true` which is + slightly more common than `false`. + +`have_c99_vsnprintf=[true/false]` +: Whether you have a `vsnprintf()` with C99 semantics. (C99 semantics means + returning the number of bytes that would have been written had the output + buffer had enough space.) Defaults to `false`. + +`have_c99_snprintf=[true/false]` +: Whether you have a `snprintf()` with C99 semantics. (C99 semantics means + returning the number of bytes that would have been written had the output + buffer had enough space.) Defaults to `false`. diff --git a/docs/reference/glib/cross.xml b/docs/reference/glib/cross.xml deleted file mode 100644 index c90b30b..0000000 --- a/docs/reference/glib/cross.xml +++ /dev/null @@ -1,147 +0,0 @@ - - - - -Cross-compiling the GLib package -3 -GLib Library - - - -Cross-compiling the GLib Package - -How to cross-compile GLib - - - - - Building the Library for a different architecture - - Cross-compilation is the process of compiling a program or - library on a different architecture or operating system then - it will be run upon. GLib is slightly more difficult to - cross-compile than many packages because much of GLib is - about hiding differences between different systems. - - - These notes cover things specific to cross-compiling GLib; - for general information about cross-compilation, see the - meson - info pages. - - - GLib tries to detect as much information as possible about - the target system by compiling and linking programs without - actually running anything; however, some information GLib - needs is not available this way. This information needs - to be provided to meson via a ‘cross file’. - - - As an example of using a cross file, to cross compile for - the ‘MingW32’ Win64 runtime environment on a Linux system, - create a file cross_file.txt with the following - contents: - - -[host_machine] -system = 'windows' -cpu_family = 'x86_64' -cpu = 'x86_64' -endian = 'little' - -[properties] -c_args = [] -c_link_args = [] - -[binaries] -c = 'x86_64-w64-mingw32-gcc' -cpp = 'x86_64-w64-mingw32-g++' -ar = 'x86_64-w64-mingw32-ar' -ld = 'x86_64-w64-mingw32-ld' -objcopy = 'x86_64-w64-mingw32-objcopy' -strip = 'x86_64-w64-mingw32-strip' -pkgconfig = 'x86_64-w64-mingw32-pkg-config' -windres = 'x86_64-w64-mingw32-windres' - - - Then execute the following commands: - - -meson --cross-file cross_file.txt builddir - - - The complete list of cross properties follows. Most - of these won't need to be set in most cases. - - - - Cross properties - - have_[function] - - - When meson checks if a function is supported, the test can be - overridden by setting the - have_function property - to true or false. - For example Checking for function "fsync" : YES - can be overridden by setting have_fsync = false - - - - growing_stack=[true/false] - - - Whether the stack grows up or down. Most places will want - false. - A few architectures, such as PA-RISC need true. - - - - have_strlcpy=[true/false] - - - Whether you have strlcpy() that matches - OpenBSD. Defaults to false, which is safe, - since GLib uses a built-in version in that case. - - - - va_val_copy=[true/false] - - - Whether va_list can be copied as a pointer. If set - to false, then memcopy() - will be used. Only matters if you don't have - va_copy() or __va_copy(). - (So, doesn't matter for GCC.) - Defaults to true which is slightly more common - than false. - - - - have_c99_vsnprintf=[true/false] - - - Whether you have a vsnprintf() with C99 - semantics. (C99 semantics means returning the number of bytes - that would have been written had the output buffer had enough - space.) Defaults to false. - - - - have_c99_snprintf=[true/false] - - - Whether you have a snprintf() with C99 - semantics. (C99 semantics means returning the number of bytes - that would have been written had the output buffer had enough - space.) Defaults to false. - - - - - - diff --git a/docs/reference/glib/data-structures.md b/docs/reference/glib/data-structures.md new file mode 100644 index 0000000..c31002a --- /dev/null +++ b/docs/reference/glib/data-structures.md @@ -0,0 +1,517 @@ +Title: Data Structures +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Allison Lortie +SPDX-FileCopyrightText: 2011 Collabora, Ltd. +SPDX-FileCopyrightText: 2012 Olivier Sessink +SPDX-FileCopyrightText: 2010, 2011, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2018 Sébastien Wilmet +SPDX-FileCopyrightText: 2018 Emmanuele Bassi +SPDX-FileCopyrightText: 2019 Emmanuel Fleury +SPDX-FileCopyrightText: 2017, 2018, 2019 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2020 Endless OS Foundation, LLC + +# Data Structures + +GLib includes a number of basic data sructures, such as arrays, linked lists, hash tables, +queues, trees, etc. + +## Arrays + +GLib arrays ([struct@GLib.Array]) are similar to standard C arrays, except that they grow +automatically as elements are added. + +Array elements can be of any size (though all elements of one array are the same size), +and the array can be automatically cleared to '0's and zero-terminated. + +To create a new array use [func@GLib.Array.new]. + +To add elements to an array with a cost of O(n) at worst, use +[func@GLib.array_append_val], +[func@GLib.Array.append_vals], +[func@GLib.array_prepend_val], +[func@GLib.Array.prepend_vals], +[func@GLib.array_insert_val] and +[func@GLib.Array.insert_vals]. + +To access an element of an array in O(1) (to read it or to write it), +use [func@GLib.array_index]. + +To set the size of an array, use [func@GLib.Array.set_size]. + +To free an array, use [func@GLib.Array.unref] or [func@GLib.Array.free]. + +All the sort functions are internally calling a quick-sort (or similar) +function with an average cost of O(n log(n)) and a worst case cost of O(n^2). + +Here is an example that stores integers in a [struct@GLib.Array]: + +```c +GArray *array; +int i; + +// We create a new array to store int values. +// We don't want it zero-terminated or cleared to 0's. +array = g_array_new (FALSE, FALSE, sizeof (int)); + +for (i = 0; i < 10000; i++) + { + g_array_append_val (array, i); + } + +for (i = 0; i < 10000; i++) + { + if (g_array_index (array, int, i) != i) + g_print ("ERROR: got %d instead of %d\n", + g_array_index (array, int, i), i); + } + +g_array_free (array, TRUE); +``` + +## Pointer Arrays + +Pointer Arrays ([struct@GLib.PtrArray]) are similar to Arrays but are used +only for storing pointers. + +If you remove elements from the array, elements at the end of the +array are moved into the space previously occupied by the removed +element. This means that you should not rely on the index of particular +elements remaining the same. You should also be careful when deleting +elements while iterating over the array. + +To create a pointer array, use [func@GLib.PtrArray.new]. + +To add elements to a pointer array, use [func@GLib.PtrArray.add]. + +To remove elements from a pointer array, use +[func@GLib.PtrArray.remove], +[func@GLib.PtrArray.remove_index] or +[func@GLib.PtrArray.remove_index_fast]. + +To access an element of a pointer array, use [func@GLib.ptr_array_index]. + +To set the size of a pointer array, use [func@GLib.PtrArray.set_size]. + +To free a pointer array, use [func@GLib.PtrArray.unref] or [func@GLib.PtrArray.free]. + +An example using a [struct@GLib.PtrArray]: + +```c +GPtrArray *array; +char *string1 = "one"; +char *string2 = "two"; +char *string3 = "three"; + +array = g_ptr_array_new (); +g_ptr_array_add (array, (gpointer) string1); +g_ptr_array_add (array, (gpointer) string2); +g_ptr_array_add (array, (gpointer) string3); + +if (g_ptr_array_index (array, 0) != (gpointer) string1) + g_print ("ERROR: got %p instead of %p\n", + g_ptr_array_index (array, 0), string1); + +g_ptr_array_free (array, TRUE); +``` + +## Byte Arrays + +[struct@GLib.ByteArray] is a mutable array of bytes based on [struct@GLib.Array], +to provide arrays of bytes which grow automatically as elements are added. + +To create a new `GByteArray` use [func@GLib.ByteArray.new]. + +To add elements to a `GByteArray`, use +[func@GLib.ByteArray.append] and [func@GLib.ByteArray.prepend]. + +To set the size of a `GByteArray`, use [func@GLib.ByteArray.set_size]. + +To free a `GByteArray`, use [func@GLib.ByteArray.unref] or [func@GLib.ByteArray.free]. + +An example for using a `GByteArray`: + +```c +GByteArray *array; +int i; + +array = g_byte_array_new (); +for (i = 0; i < 10000; i++) + { + g_byte_array_append (array, (guint8*) "abcd", 4); + } + +for (i = 0; i < 10000; i++) + { + g_assert (array->data[4*i] == 'a'); + g_assert (array->data[4*i+1] == 'b'); + g_assert (array->data[4*i+2] == 'c'); + g_assert (array->data[4*i+3] == 'd'); + } + +g_byte_array_free (array, TRUE); +``` + +See [struct@GLib.Bytes] if you are interested in an immutable object representing a +sequence of bytes. + +## Singly-linked Lists + +The [struct@GLib.SList] structure and its associated functions provide a standard +singly-linked list data structure. The benefit of this data structure is to provide +insertion/deletion operations in O(1) complexity where access/search operations are +in O(n). The benefit of `GSList` over [struct@GLib.List] (doubly-linked list) is that +they are lighter in space as they only need to retain one pointer but it double the +cost of the worst case access/search operations. + +Each element in the list contains a piece of data, together with a pointer which links +to the next element in the list. Using this pointer it is possible to move through the +list in one direction only (unlike the [doubly-linked lists](#doubly-linked-lists), +which allow movement in both directions). + +The data contained in each element can be either integer values, by +using one of the [Type Conversion Macros](conversion-macros.html), +or simply pointers to any type of data. + +Note that most of the #GSList functions expect to be passed a pointer to the first element +in the list. The functions which insert elements return the new start of the list, which +may have changed. + +There is no function to create a `GSList`. `NULL` is considered to be the empty list so you +simply set a `GSList*` to `NULL`. + +To add elements, use [func@GLib.SList.append], [func@GLib.SList.prepend], +[func@GLib.SList.insert] and [func@GLib.SList.insert_sorted]. + +To remove elements, use [func@GLib.SList.remove]. + +To find elements in the list use [func@GLib.SList.last], [func@GLib.slist_next], +[func@GLib.SList.nth], [func@GLib.SList.nth_data], [func@GLib.SList.find] and +[func@GLib.SList.find_custom]. + +To find the index of an element use [func@GLib.SList.position] and [func@GLib.SList.index]. + +To call a function for each element in the list use [func@GLib.SList.foreach]. + +To free the entire list, use [func@GLib.SList.free]. + +## Doubly-linked Lists + +The [struct@GLib.List] structure and its associated functions provide a standard +doubly-linked list data structure. The benefit of this data-structure is to provide +insertion/deletion operations in O(1) complexity where access/search operations are in O(n). +The benefit of `GList` over [struct@GLib.SList] (singly-linked list) is that the worst case +on access/search operations is divided by two which comes at a cost in space as we need +to retain two pointers in place of one. + +Each element in the list contains a piece of data, together with pointers which link to the +previous and next elements in the list. Using these pointers it is possible to move through +the list in both directions (unlike the singly-linked [struct@GLib.SList], +which only allows movement through the list in the forward direction). + +The doubly-linked list does not keep track of the number of items and does not keep track of +both the start and end of the list. If you want fast access to both the start and the end of +the list, and/or the number of items in the list, use a [struct@GLib.Queue] instead. + +The data contained in each element can be either integer values, by using one of the +[Type Conversion Macros](conversion-macros.html), or simply pointers to any type of data. + +Note that most of the `GList` functions expect to be passed a pointer to the first element in the list. +The functions which insert elements return the new start of the list, which may have changed. + +There is no function to create a `GList`. `NULL` is considered to be a valid, empty list so you simply +set a `GList*` to `NULL` to initialize it. + +To add elements, use [func@GLib.List.append], [func@GLib.List.prepend], +[func@GLib.List.insert] and [func@GLib.List.insert_sorted]. + +To visit all elements in the list, use a loop over the list: + +```c +GList *l; +for (l = list; l != NULL; l = l->next) + { + // do something with l->data + } +``` + +To call a function for each element in the list, use [func@GLib.List.foreach]. + +To loop over the list and modify it (e.g. remove a certain element) a while loop is more appropriate, +for example: + +```c +GList *l = list; +while (l != NULL) + { + GList *next = l->next; + if (should_be_removed (l)) + { + // possibly free l->data + list = g_list_delete_link (list, l); + } + l = next; + } +``` + +To remove elements, use [func@GLib.List.remove]. + +To navigate in a list, use [func@GLib.List.first], [func@GLib.List.last], +[func@GLib.list_next], [func@GLib.list_previous]. + +To find elements in the list use [func@GLib.List.nth], [func@GLib.List.nth_data], +[func@GLib.List.find] and [func@GLib.List.find_custom]. + +To find the index of an element use [func@GLib.List.position] and [func@GLib.List.index]. + +To free the entire list, use [func@GLib.List.free] or [func@GLib.List.free_full]. + + +## Hash Tables + +A [struct@GLib.HashTable] provides associations between keys and values which is +optimized so that given a key, the associated value can be found, inserted or removed +in amortized O(1). All operations going through each element take O(n) time (list all +keys/values, table resize, etc.). + +Note that neither keys nor values are copied when inserted into the `GHashTable`, +so they must exist for the lifetime of the `GHashTable`. This means that the use +of static strings is OK, but temporary strings (i.e. those created in buffers and those +returned by GTK widgets) should be copied with [func@GLib.strdup] before being inserted. + +If keys or values are dynamically allocated, you must be careful to ensure that they are freed +when they are removed from the `GHashTable`, and also when they are overwritten by +new insertions into the `GHashTable`. It is also not advisable to mix static strings +and dynamically-allocated strings in a [struct@GLib.HashTable], because it then becomes difficult +to determine whether the string should be freed. + +To create a `GHashTable`, use [func@GLib.HashTable.new]. + +To insert a key and value into a `GHashTable`, use [func@GLib.HashTable.insert]. + +To look up a value corresponding to a given key, use [func@GLib.HashTable.lookup] or +[func@GLib.HashTable.lookup_extended]. + +[func@GLib.HashTable.lookup_extended] can also be used to simply check if a key is present +in the hash table. + +To remove a key and value, use [func@GLib.HashTable.remove]. + +To call a function for each key and value pair use [func@GLib.HashTable.foreach] or use +an iterator to iterate over the key/value pairs in the hash table, see [struct@GLib.HashTableIter]. +The iteration order of a hash table is not defined, and you must not rely on iterating over +keys/values in the same order as they were inserted. + +To destroy a `GHashTable` use [func@GLib.HashTable.unref] or [func@GLib.HashTable.destroy]. + +A common use-case for hash tables is to store information about a set of keys, without associating any +particular value with each key. `GHashTable` optimizes one way of doing so: If you store only +key-value pairs where key == value, then `GHashTable` does not allocate memory to store the values, +which can be a considerable space saving, if your set is large. The functions [func@GLib.HashTable.add] +and [func@GLib.HashTable.contains] are designed to be used when using `GHashTable` this way. + +`GHashTable` is not designed to be statically initialised with keys and values known at compile time. +To build a static hash table, use a tool such as [gperf](https://www.gnu.org/software/gperf/). + +## Double-ended Queues + +The [struct@GLib.Queue] structure and its associated functions provide a standard queue data structure. +Internally, `GQueue` uses the same data structure as [struct@GLib.List] to store elements with the same +complexity over insertion/deletion (O(1)) and access/search (O(n)) operations. + +The data contained in each element can be either integer values, by using one of the +[Type Conversion Macros](conversion-macros.html), or simply pointers to any type of data. + +As with all other GLib data structures, `GQueue` is not thread-safe. For a thread-safe queue, use +[struct@GLib.AsyncQueue]. + +To create a new GQueue, use [func@GLib.Queue.new]. + +To initialize a statically-allocated GQueue, use `G_QUEUE_INIT` or [method@GLib.Queue.init]. + +To add elements, use [method@GLib.Queue.push_head], [method@GLib.Queue.push_head_link], +[method@GLib.Queue.push_tail] and [method@GLib.Queue.push_tail_link]. + +To remove elements, use [method@GLib.Queue.pop_head] and [method@GLib.Queue.pop_tail]. + +To free the entire queue, use [method@GLib.Queue.free]. + +## Asynchronous Queues + +Often you need to communicate between different threads. In general it's safer not to do this +by shared memory, but by explicit message passing. These messages only make sense asynchronously +for multi-threaded applications though, as a synchronous operation could as well be done in the +same thread. + +Asynchronous queues are an exception from most other GLib data structures, as they can be used +simultaneously from multiple threads without explicit locking and they bring their own builtin +reference counting. This is because the nature of an asynchronous queue is that it will always +be used by at least 2 concurrent threads. + +For using an asynchronous queue you first have to create one with [func@GLib.AsyncQueue.new]. +[struct@GLib.AsyncQueue] structs are reference counted, use [method@GLib.AsyncQueue.ref] and +[method@GLib.AsyncQueue.unref] to manage your references. + +A thread which wants to send a message to that queue simply calls [method@GLib.AsyncQueue.push] +to push the message to the queue. + +A thread which is expecting messages from an asynchronous queue simply calls [method@GLib.AsyncQueue.pop] +for that queue. If no message is available in the queue at that point, the thread is now put to sleep +until a message arrives. The message will be removed from the queue and returned. The functions +[method@GLib.AsyncQueue.try_pop] and [method@GLib.AsyncQueue.timeout_pop] can be used to only check +for the presence of messages or to only wait a certain time for messages respectively. + +For almost every function there exist two variants, one that locks the queue and one that doesn't. +That way you can hold the queue lock (acquire it with [method@GLib.AsyncQueue.lock] and release it +with [method@GLib.AsyncQueue.unlock] over multiple queue accessing instructions. This can be necessary +to ensure the integrity of the queue, but should only be used when really necessary, as it can make your +life harder if used unwisely. Normally you should only use the locking function variants (those without +the `_unlocked` suffix). + +In many cases, it may be more convenient to use [struct@GLib.ThreadPool] when you need to distribute work +to a set of worker threads instead of using `GAsyncQueue` manually. `GThreadPool` uses a `GAsyncQueue` +internally. + +## Binary Trees + +The [struct@GLib.Tree] structure and its associated functions provide a sorted collection of key/value +pairs optimized for searching and traversing in order. This means that most of the operations (access, +search, insertion, deletion, …) on `GTree` are O(log(n)) in average and O(n) in worst case for time +complexity. But, note that maintaining a balanced sorted `GTree` of n elements is done in time O(n log(n)). + +To create a new `GTree` use [ctor@GLib.Tree.new]. + +To insert a key/value pair into a `GTree` use [method@GLib.Tree.insert] (O(n log(n))). + +To remove a key/value pair use [method@GLib.Tree.remove] (O(n log(n))). + +To look up the value corresponding to a given key, use [method@GLib.Tree.lookup] and +[method@GLib.Tree.lookup_extended]. + +To find out the number of nodes in a `GTree`, use [method@GLib.Tree.nnodes]. +To get the height of a `GTree`, use [method@GLib.Tree.height]. + +To traverse a `GTree`, calling a function for each node visited in +the traversal, use [method@GLib.Tree.foreach]. + +To destroy a `GTree`, use [method@GLib.Tree.destroy]. + +## N-ary Trees + +The [struct@GLib.Node] struct and its associated functions provide a N-ary tree +data structure, where nodes in the tree can contain arbitrary data. + +To create a new tree use [func@GLib.Node.new]. + +To insert a node into a tree use [method@GLib.Node.insert], [method@GLib.Node.insert_before], +[func@GLib.node_append] and [method@GLib.Node.prepend], + +To create a new node and insert it into a tree use [func@GLib.node_insert_data], +[func@GLib.node_insert_data_after], [func@GLib.node_insert_data_before], +[func@GLib.node_append_data] and [func@GLib.node_prepend_data]. + +To reverse the children of a node use [method@GLib.Node.reverse_children]. + +To find a node use [method@GLib.Node.get_root], [method@GLib.Node.find], [method@GLib.Node.find_child], +[method@GLib.Node.child_index], [method@GLib.Node.child_position], [func@GLib.node_first_child], +[method@GLib.Node.last_child], [method@GLib.Node.nth_child], [method@GLib.Node.first_sibling], +[func@GLib.node_prev_sibling], [func@GLib.node_next_sibling] or [method@GLib.Node.last_sibling]. + +To get information about a node or tree use `G_NODE_IS_LEAF()`, +`G_NODE_IS_ROOT()`, [method@GLib.Node.depth], [method@GLib.Node.n_nodes], +[method@GLib.Node.n_children], [method@GLib.Node.is_ancestor] or [method@GLib.Node.max_height]. + +To traverse a tree, calling a function for each node visited in the traversal, use +[method@GLib.Node.traverse] or [method@GLib.Node.children_foreach]. + +To remove a node or subtree from a tree use [method@GLib.Node.unlink] or [method@GLib.Node.destroy]. + +## Scalable Lists + +The [struct@GLib.Sequence] data structure has the API of a list, but is implemented internally with +a balanced binary tree. This means that most of the operations (access, search, insertion, deletion, +...) on `GSequence` are O(log(n)) in average and O(n) in worst case for time complexity. But, note that +maintaining a balanced sorted list of n elements is done in time O(n log(n)). The data contained +in each element can be either integer values, by using of the +[Type Conversion Macros](conversion-macros.md), or simply pointers to any type of data. + +A `GSequence` is accessed through "iterators", represented by a [struct@GLib.SequenceIter]. An iterator +represents a position between two elements of the sequence. For example, the "begin" iterator represents +the gap immediately before the first element of the sequence, and the "end" iterator represents the gap +immediately after the last element. In an empty sequence, the begin and end iterators are the same. + +Some methods on `GSequence` operate on ranges of items. For example [func@GLib.Sequence.foreach_range] +will call a user-specified function on each element with the given range. The range is delimited by the +gaps represented by the passed-in iterators, so if you pass in the begin and end iterators, the range in +question is the entire sequence. + +The function [func@GLib.Sequence.get] is used with an iterator to access the element immediately following +the gap that the iterator represents. The iterator is said to "point" to that element. + +Iterators are stable across most operations on a `GSequence`. For example an iterator pointing to some element +of a sequence will continue to point to that element even after the sequence is sorted. Even moving an element +to another sequence using for example [func@GLib.Sequence.move_range] will not invalidate the iterators pointing +to it. The only operation that will invalidate an iterator is when the element it points to is removed from +any sequence. + +To sort the data, either use [method@GLib.Sequence.insert_sorted] or [method@GLib.Sequence.insert_sorted_iter] +to add data to the `GSequence` or, if you want to add a large amount of data, it is more efficient to call +[method@GLib.Sequence.sort] or [method@GLib.Sequence.sort_iter] after doing unsorted insertions. + +## Reference-counted strings + +Reference-counted strings are normal C strings that have been augmented with a reference count to manage +their resources. You allocate a new reference counted string and acquire and release references as needed, +instead of copying the string among callers; when the last reference on the string is released, the resources +allocated for it are freed. + +Typically, reference-counted strings can be used when parsing data from files and storing them into data +structures that are passed to various callers: + +```c +PersonDetails * +person_details_from_data (const char *data) +{ + // Use g_autoptr() to simplify error cases + g_autoptr(GRefString) full_name = NULL; + g_autoptr(GRefString) address = NULL; + g_autoptr(GRefString) city = NULL; + g_autoptr(GRefString) state = NULL; + g_autoptr(GRefString) zip_code = NULL; + + // parse_person_details() is defined elsewhere; returns refcounted strings + if (!parse_person_details (data, &full_name, &address, &city, &state, &zip_code)) + return NULL; + + if (!validate_zip_code (zip_code)) + return NULL; + + // add_address_to_cache() and add_full_name_to_cache() are defined + // elsewhere; they add strings to various caches, using refcounted + // strings to avoid copying data over and over again + add_address_to_cache (address, city, state, zip_code); + add_full_name_to_cache (full_name); + + // person_details_new() is defined elsewhere; it takes a reference + // on each string + PersonDetails *res = person_details_new (full_name, + address, + city, + state, + zip_code); + + return res; +} +``` + +In the example above, we have multiple functions taking the same strings for different uses; with typical +C strings, we'd have to copy the strings every time the life time rules of the data differ from the +life-time of the string parsed from the original buffer. With reference counted strings, each caller can +ake a reference on the data, and keep it as long as it needs to own the string. + +Reference-counted strings can also be "interned" inside a global table owned by GLib; while an interned +string has at least a reference, creating a new interned reference-counted string with the same contents +will return a reference to the existing string instead of creating a new reference-counted string instance. +Once the string loses its last reference, it will be automatically removed from the global interned strings +table. + +Reference-counted strings were added to GLib in 2.58. diff --git a/docs/reference/glib/datalist-and-dataset.md b/docs/reference/glib/datalist-and-dataset.md new file mode 100644 index 0000000..3a17c9b --- /dev/null +++ b/docs/reference/glib/datalist-and-dataset.md @@ -0,0 +1,78 @@ +Title: Keyed Data Lists and Datasets +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 1999 Owen Taylor +SPDX-FileCopyrightText: 2000 Red Hat, Inc. +SPDX-FileCopyrightText: 2005 Tim Janik + +## Keyed Data Lists + +Keyed data lists provide lists of arbitrary data elements which can +be accessed either with a string or with a [type@GLib.Quark] corresponding to +the string. + +The [type@GLib.Quark] methods are quicker, since the strings have to be +converted to [type@GLib.Quark]s anyway. + +Data lists are used for associating arbitrary data with +[class@GObject.Object]s, using [method@GObject.Object.set_data] and related +functions. The data is stored inside opaque [type@GLib.Data] elements. + +To create a datalist, use [func@GLib.datalist_init]. + +To add data elements to a datalist use [func@GLib.datalist_id_set_data], +[func@GLib.datalist_id_set_data_full], [func@GLib.datalist_set_data], +[func@GLib.datalist_set_data_full] and [func@GLib.datalist_id_replace_data]. + +To get data elements from a datalist use [func@GLib.datalist_id_get_data], +[func@GLib.datalist_get_data] and [func@GLib.datalist_id_dup_data]. + +To iterate over all data elements in a datalist use +[func@GLib.datalist_foreach] (not thread-safe). + +To remove data elements from a datalist use +[func@GLib.datalist_id_remove_data], [func@GLib.datalist_remove_data] and +[func@GLib.datalist_id_remove_multiple]. To remove elements without destroying +them, use [func@GLib.datalist_id_remove_no_notify] and +[func@GLib.datalist_remove_no_notify]. + +To remove all data elements from a datalist, use [func@GLib.datalist_clear]. + +A small number of boolean flags can be stored alongside a datalist, using +[func@GLib.datalist_set_flags], [func@GLib.datalist_unset_flags] and +[func@GLib.datalist_get_flags]. + +## Datasets + +Datasets associate groups of data elements with particular memory +locations. These are useful if you need to associate data with a +structure returned from an external library. Since you cannot modify +the structure, you use its location in memory as the key into a +dataset, where you can associate any number of data elements with it. + +There are two forms of most of the dataset functions. The first form +uses strings to identify the data elements associated with a +location. The second form uses [type@GLib.Quark] identifiers, which are +created with a call to [func@GLib.quark_from_string] or +[func@GLib.quark_from_static_string]. The second form is quicker, since it +does not require looking up the string in the hash table of [type@GLib.Quark] +identifiers. + +There is no function to create a dataset. It is automatically +created as soon as you add elements to it. + +To add data elements to a dataset use [func@GLib.dataset_id_set_data], +[func@GLib.dataset_id_set_data_full], [func@GLib.dataset_set_data] and +[func@GLib.dataset_set_data_full]. + +To get data elements from a dataset use [func@GLib.dataset_id_get_data] and +[func@GLib.dataset_get_data]. + +To iterate over all data elements in a dataset use +[func@GLib.dataset_foreach] (not thread-safe). + +To remove data elements from a dataset use +[func@GLib.dataset_id_remove_data] and [func@GLib.dataset_remove_data]. To +remove data without destroying it, use [func@GLib.dataset_id_remove_no_notify] +and [func@GLib.dataset_remove_no_notify]. + +To destroy a dataset, use [func@GLib.dataset_destroy]. diff --git a/docs/reference/glib/error-reporting.md b/docs/reference/glib/error-reporting.md new file mode 100644 index 0000000..5cc9fa2 --- /dev/null +++ b/docs/reference/glib/error-reporting.md @@ -0,0 +1,487 @@ +Title: Error Reporting + +# Error Reporting + +GLib provides a standard method of reporting errors from a called function +to the calling code. (This is the same problem solved by exceptions in other +languages.) It's important to understand that this method is both a data +type (the [`type@GLib.Error`] struct) and a set of rules. If you use +`GError` incorrectly, then your code will not properly interoperate with +other code that uses `GError`, and users of your API will probably get +confused. In most cases, using `GError` is preferred over numeric error +codes, but there are situations where numeric error codes are useful for +performance. + +First and foremost: `GError` should only be used to report recoverable +runtime errors, never to report programming errors. If the programmer has +screwed up, then you should use `g_warning()`, `g_return_if_fail()`, +`g_assert()`, `g_error()`, or some similar facility. (Incidentally, remember +that the `g_error()` function should only be used for programming errors, it +should not be used to print any error reportable via `GError`.) + +Examples of recoverable runtime errors are "file not found" or "failed to +parse input." Examples of programming errors are "NULL passed to `strcmp()`" +or "attempted to free the same pointer twice." These two kinds of errors are +fundamentally different: runtime errors should be handled or reported to the +user, programming errors should be eliminated by fixing the bug in the +program. This is why most functions in GLib and GTK do not use the `GError` +facility. + +Functions that can fail take a return location for a `GError` as their last +argument. On error, a new `GError` instance will be allocated and returned +to the caller via this argument. For example: + +```c +gboolean g_file_get_contents (const char *filename, + char **contents, + gsize *length, + GError **error); +``` + +If you pass a non-`NULL` value for the `error` argument, it should +point to a location where an error can be placed. For example: + +```c +char *contents; +GError *err = NULL; + +g_file_get_contents ("foo.txt", &contents, NULL, &err); +g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL)); +if (err != NULL) + { + // Report error to user, and free error + g_assert (contents == NULL); + fprintf (stderr, "Unable to read file: %s\n", err->message); + g_error_free (err); + } +else + { + // Use file contents + g_assert (contents != NULL); + } +``` + +Note that `err != NULL` in this example is a reliable indicator of whether +`g_file_get_contents()` failed. Additionally, `g_file_get_contents()` +returns a boolean which indicates whether it was successful. + +Because `g_file_get_contents()` returns `FALSE` on failure, if you +are only interested in whether it failed and don't need to display +an error message, you can pass `NULL` for the `error` argument: + +```c +if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) // ignore errors + // no error occurred + ; +else + // error + ; +``` + +The `GError` object contains three fields: `domain` indicates the module the +error-reporting function is located in, `code` indicates the specific error +that occurred, and `message` is a user-readable error message with as many +details as possible. Several functions are provided to deal with an error +received from a called function: `g_error_matches()` returns `TRUE` if the +error matches a given domain and code, `g_propagate_error()` copies an error +into an error location (so the calling function will receive it), and +`g_clear_error()` clears an error location by freeing the error and +resetting the location to `NULL`. To display an error to the user, simply +display the `message`, perhaps along with additional context known only to +the calling function (the file being opened, or whatever - though in the +`g_file_get_contents()` case, the `message` already contains a filename). + +Since error messages may be displayed to the user, they need to be valid +UTF-8 (all GTK widgets expect text to be UTF-8). Keep this in mind in +particular when formatting error messages with filenames, which are in the +'filename encoding', and need to be turned into UTF-8 using +`g_filename_to_utf8()`, `g_filename_display_name()` or +`g_utf8_make_valid()`. + +Note, however, that many error messages are too technical to display to the +user in an application, so prefer to use `g_error_matches()` to categorize +errors from called functions, and build an appropriate error message for the +context within your application. Error messages from a `GError` are more +appropriate to be printed in system logs or on the command line. They are +typically translated. + +## Reporting errors + +When implementing a function that can report errors, the basic tool is +`g_set_error()`. Typically, if a fatal error occurs you want to +`g_set_error()`, then return immediately. `g_set_error()` does nothing if +the error location passed to it is `NULL`. Here's an example: + +```c +int +foo_open_file (GError **error) +{ + int fd; + int saved_errno; + + g_return_val_if_fail (error == NULL || *error == NULL, -1); + + fd = open ("file.txt", O_RDONLY); + saved_errno = errno; + + if (fd < 0) + { + g_set_error (error, + FOO_ERROR, // error domain + FOO_ERROR_BLAH, // error code + "Failed to open file: %s", // error message format string + g_strerror (saved_errno)); + return -1; + } + else + return fd; +} +``` + +Things are somewhat more complicated if you yourself call another function +that can report a `GError`. If the sub-function indicates fatal errors in +some way other than reporting a `GError`, such as by returning `TRUE` on +success, you can simply do the following: + +```c +gboolean +my_function_that_can_fail (GError **err) +{ + g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + + if (!sub_function_that_can_fail (err)) + { + // assert that error was set by the sub-function + g_assert (err == NULL || *err != NULL); + return FALSE; + } + + // otherwise continue, no error occurred + g_assert (err == NULL || *err == NULL); +} +``` + +If the sub-function does not indicate errors other than by reporting a +`GError` (or if its return value does not reliably indicate errors) you need +to create a temporary `GError` since the passed-in one may be `NULL`. +`g_propagate_error()` is intended for use in this case. + +```c +gboolean +my_function_that_can_fail (GError **err) +{ + GError *tmp_error; + + g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + + tmp_error = NULL; + sub_function_that_can_fail (&tmp_error); + + if (tmp_error != NULL) + { + // store tmp_error in err, if err != NULL, + // otherwise call g_error_free() on tmp_error + g_propagate_error (err, tmp_error); + return FALSE; + } + + // otherwise continue, no error occurred +} +``` + +Error pileups are always a bug. For example, this code is incorrect: + +```c +gboolean +my_function_that_can_fail (GError **err) +{ + GError *tmp_error; + + g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + + tmp_error = NULL; + sub_function_that_can_fail (&tmp_error); + other_function_that_can_fail (&tmp_error); + + if (tmp_error != NULL) + { + g_propagate_error (err, tmp_error); + return FALSE; + } +} +``` + +`tmp_error` should be checked immediately after +`sub_function_that_can_fail()`, and either cleared or propagated upward. The +rule is: after each error, you must either handle the error, or return it to +the calling function. + +Note that passing `NULL` for the error location is the equivalent of +handling an error by always doing nothing about it. So the following code is +fine, assuming errors in `sub_function_that_can_fail()` are not fatal to +`my_function_that_can_fail()`: + +```c +gboolean +my_function_that_can_fail (GError **err) +{ + GError *tmp_error; + + g_return_val_if_fail (err == NULL || *err == NULL, FALSE); + + sub_function_that_can_fail (NULL); // ignore errors + + tmp_error = NULL; + other_function_that_can_fail (&tmp_error); + + if (tmp_error != NULL) + { + g_propagate_error (err, tmp_error); + return FALSE; + } +} +``` + +Note that passing `NULL` for the error location ignores errors; it's +equivalent to: + +```cpp +try { sub_function_that_can_fail (); } catch (...) {} +``` + +in C++. It does not mean to leave errors unhandled; it means to handle them +by doing nothing. + +## Error domains + +Error domains and codes are conventionally named as follows: + +- The error domain is called `__ERROR`, for example + `G_SPAWN_ERROR` or `G_THREAD_ERROR`: + ```c + #define G_SPAWN_ERROR g_spawn_error_quark () + + G_DEFINE_QUARK (g-spawn-error-quark, g_spawn_error) + ``` + +- The quark function for the error domain is called + `__error_quark`, for example `g_spawn_error_quark()` or + `g_thread_error_quark()`. + +- The error codes are in an enumeration called `Error`; + for example, `GThreadError` or `GSpawnError`. + +- Members of the error code enumeration are called + `__ERROR_`, for example `G_SPAWN_ERROR_FORK` or + `G_THREAD_ERROR_AGAIN`. + +- If there's a "generic" or "unknown" error code for unrecoverable errors it + doesn't make sense to distinguish with specific codes, it should be called + `__ERROR_FAILED`, for example `G_SPAWN_ERROR_FAILED`. + In the case of error code enumerations that may be extended in future + releases, you should generally not handle this error code explicitly, but + should instead treat any unrecognized error code as equivalent to + `FAILED`. + +## Comparison of `GError` and traditional error handling + +`GError` has several advantages over traditional numeric error codes: +importantly, tools like [gobject-introspection](https://gi.readthedocs.org) +understand `GError`s and convert them to exceptions in bindings; the message +includes more information than just a code; and use of a domain helps +prevent misinterpretation of error codes. + +`GError` has disadvantages though: it requires a memory allocation, and +formatting the error message string has a performance overhead. This makes +it unsuitable for use in retry loops where errors are a common case, rather +than being unusual. For example, using `G_IO_ERROR_WOULD_BLOCK` means +hitting these overheads in the normal control flow. String formatting +overhead can be eliminated by using `g_set_error_literal()` in some cases. + +These performance issues can be compounded if a function wraps the `GError`s +returned by the functions it calls: this multiplies the number of +allocations and string formatting operations. This can be partially +mitigated by using `g_prefix_error()`. + +## Rules for use of `GError` + +Summary of rules for use of `GError`: + +- Do not report programming errors via `GError`. + +- The last argument of a function that returns an error should be a location + where a `GError` can be placed (i.e. `GError **error`). If `GError` is + used with varargs, the `GError**` should be the last argument before the + `...`. + +- The caller may pass `NULL` for the `GError**` if they are not interested + in details of the exact error that occurred. + +- If `NULL` is passed for the `GError**` argument, then errors should not be + returned to the caller, but your function should still abort and return if + an error occurs. That is, control flow should not be affected by whether + the caller wants to get a `GError`. + +- If a `GError` is reported, then your function by definition had a fatal + failure and did not complete whatever it was supposed to do. If the + failure was not fatal, then you handled it and you should not report it. + If it was fatal, then you must report it and discontinue whatever you were + doing immediately. + +- If a `GError` is reported, out parameters are not guaranteed to be set to + any defined value. + +- A `GError*` must be initialized to `NULL` before passing its address to a + function that can report errors. + +- `GError` structs must not be stack-allocated. + +- "Piling up" errors is always a bug. That is, if you assign a new `GError` + to a `GError*` that is non-`NULL`, thus overwriting the previous error, it + indicates that you should have aborted the operation instead of + continuing. If you were able to continue, you should have cleared the + previous error with `g_clear_error()`. `g_set_error()` will complain if + you pile up errors. + +- By convention, if you return a boolean value indicating success then + `TRUE` means success and `FALSE` means failure. Avoid creating functions + which have a boolean return value and a `GError` parameter, but where the + boolean does something other than signal whether the `GError` is set. + Among other problems, it requires C callers to allocate a temporary error. + Instead, provide a `gboolean *` out parameter. There are functions in + GLib itself such as `g_key_file_has_key()` that are hard to use because of + this. If `FALSE` is returned, the error must be set to a non-`NULL` value. + One exception to this is that in situations that are already considered to + be undefined behaviour (such as when a `g_return_val_if_fail()` check + fails), the error need not be set. Instead of checking separately whether + the error is set, callers should ensure that they do not provoke undefined + behaviour, then assume that the error will be set on failure. + +- A `NULL` return value is also frequently used to mean that an error + occurred. You should make clear in your documentation whether `NULL` is a + valid return value in non-error cases; if `NULL` is a valid value, then + users must check whether an error was returned to see if the function + succeeded. + +- When implementing a function that can report errors, you may want + to add a check at the top of your function that the error return + location is either `NULL` or contains a `NULL` error (e.g. + `g_return_if_fail (error == NULL || *error == NULL);`). + +## Extended `GError` Domains + +Since GLib 2.68 it is possible to extend the `GError` type. This is +done with the `G_DEFINE_EXTENDED_ERROR()` macro. To create an +extended `GError` type do something like this in the header file: + +```c +typedef enum +{ + MY_ERROR_BAD_REQUEST, +} MyError; +#define MY_ERROR (my_error_quark ()) +GQuark my_error_quark (void); +int +my_error_get_parse_error_id (GError *error); +const char * +my_error_get_bad_request_details (GError *error); +``` + +and in the implementation: + +```c +typedef struct +{ + int parse_error_id; + char *bad_request_details; +} MyErrorPrivate; + +static void +my_error_private_init (MyErrorPrivate *priv) +{ + priv->parse_error_id = -1; + // No need to set priv->bad_request_details to NULL, + // the struct is initialized with zeros. +} + +static void +my_error_private_copy (const MyErrorPrivate *src_priv, MyErrorPrivate *dest_priv) +{ + dest_priv->parse_error_id = src_priv->parse_error_id; + dest_priv->bad_request_details = g_strdup (src_priv->bad_request_details); +} + +static void +my_error_private_clear (MyErrorPrivate *priv) +{ + g_free (priv->bad_request_details); +} + +// This defines the my_error_get_private and my_error_quark functions. +G_DEFINE_EXTENDED_ERROR (MyError, my_error) + +int +my_error_get_parse_error_id (GError *error) +{ + MyErrorPrivate *priv = my_error_get_private (error); + g_return_val_if_fail (priv != NULL, -1); + return priv->parse_error_id; +} + +const char * +my_error_get_bad_request_details (GError *error) +{ + MyErrorPrivate *priv = my_error_get_private (error); + g_return_val_if_fail (priv != NULL, NULL); + g_return_val_if_fail (error->code != MY_ERROR_BAD_REQUEST, NULL); + return priv->bad_request_details; +} + +static void +my_error_set_bad_request (GError **error, + const char *reason, + int error_id, + const char *details) +{ + MyErrorPrivate *priv; + g_set_error (error, MY_ERROR, MY_ERROR_BAD_REQUEST, "Invalid request: %s", reason); + if (error != NULL && *error != NULL) + { + priv = my_error_get_private (error); + g_return_val_if_fail (priv != NULL, NULL); + priv->parse_error_id = error_id; + priv->bad_request_details = g_strdup (details); + } +} +``` + +An example of use of the error could be: + +```c +gboolean +send_request (GBytes *request, GError **error) +{ + ParseFailedStatus *failure = validate_request (request); + if (failure != NULL) + { + my_error_set_bad_request (error, failure->reason, failure->error_id, failure->details); + parse_failed_status_free (failure); + return FALSE; + } + + return send_one (request, error); +} +``` + +Please note that if you are a library author and your library exposes an +existing error domain, then you can't make this error domain an extended one +without breaking ABI. This is because earlier it was possible to create an +error with this error domain on the stack and then copy it with +`g_error_copy()`. If the new version of your library makes the error domain +an extended one, then `g_error_copy()` called by code that allocated the +error on the stack will try to copy more data than it used to, which will +lead to undefined behavior. You must not stack-allocate errors with an +extended error domain, and it is bad practice to stack-allocate any other +`GError`s. + +Extended error domains in unloadable plugins/modules are not supported. diff --git a/docs/reference/glib/file-utils.md b/docs/reference/glib/file-utils.md new file mode 100644 index 0000000..ec16851 --- /dev/null +++ b/docs/reference/glib/file-utils.md @@ -0,0 +1,110 @@ +Title: File Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2012 Dan Winship + +# File Utilities + +Do not use these APIs unless you are porting a POSIX application to Windows. +A more high-level file access API is provided as GIO — see the documentation +for [iface@Gio.File]. + +## POSIX File Wrappers + +There is a group of functions which wrap the common POSIX functions +dealing with filenames: + + * [func@GLib.access] + * [func@GLib.chdir] + * [func@GLib.chmod] + * [func@GLib.close] + * [func@GLib.creat] + * [func@GLib.fopen], + * [func@GLib.freopen] + * [func@GLib.fsync] + * [func@GLib.lstat] + * [func@GLib.mkdir] + * [func@GLib.open] + * [func@GLib.remove] + * [func@GLib.rename] + * [func@GLib.rmdir] + * [func@GLib.stat] + * [func@GLib.unlink] + * [func@GLib.utime] + +The point of these wrappers is to make it possible to handle file names with any +Unicode characters in them on Windows without having to use `#ifdef`s and the +wide character API in the application code. + +On some Unix systems, these APIs may be defined as identical to their POSIX +counterparts. For this reason, you must check for and include the necessary +header files (such as `fcntl.h`) before using functions like [func@GLib.creat]. +You must also define the relevant feature test macros. + +The pathname argument should be in the GLib file name encoding. +On POSIX this is the actual on-disk encoding which might correspond +to the locale settings of the process (or the `G_FILENAME_ENCODING` +environment variable), or not. + +On Windows the GLib file name encoding is UTF-8. Note that the +Microsoft C library does not use UTF-8, but has separate APIs for +current system code page and wide characters (UTF-16). The GLib +wrappers call the wide character API if present (on modern Windows +systems), otherwise convert to/from the system code page. + +## POSIX Directory Wrappers + +Another group of functions allows to open and read directories +in the GLib file name encoding: + + * [ctor@GLib.Dir.open] + * [method@GLib.Dir.read_name] + * [method@GLib.Dir.rewind] + * [method@GLib.Dir.close] + +## Error Handling + + * [func@GLib.file_error_from_errno] + +## Setting/Getting File Contents + + * [func@GLib.file_get_contents] + * [func@GLib.file_set_contents] + * [func@GLib.file_set_contents_full] + +## File Tests + + * [func@GLib.file_test] + * [func@GLib.file_read_link] + +## Temporary File Handling + + * [func@GLib.mkdtemp] + * [func@GLib.mkdtemp_full] + * [func@GLib.mkstemp] + * [func@GLib.mkstemp_full] + * [func@GLib.file_open_tmp] + * [id@g_dir_make_tmp] + +## Building and Manipulating Paths + + * [func@GLib.build_path] + * [func@GLib.build_pathv] + * [func@GLib.build_filename] + * [func@GLib.build_filenamev] + * [func@GLib.build_filename_valist] + * [func@GLib.IS_DIR_SEPARATOR] + * [func@GLib.path_is_absolute] + * [func@GLib.path_skip_root] + * [func@GLib.get_current_dir] + * [func@GLib.path_get_basename] + * [func@GLib.path_get_dirname] + * [func@GLib.canonicalize_filename] + +## Creating Directories + + * [func@GLib.mkdir_with_parents] + +## Deprecated API + + * [func@GLib.basename] + diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml deleted file mode 100644 index 5bf2e5c..0000000 --- a/docs/reference/glib/glib-docs.xml +++ /dev/null @@ -1,315 +0,0 @@ - - - -]> - - - GLib Reference Manual - - for GLib &version; - The latest version of this documentation can be found on-line at - https://developer.gnome.org/glib/unstable/. - - - - - GLib Overview - - GLib is a general-purpose utility library, which provides many useful - data types, macros, type conversions, string utilities, file utilities, - a mainloop abstraction, and so on. It works on many UNIX-like platforms, - as well as Windows and OS X. GLib is released under the GNU Lesser - General Public License (GNU LGPL). - - - - - - - - - - - - - - GLib Fundamentals - - - - - - - - - - - - - GLib Core Application Support - - - - - - - - - - - - - - - GLib Utilities - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - GLib Data Types - - - - - - - - - - - - - - - - - - - - - - - - - - - - Deprecated APIs - - - - - - - - GLib Tools - - - - - Deprecated Tools - - - - - - Index - - - - Index of deprecated symbols - - - - Index of new symbols in 2.2 - - - - Index of new symbols in 2.4 - - - - Index of new symbols in 2.6 - - - - Index of new symbols in 2.8 - - - - Index of new symbols in 2.10 - - - - Index of new symbols in 2.12 - - - - Index of new symbols in 2.14 - - - - Index of new symbols in 2.16 - - - - Index of new symbols in 2.18 - - - - Index of new symbols in 2.20 - - - - Index of new symbols in 2.22 - - - - Index of new symbols in 2.24 - - - - Index of new symbols in 2.26 - - - - Index of new symbols in 2.28 - - - - Index of new symbols in 2.30 - - - - Index of new symbols in 2.32 - - - - Index of new symbols in 2.34 - - - - Index of new symbols in 2.36 - - - - Index of new symbols in 2.38 - - - - Index of new symbols in 2.40 - - - - Index of new symbols in 2.42 - - - - Index of new symbols in 2.44 - - - - Index of new symbols in 2.46 - - - - Index of new symbols in 2.48 - - - - Index of new symbols in 2.50 - - - - Index of new symbols in 2.52 - - - - Index of new symbols in 2.54 - - - - Index of new symbols in 2.56 - - - - Index of new symbols in 2.58 - - - - Index of new symbols in 2.60 - - - - Index of new symbols in 2.62 - - - - Index of new symbols in 2.64 - - - - Index of new symbols in 2.66 - - - - Index of new symbols in 2.68 - - - - Index of new symbols in 2.70 - - - - Index of new symbols in 2.72 - - - - Index of new symbols in 2.74 - - - - Index of new symbols in 2.76 - - - - Index of new symbols in 2.78 - - - - - - diff --git a/docs/reference/glib/glib-gettextize.rst b/docs/reference/glib/glib-gettextize.rst new file mode 100644 index 0000000..78b3a06 --- /dev/null +++ b/docs/reference/glib/glib-gettextize.rst @@ -0,0 +1,59 @@ +.. _glib-gettextize(1): +.. meta:: + :copyright: Copyright 2003 Matthias Clasen + :copyright: Copyright 2012 Red Hat, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2003 Matthias Clasen + SPDX-FileCopyrightText: 2012 Red Hat, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +=============== +glib-gettextize +=============== + +------------------------------------ +gettext internationalization utility +------------------------------------ + +SYNOPSIS +-------- + +| **glib-gettextize** [*OPTION*…] [*DIRECTORY*] + +DESCRIPTION +----------- + +``glib-gettextize`` helps to prepare a source package for being +internationalized through `gettext `_. +It is a variant of the ``gettextize`` that ships with gettext. + +``glib-gettextize`` differs from ``gettextize`` in that it doesn’t create an +``intl/`` subdirectory and doesn’t modify ``po/ChangeLog`` (note that newer +versions of ``gettextize`` behave like this when called with the +``--no-changelog`` option). + +OPTIONS +------- + +``--help`` + + Print help and exit. + +``--version`` + + Print version information and exit. + +``-c``, ``--copy`` + + Copy files instead of making symlinks. + +``-f``, ``--force`` + + Force writing of new files even if old ones exist. + +SEE ALSO +-------- + +`gettextize(1) `_ \ No newline at end of file diff --git a/docs/reference/glib/glib-gettextize.xml b/docs/reference/glib/glib-gettextize.xml deleted file mode 100644 index f016b28..0000000 --- a/docs/reference/glib/glib-gettextize.xml +++ /dev/null @@ -1,88 +0,0 @@ - - - -glib-gettextize -GLib - - -Developer -Owen -Taylor - - - - - -glib-gettextize -1 -User Commands - - - -glib-gettextize -gettext internationalization utility - - - - -glib-gettextize -OPTION -DIRECTORY - - - -Description -glib-gettextize helps to prepare a source package for being -internationalized through gettext. -It is a variant of the gettextize that ships with -gettext. - - -glib-gettextize differs -from gettextize in that it doesn't create an -intl/ subdirectory and doesn't modify -po/ChangeLog (note that newer versions of -gettextize behave like this when called with the - option). - - - -Options - - - - - -print help and exit - - - - - - -print version information and exit - - - - -, - -copy files instead of making symlinks - - - - -, - -force writing of new files even if old ones exist - - - - - -See also - -gettextize1 - - - diff --git a/docs/reference/glib/glib-overrides.txt b/docs/reference/glib/glib-overrides.txt deleted file mode 100644 index 991fcf2..0000000 --- a/docs/reference/glib/glib-overrides.txt +++ /dev/null @@ -1,294 +0,0 @@ -# This file makes most of the thread related macros look like -# functions, which they really were, if possible easy. - - -GLIB_DISABLE_DEPRECATION_WARNINGS -#ifdef GLIB_DISABLE_DEPRECATION_WARNINGS - - - -G_ATOMIC_LOCK_FREE -#define G_ATOMIC_LOCK_FREE - - -# default thread implementation - - -G_THREADS_IMPL_POSIX -#define G_THREADS_IMPL_POSIX - - - -G_THREADS_IMPL_WIN32 -#define G_THREADS_IMPL_NONE - - -# threads supported? - - -g_thread_supported -gboolean - - -# GMutex - - -g_mutex_new -GMutex * - - - -g_mutex_lock -void -GMutex *mutex - - - -g_mutex_trylock -gboolean -GMutex *mutex - - - -g_mutex_unlock -void -GMutex *mutex - - - -g_mutex_free -void -GMutex *mutex - - -# GStaticMutex - - -GStaticMutex - - - -G_STATIC_MUTEX_INIT -#define G_STATIC_MUTEX_INIT - - - -g_static_mutex_lock -void -GStaticMutex* mutex - - - -g_static_mutex_trylock -gboolean -GStaticMutex* mutex - - - -g_static_mutex_unlock -void -GStaticMutex* mutex - - - -g_static_mutex_get_mutex -GMutex * -GStaticMutex* mutex - - -# GThread - - -g_thread_yield -void - - - -g_thread_create -GThread * -GThreadFunc func -gpointer data, -gboolean joinable, -GError **error - - -# G_LOCK_* macros - - -G_LOCK_DEFINE -#define G_LOCK_DEFINE(name) - - - -G_LOCK_DEFINE_STATIC -#define G_LOCK_DEFINE_STATIC(name) - - - -G_LOCK_EXTERN -#define G_LOCK_EXTERN(name) - - - -G_LOCK -#define G_LOCK(name) - - - -G_UNLOCK -#define G_UNLOCK(name) - - - -G_TRYLOCK -#define G_TRYLOCK(name) - - -# GCond - - -g_cond_new -GCond* - - - -g_cond_signal -void -GCond *cond - - - -g_cond_broadcast -void -GCond *cond - - - -g_cond_wait -void -GCond *cond, GMutex *mutex - - - -g_cond_timed_wait -gboolean -GCond *cond, GMutex *mutex, GTimeVal *abs_time - - - -g_cond_free -void -GCond *cond - - -# GPrivate - -G_PRIVATE_INIT -#define G_PRIVATE_INIT(notify) - - -# GStaticPrivate - - -G_STATIC_PRIVATE_INIT -#define G_STATIC_PRIVATE_INIT - - -# Definitions for different operating systems - - -G_OS_UNIX -#define G_OS_UNIX - - - -G_OS_WIN32 -#define G_OS_WIN32 - - -# g_ascii_isxxx - - -g_ascii_isalnum -gboolean -gchar c - - - -g_ascii_isalpha -gboolean -gchar c - - - -g_ascii_iscntrl -gboolean -gchar c - - - -g_ascii_isdigit -gboolean -gchar c - - - -g_ascii_isgraph -gboolean -gchar c - - - -g_ascii_islower -gboolean -gchar c - - - -g_ascii_isprint -gboolean -gchar c - - - -g_ascii_ispunct -gboolean -gchar c - - - -g_ascii_isspace -gboolean -gchar c - - - -g_ascii_isupper -gboolean -gchar c - - - -g_ascii_isxdigit -gboolean -gchar c - - -# g_atomic - - -g_atomic_int_inc -void -gint *atomic - - - -g_atomic_int_dec_and_test -gboolean -gint *atomic - - - -G_VA_COPY -#define G_VA_COPY(ap1,ap2) - diff --git a/docs/reference/glib/glib-sections.txt.in b/docs/reference/glib/glib-sections.txt.in deleted file mode 100644 index 5258544..0000000 --- a/docs/reference/glib/glib-sections.txt.in +++ /dev/null @@ -1,3763 +0,0 @@ -glib.h - -
-Basic Types -types -gboolean -gpointer -gconstpointer -gchar -guchar - - -gint -G_MININT -G_MAXINT -guint -G_MAXUINT -gshort -G_MINSHORT -G_MAXSHORT -gushort -G_MAXUSHORT -glong -G_MINLONG -G_MAXLONG -gulong -G_MAXULONG - - -gint8 -G_MININT8 -G_MAXINT8 -guint8 -G_MAXUINT8 -gint16 -G_MININT16 -G_MAXINT16 -G_GINT16_MODIFIER -G_GINT16_FORMAT -guint16 -G_MAXUINT16 -G_GUINT16_FORMAT -gint32 -G_MININT32 -G_MAXINT32 -G_GINT32_MODIFIER -G_GINT32_FORMAT -guint32 -G_MAXUINT32 -G_GUINT32_FORMAT -gint64 -G_MININT64 -G_MAXINT64 -G_GINT64_MODIFIER -G_GINT64_FORMAT -G_GINT64_CONSTANT -guint64 -G_MAXUINT64 -G_GUINT64_FORMAT -G_GUINT64_CONSTANT - - -gfloat -G_MINFLOAT -G_MAXFLOAT -gdouble -G_MINDOUBLE -G_MAXDOUBLE - - -gsize -G_MAXSIZE -G_GSIZE_MODIFIER -G_GSIZE_FORMAT -gssize -G_MINSSIZE -G_MAXSSIZE -G_GSSIZE_MODIFIER -G_GSSIZE_FORMAT -goffset -G_MINOFFSET -G_MAXOFFSET -G_GOFFSET_MODIFIER -G_GOFFSET_FORMAT -G_GOFFSET_CONSTANT - - -gintptr -G_GINTPTR_MODIFIER -G_GINTPTR_FORMAT -guintptr -G_GUINTPTR_FORMAT - - -GLIB_SIZEOF_SSIZE_T -GLIB_SIZEOF_VOID_P -GLIB_SIZEOF_LONG -GLIB_SIZEOF_SIZE_T -G_HAVE_GINT64 -
- -
-Version Information -version -glib_major_version -glib_minor_version -glib_micro_version -glib_binary_age -glib_interface_age -glib_check_version - - -GLIB_MAJOR_VERSION -GLIB_MINOR_VERSION -GLIB_MICRO_VERSION -GLIB_CHECK_VERSION - - -GLIB_VERSION_CUR_STABLE -GLIB_VERSION_PREV_STABLE -GLIB_VERSION_MIN_REQUIRED -GLIB_VERSION_MAX_ALLOWED -GLIB_DISABLE_DEPRECATION_WARNINGS -@GLIB_VERSIONS@ - - -G_ENCODE_VERSION -GLIB_AVAILABLE_IN_ALL -GLIB_DEPRECATED_ENUMERATOR -GLIB_DEPRECATED_ENUMERATOR_FOR -GLIB_DEPRECATED_MACRO -GLIB_DEPRECATED_MACRO_FOR -GLIB_DEPRECATED_TYPE -GLIB_DEPRECATED_TYPE_FOR -GLIB_VERSION_CUR_STABLE -GLIB_VERSION_PREV_STABLE -
- -
-Standard Macros -macros - -G_OS_WIN32 -G_OS_UNIX - - -G_DIR_SEPARATOR -G_DIR_SEPARATOR_S -G_IS_DIR_SEPARATOR -G_SEARCHPATH_SEPARATOR -G_SEARCHPATH_SEPARATOR_S - - -TRUE -FALSE - - -NULL - - -MIN -MAX - - -ABS -CLAMP -G_APPROX_VALUE - - -G_SIZEOF_MEMBER -G_STRUCT_MEMBER -G_STRUCT_MEMBER_P -G_STRUCT_OFFSET - - -G_MEM_ALIGN - - -G_ALIGNOF - - -G_CONST_RETURN -G_NORETURN -G_NORETURN_FUNCPTR - - -G_ALWAYS_INLINE -G_NO_INLINE - - -G_N_ELEMENTS -
- -
-Type Conversion Macros -type_conversion -GINT_TO_POINTER -GPOINTER_TO_INT - - -GUINT_TO_POINTER -GPOINTER_TO_UINT -GSIZE_TO_POINTER -GPOINTER_TO_SIZE -
- -
-Byte Order Macros -byte_order -G_BYTE_ORDER -G_LITTLE_ENDIAN -G_BIG_ENDIAN -G_PDP_ENDIAN - - -g_htonl -g_htons -g_ntohl -g_ntohs - - -GINT_FROM_BE -GINT_FROM_LE -GINT_TO_BE -GINT_TO_LE - - -GUINT_FROM_BE -GUINT_FROM_LE -GUINT_TO_BE -GUINT_TO_LE - - -GLONG_FROM_BE -GLONG_FROM_LE -GLONG_TO_BE -GLONG_TO_LE - - -GULONG_FROM_BE -GULONG_FROM_LE -GULONG_TO_BE -GULONG_TO_LE - - -GSIZE_FROM_BE -GSIZE_FROM_LE -GSIZE_TO_BE -GSIZE_TO_LE - - -GSSIZE_FROM_BE -GSSIZE_FROM_LE -GSSIZE_TO_BE -GSSIZE_TO_LE - - -GINT16_FROM_BE -GINT16_FROM_LE -GINT16_TO_BE -GINT16_TO_LE - - -GUINT16_FROM_BE -GUINT16_FROM_LE -GUINT16_TO_BE -GUINT16_TO_LE - - -GINT32_FROM_BE -GINT32_FROM_LE -GINT32_TO_BE -GINT32_TO_LE - - -GUINT32_FROM_BE -GUINT32_FROM_LE -GUINT32_TO_BE -GUINT32_TO_LE - - -GINT64_FROM_BE -GINT64_FROM_LE -GINT64_TO_BE -GINT64_TO_LE - - -GUINT64_FROM_BE -GUINT64_FROM_LE -GUINT64_TO_BE -GUINT64_TO_LE - - -GUINT16_SWAP_BE_PDP -GUINT16_SWAP_LE_BE -GUINT16_SWAP_LE_PDP - - -GUINT32_SWAP_BE_PDP -GUINT32_SWAP_LE_BE -GUINT32_SWAP_LE_PDP - - -GUINT64_SWAP_LE_BE - - -GUINT16_SWAP_LE_BE_CONSTANT -GUINT32_SWAP_LE_BE_CONSTANT -GUINT64_SWAP_LE_BE_CONSTANT -GUINT16_SWAP_LE_BE_IA32 -GUINT32_SWAP_LE_BE_IA32 -GUINT64_SWAP_LE_BE_IA32 -GUINT16_SWAP_LE_BE_IA64 -GUINT32_SWAP_LE_BE_IA64 -GUINT64_SWAP_LE_BE_IA64 -GUINT32_SWAP_LE_BE_X86_64 -GUINT64_SWAP_LE_BE_X86_64 - -
- -
-Bounds-checked integer arithmetic -checkedmath -g_uint_checked_add -g_uint_checked_mul -g_uint64_checked_add -g_uint64_checked_mul -g_size_checked_add -g_size_checked_mul -
- -
-Numerical Definitions -numerical -G_IEEE754_FLOAT_BIAS -G_IEEE754_DOUBLE_BIAS -GFloatIEEE754 -GDoubleIEEE754 - - -G_E -G_LN2 -G_LN10 -G_PI -G_PI_2 -G_PI_4 -G_SQRT2 -G_LOG_2_BASE_10 -
- -
-Miscellaneous Macros -macros_misc -G_INLINE_FUNC - - -g_auto -g_autoptr -g_autofree -g_autolist -g_autoslist -g_autoqueue -G_DEFINE_AUTOPTR_CLEANUP_FUNC -G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC -G_DEFINE_AUTO_CLEANUP_FREE_FUNC - - -G_STMT_START -G_STMT_END - - -G_BEGIN_DECLS -G_END_DECLS - - -G_VA_COPY - - -G_STRINGIFY -G_PASTE -G_STATIC_ASSERT -G_STATIC_ASSERT_EXPR - - -G_GNUC_CHECK_VERSION -G_GNUC_EXTENSION -G_GNUC_CONST -G_GNUC_PURE -G_GNUC_MALLOC -G_GNUC_ALLOC_SIZE -G_GNUC_ALLOC_SIZE2 -G_GNUC_DEPRECATED -G_GNUC_DEPRECATED_FOR -G_GNUC_BEGIN_IGNORE_DEPRECATIONS -G_GNUC_END_IGNORE_DEPRECATIONS -G_GNUC_NORETURN -G_GNUC_FALLTHROUGH -G_GNUC_UNUSED -G_GNUC_PRINTF -G_GNUC_SCANF -G_GNUC_STRFTIME -G_GNUC_FORMAT -G_GNUC_NULL_TERMINATED -G_GNUC_WARN_UNUSED_RESULT -G_GNUC_FUNCTION -G_GNUC_PRETTY_FUNCTION -G_GNUC_NO_INLINE -G_GNUC_NO_INSTRUMENT -G_HAVE_GNUC_VISIBILITY -G_GNUC_INTERNAL -G_GNUC_MAY_ALIAS - - -G_C_STD_VERSION -G_C_STD_CHECK_VERSION -G_CXX_STD_VERSION -G_CXX_STD_CHECK_VERSION - - -G_DEPRECATED -G_DEPRECATED_FOR -G_UNAVAILABLE - - -G_LIKELY -G_UNLIKELY - - -G_STRLOC -G_STRFUNC - - -GLIB_VAR -G_STRINGIFY_ARG -G_PASTE_ARGS -G_HAVE_INLINE -G_CAN_INLINE -inline -G_HAVE___INLINE -G_HAVE___INLINE__ -G_INLINE_DEFINE_NEEDED -G_HAVE_GNUC_VARARGS -G_HAVE_ISO_VARARGS -G_HAVE_GROWING_STACK -G_VA_COPY_AS_ARRAY -GLIB_CANNOT_IGNORE_DEPRECATIONS -GLIB_DEPRECATED -GLIB_DEPRECATED_FOR -GLIB_UNAVAILABLE -GLIB_UNAVAILABLE_ENUMERATOR -GLIB_UNAVAILABLE_MACRO -GLIB_UNAVAILABLE_STATIC_INLINE -GLIB_UNAVAILABLE_TYPE -G_ANALYZER_ANALYZING -G_ANALYZER_NORETURN -g_autoptr_cleanup_generic_gfree -glib_typeof -g_macro__has_attribute -g_macro__has_builtin -g_macro__has_feature -g_macro__has_extension -g_macro__has_attribute___always_inline__ -g_macro__has_attribute___alloc_size__ -g_macro__has_attribute___const__ -g_macro__has_attribute___deprecated__ -g_macro__has_attribute___format__ -g_macro__has_attribute___format_arg__ -g_macro__has_attribute___malloc__ -g_macro__has_attribute___no_instrument_function__ -g_macro__has_attribute___noreturn__ -g_macro__has_attribute___pure__ -g_macro__has_attribute___sentinel__ -g_macro__has_attribute___unused__ -g_macro__has_attribute_fallthrough -g_macro__has_attribute_may_alias -g_macro__has_attribute___noinline__ -g_macro__has_attribute_warn_unused_result -g_macro__has_attribute_cleanup -
- -
-Error Reporting -error_reporting -GError -g_error_new -g_error_new_literal -g_error_new_valist -g_error_free -g_error_copy -g_error_matches -g_set_error -g_set_error_literal -g_propagate_error -g_clear_error -g_prefix_error -g_prefix_error_literal -g_propagate_prefixed_error - -GErrorInitFunc -GErrorCopyFunc -GErrorClearFunc -G_DEFINE_EXTENDED_ERROR -g_error_domain_register_static -g_error_domain_register -
- -
-The Main Event Loop -main -GMainLoop -g_main_loop_new -g_main_loop_ref -g_main_loop_unref -g_main_loop_run -g_main_loop_quit -g_main_loop_is_running -g_main_loop_get_context -g_main_new -g_main_destroy -g_main_run -g_main_quit -g_main_is_running - - -G_PRIORITY_HIGH -G_PRIORITY_DEFAULT -G_PRIORITY_HIGH_IDLE -G_PRIORITY_DEFAULT_IDLE -G_PRIORITY_LOW - - -G_SOURCE_CONTINUE -G_SOURCE_REMOVE - - -GMainContext -GMainContextFlags -g_main_context_new -g_main_context_new_with_flags -g_main_context_ref -g_main_context_unref -g_main_context_default -g_main_context_iteration -g_main_iteration -g_main_context_pending -g_main_pending -g_main_context_find_source_by_id -g_main_context_find_source_by_user_data -g_main_context_find_source_by_funcs_user_data -g_main_context_wakeup -g_main_context_acquire -g_main_context_release -g_main_context_is_owner -g_main_context_wait -g_main_context_prepare -g_main_context_query -g_main_context_check -g_main_context_dispatch -g_main_context_set_poll_func -g_main_context_get_poll_func -GPollFunc -g_main_context_add_poll -g_main_context_remove_poll -g_main_depth -g_main_current_source -g_main_set_poll_func -g_main_context_invoke -g_main_context_invoke_full - - -GMainContextPusher -g_main_context_pusher_new -g_main_context_pusher_free - - -g_main_context_get_thread_default -g_main_context_ref_thread_default -g_main_context_push_thread_default -g_main_context_pop_thread_default - - -g_timeout_source_new -g_timeout_source_new_seconds -g_timeout_add -g_timeout_add_once -g_timeout_add_full -g_timeout_add_seconds -g_timeout_add_seconds_full -g_timeout_add_seconds_once - - -g_idle_source_new -g_idle_add -g_idle_add_once -g_idle_add_full -g_idle_remove_by_data - - -GPid -G_PID_FORMAT -GChildWatchFunc -g_child_watch_source_new -g_child_watch_add -g_child_watch_add_full - - -GPollFD -g_poll -G_POLLFD_FORMAT - - -GSource -GSourceDummyMarshal -GSourceFuncs -GSourceDisposeFunc -GSourceCallbackFuncs -g_source_new -g_source_ref -g_source_unref -g_source_set_funcs -g_source_set_dispose_function -g_source_attach -g_source_destroy -g_source_is_destroyed -g_source_set_priority -g_source_get_priority -g_source_set_can_recurse -g_source_get_can_recurse -g_source_get_id -g_source_get_name -g_source_set_name -g_source_set_static_name -g_source_set_name_by_id -g_source_get_context -g_source_set_callback -GSourceFunc -G_SOURCE_FUNC -GSourceOnceFunc -g_source_set_callback_indirect -g_source_set_ready_time -g_source_get_ready_time -g_source_add_unix_fd -g_source_remove_unix_fd -g_source_modify_unix_fd -g_source_query_unix_fd -g_source_add_poll -g_source_remove_poll -g_source_add_child_source -g_source_remove_child_source -g_source_get_time -g_source_get_current_time -g_source_remove -g_source_remove_by_funcs_user_data -g_source_remove_by_user_data -GClearHandleFunc -g_clear_handle_id - - -g_steal_fd - - -GLIB_HAVE_ALLOCA_H -alloca -GLIB_USING_SYSTEM_PRINTF -GLIB_SYSDEF_POLLERR -GLIB_SYSDEF_POLLHUP -GLIB_SYSDEF_POLLIN -GLIB_SYSDEF_POLLNVAL -GLIB_SYSDEF_POLLOUT -GLIB_SYSDEF_POLLPRI -GLIB_SYSDEF_AF_INET -GLIB_SYSDEF_AF_INET6 -GLIB_SYSDEF_AF_UNIX -GLIB_SYSDEF_MSG_DONTROUTE -GLIB_SYSDEF_MSG_OOB -GLIB_SYSDEF_MSG_PEEK -G_WIN32_MSG_HANDLE -g_idle_funcs -g_timeout_funcs -g_child_watch_funcs -g_unix_signal_funcs -g_unix_fd_source_funcs -GSourcePrivate -
- - -
-Threads -threads - -G_THREAD_ERROR -GThreadError - - -GThread -GThreadFunc -g_thread_new -g_thread_try_new -g_thread_ref -g_thread_unref -g_thread_join -g_thread_yield -g_thread_exit -g_thread_self - - -GMutex -g_mutex_init -g_mutex_clear -g_mutex_lock -g_mutex_trylock -g_mutex_unlock - - -GMutexLocker -g_mutex_locker_new -g_mutex_locker_free - - -G_LOCK_DEFINE -G_LOCK_DEFINE_STATIC -G_LOCK_EXTERN -G_LOCK -G_TRYLOCK -G_UNLOCK - - -GRecMutex -g_rec_mutex_init -g_rec_mutex_clear -g_rec_mutex_lock -g_rec_mutex_trylock -g_rec_mutex_unlock - - -GRecMutexLocker -g_rec_mutex_locker_new -g_rec_mutex_locker_free - - -GRWLockWriterLocker -g_rw_lock_writer_locker_new -g_rw_lock_writer_locker_free - - -GRWLockReaderLocker -g_rw_lock_reader_locker_new -g_rw_lock_reader_locker_free - - -GRWLock -g_rw_lock_init -g_rw_lock_clear -g_rw_lock_writer_lock -g_rw_lock_writer_trylock -g_rw_lock_writer_unlock -g_rw_lock_reader_lock -g_rw_lock_reader_trylock -g_rw_lock_reader_unlock - - -GCond -g_cond_init -g_cond_clear -g_cond_wait -g_cond_timed_wait -g_cond_wait_until -g_cond_signal -g_cond_broadcast - - -GPrivate -G_PRIVATE_INIT -g_private_get -g_private_set -g_private_replace - - -GOnce -GOnceStatus -G_ONCE_INIT -g_once -g_once_init_enter -g_once_init_leave - - -g_bit_lock -g_bit_trylock -g_bit_unlock -g_pointer_bit_lock -g_pointer_bit_trylock -g_pointer_bit_unlock - - -g_get_num_processors - - -G_LOCK_NAME -atexit -g_thread_error_quark -g_once_impl -
- -
-Deprecated Thread APIs -threads-deprecated - - -G_THREADS_IMPL_POSIX -G_THREADS_IMPL_WIN32 - - -g_thread_init -g_thread_supported -g_thread_get_initialized - - -g_thread_create -g_thread_create_full -GThreadPriority -g_thread_set_priority -g_thread_foreach - - -g_mutex_new -g_mutex_free -g_cond_new -g_cond_free -g_private_new - - -GStaticMutex -G_STATIC_MUTEX_INIT -g_static_mutex_init -g_static_mutex_lock -g_static_mutex_trylock -g_static_mutex_unlock -g_static_mutex_get_mutex -g_static_mutex_free - - -GStaticRecMutex -G_STATIC_REC_MUTEX_INIT -g_static_rec_mutex_init -g_static_rec_mutex_lock -g_static_rec_mutex_trylock -g_static_rec_mutex_unlock -g_static_rec_mutex_lock_full -g_static_rec_mutex_unlock_full -g_static_rec_mutex_free - - -GStaticRWLock -G_STATIC_RW_LOCK_INIT -g_static_rw_lock_init -g_static_rw_lock_reader_lock -g_static_rw_lock_reader_trylock -g_static_rw_lock_reader_unlock -g_static_rw_lock_writer_lock -g_static_rw_lock_writer_trylock -g_static_rw_lock_writer_unlock -g_static_rw_lock_free - - -GStaticPrivate -G_STATIC_PRIVATE_INIT -g_static_private_init -g_static_private_get -g_static_private_set -g_static_private_free - - -GThreadFunctions -g_thread_init_with_errorcheck_mutexes -G_THREADS_ENABLED -g_static_mutex_get_mutex_impl -g_thread_use_default_impl -g_threads_got_initialized -g_thread_functions_for_glib_use -g_thread_gettime -g_once_init_enter_impl -
- -
-Thread Pools -thread_pools -GThreadPool -g_thread_pool_new -g_thread_pool_new_full -g_thread_pool_push -g_thread_pool_set_max_threads -g_thread_pool_get_max_threads -g_thread_pool_get_num_threads -g_thread_pool_unprocessed -g_thread_pool_free -g_thread_pool_set_max_unused_threads -g_thread_pool_get_max_unused_threads -g_thread_pool_get_num_unused_threads -g_thread_pool_stop_unused_threads -g_thread_pool_set_sort_function -g_thread_pool_set_max_idle_time -g_thread_pool_get_max_idle_time -g_thread_pool_move_to_front -
- -
-Asynchronous Queues -async_queues -GAsyncQueue -g_async_queue_new -g_async_queue_new_full -g_async_queue_ref -g_async_queue_unref -g_async_queue_push -g_async_queue_push_sorted -g_async_queue_push_front -g_async_queue_remove -g_async_queue_pop -g_async_queue_try_pop -g_async_queue_timeout_pop -g_async_queue_length -g_async_queue_sort - - -g_async_queue_lock -g_async_queue_unlock -g_async_queue_ref_unlocked -g_async_queue_unref_and_unlock -g_async_queue_push_unlocked -g_async_queue_push_sorted_unlocked -g_async_queue_push_front_unlocked -g_async_queue_remove_unlocked -g_async_queue_pop_unlocked -g_async_queue_try_pop_unlocked -g_async_queue_timeout_pop_unlocked -g_async_queue_length_unlocked -g_async_queue_sort_unlocked - - -g_async_queue_timed_pop -g_async_queue_timed_pop_unlocked -
- -
-Atomic Operations -atomic_operations -G_ATOMIC_LOCK_FREE - - -g_atomic_int_get -g_atomic_int_set -g_atomic_int_inc -g_atomic_int_dec_and_test -g_atomic_int_compare_and_exchange -g_atomic_int_compare_and_exchange_full -g_atomic_int_exchange -g_atomic_int_add -g_atomic_int_and -g_atomic_int_or -g_atomic_int_xor - - -g_atomic_pointer_get -g_atomic_pointer_set -g_atomic_pointer_compare_and_exchange -g_atomic_pointer_compare_and_exchange_full -g_atomic_pointer_exchange -g_atomic_pointer_add -g_atomic_pointer_and -g_atomic_pointer_or -g_atomic_pointer_xor - - -g_atomic_int_exchange_and_add -
- -
-IO Channels -iochannels -GIOChannel - - -g_io_channel_unix_new -g_io_channel_unix_get_fd -g_io_channel_win32_new_fd -g_io_channel_win32_new_socket -g_io_channel_win32_new_messages - - -g_io_channel_init - - -g_io_channel_new_file -g_io_channel_read_chars -g_io_channel_read_unichar -g_io_channel_read_line -g_io_channel_read_line_string -g_io_channel_read_to_end -g_io_channel_write_chars -g_io_channel_write_unichar -g_io_channel_flush -g_io_channel_seek_position -GSeekType -g_io_channel_shutdown - - -GIOStatus -GIOChannelError -G_IO_CHANNEL_ERROR -g_io_channel_error_from_errno - - -g_io_channel_ref -g_io_channel_unref - - -g_io_create_watch -g_io_add_watch -g_io_add_watch_full -GIOCondition -GIOFunc - - -GIOFuncs - - -g_io_channel_get_buffer_size -g_io_channel_set_buffer_size -g_io_channel_get_buffer_condition -g_io_channel_get_flags -g_io_channel_set_flags -GIOFlags -g_io_channel_get_line_term -g_io_channel_set_line_term -g_io_channel_get_buffered -g_io_channel_set_buffered -g_io_channel_get_encoding -g_io_channel_set_encoding -g_io_channel_get_close_on_unref -g_io_channel_set_close_on_unref - - -g_io_channel_read -GIOError -g_io_channel_write -g_io_channel_seek -g_io_channel_close - - -g_io_channel_win32_poll -g_io_channel_win32_make_pollfd -g_io_channel_win32_get_fd -g_io_channel_win32_new_stream_socket -g_io_channel_win32_set_debug -g_io_channel_error_quark -g_io_watch_funcs -G_IO_FLAG_IS_WRITEABLE -
- -
-Memory Allocation -memory -g_new -g_new0 -g_renew -g_try_new -g_try_new0 -g_try_renew - - -g_malloc -g_malloc0 -g_realloc -g_try_malloc -g_try_malloc0 -g_try_realloc -g_malloc_n -g_malloc0_n -g_realloc_n -g_try_malloc_n -g_try_malloc0_n -g_try_realloc_n - - -g_free -g_free_sized -g_clear_pointer -g_steal_pointer -g_mem_gc_friendly - - -g_alloca -g_alloca0 -g_newa -g_newa0 - - -g_aligned_alloc -g_aligned_alloc0 -g_aligned_free -g_aligned_free_sized - - -g_memmove -g_memdup -g_memdup2 - - -GMemVTable -g_mem_set_vtable -g_mem_is_system_malloc - - -glib_mem_profiler_table -g_mem_profile -
- -
-Warnings and Assertions -warnings -g_print -g_set_print_handler -GPrintFunc - - -g_printerr -g_set_printerr_handler - - -g_return_if_fail -g_return_val_if_fail -g_return_if_reached -g_return_val_if_reached -g_warn_if_fail -g_warn_if_reached - - -g_on_error_query -g_on_error_stack_trace - - -G_BREAKPOINT - - -g_return_if_fail_warning -g_assert_warning -g_warn_message -
- -
-Glob-style pattern matching -patterns -GPatternSpec -g_pattern_spec_new -g_pattern_spec_free -g_pattern_spec_equal -g_pattern_spec_copy -g_pattern_spec_match -g_pattern_spec_match_string -g_pattern_match -g_pattern_match_string -g_pattern_match_simple -
- -
-Perl-compatible regular expressions -gregex -GRegexError -G_REGEX_ERROR -GRegexCompileFlags -GRegexMatchFlags -GRegex -GRegexEvalCallback -g_regex_new -g_regex_ref -g_regex_unref -g_regex_get_pattern -g_regex_get_max_backref -g_regex_get_capture_count -g_regex_get_has_cr_or_lf -g_regex_get_max_lookbehind -g_regex_get_string_number -g_regex_get_compile_flags -g_regex_get_match_flags -g_regex_escape_string -g_regex_escape_nul -g_regex_match_simple -g_regex_match -g_regex_match_full -g_regex_match_all -g_regex_match_all_full -g_regex_split_simple -g_regex_split -g_regex_split_full -g_regex_replace -g_regex_replace_literal -g_regex_replace_eval -g_regex_check_replacement -GMatchInfo -g_match_info_get_regex -g_match_info_get_string -g_match_info_ref -g_match_info_unref -g_match_info_free -g_match_info_matches -g_match_info_next -g_match_info_get_match_count -g_match_info_is_partial_match -g_match_info_expand_references -g_match_info_fetch -g_match_info_fetch_pos -g_match_info_fetch_named -g_match_info_fetch_named_pos -g_match_info_fetch_all - -g_regex_error_quark -
- -
-Message Logging -messages -G_LOG_DOMAIN -G_LOG_FATAL_MASK -G_LOG_LEVEL_USER_SHIFT -GLogFunc -GLogLevelFlags - - -g_log -g_logv -g_message -g_warning -g_warning_once -g_critical -g_error -g_info -g_debug - - -g_log_set_handler -g_log_set_handler_full -g_log_remove_handler -g_log_set_always_fatal -g_log_set_fatal_mask -g_log_default_handler -g_log_set_default_handler -g_log_get_debug_enabled -g_log_set_debug_enabled - - -g_log_structured -g_log_variant -GLogField -g_log_structured_array -G_DEBUG_HERE - - -GLogWriterOutput -GLogWriterFunc -g_log_set_writer_func -g_log_writer_supports_color -g_log_writer_is_journald -g_log_writer_format_fields -g_log_writer_journald -g_log_writer_standard_streams -g_log_writer_default -g_log_writer_default_set_use_stderr -g_log_writer_default_would_drop - - -g_log_structured_standard -
- -
-Timers -timers -GTimer -g_timer_new -g_timer_start -g_timer_stop -g_timer_continue -g_timer_elapsed -g_timer_reset -g_timer_destroy -g_timer_is_active -
- -
-Spawning Processes -spawn -GSpawnError -G_SPAWN_ERROR -GSpawnFlags -GSpawnChildSetupFunc -g_spawn_async_with_fds -g_spawn_async_with_pipes -g_spawn_async_with_pipes_and_fds -g_spawn_async -g_spawn_sync -G_SPAWN_EXIT_ERROR -g_spawn_check_wait_status -g_spawn_check_exit_status -g_spawn_command_line_async -g_spawn_command_line_sync -g_spawn_close_pid - -g_spawn_error_quark -g_spawn_exit_error_quark -
- -
-Simple XML Subset Parser -markup -GMarkupError -G_MARKUP_ERROR -GMarkupParseFlags -GMarkupParseContext -GMarkupParser -g_markup_escape_text -g_markup_printf_escaped -g_markup_vprintf_escaped -g_markup_parse_context_new -g_markup_parse_context_parse -g_markup_parse_context_end_parse -g_markup_parse_context_free -g_markup_parse_context_get_position -g_markup_parse_context_get_element -g_markup_parse_context_get_element_stack -g_markup_parse_context_get_user_data -g_markup_parse_context_push -g_markup_parse_context_pop -g_markup_parse_context_ref -g_markup_parse_context_unref - -GMarkupCollectType -g_markup_collect_attributes - -g_markup_error_quark -
- - -
-Shell-related Utilities -shell -GShellError -G_SHELL_ERROR -g_shell_parse_argv -g_shell_quote -g_shell_unquote - -g_shell_error_quark -
- - -
-Commandline option parser -goptioncontext -GOptionError -G_OPTION_ERROR -GOptionArgFunc -GOptionContext -g_option_context_new -g_option_context_set_summary -g_option_context_get_summary -g_option_context_set_description -g_option_context_get_description -GTranslateFunc -g_option_context_set_translate_func -g_option_context_set_translation_domain -g_option_context_free -g_option_context_parse -g_option_context_parse_strv -g_option_context_set_help_enabled -g_option_context_get_help_enabled -g_option_context_set_ignore_unknown_options -g_option_context_get_ignore_unknown_options -g_option_context_get_help -g_option_context_get_strict_posix -g_option_context_set_strict_posix -GOptionArg -GOptionFlags -G_OPTION_REMAINING -GOptionEntry -G_OPTION_ENTRY_NULL -g_option_context_add_main_entries -GOptionGroup -g_option_context_add_group -g_option_context_set_main_group -g_option_context_get_main_group -g_option_group_new -g_option_group_ref -g_option_group_unref -g_option_group_free -g_option_group_add_entries -GOptionParseFunc -g_option_group_set_parse_hooks -GOptionErrorFunc -g_option_group_set_error_hook -g_option_group_set_translate_func -g_option_group_set_translation_domain - -g_option_error_quark -
- - -
-File Utilities -fileutils -glib.h,glib/gstdio.h,fcntl.h,sys/types.h,sys/stat.h -GFileError -G_FILE_ERROR -GFileTest -g_file_error_from_errno -g_file_get_contents -GFileSetContentsFlags -g_file_set_contents -g_file_set_contents_full -g_file_test -g_mkstemp -g_mkstemp_full -g_file_open_tmp -g_file_read_link -g_mkdir_with_parents -g_mkdtemp -g_mkdtemp_full -g_dir_make_tmp - - -GDir -g_dir_open -g_dir_read_name -g_dir_rewind -g_dir_close - - -GMappedFile -g_mapped_file_new -g_mapped_file_new_from_fd -g_mapped_file_ref -g_mapped_file_unref -g_mapped_file_free -g_mapped_file_get_length -g_mapped_file_get_contents -g_mapped_file_get_bytes - - -g_open -g_rename -g_mkdir -GStatBuf -g_stat -g_lstat -g_unlink -g_remove -g_rmdir -g_fopen -g_freopen -g_fsync -g_chmod -g_access -g_creat -g_chdir -g_utime -g_close -g_clear_fd -g_autofd - - -g_file_error_quark -utimbuf -
- - -
-String Utility Functions -string_utils -glib.h,glib/gprintf.h -g_set_str -g_strdup -g_strndup -g_strdupv -g_strnfill -g_stpcpy -g_strstr_len -g_strrstr -g_strrstr_len -g_str_has_prefix -g_str_has_suffix -g_strcmp0 -g_str_to_ascii -g_str_tokenize_and_fold -g_str_match_string - - -g_strlcpy -g_strlcat - - -g_strdup_printf -g_strdup_vprintf -g_printf -g_vprintf -g_fprintf -g_vfprintf -g_sprintf -g_vsprintf -g_snprintf -g_vsnprintf -g_vasprintf -g_printf_string_upper_bound - - -g_str_is_ascii -g_ascii_isalnum -g_ascii_isalpha -g_ascii_iscntrl -g_ascii_isdigit -g_ascii_isgraph -g_ascii_islower -g_ascii_isprint -g_ascii_ispunct -g_ascii_isspace -g_ascii_isupper -g_ascii_isxdigit - - -g_ascii_digit_value -g_ascii_xdigit_value - - -g_ascii_strcasecmp -g_ascii_strncasecmp - - -g_ascii_strup -g_ascii_strdown - - -g_ascii_tolower -g_ascii_toupper - - -g_string_ascii_up -g_string_ascii_down - - -g_strup -g_strdown - - -g_strcasecmp -g_strncasecmp - - -g_strreverse - - -g_ascii_strtoll -g_ascii_strtoull -G_ASCII_DTOSTR_BUF_SIZE -g_ascii_strtod -g_ascii_dtostr -g_ascii_formatd -g_strtod - - -GNumberParserError -G_NUMBER_PARSER_ERROR -g_ascii_string_to_signed -g_ascii_string_to_unsigned - - -g_number_parser_error_quark - - -g_strchug -g_strchomp -g_strstrip - - -g_strdelimit -G_STR_DELIMITERS -g_strescape -g_strcompress -g_strcanon -g_strsplit -g_strsplit_set -g_strfreev -g_strconcat -g_strjoin -g_strjoinv - - -GStrv -GStrvBuilder -g_strv_length -g_strv_contains -g_strv_equal -g_strv_builder_new -g_strv_builder_ref -g_strv_builder_unref -g_strv_builder_add -g_strv_builder_addv -g_strv_builder_add_many -g_strv_builder_end - - -g_strerror -g_strsignal - - -GAsciiType -g_ascii_table -
- -
-Date and Time Functions -date -G_USEC_PER_SEC -GTimeVal -g_get_current_time -g_usleep -g_time_val_add -g_time_val_from_iso8601 -g_time_val_to_iso8601 - - -g_get_monotonic_time -g_get_real_time - - -GDate -GTime -GDateDMY -GDateDay -GDateMonth -GDateYear -GDateWeekday - - -G_DATE_BAD_DAY -G_DATE_BAD_JULIAN -G_DATE_BAD_YEAR - - -g_date_new -g_date_new_dmy -g_date_new_julian -g_date_clear -g_date_free -g_date_copy - - -g_date_set_day -g_date_set_month -g_date_set_year -g_date_set_dmy -g_date_set_julian -g_date_set_time -g_date_set_time_t -g_date_set_time_val -g_date_set_parse - - -g_date_add_days -g_date_subtract_days -g_date_add_months -g_date_subtract_months -g_date_add_years -g_date_subtract_years -g_date_days_between -g_date_compare -g_date_clamp -g_date_order - - -g_date_get_day -g_date_get_month -g_date_get_year -g_date_get_julian -g_date_get_weekday -g_date_get_day_of_year - - -g_date_get_days_in_month -g_date_is_first_of_month -g_date_is_last_of_month -g_date_is_leap_year -g_date_get_monday_week_of_year -g_date_get_monday_weeks_in_year -g_date_get_sunday_week_of_year -g_date_get_sunday_weeks_in_year -g_date_get_iso8601_week_of_year - - -g_date_strftime -g_date_to_struct_tm - - -g_date_valid -g_date_valid_day -g_date_valid_month -g_date_valid_year -g_date_valid_dmy -g_date_valid_julian -g_date_valid_weekday - - -g_date_weekday -g_date_month -g_date_year -g_date_day -g_date_julian -g_date_day_of_year -g_date_monday_week_of_year -g_date_sunday_week_of_year -g_date_days_in_month -g_date_monday_weeks_in_year -g_date_sunday_weeks_in_year -
- -
-timezone - -GTimeZone -g_time_zone_unref -g_time_zone_ref - -g_time_zone_new -g_time_zone_new_identifier -g_time_zone_new_local -g_time_zone_new_utc -g_time_zone_new_offset - -GTimeType -g_time_zone_find_interval -g_time_zone_adjust_time - -g_time_zone_get_identifier -g_time_zone_get_abbreviation -g_time_zone_get_offset -g_time_zone_is_dst -
- -
-date-time -GTimeSpan -G_TIME_SPAN_DAY -G_TIME_SPAN_HOUR -G_TIME_SPAN_MINUTE -G_TIME_SPAN_SECOND -G_TIME_SPAN_MILLISECOND - - -GDateTime -g_date_time_unref -g_date_time_ref - - -g_date_time_new_now -g_date_time_new_now_local -g_date_time_new_now_utc - - -g_date_time_new_from_unix_local -g_date_time_new_from_unix_utc - - -g_date_time_new_from_timeval_local -g_date_time_new_from_timeval_utc -g_date_time_new_from_iso8601 - - -g_date_time_new -g_date_time_new_local -g_date_time_new_utc - - -g_date_time_add - - -g_date_time_add_years -g_date_time_add_months -g_date_time_add_weeks -g_date_time_add_days - - -g_date_time_add_hours -g_date_time_add_minutes -g_date_time_add_seconds - - -g_date_time_add_full - - -g_date_time_compare -g_date_time_difference -g_date_time_hash -g_date_time_equal - - -g_date_time_get_ymd - - -g_date_time_get_year -g_date_time_get_month -g_date_time_get_day_of_month - - -g_date_time_get_week_numbering_year -g_date_time_get_week_of_year -g_date_time_get_day_of_week - - -g_date_time_get_day_of_year - - -g_date_time_get_hour -g_date_time_get_minute -g_date_time_get_second -g_date_time_get_microsecond -g_date_time_get_seconds - - -g_date_time_to_unix -g_date_time_to_timeval - - -g_date_time_get_utc_offset -g_date_time_get_timezone -g_date_time_get_timezone_abbreviation -g_date_time_is_daylight_savings - - -g_date_time_to_timezone -g_date_time_to_local -g_date_time_to_utc - - -g_date_time_format -g_date_time_format_iso8601 -
- -
-Hook Functions -hooks -GHookList -GHookFinalizeFunc -GHook -GHookFunc -GHookCheckFunc - - -g_hook_list_init -g_hook_list_invoke -g_hook_list_invoke_check -g_hook_list_marshal -GHookMarshaller -g_hook_list_marshal_check -GHookCheckMarshaller -g_hook_list_clear - - -g_hook_alloc -g_hook_append -g_hook_prepend -g_hook_insert_before -g_hook_insert_sorted -GHookCompareFunc -g_hook_compare_ids - - -g_hook_get -g_hook_find -GHookFindFunc -g_hook_find_data -g_hook_find_func -g_hook_find_func_data - - -g_hook_first_valid -g_hook_next_valid - -GHookFlagMask -G_HOOK_FLAGS -G_HOOK_FLAG_USER_SHIFT - - -G_HOOK -G_HOOK_IS_VALID -G_HOOK_ACTIVE -G_HOOK_IN_CALL -G_HOOK_IS_UNLINKED - - -g_hook_ref -g_hook_unref - -g_hook_free -g_hook_destroy -g_hook_destroy_link -
- -
-Miscellaneous Utility Functions -misc_utils -g_get_application_name -g_set_application_name -g_get_prgname -g_set_prgname -g_get_environ -g_environ_getenv -g_environ_setenv -g_environ_unsetenv -g_getenv -g_setenv -g_unsetenv -g_listenv -g_get_user_name -g_get_real_name -g_get_user_cache_dir -g_get_user_data_dir -g_get_user_config_dir -g_get_user_state_dir -g_get_user_runtime_dir -GUserDirectory -g_get_user_special_dir -g_get_system_data_dirs -g_get_system_config_dirs -g_reload_user_special_dirs_cache -g_get_os_info - - -G_OS_INFO_KEY_NAME -G_OS_INFO_KEY_PRETTY_NAME -G_OS_INFO_KEY_VERSION -G_OS_INFO_KEY_VERSION_CODENAME -G_OS_INFO_KEY_VERSION_ID -G_OS_INFO_KEY_ID -G_OS_INFO_KEY_HOME_URL -G_OS_INFO_KEY_DOCUMENTATION_URL -G_OS_INFO_KEY_SUPPORT_URL -G_OS_INFO_KEY_BUG_REPORT_URL -G_OS_INFO_KEY_PRIVACY_POLICY_URL - - -g_get_host_name -g_get_home_dir -g_get_tmp_dir -g_get_current_dir -g_basename -g_dirname -g_canonicalize_filename -g_path_is_absolute -g_path_skip_root -g_path_get_basename -g_path_get_dirname -g_build_filename -g_build_filenamev -g_build_filename_valist -g_build_path -g_build_pathv - - -g_format_size -GFormatSizeFlags -g_format_size_full -g_format_size_for_display - - -g_find_program_in_path - - -g_bit_nth_lsf -g_bit_nth_msf -g_bit_storage - - -g_spaced_primes_closest - - -g_atexit -g_abort - - -g_parse_debug_string -GDebugKey - - -GVoidFunc -GFreeFunc - - -g_qsort_with_data - - -g_nullify_pointer - - -G_NATIVE_ATEXIT -g_ATEXIT -g_win32_get_system_data_dirs_for_module -ATEXIT -g_bit_nth_lsf_impl -g_bit_nth_msf_impl -g_bit_storage_impl - -
- -
-Lexical Scanner -scanner -GScanner -GScannerConfig -g_scanner_new -g_scanner_destroy - - -g_scanner_input_file -g_scanner_sync_file_offset -g_scanner_input_text -g_scanner_peek_next_token -g_scanner_get_next_token -g_scanner_eof - - -g_scanner_cur_line -g_scanner_cur_position -g_scanner_cur_token -g_scanner_cur_value - - -g_scanner_set_scope -g_scanner_scope_add_symbol -g_scanner_scope_foreach_symbol -g_scanner_scope_lookup_symbol -g_scanner_scope_remove_symbol -g_scanner_add_symbol -g_scanner_remove_symbol -g_scanner_foreach_symbol - - -g_scanner_freeze_symbol_table -g_scanner_thaw_symbol_table -g_scanner_lookup_symbol - - -g_scanner_warn -g_scanner_error -g_scanner_unexp_token -GScannerMsgFunc - - -G_CSET_a_2_z -G_CSET_A_2_Z -G_CSET_DIGITS -G_CSET_LATINC -G_CSET_LATINS -GTokenType -GTokenValue -GErrorType - -
- -
-Key-value file parser -gkeyfile -GKeyFile -G_KEY_FILE_ERROR -GKeyFileError -GKeyFileFlags - - -g_key_file_new -g_key_file_free -g_key_file_ref -g_key_file_unref -g_key_file_set_list_separator -g_key_file_load_from_file -g_key_file_load_from_data -g_key_file_load_from_bytes -g_key_file_load_from_data_dirs -g_key_file_load_from_dirs -g_key_file_to_data -g_key_file_save_to_file -g_key_file_get_start_group -g_key_file_get_groups -g_key_file_get_keys -g_key_file_has_group -g_key_file_has_key - - -g_key_file_get_value -g_key_file_get_string -g_key_file_get_locale_string -g_key_file_get_locale_for_key -g_key_file_get_boolean -g_key_file_get_integer -g_key_file_get_int64 -g_key_file_get_uint64 -g_key_file_get_double -g_key_file_get_string_list -g_key_file_get_locale_string_list -g_key_file_get_boolean_list -g_key_file_get_integer_list -g_key_file_get_double_list -g_key_file_get_comment - - -g_key_file_set_value -g_key_file_set_string -g_key_file_set_locale_string -g_key_file_set_boolean -g_key_file_set_integer -g_key_file_set_int64 -g_key_file_set_uint64 -g_key_file_set_double -g_key_file_set_string_list -g_key_file_set_locale_string_list -g_key_file_set_boolean_list -g_key_file_set_integer_list -g_key_file_set_double_list -g_key_file_set_comment -g_key_file_remove_group -g_key_file_remove_key -g_key_file_remove_comment - - -G_KEY_FILE_DESKTOP_GROUP -G_KEY_FILE_DESKTOP_KEY_TYPE -G_KEY_FILE_DESKTOP_KEY_VERSION -G_KEY_FILE_DESKTOP_KEY_NAME -G_KEY_FILE_DESKTOP_KEY_GENERIC_NAME -G_KEY_FILE_DESKTOP_KEY_NO_DISPLAY -G_KEY_FILE_DESKTOP_KEY_COMMENT -G_KEY_FILE_DESKTOP_KEY_ICON -G_KEY_FILE_DESKTOP_KEY_HIDDEN -G_KEY_FILE_DESKTOP_KEY_ONLY_SHOW_IN -G_KEY_FILE_DESKTOP_KEY_NOT_SHOW_IN -G_KEY_FILE_DESKTOP_KEY_TRY_EXEC -G_KEY_FILE_DESKTOP_KEY_EXEC -G_KEY_FILE_DESKTOP_KEY_PATH -G_KEY_FILE_DESKTOP_KEY_TERMINAL -G_KEY_FILE_DESKTOP_KEY_MIME_TYPE -G_KEY_FILE_DESKTOP_KEY_CATEGORIES -G_KEY_FILE_DESKTOP_KEY_STARTUP_NOTIFY -G_KEY_FILE_DESKTOP_KEY_STARTUP_WM_CLASS -G_KEY_FILE_DESKTOP_KEY_URL -G_KEY_FILE_DESKTOP_KEY_ACTIONS -G_KEY_FILE_DESKTOP_KEY_DBUS_ACTIVATABLE -G_KEY_FILE_DESKTOP_TYPE_APPLICATION -G_KEY_FILE_DESKTOP_TYPE_LINK -G_KEY_FILE_DESKTOP_TYPE_DIRECTORY - - -g_key_file_error_quark -g_key_file_get_type -
- -
-Bookmark file parser -gbookmarkfile -GBookmarkFile -G_BOOKMARK_FILE_ERROR -GBookmarkFileError -g_bookmark_file_new -g_bookmark_file_copy -g_bookmark_file_free -g_bookmark_file_load_from_file -g_bookmark_file_load_from_data -g_bookmark_file_load_from_data_dirs -g_bookmark_file_to_data -g_bookmark_file_to_file -g_bookmark_file_has_item -g_bookmark_file_has_group -g_bookmark_file_has_application -g_bookmark_file_get_size -g_bookmark_file_get_uris G_GNUC_MALLOC - - -g_bookmark_file_get_title -g_bookmark_file_get_description -g_bookmark_file_get_mime_type -g_bookmark_file_get_is_private -g_bookmark_file_get_icon -g_bookmark_file_get_added -g_bookmark_file_get_added_date_time -g_bookmark_file_get_modified -g_bookmark_file_get_modified_date_time -g_bookmark_file_get_visited -g_bookmark_file_get_visited_date_time -g_bookmark_file_get_groups -g_bookmark_file_get_applications -g_bookmark_file_get_app_info -g_bookmark_file_get_application_info - - -g_bookmark_file_set_title -g_bookmark_file_set_description -g_bookmark_file_set_mime_type -g_bookmark_file_set_is_private -g_bookmark_file_set_icon -g_bookmark_file_set_added -g_bookmark_file_set_added_date_time -g_bookmark_file_set_groups -g_bookmark_file_set_modified -g_bookmark_file_set_modified_date_time -g_bookmark_file_set_visited -g_bookmark_file_set_visited_date_time -g_bookmark_file_set_app_info -g_bookmark_file_set_application_info -g_bookmark_file_add_group -g_bookmark_file_add_application -g_bookmark_file_remove_group -g_bookmark_file_remove_application -g_bookmark_file_remove_item -g_bookmark_file_move_item - - -g_bookmark_file_error_quark -
- -
-Dynamic Loading of Modules -modules -gmodule.h -GModule -GModuleError -G_MODULE_ERROR -g_module_supported -g_module_build_path -g_module_open -g_module_open_full -GModuleFlags -g_module_symbol -g_module_name -g_module_make_resident -g_module_close -g_module_error - -GModuleCheckInit -GModuleUnload -G_MODULE_SUFFIX -G_MODULE_EXPORT -G_MODULE_IMPORT - -g_module_error_quark -
- -
-Automatic String Completion -completion -GCompletion -g_completion_new -GCompletionFunc -g_completion_add_items -g_completion_remove_items -g_completion_clear_items -g_completion_complete -g_completion_complete_utf8 -g_completion_set_compare -GCompletionStrncmpFunc -g_completion_free -
- -
-Windows Compatibility Functions -windows -MAXPATHLEN -GWin32OSType - -g_win32_check_windows_version -g_win32_get_command_line -g_win32_error_message -g_win32_getlocale -g_win32_get_package_installation_directory -g_win32_get_package_installation_directory_of_module -g_win32_get_package_installation_subdirectory -g_win32_get_windows_version -g_win32_locale_filename_from_utf8 -G_WIN32_DLLMAIN_FOR_DLL_NAME -G_WIN32_HAVE_WIDECHAR_API -G_WIN32_IS_NT_BASED - - -g_win32_ftruncate - -
- -
-UNIX-specific utilities and integration -gunix -G_UNIX_ERROR -g_unix_open_pipe -g_unix_set_fd_nonblocking - - -g_unix_signal_add -g_unix_signal_add_full -g_unix_signal_source_new - - -GUnixFDSourceFunc -g_unix_fd_add -g_unix_fd_add_full -g_unix_fd_source_new - - -g_unix_get_passwd_entry - - -g_unix_error_quark -
- -# Data Structures - -
-Memory Slices -memory_slices -g_slice_alloc -g_slice_alloc0 -g_slice_copy -g_slice_free1 -g_slice_free_chain_with_offset - - -g_slice_new -g_slice_new0 -g_slice_dup -g_slice_free -g_slice_free_chain - - -GSliceConfig -g_slice_set_config -g_slice_get_config -g_slice_get_config_state -g_slice_debug_tree_statistics -
- -
-Doubly-Linked Lists -linked_lists_double -GList - - -g_list_append -g_list_prepend -g_list_insert -g_list_insert_before -g_list_insert_before_link -g_list_insert_sorted -g_list_remove -g_list_remove_link -g_list_delete_link -g_list_remove_all -g_list_free -g_list_free_full -g_clear_list - - -g_list_alloc -g_list_free_1 -g_list_free1 - - -g_list_length -g_list_copy -g_list_copy_deep -g_list_reverse -g_list_sort -GCompareFunc -g_list_insert_sorted_with_data -g_list_sort_with_data -GCompareDataFunc -g_list_concat -g_list_foreach -GFunc - - -g_list_first -g_list_last -g_list_previous -g_list_next -g_list_nth -g_list_nth_data -g_list_nth_prev - - -g_list_find -g_list_find_custom -g_list_position -g_list_index -
- -
-Singly-Linked Lists -linked_lists_single -GSList - - -g_slist_alloc -g_slist_append -g_slist_prepend -g_slist_insert -g_slist_insert_before -g_slist_insert_sorted -g_slist_remove -g_slist_remove_link -g_slist_delete_link -g_slist_remove_all -g_slist_free -g_slist_free_full -g_slist_free_1 -g_slist_free1 -g_clear_slist - - -g_slist_length -g_slist_copy -g_slist_copy_deep -g_slist_reverse -g_slist_insert_sorted_with_data -g_slist_sort -g_slist_sort_with_data -g_slist_concat -g_slist_foreach - - -g_slist_last -g_slist_next -g_slist_nth -g_slist_nth_data - - -g_slist_find -g_slist_find_custom -g_slist_position -g_slist_index -
- -
-Double-ended Queues -queue - -GQueue -g_queue_new -g_queue_free -g_queue_free_full -G_QUEUE_INIT -g_queue_init -g_queue_clear -g_queue_clear_full -g_queue_is_empty -g_queue_get_length -g_queue_reverse -g_queue_copy -g_queue_foreach -g_queue_find -g_queue_find_custom -g_queue_sort -g_queue_push_head -g_queue_push_tail -g_queue_push_nth -g_queue_pop_head -g_queue_pop_tail -g_queue_pop_nth -g_queue_peek_head -g_queue_peek_tail -g_queue_peek_nth -g_queue_index -g_queue_remove -g_queue_remove_all -g_queue_insert_before -g_queue_insert_before_link -g_queue_insert_after -g_queue_insert_after_link -g_queue_insert_sorted -g_queue_push_head_link -g_queue_push_tail_link -g_queue_push_nth_link -g_queue_pop_head_link -g_queue_pop_tail_link -g_queue_pop_nth_link -g_queue_peek_head_link -g_queue_peek_tail_link -g_queue_peek_nth_link -g_queue_link_index -g_queue_unlink -g_queue_delete_link -
- -
-Sequences -sequence - -GSequence -GSequenceIter -GSequenceIterCompareFunc - - -g_sequence_new -g_sequence_free -g_sequence_get_length -g_sequence_is_empty -g_sequence_foreach -g_sequence_foreach_range -g_sequence_sort -g_sequence_sort_iter - - -g_sequence_get_begin_iter -g_sequence_get_end_iter -g_sequence_get_iter_at_pos -g_sequence_append -g_sequence_prepend -g_sequence_insert_before -g_sequence_move -g_sequence_swap -g_sequence_insert_sorted -g_sequence_insert_sorted_iter -g_sequence_sort_changed -g_sequence_sort_changed_iter -g_sequence_remove -g_sequence_remove_range -g_sequence_move_range -g_sequence_search -g_sequence_search_iter -g_sequence_lookup -g_sequence_lookup_iter - - -g_sequence_get -g_sequence_set - - -g_sequence_iter_is_begin -g_sequence_iter_is_end -g_sequence_iter_next -g_sequence_iter_prev -g_sequence_iter_get_position -g_sequence_iter_move -g_sequence_iter_get_sequence - - -g_sequence_iter_compare -g_sequence_range_get_midpoint -
- -
-Trash Stacks -trash_stack -GTrashStack - -g_trash_stack_push -g_trash_stack_pop -g_trash_stack_peek -g_trash_stack_height -
- -
-Hash Tables -hash_tables -GHashTable -g_hash_table_new -g_hash_table_new_full -g_hash_table_new_similar -GHashFunc -GEqualFunc -GEqualFuncFull -g_hash_table_insert -g_hash_table_replace -g_hash_table_add -g_hash_table_contains -g_hash_table_size -g_hash_table_lookup -g_hash_table_lookup_extended -g_hash_table_foreach -g_hash_table_find -GHFunc -g_hash_table_remove -g_hash_table_steal -g_hash_table_steal_extended -g_hash_table_steal_all_keys -g_hash_table_steal_all_values -g_hash_table_foreach_remove -g_hash_table_foreach_steal -g_hash_table_remove_all -g_hash_table_steal_all -g_hash_table_get_keys -g_hash_table_get_values -g_hash_table_get_values_as_ptr_array -g_hash_table_get_keys_as_array -g_hash_table_get_keys_as_ptr_array -GHRFunc -g_hash_table_freeze -g_hash_table_thaw -g_hash_table_destroy -g_hash_table_ref -g_hash_table_unref -GHashTableIter -g_hash_table_iter_init -g_hash_table_iter_next -g_hash_table_iter_get_hash_table -g_hash_table_iter_replace -g_hash_table_iter_remove -g_hash_table_iter_steal - - -g_direct_equal -g_direct_hash -g_int_equal -g_int_hash -g_int64_equal -g_int64_hash -g_double_equal -g_double_hash -g_str_equal -g_str_hash - -
- -
-Strings -strings -GString -g_string_new -g_string_new_take -g_string_new_len -g_string_sized_new -g_string_assign -g_string_sprintf -g_string_sprintfa -g_string_vprintf -g_string_append_vprintf -g_string_printf -g_string_append_printf -g_string_append -g_string_append_c -g_string_append_unichar -g_string_append_len -g_string_append_uri_escaped -g_string_prepend -g_string_prepend_c -g_string_prepend_unichar -g_string_prepend_len -g_string_insert -g_string_insert_c -g_string_insert_unichar -g_string_insert_len -g_string_overwrite -g_string_overwrite_len -g_string_replace -g_string_erase -g_string_truncate -g_string_set_size -g_string_free -g_string_free_to_bytes -g_string_free_and_steal - - -g_string_up -g_string_down - - -g_string_hash -g_string_equal - - -g_string_append_c_inline -g_autoptr_cleanup_gstring_free -
- -
-String Chunks -string_chunks -GStringChunk -g_string_chunk_new -g_string_chunk_insert -g_string_chunk_insert_const -g_string_chunk_insert_len -g_string_chunk_clear -g_string_chunk_free - -
- -
-Arrays -arrays -GArray -g_array_new -g_array_new_take -g_array_new_take_zero_terminated -g_array_steal -g_array_sized_new -g_array_copy -g_array_ref -g_array_unref -g_array_get_element_size -g_array_append_val -g_array_append_vals -g_array_prepend_val -g_array_prepend_vals -g_array_insert_val -g_array_insert_vals -g_array_remove_index -g_array_remove_index_fast -g_array_remove_range -g_array_sort -g_array_sort_with_data -g_array_binary_search -g_array_index -g_array_set_size -g_array_set_clear_func -g_array_free -
- -
-Pointer Arrays -arrays_pointer -GPtrArray -g_ptr_array_new -g_ptr_array_steal -g_ptr_array_sized_new -g_ptr_array_new_with_free_func -g_ptr_array_copy -g_ptr_array_new_full -g_ptr_array_new_null_terminated -g_ptr_array_new_take -g_ptr_array_new_take_null_terminated -g_ptr_array_new_from_array -g_ptr_array_new_from_null_terminated_array -g_ptr_array_set_free_func -g_ptr_array_is_null_terminated -g_ptr_array_ref -g_ptr_array_unref -g_ptr_array_add -g_ptr_array_extend -g_ptr_array_extend_and_steal -g_ptr_array_insert -g_ptr_array_remove -g_ptr_array_remove_index -g_ptr_array_remove_fast -g_ptr_array_remove_index_fast -g_ptr_array_remove_range -g_ptr_array_steal_index -g_ptr_array_steal_index_fast -g_ptr_array_sort -g_ptr_array_sort_with_data -g_ptr_array_sort_values -g_ptr_array_sort_values_with_data -g_ptr_array_set_size -g_ptr_array_index -g_ptr_array_free -g_ptr_array_foreach -g_ptr_array_find -g_ptr_array_find_with_equal_func - -
- -
-Byte Arrays -arrays_byte - -GByteArray -g_byte_array_new -g_byte_array_steal -g_byte_array_new_take -g_byte_array_sized_new -g_byte_array_ref -g_byte_array_unref -g_byte_array_append -g_byte_array_prepend -g_byte_array_remove_index -g_byte_array_remove_index_fast -g_byte_array_remove_range -g_byte_array_sort -g_byte_array_sort_with_data -g_byte_array_set_size -g_byte_array_free -g_byte_array_free_to_bytes - - -GBytes -g_bytes_new -g_bytes_new_take -g_bytes_new_static -g_bytes_new_with_free_func -g_bytes_new_from_bytes -g_bytes_get_data -g_bytes_get_region -g_bytes_get_size -g_bytes_hash -g_bytes_equal -g_bytes_compare -g_bytes_ref -g_bytes_unref -g_bytes_unref_to_data -g_bytes_unref_to_array - - -g_bytes_get_type -
- -
-Balanced Binary Trees -trees-binary -GTree -GTreeNode -g_tree_new -g_tree_ref -g_tree_unref -g_tree_new_with_data -g_tree_new_full -g_tree_node_first -g_tree_node_last -g_tree_node_previous -g_tree_node_next -g_tree_insert_node -g_tree_insert -g_tree_replace_node -g_tree_replace -g_tree_node_key -g_tree_node_value -g_tree_nnodes -g_tree_height -g_tree_lookup_node -g_tree_lookup -g_tree_lookup_extended -g_tree_foreach_node -g_tree_foreach -g_tree_traverse -GTraverseFunc -GTraverseNodeFunc -g_tree_search_node -g_tree_search -g_tree_lower_bound -g_tree_upper_bound -g_tree_remove -g_tree_steal -g_tree_remove_all -g_tree_destroy -
- -
-N-ary Trees -trees-nary -GNode -g_node_new -g_node_copy -GCopyFunc -g_node_copy_deep - - -g_node_insert -g_node_insert_before -g_node_insert_after -g_node_append -g_node_prepend - - -g_node_insert_data -g_node_insert_data_after -g_node_insert_data_before -g_node_append_data -g_node_prepend_data - - -g_node_reverse_children -g_node_traverse -GTraverseType -GTraverseFlags -GNodeTraverseFunc -g_node_children_foreach -GNodeForeachFunc - - -g_node_get_root -g_node_find -g_node_find_child -g_node_child_index -g_node_child_position -g_node_first_child -g_node_last_child -g_node_nth_child -g_node_first_sibling -g_node_next_sibling -g_node_prev_sibling -g_node_last_sibling - - -G_NODE_IS_LEAF -G_NODE_IS_ROOT -g_node_depth -g_node_n_nodes -g_node_n_children -g_node_is_ancestor -g_node_max_height - - -g_node_unlink -g_node_destroy -
- - -
-Quarks -quarks -GQuark -G_DEFINE_QUARK -g_quark_from_string -g_quark_from_static_string -g_quark_to_string -g_quark_try_string -g_intern_string -g_intern_static_string -
- -
-Keyed Data Lists -datalist -GData -g_datalist_init - - -g_datalist_id_set_data -g_datalist_id_set_data_full -g_datalist_id_get_data -g_datalist_id_remove_data -g_datalist_id_remove_no_notify -g_datalist_id_remove_multiple -GDuplicateFunc -g_datalist_id_dup_data -g_datalist_id_replace_data - - -g_datalist_set_data -g_datalist_set_data_full -g_datalist_get_data -g_datalist_remove_data -g_datalist_remove_no_notify - - -g_datalist_foreach -g_datalist_clear -g_datalist_set_flags -g_datalist_unset_flags -g_datalist_get_flags -G_DATALIST_FLAGS_MASK -
- - -
-Datasets -datasets -g_dataset_id_set_data -g_dataset_id_set_data_full -GDestroyNotify -g_dataset_id_get_data -g_dataset_id_remove_data -g_dataset_id_remove_no_notify - - -g_dataset_set_data -g_dataset_set_data_full -g_dataset_get_data -g_dataset_remove_data -g_dataset_remove_no_notify - - -g_dataset_foreach -GDataForeachFunc -g_dataset_destroy - -
- -
-Relations and Tuples -relations -GRelation -g_relation_new -g_relation_index -g_relation_insert -g_relation_exists -g_relation_count -g_relation_select -g_relation_delete -g_relation_destroy - - -g_relation_print - - -GTuples -g_tuples_destroy -g_tuples_index -
- -
-Caches -caches -GCache -g_cache_new -g_cache_insert -g_cache_remove -g_cache_destroy - - -g_cache_key_foreach -g_cache_value_foreach - - -GCacheDestroyFunc -GCacheDupFunc -GCacheNewFunc -
- -
-Random Numbers -random_numbers -GRand -g_rand_new_with_seed -g_rand_new_with_seed_array -g_rand_new -g_rand_copy -g_rand_free -g_rand_set_seed -g_rand_set_seed_array -g_rand_boolean -g_rand_int -g_rand_int_range -g_rand_double -g_rand_double_range -g_random_set_seed -g_random_boolean -g_random_int -g_random_int_range -g_random_double -g_random_double_range -
- -
-Character Set Conversion -conversions -g_convert -g_convert_with_fallback -GIConv -g_convert_with_iconv -G_CONVERT_ERROR -g_iconv_open -g_iconv -g_iconv_close -g_locale_to_utf8 -g_filename_to_utf8 -g_filename_from_utf8 -g_get_filename_charsets -g_filename_display_name -g_filename_display_basename -g_locale_from_utf8 -GConvertError - - -g_get_charset -g_get_codeset -g_get_console_charset - - -g_convert_error_quark -
- -
-Unicode Manipulation -unicode -gunichar -gunichar2 - - -g_unichar_validate -g_unichar_isalnum -g_unichar_isalpha -g_unichar_iscntrl -g_unichar_isdefined -g_unichar_isdigit -g_unichar_isgraph -g_unichar_islower -g_unichar_ismark -g_unichar_isprint -g_unichar_ispunct -g_unichar_isspace -g_unichar_istitle -g_unichar_isupper -g_unichar_isxdigit -g_unichar_iswide -g_unichar_iswide_cjk -g_unichar_iszerowidth -g_unichar_toupper -g_unichar_tolower -g_unichar_totitle -g_unichar_digit_value -g_unichar_xdigit_value -g_unichar_compose -g_unichar_decompose -g_unichar_fully_decompose -G_UNICHAR_MAX_DECOMPOSITION_LENGTH -GUnicodeType -G_UNICODE_COMBINING_MARK -g_unichar_type -GUnicodeBreakType -g_unichar_break_type -g_unichar_combining_class -g_unicode_canonical_ordering -g_unicode_canonical_decomposition -g_unichar_get_mirror_char -GUnicodeScript -g_unichar_get_script -g_unicode_script_from_iso15924 -g_unicode_script_to_iso15924 - - -g_utf8_next_char -g_utf8_get_char -g_utf8_get_char_validated -g_utf8_offset_to_pointer -g_utf8_pointer_to_offset -g_utf8_prev_char -g_utf8_find_next_char -g_utf8_find_prev_char -g_utf8_strlen -g_utf8_strncpy -g_utf8_strchr -g_utf8_strrchr -g_utf8_strreverse -g_utf8_substring -g_utf8_truncate_middle -g_utf8_validate -g_utf8_validate_len -g_utf8_make_valid - - -g_utf8_strup -g_utf8_strdown -g_utf8_casefold -g_utf8_normalize -GNormalizeMode -g_utf8_collate -g_utf8_collate_key -g_utf8_collate_key_for_filename - - -g_utf8_to_utf16 -g_utf8_to_ucs4 -g_utf8_to_ucs4_fast -g_utf16_to_ucs4 -g_utf16_to_utf8 -g_ucs4_to_utf16 -g_ucs4_to_utf8 -g_unichar_to_utf8 - - -g_utf8_skip -
- -
-I18N -i18n -glib.h,glib/gi18n.h -_ -Q_ -C_ -N_ -NC_ -g_dgettext -g_dcgettext -g_dngettext -g_dpgettext -g_dpgettext2 -g_strip_context - -g_get_language_names -g_get_locale_variants -
- -
-Base64 Encoding -base64 -g_base64_encode_step -g_base64_encode_close -g_base64_encode -g_base64_decode_step -g_base64_decode -g_base64_decode_inplace -
- -
-URI Functions -guri -GUri -g_uri_ref -g_uri_unref - -GUriFlags -g_uri_split -g_uri_split_with_user -g_uri_split_network -g_uri_is_valid -g_uri_join -g_uri_join_with_user -g_uri_parse -g_uri_parse_relative -g_uri_resolve_relative -g_uri_build -g_uri_build_with_user -g_uri_peek_scheme -g_uri_parse_scheme - -GUriHideFlags -g_uri_to_string -g_uri_to_string_partial - -g_uri_get_scheme -g_uri_get_userinfo -g_uri_get_user -g_uri_get_password -g_uri_get_auth_params -g_uri_get_host -g_uri_get_port -g_uri_get_path -g_uri_get_query -g_uri_get_fragment -g_uri_get_flags - -GUriParamsIter -GUriParamsFlags -g_uri_params_iter_init -g_uri_params_iter_next -g_uri_parse_params - -G_URI_RESERVED_CHARS_ALLOWED_IN_PATH -G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT -G_URI_RESERVED_CHARS_ALLOWED_IN_USERINFO -G_URI_RESERVED_CHARS_GENERIC_DELIMITERS -G_URI_RESERVED_CHARS_SUBCOMPONENT_DELIMITERS -g_uri_escape_string -g_uri_unescape_string -g_uri_escape_bytes -g_uri_unescape_bytes -g_uri_unescape_segment - -g_uri_list_extract_uris -g_filename_from_uri -g_filename_to_uri - -G_URI_ERROR -GUriError - -g_uri_error_quark -
- -
-Data Checksums -checksum -GChecksumType -g_checksum_type_get_length -GChecksum -g_checksum_new -g_checksum_copy -g_checksum_free -g_checksum_reset -g_checksum_update -g_checksum_get_string -g_checksum_get_digest - -g_compute_checksum_for_data -g_compute_checksum_for_string -g_compute_checksum_for_bytes -
- -
-Data HMACs -hmac -GHmac -g_hmac_new -g_hmac_copy -g_hmac_ref -g_hmac_unref -g_hmac_update -g_hmac_get_string -g_hmac_get_digest - -g_compute_hmac_for_data -g_compute_hmac_for_string -g_compute_hmac_for_bytes -
- -
-Testing -testing -G_TEST_OPTION_ISOLATE_DIRS -g_test_minimized_result -g_test_maximized_result -g_test_init -g_test_initialized -g_test_quick -g_test_slow -g_test_thorough -g_test_perf -g_test_verbose -g_test_undefined -g_test_quiet -g_test_subprocess -g_test_run -GTestFunc -g_test_add_func -GTestDataFunc -g_test_add_data_func -g_test_add_data_func_full -g_test_add -g_test_get_path - -GTestFileType -g_test_build_filename -g_test_get_filename -g_test_get_dir - -g_test_fail -g_test_fail_printf -g_test_skip -g_test_skip_printf -g_test_incomplete -g_test_incomplete_printf -g_test_failed -g_test_message -g_test_bug_base -g_test_bug -g_test_summary -GTestLogFatalFunc -g_test_log_set_fatal_handler - -g_test_timer_start -g_test_timer_elapsed -g_test_timer_last - -g_test_queue_free -g_test_queue_destroy -g_test_queue_unref - -g_test_expect_message -g_test_assert_expected_messages - -GTestTrapFlags -GTestSubprocessFlags -g_test_trap_subprocess -g_test_trap_has_passed -g_test_trap_reached_timeout -g_test_trap_assert_passed -g_test_trap_assert_failed -g_test_trap_assert_stdout -g_test_trap_assert_stdout_unmatched -g_test_trap_assert_stderr -g_test_trap_assert_stderr_unmatched -g_test_trap_fork -g_test_disable_crash_reporting - -g_test_rand_bit -g_test_rand_int -g_test_rand_int_range -g_test_rand_double -g_test_rand_double_range - -g_assert -g_assert_not_reached - -g_assert_cmpstr -g_assert_cmpstrv -g_assert_cmpint -g_assert_cmpuint -g_assert_cmphex -g_assert_cmpfloat -g_assert_cmpfloat_with_epsilon -g_assert_cmpmem -g_assert_cmpvariant -g_assert_no_error -g_assert_error -g_assert_true -g_assert_false -g_assert_null -g_assert_nonnull -g_assert_no_errno -g_test_set_nonfatal_assertions - -GTestCase -GTestSuite -GTestFixtureFunc -g_test_create_case -g_test_create_suite -g_test_get_root -g_test_suite_add -g_test_suite_add_suite -g_test_run_suite -g_test_case_free -g_test_suite_free - - -g_test_trap_assertions -g_assertion_message -g_assertion_message_expr -g_assertion_message_cmpstr -g_assertion_message_cmpint -g_assertion_message_cmpnum -g_assertion_message_error -g_test_assert_expected_messages_internal - -g_test_config_vars - -g_test_add_vtable -GTestConfig -GTestLogType -GTestLogMsg -GTestLogBuffer -GTestResult - -g_test_log_type_name -g_test_log_buffer_new -g_test_log_buffer_free -g_test_log_buffer_push -g_test_log_buffer_pop -g_test_log_msg_free -
- -
-GVariantType -gvarianttype -GVariantType -G_VARIANT_TYPE_BOOLEAN -G_VARIANT_TYPE_BYTE -G_VARIANT_TYPE_INT16 -G_VARIANT_TYPE_UINT16 -G_VARIANT_TYPE_INT32 -G_VARIANT_TYPE_UINT32 -G_VARIANT_TYPE_INT64 -G_VARIANT_TYPE_UINT64 -G_VARIANT_TYPE_HANDLE -G_VARIANT_TYPE_DOUBLE -G_VARIANT_TYPE_STRING -G_VARIANT_TYPE_OBJECT_PATH -G_VARIANT_TYPE_SIGNATURE -G_VARIANT_TYPE_VARIANT -G_VARIANT_TYPE_ANY -G_VARIANT_TYPE_BASIC -G_VARIANT_TYPE_MAYBE -G_VARIANT_TYPE_ARRAY -G_VARIANT_TYPE_TUPLE -G_VARIANT_TYPE_UNIT -G_VARIANT_TYPE_DICT_ENTRY -G_VARIANT_TYPE_DICTIONARY -G_VARIANT_TYPE_STRING_ARRAY -G_VARIANT_TYPE_OBJECT_PATH_ARRAY -G_VARIANT_TYPE_BYTESTRING -G_VARIANT_TYPE_BYTESTRING_ARRAY -G_VARIANT_TYPE_VARDICT - - -G_VARIANT_TYPE -g_variant_type_free -g_variant_type_copy -g_variant_type_new - - -g_variant_type_string_is_valid -g_variant_type_string_scan -g_variant_type_get_string_length -g_variant_type_peek_string -g_variant_type_dup_string - - -g_variant_type_is_definite -g_variant_type_is_container -g_variant_type_is_basic -g_variant_type_is_maybe -g_variant_type_is_array -g_variant_type_is_tuple -g_variant_type_is_dict_entry -g_variant_type_is_variant - - -g_variant_type_hash -g_variant_type_equal -g_variant_type_is_subtype_of - - -g_variant_type_new_maybe -g_variant_type_new_array -g_variant_type_new_tuple -g_variant_type_new_dict_entry - - -g_variant_type_element -g_variant_type_n_items -g_variant_type_first -g_variant_type_next -g_variant_type_key -g_variant_type_value -
- -
-GVariant -gvariant -GVariant -g_variant_unref -g_variant_ref -g_variant_ref_sink -g_variant_is_floating -g_variant_take_ref -g_variant_get_type -g_variant_get_type_string -g_variant_is_of_type -g_variant_is_container -g_variant_compare - - -g_variant_classify -GVariantClass - - -g_variant_check_format_string -g_variant_get -g_variant_get_va -g_variant_new -g_variant_new_va - - -g_variant_new_boolean -g_variant_new_byte -g_variant_new_int16 -g_variant_new_uint16 -g_variant_new_int32 -g_variant_new_uint32 -g_variant_new_int64 -g_variant_new_uint64 -g_variant_new_handle -g_variant_new_double -g_variant_new_string -g_variant_new_take_string -g_variant_new_printf -g_variant_new_object_path -g_variant_is_object_path -g_variant_new_signature -g_variant_is_signature -g_variant_new_variant -g_variant_new_strv -g_variant_new_objv -g_variant_new_bytestring -g_variant_new_bytestring_array - - -g_variant_get_boolean -g_variant_get_byte -g_variant_get_int16 -g_variant_get_uint16 -g_variant_get_int32 -g_variant_get_uint32 -g_variant_get_int64 -g_variant_get_uint64 -g_variant_get_handle -g_variant_get_double -g_variant_get_string -g_variant_dup_string -g_variant_get_variant -g_variant_get_strv -g_variant_dup_strv -g_variant_get_objv -g_variant_dup_objv -g_variant_get_bytestring -g_variant_dup_bytestring -g_variant_get_bytestring_array -g_variant_dup_bytestring_array - - -g_variant_new_maybe -g_variant_new_array -g_variant_new_tuple -g_variant_new_dict_entry -g_variant_new_fixed_array - - -g_variant_get_maybe -g_variant_n_children -g_variant_get_child_value -g_variant_get_child -g_variant_lookup_value -g_variant_lookup -g_variant_get_fixed_array - - -g_variant_get_size -g_variant_get_data -g_variant_get_data_as_bytes -g_variant_store -g_variant_new_from_data -g_variant_new_from_bytes -g_variant_byteswap -g_variant_get_normal_form -g_variant_is_normal_form - - -g_variant_hash -g_variant_equal - - -g_variant_print -g_variant_print_string - - -GVariantIter -g_variant_iter_copy -g_variant_iter_free -g_variant_iter_init -g_variant_iter_n_children -g_variant_iter_new -g_variant_iter_next_value -g_variant_iter_next -g_variant_iter_loop - - -G_VARIANT_BUILDER_INIT -GVariantBuilder -g_variant_builder_unref -g_variant_builder_ref -g_variant_builder_new -g_variant_builder_init -g_variant_builder_clear -g_variant_builder_add_value -g_variant_builder_add -g_variant_builder_add_parsed -g_variant_builder_end -g_variant_builder_open -g_variant_builder_close - - -G_VARIANT_DICT_INIT -GVariantDict -g_variant_dict_unref -g_variant_dict_ref -g_variant_dict_new -g_variant_dict_init -g_variant_dict_clear -g_variant_dict_contains -g_variant_dict_lookup -g_variant_dict_lookup_value -g_variant_dict_insert -g_variant_dict_insert_value -g_variant_dict_remove -g_variant_dict_end - - -GVariantParseError -G_VARIANT_PARSE_ERROR -g_variant_parse -g_variant_new_parsed_va -g_variant_new_parsed -g_variant_parse_error_print_context - - -g_variant_parse_error_quark -g_variant_parser_get_error_quark -g_variant_type_checked_ -g_variant_type_string_get_depth_ -
- - -
-ghostutils -Hostname Utilities -g_hostname_to_ascii -g_hostname_to_unicode - -g_hostname_is_non_ascii -g_hostname_is_ascii_encoded - -g_hostname_is_ip_address -
- -
-uuid -GUuid -g_uuid_string_is_valid -g_uuid_string_random -
- -
-refcount -grefcount -g_ref_count_init -g_ref_count_inc -g_ref_count_dec -g_ref_count_compare -G_REF_COUNT_INIT - -gatomicrefcount -g_atomic_ref_count_init -g_atomic_ref_count_inc -g_atomic_ref_count_dec -g_atomic_ref_count_compare -G_ATOMIC_REF_COUNT_INIT -
- -
-rcbox -g_rc_box_alloc -g_rc_box_alloc0 -g_rc_box_new -g_rc_box_new0 -g_rc_box_dup -g_rc_box_acquire -g_rc_box_release -g_rc_box_release_full -g_rc_box_get_size -
- -
-arcbox -g_atomic_rc_box_alloc -g_atomic_rc_box_alloc0 -g_atomic_rc_box_new -g_atomic_rc_box_new0 -g_atomic_rc_box_dup -g_atomic_rc_box_acquire -g_atomic_rc_box_release -g_atomic_rc_box_release_full -g_atomic_rc_box_get_size -
- -
-refstring -GRefString -g_ref_string_new -g_ref_string_new_intern -g_ref_string_new_len -g_ref_string_acquire -g_ref_string_release -g_ref_string_length -
- -
-gpathbuf -GPathBuf -G_PATH_BUF_INIT -g_path_buf_new -g_path_buf_new_from_path -g_path_buf_init -g_path_buf_init_from_path -g_path_buf_clear -g_path_buf_clear_to_path -g_path_buf_free -g_path_buf_free_to_path -g_path_buf_push -g_path_buf_pop -g_path_buf_set_filename -g_path_buf_set_extension -g_path_buf_to_path -g_path_buf_copy -g_path_buf_equal -
diff --git a/docs/reference/glib/glib.toml.in b/docs/reference/glib/glib.toml.in new file mode 100644 index 0000000..9691479 --- /dev/null +++ b/docs/reference/glib/glib.toml.in @@ -0,0 +1,125 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2023 Matthias Clasen +# Copyright 2023 Philip Withnall + +[library] +name = "GLib" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/glib/" +repository_url = "https://gitlab.gnome.org/GNOME/glib.git" +website_url = "https://www.gtk.org" +docs_url = "https://docs.gtk.org/glib/" +authors = "GLib Development Team" +license = "LGPL-2.1-or-later" +description = "GLib is a general-purpose, portable utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, and so on." +related = [ "GModule-2.0", "GObject-2.0", "Gio-2.0" ] +devhelp = true +search_index = true + + [related."GModule-2.0"] + name = "GModule" + description = "Portable API for dynamically loading modules" + docs_url = "https://docs.gtk.org/gmodule/" + + [related."GObject-2.0"] + name = "GObject" + description = "The base type system library" + docs_url = "https://docs.gtk.org/gobject/" + + [related."Gio-2.0"] + name = "GIO" + description = "GObject Interfaces and Objects, Networking, IPC, and I/O" + docs_url = "https://docs.gtk.org/gio/" + +[theme] +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +[extra] +urlmap_file = "urlmap.js" +# The same order will be used when generating the index +content_files = [ + "building.md", + "compiling.md", + "cross-compiling.md", + "running.md", + "programming.md", + "resources.md", + + "gvariant-format-strings.md", + "gvariant-text-format.md", + + "character-set.md", + "i18n.md", + + "string-utils.md", + + "types.md", + "macros.md", + "conversion-macros.md", + "auto-cleanup.md", + + "memory.md", + "memory-slices.md", + "error-reporting.md", + "logging.md", + "warnings.md", + "file-utils.md", + "host-utils.md", + "misc-utils.md", + "main-loop.md", + "reference-counting.md", + "testing.md", + "atomic.md", + "checked-math.md", + "threads.md", + "spawn.md", + "unix.md", + "windows.md", + "random.md", + "numerical.md", + "markup.md", + "base64.md", + "goption.md", + "data-structures.md", + "datalist-and-dataset.md", + "shell.md", + "uuid.md", + "unicode.md", + "version.md", + + "threads-deprecated.md", +] +content_images = [ + "file-name-encodings.png", + "mainloop-states.gif", + "Sorted_binary_tree_breadth-first_traversal.svg", + "Sorted_binary_tree_inorder.svg", + "Sorted_binary_tree_postorder.svg", + "Sorted_binary_tree_preorder.svg", +] + +[[object]] +pattern = "DEPRECATED_IN_2_*" +hidden = true + +[[object]] +pattern = "DEPRECATED_MACRO_IN_2_*" +hidden = true + +[[object]] +pattern = "DEPRECATED_ENUMERATOR_IN_2_*" +hidden = true + +[[object]] +pattern = "DEPRECATED_TYPE_IN_2_*" +hidden = true + +[[object]] +name = "test_assert_expected_messages_internal" +hidden = true + +[[object]] +pattern = "macro__has_*" +hidden = true diff --git a/docs/reference/glib/goption.md b/docs/reference/glib/goption.md new file mode 100644 index 0000000..292a1d3 --- /dev/null +++ b/docs/reference/glib/goption.md @@ -0,0 +1,149 @@ +Title: Commandline Option Parser + +# Commandline Option Parser + +The GOption commandline parser is intended to be a simpler replacement +for the popt library. It supports short and long commandline options, +as shown in the following example: + + testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2 + +The example demonstrates a number of features of the GOption commandline parser: + + - Options can be single letters, prefixed by a single dash. + - Multiple short options can be grouped behind a single dash. + - Long options are prefixed by two consecutive dashes. + - Options can have an extra argument, which can be a number, a string or + a filename. For long options, the extra argument can be appended with + an equals sign after the option name, which is useful if the extra + argument starts with a dash, which would otherwise cause it to be + interpreted as another option. + - Non-option arguments are returned to the application as rest arguments. + - An argument consisting solely of two dashes turns off further parsing, + any remaining arguments (even those starting with a dash) are returned + to the application as rest arguments. + +Another important feature of GOption is that it can automatically +generate nicely formatted help output. Unless it is explicitly turned +off with [method@GLib.OptionContext.set_help_enabled], GOption will recognize +the `--help`, `-?`, `--help-all` and `--help-groupname` options (where `groupname` +is the name of a [struct@GLib.OptionGroup]) and write a text similar to the one shown +in the following example to stdout. + + Usage: + testtreemodel [OPTION...] - test tree model performance + + Help Options: + -h, --help Show help options + --help-all Show all help options + --help-gtk Show GTK Options + + Application Options: + -r, --repeats=N Average over N repetitions + -m, --max-size=M Test up to 2^M items + --display=DISPLAY X display to use + -v, --verbose Be verbose + -b, --beep Beep when done + --rand Randomize the data + +GOption groups options in [struct@GLib.OptionGroup]s, which makes it easy to +incorporate options from multiple sources. The intended use for this is +to let applications collect option groups from the libraries it uses, +add them to their #GOptionContext, and parse all options by a single call +to [method@GLib.OptionContext.parse]. + +If an option is declared to be of type string or filename, GOption takes +care of converting it to the right encoding; strings are returned in UTF-8, +filenames are returned in the GLib filename encoding. Note that this only +works if `setlocale()` has been called before [method@GLib.OptionContext.parse] + +Here is a complete example of setting up GOption to parse the example +commandline above and produce the example help output. + +```c +static gint repeats = 2; +static gint max_size = 8; +static gboolean verbose = FALSE; +static gboolean beep = FALSE; +static gboolean randomize = FALSE; + +static GOptionEntry entries[] = +{ + { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" }, + { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" }, + { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, + { "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL }, + { "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL }, + G_OPTION_ENTRY_NULL +}; + +int +main (int argc, char *argv[]) +{ + GError *error = NULL; + GOptionContext *context; + + context = g_option_context_new ("- test tree model performance"); + g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + if (!g_option_context_parse (context, &argc, &argv, &error)) + { + g_print ("option parsing failed: %s\n", error->message); + exit (1); + } + + ... + +} +``` + +On UNIX systems, the argv that is passed to `main()` has no particular +encoding, even to the extent that different parts of it may have different +encodings. In general, normal arguments and flags will be in the current +locale and filenames should be considered to be opaque byte strings. +Proper use of `G_OPTION_ARG_FILENAME` vs `G_OPTION_ARG_STRING` is +therefore important. + +Note that on Windows, filenames do have an encoding, but using +[struct@GLib.OptionContext] with the argv as passed to `main()` will result +in a program that can only accept commandline arguments with characters +from the system codepage.This can cause problems when attempting to +deal with filenames containing Unicode characters that fall outside +of the codepage. + +A solution to this is to use `g_win32_get_command_line()` and +[method@GLib.OptionContext.parse_strv] which will properly handle full +Unicode filenames. If you are using #GApplication, this is done +automatically for you. + +The following example shows how you can use #GOptionContext directly +in order to correctly deal with Unicode filenames on Windows: + +```c +int +main (int argc, char **argv) +{ + GError *error = NULL; + GOptionContext *context; + gchar **args; + +#ifdef G_OS_WIN32 + args = g_win32_get_command_line (); +#else + args = g_strdupv (argv); +#endif + + // set up context + + if (!g_option_context_parse_strv (context, &args, &error)) + { + // error happened + } + + ... + + g_strfreev (args); + + ... +} +``` diff --git a/docs/reference/glib/gtester-report.rst b/docs/reference/glib/gtester-report.rst new file mode 100644 index 0000000..b6c5b31 --- /dev/null +++ b/docs/reference/glib/gtester-report.rst @@ -0,0 +1,54 @@ +.. _gtester-report(1): +.. meta:: + :copyright: Copyright 2008 Matthias Clasen + :copyright: Copyright 2012, 2013 Red Hat, Inc. + :copyright: Copyright 2019 Endless Mobile, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2008 Matthias Clasen + SPDX-FileCopyrightText: 2012, 2013 Red Hat, Inc. + SPDX-FileCopyrightText: 2019 Endless Mobile, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +============== +gtester-report +============== + +------------------------------ +test report formatting utility +------------------------------ + +SYNOPSIS +-------- + +| **gtester-report** [*OPTION*…] *gtester-log* + +DESCRIPTION +----------- + +``gtester-report`` is a script which converts the XML output generated by +``gtester`` into HTML. + +Since GLib 2.62, ``gtester-report`` is deprecated. Use TAP for reporting test +results instead, and feed it to the test harness provided by your build system. + +OPTIONS +------- + +``-h``, ``--help`` + + Print help and exit. + +``-v``, ``--version`` + + Print version information and exit. + +``-s``, ``--subunit`` + + Output subunit. Needs ``python-subunit``. + +SEE ALSO +-------- + +`gtester(1) `_ \ No newline at end of file diff --git a/docs/reference/glib/gtester-report.xml b/docs/reference/glib/gtester-report.xml deleted file mode 100644 index eee9337..0000000 --- a/docs/reference/glib/gtester-report.xml +++ /dev/null @@ -1,78 +0,0 @@ - - - -gtester-report -GLib - - -Developer -Tim -Janik - - - - - -gtester-report -1 -User Commands - - - -gtester-report -test report formatting utility - - - - -gtester-report -option -gtester-log - - - -Description -gtester-report is a script which converts -the XML output generated by gtester into HTML. - -Since GLib 2.62, gtester-report is deprecated. Use -TAP for reporting test results instead, and feed it to the test harness provided -by your build system. - - -Options - - - -, - -print help and exit - - - - -, - -print version information and exit - - - - -, - -Output subunit. Needs python-subunit. - - - - - - -See also - - -gtester -1 - - - - diff --git a/docs/reference/glib/gtester.rst b/docs/reference/glib/gtester.rst new file mode 100644 index 0000000..68c3f24 --- /dev/null +++ b/docs/reference/glib/gtester.rst @@ -0,0 +1,120 @@ +.. _gtester(1): +.. meta:: + :copyright: Copyright 2008 Matthias Clasen + :copyright: Copyright 2011 Collabora, Ltd. + :copyright: Copyright 2011 Carlos Garcia Campos + :copyright: Copyright 2012 Red Hat, Inc. + :copyright: Copyright 2019 Endless Mobile, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2008 Matthias Clasen + SPDX-FileCopyrightText: 2011 Collabora, Ltd. + SPDX-FileCopyrightText: 2011 Carlos Garcia Campos + SPDX-FileCopyrightText: 2012 Red Hat, Inc. + SPDX-FileCopyrightText: 2019 Endless Mobile, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +======= +gtester +======= + +-------------------- +test running utility +-------------------- + +SYNOPSIS +-------- + +| **gtester** [*OPTION*…] *test-program* + +DESCRIPTION +----------- + +``gtester`` is a utility to run unit tests that have been written using the GLib +test framework. + +Since GLib 2.62, ``gtester-report`` is deprecated. Use TAP for reporting test +results instead, and feed it to the test harness provided by your build system. + +When called with the ``-o`` option, ``gtester`` writes an XML report of the test +results, which can be converted into HTML using the ``gtester-report`` utility. + +OPTIONS +------- + +``-h``, ``--help`` + + Print help and exit. + +``-v``, ``--verbose`` + + Print version information and exit. + +``--g-fatal-warnings`` + + Make warnings fatal. + +``-k``, ``--keep-going`` + + Continue running after tests failed. + +``-l`` + + List paths of available test cases. + +``-m=`` + + Run test cases in ``MODE``, which can be one of: + + * ``perf`` + + Run performance tests. + + * ``slow``, ``thorough`` + + Run slow tests, or repeat non-deterministic tests more often. + + * ``quick`` + + Do not run slow or performance tests, or do extra repeats of + non-deterministic tests (default). + + * ``undefined`` + + Run test cases that deliberately provoke checks or assertion failures, if + implemented (default). + + * ``no-undefined`` + + Do not run test cases that deliberately provoke checks or assertion + failures. + +``-p=`` + + Only run test cases matching ``TEST-PATH``. + +``-s=`` + + Skip test cases matching ``TEST-PATH``. + +``--seed=`` + + Run all test cases with random number seed ``SEED-STRING``. + +``-o=`` + + Write the test log to ``LOG-FILE``. + +``-q``, ``--quiet`` + + Suppress per-test-binary output. + +``--verbose`` + + Report success per testcase. + +SEE ALSO +-------- + +`gtester-report(1) `_ \ No newline at end of file diff --git a/docs/reference/glib/gtester.xml b/docs/reference/glib/gtester.xml deleted file mode 100644 index 5626d4d..0000000 --- a/docs/reference/glib/gtester.xml +++ /dev/null @@ -1,192 +0,0 @@ - - - -gtester -GLib - - -Developer -Tim -Janik - - -Developer -Sven -Herzberg - - - - - -gtester -1 -User Commands - - - -gtester -test running utility - - - - -gtester -OPTION -testprogram - - - -Description -gtester is a utility to run unit tests that have -been written using the GLib test framework. - -Since GLib 2.62, gtester-report is deprecated. Use -TAP for reporting test results instead, and feed it to the test harness provided -by your build system. - -When called with the option, gtester -writes an XML report of the test results, which can be converted -into HTML using the gtester-report utility. - - - -Options - - - -, - -print help and exit - - - - -, - -print version information and exit - - - - - - -make warnings fatal - - - - -, - -continue running after tests failed - - - - - - -list paths of available test cases - - - - - - - run test cases in MODE, which can be one of: - - - - - - run performance tests - - - - - , - - run slow tests, or repeat non-deterministic tests more often - - - - - - - do not run slow or performance tests, or do extra repeats - of non-deterministic tests (default) - - - - - - - run test cases that deliberately provoke checks or assertion - failures, if implemented (default) - - - - - - - do not run test cases that deliberately provoke checks or - assertion failures - - - - - - - - - - -only run test cases matching TESTPATH - - - - - - -skip test cases matching TESTPATH - - - - - - -run all test cases with random number seed SEEDSTRING - - - - - - -write the test log to LOGFILE - - - - -, - -suppress per test binary output - - - - - - -report success per testcase - - - - - - -See also - - -gtester-report -1 - - - - diff --git a/docs/reference/glib/gvariant-format-strings.md b/docs/reference/glib/gvariant-format-strings.md new file mode 100644 index 0000000..668282c --- /dev/null +++ b/docs/reference/glib/gvariant-format-strings.md @@ -0,0 +1,503 @@ +Title: GVariant Format Strings + +# GVariant Format Strings + +## Variable Argument Conversions + +This page attempts to document how to perform variable argument conversions +with [struct@GLib.Variant]. + +Conversions occur according to format strings. A format string is a two-way +mapping between a single `GVariant` value and one or more C values. + +A conversion from C values into a `GVariant` value is made using the +[ctor@GLib.Variant.new] function. A conversion from a `GVariant` into C +values is made using the [method@GLib.Variant.get] function. + +## Syntax + +This section exhaustively describes all possibilities for GVariant format +strings. There are no valid forms of format strings other than those +described here. Please note that the format string syntax is likely to +expand in the future. + +Valid format strings have one of the following forms: + +- any type string +- a type string prefixed with a `@` +- `&s`, `&o`, `&g`, `^as`, `^a&s`, `^ao`, `^a&o`, `^ay`, `^&ay`, `^aay` or + `^a&ay`. +- any format string, prefixed with an `m` +- a sequence of zero or more format strings, concatenated and enclosed in + parentheses +- an opening brace, followed by two format strings, followed by a closing + brace (subject to the constraint that the first format string correspond + to a type valid for use as the key type of a dictionary) + +## Symbols + +The following table describes the rough meaning of symbols that may appear inside a GVariant format string. Each symbol is described in detail in its own section, including usage examples. + +| Symbol | Meaning | +|--------|---------| +| `b`, `y`, `n`, `q`, `i`, `u`, `x`, `t`, `h`, `d` | Used for building or deconstructing boolean, byte and numeric types. See [Numeric Types](#numeric-types) below. | +| `s`, `o`, `g` | Used for building or deconstructing string types. See [Strings](#strings) below. | +| `v` | Used for building or deconstructing variant types. See [Variants](#variants) below. | +| `a` | Used for building or deconstructing arrays. See [Arrays](#arrays) below. | +| `m` | Used for building or deconstructing maybe types. See [Maybe Types](#maybe-types) below. | +| `()` | Used for building or deconstructing tuples. See [Tuples](#tuples) below. | +| `{}` | Used for building or deconstructing dictionary entries. See [Dictionaries](#dictionaries) below. | +| `@` | Used as a prefix for a `GVariant` type string (not a prefix for a format string, so `@as` is a valid format string but `@^as` is not). Denotes that a pointer to a GVariant should be used in place of the normal C type or types. For `g_variant_new()` this means that you must pass a non-`NULL` `(GVariant *)`; if it is a floating reference, ownership will be taken, as if by using `g_variant_ref_sink()`. For `g_variant_get()` this means that you must pass a pointer to a `(GVariant *)` for the value to be returned by reference or `NULL` to ignore the value. See [`GVariant *`](#gvariant) below. | +| `*`, `?`, `r` | Exactly equivalent to `@*`, `@?` and `@r`. Provided only for completeness so that all `GVariant` type strings can be used also as format strings. See [`GVariant *`](#gvariant) below. | +| `&` | Used as a prefix for a `GVariant` type string (not a prefix for a format string, so `&s` is a valid format string but `&@s` is not). Denotes that a C pointer to serialised data should be used in place of the normal C type. See [Pointers](#pointers) below. | +| `^` | Used as a prefix on some specific types of format strings. See [Convenience Conversions](#convenience-conversions) below. | + +## Numeric Types + +Characters: `b`, `y`, `n`, `q`, `i`, `u`, `x`, `t`, `h`, `d` + +Variable argument conversions from numeric types work in the most obvious +way possible. Upon encountering one of these characters, `g_variant_new()` +takes the equivalent C type as an argument. `g_variant_get()` takes a pointer +to the equivalent C type (or `NULL` to ignore the value). + +The equivalent C types are as follows: + +| Character | Equivalent C type | +|-----------|-------------------| +| `b` | `gboolean` | +| `y` | `guchar` | +| `n` | `gint16` | +| `q` | `guint16` | +| `i` | `gint32` | +| `u` | `guint32` | +| `x` | `gint64` | +| `t` | `guint64` | +| `h` | `gint32` | +| `d` | `gdouble` | + +Note that in C, small integer types in variable argument lists are promoted +up to `int` or `unsigned int` as appropriate, and read back accordingly. `int` +is 32 bits on every platform on which GLib is currently supported. This +means that you can use C expressions of type `int` with `g_variant_new()` and +format characters `b`, `y`, `n`, `q`, `i`, `u` and `h`. Specifically, you +can use integer literals with these characters. + +When using the `x` and `t` characters, you must ensure that the value that +you provide is 64 bit. This means that you should use a cast or make use of +the `G_GINT64_CONSTANT` or `G_GUINT64_CONSTANT` macros. + +No type promotion occurs when using `g_variant_get()` since it operates with +pointers. The pointers must always point to a memory region of exactly the +correct size. + +### Examples + +```c +GVariant *value1, *value2, *value3, *value4; + +value1 = g_variant_new ("y", 200); +value2 = g_variant_new ("b", TRUE); +value3 = g_variant_new ("d", 37.5): +value4 = g_variant_new ("x", G_GINT64_CONSTANT (998877665544332211)); + +{ + gdouble floating; + gboolean truth; + gint64 bignum; + + + g_variant_get (value1, "y", NULL); /* ignore the value. */ + g_variant_get (value2, "b", &truth); + g_variant_get (value3, "d", &floating); + g_variant_get (value4, "x", &bignum); +} +``` + +## Strings + +Characters: `s`, `o`, `g` + +String conversions occur to and from standard nul-terminated C strings. Upon +encountering an `s`, `o` or `g` in a format string, `g_variant_new()` takes a +`(const gchar *)` and makes a copy of it. `NULL` is not a valid string; use +maybe types to encode that. If the `o` or `g` characters are used, care must +be taken to ensure that the passed string is a valid D-Bus object path or +D-Bus type signature, respectively. + +Upon encountering `s`, `o` or `g`, `g_variant_get()` takes a pointer to a +`(gchar *)` (ie: `(gchar **)`) and sets it to a newly-allocated copy of the +string. It is appropriate to free this copy using `g_free()`. `NULL` may +also be passed to indicate that the value of the string should be ignored +(in which case no copy is made). + +### Examples + +```c +GVariant *value1, *value2, *value3; + +value1 = g_variant_new ("s", "hello world!"); +value2 = g_variant_new ("o", "/must/be/a/valid/path"); +value3 = g_variant_new ("g", "iias"); + +#if 0 + g_variant_new ("s", NULL); /* not valid: NULL is not a string. */ +#endif + +{ + gchar *result; + + g_variant_get (value1, "s", &result); + g_print ("It was '%s'\n", result); + g_free (result); +} +``` + +## Variants + +Characters: `v` + +Upon encountering a `v`, `g_variant_new()` takes a `(GVariant *)`. The value +of the `GVariant` is used as the contents of the variant value. + +Upon encountering a `v`, `g_variant_get()` takes a pointer to a `(GVariant +*)` (ie: `(GVariant **)`). It is set to a new reference to a `GVariant` +instance containing the contents of the variant value. It is appropriate to +free this reference using `g_variant_unref()`. `NULL` may also be passed to +indicate that the value should be ignored (in which case no new reference is +created). + +### Examples + +```c +GVariant *x, *y; + +/* the following two lines are equivalent: */ +x = g_variant_new ("v", y); +x = g_variant_new_variant (y); + +/* as are these: */ +g_variant_get (x, "v", &y); +y = g_variant_get_variant (x); +``` + +## Arrays + +Characters: `a` + +Upon encountering an `a` character followed by a type string, +`g_variant_new()` will take a `(GVariantBuilder *)` that has been created as +an array builder for an array of the type given in the type string. The +builder will have `g_variant_builder_end()` called on it and the result will +be used as the value. As a special exception, if the given type string is a +definite type, then `NULL` may be given to mean an empty array of that type. + +Upon encountering an `a` character followed by a type string, +`g_variant_get()` will take a pointer to a `(GVariantIter *)` (ie: +`(GVariantIter **)`). A new heap-allocated iterator is created and returned, +initialised for iterating over the elements of the array. This iterator +should be freed when you are done with it, using `g_variant_iter_free()`. +`NULL` may also be given to indicate that the value of the array should be +ignored. + +### Examples + +```c +GVariantBuilder *builder; +GVariant *value; + +builder = g_variant_builder_new (G_VARIANT_TYPE ("as")); +g_variant_builder_add (builder, "s", "when"); +g_variant_builder_add (builder, "s", "in"); +g_variant_builder_add (builder, "s", "the"); +g_variant_builder_add (builder, "s", "course"); +value = g_variant_new ("as", builder); +g_variant_builder_unref (builder); + +{ + GVariantIter *iter; + gchar *str; + + g_variant_get (value, "as", &iter); + while (g_variant_iter_loop (iter, "s", &str)) + g_print ("%s\n", str); + g_variant_iter_free (iter); +} + +g_variant_unref (value); +``` + +## Maybe Types + +Characters: `m` + +Maybe types are handled in two separate ways depending on the format string +that follows the `m`. The method that is used currently depends entirely on +the character immediately following the `m`. + +The first way is used with format strings starting with `a`, `s`, `o`, `g`, +`v`, `@`, `*`, `?`, `r`, `&`, or `^`. In all of these cases, for non-maybe +types, `g_variant_new()` takes a pointer to a non-`NULL` value and +`g_variant_get()` returns (by reference) a non-`NULL` pointer. When any of +these format strings are prefixed with an `m`, the type of arguments that +are collected does not change in any way, but `NULL` becomes a permissible +value, to indicate the Nothing case. + +Note that the "special exception" introduced in the array section for +constructing empty arrays is ignored here. Using a `NULL` pointer with the +format string `mas` constructs the Nothing value -- not an empty array. + +The second way is used with all other format strings. For `g_variant_new()` +an additional gboolean argument is collected and for `g_variant_get()` an +additional `(gboolean *)`. Following this argument, the arguments that are +normally collected for the equivalent non-maybe type will be collected. + +If `FALSE` is given to `g_variant_new()` then the Nothing value is +constructed and the collected arguments are ignored. Otherwise (if `TRUE` +was given), the arguments are used in the normal way to create the Just +value. + +If `NULL` is given to `g_variant_get()` then the value is ignored. If a +non-`NULL` pointer is given then it is used to return by reference whether +the value was Just. In the case that the value was Just, the `gboolean` will +be set to `TRUE` and the value will be stored in the arguments in the usual +way. In the case that the value was Nothing, the `gboolean` will be set to +`FALSE` and the arguments will be collected in the normal way but have their +values set to binary zero. + +### Examples + +```c +GVariant *value1, *value2, *value3, *value4, *value5, *value6; +value1 = g_variant_new ("ms", "Hello world"); +value2 = g_variant_new ("ms", NULL); +value3 = g_variant_new ("(m(ii)s)", TRUE, 123, 456, "Done"); +value4 = g_variant_new ("(m(ii)s)", FALSE, -1, -1, "Done"); /* both '-1' are ignored. */ +value5 = g_variant_new ("(m@(ii)s)", NULL, "Done"); + +{ + GVariant *contents; + const gchar *cstr; + gboolean just; + gint32 x, y; + gchar *str; + + g_variant_get (value1, "ms", &str); + if (str != NULL) + g_print ("str: %s\n", str); + else + g_print ("it was null\n"); + g_free (str); + + + g_variant_get (value2, "m&s", &cstr); + if (cstr != NULL) + g_print ("str: %s\n", cstr); + else + g_print ("it was null\n"); + /* don't free 'cstr' */ + + + /* NULL passed for the gboolean *, but two 'gint32 *' still collected */ + g_variant_get (value3, "(m(ii)s)", NULL, NULL, NULL, &str); + g_print ("string is %s\n", str); + g_free (str); + + /* note: &s used, so g_free() not needed */ + g_variant_get (value4, "(m(ii)&s)", &just, &x, &y, &cstr); + if (just) + g_print ("it was (%d, %d)\n", x, y); + else + g_print ("it was null\n"); + g_print ("string is %s\n", cstr); + /* don't free 'cstr' */ + + + g_variant_get (value5, "(m*s)", &contents, NULL); /* ignore the string. */ + if (contents != NULL) + { + g_variant_get (contents, "(ii)", &x, &y); + g_print ("it was (%d, %d)\n", x, y); + g_variant_unref (contents); + } + else + g_print ("it was null\n"); +} +``` + +## Tuples + +Characters: `()` + +Tuples are handled by handling each item in the tuple, in sequence. Each +item is handled in the usual way. + +### Examples + +```c +GVariant *value1, *value2; + +value1 = g_variant_new ("(s(ii))", "Hello", 55, 77); +value2 = g_variant_new ("()"); + +{ + gchar *string; + gint x, y; + + g_variant_get (value1, "(s(ii))", &string, &x, &y); + g_print ("%s, %d, %d\n", string, x, y); + g_free (string); + + g_variant_get (value2, "()"); /* do nothing... */ +} +``` + +## `GVariant *` + +Characters: `@`, `*`, `?`, `r` + +Upon encountering a `@` in front of a type string, `g_variant_new()` takes a +non-`NULL` pointer to a `GVariant` and uses its value directly instead of +collecting arguments to create the value. The provided `GVariant` must have +a type that matches the type string following the `@`. `*` is the same as +`@*` (ie: take a `GVariant` of any type). `?` is the same as `@?` (ie: take +a `GVariant` of any basic type). `r` is the same as `@r` (ie: take a +`GVariant` of any tuple type). + +Upon encountering a `@` in front of a type string, `g_variant_get()` takes a +pointer to a `(GVariant *)` (ie: a `(GVariant **)`) and sets it to a new +reference to a `GVariant` containing the value (instead of deconstructing +the value into C types in the usual way). `NULL` can be given to ignore the +value. `*`, `?` and `r` are handled in a way analogous to what is stated +above. + +You can always use `*` as an alternative to `?`, `r` or any use of `@`. +Using the other characters where possible is recommended, however, due to +the improvements in type safety and code self-documentation. + +### Examples + +```c +GVariant *value1, *value2; + +value1 = g_variant_new ("(i@ii)", 44, g_variant_new_int32 (55), 66); + +/* note: consumes floating reference count on 'value1' */ +value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo")); + +{ + const gchar *string; + GVariant *tmp; + gsize length; + gint x, y, z; + + g_variant_get (value2, "((iii)*)", &x, &y, &z, &tmp); + string = g_variant_get_string (tmp, &length); + g_print ("it is %d %d %d %s (length=%d)\n", x, y, z, string, (int) length); + g_variant_unref (tmp); + + /* quick way to skip all the values in a tuple */ + g_variant_get (value2, "(rs)", NULL, &string); /* or "(@(iii)s)" */ + g_print ("i only got the string: %s\n", string); + g_free (string); +} +``` + +## Dictionaries + +Characters: `{}` + +Dictionary entries are handled by handling first the key, then the value. Each is handled in the usual way. + +### Examples + +```c +GVariantBuilder *b; +GVariant *dict; + +b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}")); +g_variant_builder_add (b, "{sv}", "name", g_variant_new_string ("foo")); +g_variant_builder_add (b, "{sv}", "timeout", g_variant_new_int32 (10)); +dict = g_variant_builder_end (b); +``` + +To extract data from nested dictionaries you can go through a vardict. + +### Examples + +```c +GVariant *data; +gint value = 1; +gint max = 3; + +/* type (oa{sa{sv}) */ +data = g_variant_new_parsed ("(%o, {'brightness': {'value': <%i>, 'max': <%i>}})", + "/object/path", value, max); +{ + GVariant *params; + GVariant *p_brightness; + gchar *obj + gint p_max; + + g_variant_get (data, "(o@a{?*})", &obj, ¶ms); + g_print ("object_path: %s\n", obj); + + p_brightness = g_variant_lookup_value (params, "brightness", G_VARIANT_TYPE_VARDICT); + g_variant_lookup (p_brightness, "max", "i", &p_max); + g_print ("max: %d\n", p_max); +} +``` + +## Pointers + +Characters: `&` + +The `&` character is used to indicate that serialised data should be +directly exchanged via a pointer. + +Currently, the only use for this character is when it is applied to a string +(ie: `&s`, `&o` or `&g`). For `g_variant_new()` this has absolutely no +effect. The string is collected and duplicated normally. For +`g_variant_get()` it means that instead of creating a newly allocated copy +of the string, a pointer to the serialised data is returned. This pointer +should not be freed. Validity checks are performed to ensure that the string +data will always be properly nul-terminated. + +### Examples + +```c +{ + const gchar *str; + GVariant *value; + + value = g_variant_new ("&s", "hello world"); + g_variant_get (value, "&s", &str); + g_print ("string is: %s\n", str); + /* no need to free str */ +} +``` + +## Convenience Conversions + +Characters: `^` + +The `^` character currently supports conversion to and from bytestrings or +to and from arrays of strings or bytestrings. It does not support byte +arrays. It has a number of forms. + +In all forms, when used with `g_variant_new()` one pointer value is +collected from the variable arguments and passed to a function (as given in +the table below). The result of that function is used as the value for this +position. When used with `g_variant_get()` one pointer value is produced by +using the function (given in the table) and returned by reference. + +| Conversion | Used with `g_variant_new()` | Used with `g_variant_get()` | +|------------|----------------------------------------------------------|------------------------------------------------------------| +| `^as` | equivalent to [`ctor@GLib.Variant.new_strv`] | equivalent to [`method@GLib.Variant.dup_strv`] | +| `^a&s` | | equivalent to [`method@GLib.Variant.get_strv`] | +| `^ao` | equivalent to [`ctor@GLib.Variant.new_objv`] | equivalent to [`method@GLib.Variant.dup_objv`] | +| `^a&o` | | equivalent to [`method@GLib.Variant.get_objv`] | +| `^ay` | equivalent to [`ctor@GLib.Variant.new_bytestring`] | equivalent to [`method@GLib.Variant.dup_bytestring`] | +| `^&ay` | | equivalent to [`method@GLib.Variant.get_bytestring`] | +| `^aay` | equivalent to [`ctor@GLib.Variant.new_bytestring_array`] | equivalent to [`method@GLib.Variant.dup_bytestring_array`] | +| `^a&ay` | | equivalent to [`method@GLib.Variant.get_bytestring_array`] | diff --git a/docs/reference/glib/gvariant-text-format.md b/docs/reference/glib/gvariant-text-format.md new file mode 100644 index 0000000..4a142e4 --- /dev/null +++ b/docs/reference/glib/gvariant-text-format.md @@ -0,0 +1,346 @@ +Title: GVariant Text Format + +# GVariant Text Format + +This page attempts to document the `GVariant` text format as produced by +[`method@GLib.Variant.print`] and parsed by the [`func@GLib.Variant.parse`] +family of functions. In most cases the style closely resembles the +formatting of literals in Python but there are some additions and +exceptions. + +The functions that deal with `GVariant` text format absolutely always deal +in UTF-8. Conceptually, `GVariant` text format is a string of Unicode +characters, not bytes. Non-ASCII but otherwise printable Unicode characters +are not treated any differently from normal ASCII characters. + +The parser makes two passes. The purpose of the first pass is to determine +the type of the value being parsed. The second pass does the actual parsing. +Based on the fact that all elements in an array have to have the same type, +`GVariant` is able to make some deductions that would not otherwise be +possible. As an example: + + [[1, 2, 3], [4, 5, 6]] + +is parsed as an array of arrays of integers (type `aai`), but + + [[1, 2, 3], [4, 5, 6.0]] + +is parsed as an array of arrays of doubles (type `aad`). + +As another example, `GVariant` is able to determine that + + ["hello", nothing] + +is an array of maybe strings (type `ams`). + +What the parser accepts as valid input is dependent on context. The API +permits for out-of-band type information to be supplied to the parser (which +will change its behaviour). This can be seen in the GSettings and GDBus +command line utilities where the type information is available from the +schema or the remote introspection information. The additional information +can cause parses to succeed when they would not otherwise have been able to +(by resolving ambiguous type information) or can cause them to fail (due to +conflicting type information). Unless stated otherwise, the examples given +in this section assume that no out-of-band type data has been given to the +parser. + +## Syntax Summary + +The following table describes the rough meaning of symbols that may appear +inside GVariant text format. Each symbol is described in detail in its own +section, including usage examples. + +| Symbol | Meaning | +|--------|---------| +| `true`, `false` | [Booleans](#booleans). | +| `""`, `''` | String literal. See [Strings](#strings) below. | +| numbers | See [Numbers](#numbers) below. | +| `()` | [Tuples](#tuples). | +| `[]` | [Arrays](#arrays). | +| `{}` | [Dictionaries and Dictionary Entries](#dictionaries-and-dictionary-entries). | +| `<>` | [Variants](#variants). | +| `just`, `nothing` | [Maybe Types](#maybe-types). | +| `@` | [Type Annotations](#type-annotations). | +| `boolean`, `byte`, `int16`, `uint16`, `int32`, `uint32`, `handle`, `int64`, `uint64`, `double`, `string`, `objectpath`, `signature` | [Type Annotations](#type-annotations) | +| `b""`, `b''` | [Bytestrings](#bytestrings). | +| `%` | [Positional Parameters](#positional-parameters). | + +## Booleans + +The strings `true` and `false` are parsed as booleans. This is the only way +to specify a boolean value. + +## Strings + +Strings literals must be quoted using `""` or `''`. The two are completely +equivalent (except for the fact that each one is unable to contain itself +unescaped). + +Strings are Unicode strings with no particular encoding. For example, to +specify the character `é`, you just write `'é'`. You could also give the +Unicode codepoint of that character (`U+E9`) as the escape sequence +`'\u00e9'`. Since the strings are pure Unicode, you should not attempt to +encode the UTF-8 byte sequence corresponding to the string using escapes; it +won't work and you'll end up with the individual characters corresponding to +each byte. + +Unicode escapes of the form `\uxxxx` and `\Uxxxxxxxx` are supported, in +hexadecimal. The usual control sequence escapes `\a`, `\b`, `\f`, `\n`, +`\r`, `\t` and `\v` are supported. Additionally, a `\` before a newline +character causes the newline to be ignored. Finally, any other character +following `\` is copied literally (for example, `\"` or `\\`) but for +forwards compatibility with future additions you should only use this +feature when necessary for escaping backslashes or quotes. + +The usual octal and hexadecimal escapes `\0nnn` and `\xnn` are not supported +here. Those escapes are used to encode byte values and `GVariant` strings +are Unicode. + +Single-character strings are not interpreted as bytes. Bytes must be +specified by their numerical value. + +## Numbers + +Numbers are given by default as decimal values. Octal and hex values can be +given in the usual way (by prefixing with `0` or `0x`). Note that `GVariant` +considers bytes to be unsigned integers and will print them as a two digit +hexadecimal number by default. + +Floating point numbers can also be given in the usual ways, including +scientific and hexadecimal notations. + +For lack of additional information, integers will be parsed as `int32` +values by default. If the number has a point or an `e` in it, then it will +be parsed as a double precision floating point number by default. If type +information is available (either explicitly or inferred) then that type will +be used instead. + +Some examples: + +`5` parses as the `int32` value five. + +`37.5` parses as a floating point value. + +`3.75e1` parses the same as the value above. + +`uint64 7` parses seven as a `uint64`. See [Type Annotations](#type-annotations). + +## Tuples + +Tuples are formed using the same syntax as Python. Here are some examples: + +`()` parses as the empty tuple. + +`(5,)` is a tuple containing a single value. + +`("hello", 42)` is a pair. Note that values of different types are +permitted. + +## Arrays + +Arrays are formed using the same syntax as Python uses for lists (which is +arguably the term that `GVariant` should have used). Note that, unlike Python +lists, `GVariant` arrays are statically typed. This has two implications. + +First, all items in the array must have the same type. Second, the type of +the array must be known, even in the case that it is empty. This means that +(unless there is some other way to infer it) type information will need to +be given explicitly for empty arrays. + +The parser is able to infer some types based on the fact that all items in +an array must have the same type. See the examples below: + +`[1]` parses (without additional type information) as a one-item array of +signed integers. + +`[1, 2, 3]` parses (similarly) as a three-item array. + +`[1, 2, 3.0]` parses as an array of doubles. This is the most simple case of +the type inferencing in action. + +`[(1, 2), (3, 4.0)]` causes the 2 to also be parsed as a double (but the 1 +and 3 are still integers). + +`["", nothing]` parses as an array of maybe strings. The presence of +"nothing" clearly implies that the array elements are nullable. + +`[[], [""]]` will parse properly because the type of the first (empty) array +can be inferred to be equal to the type of the second array (both are arrays +of strings). + +`[b'hello', []]` looks odd but will parse properly. See +[Bytestrings](#bytestrings). + +And some examples of errors: + +`["hello", 42]` fails to parse due to conflicting types. + +`[]` will fail to parse without additional type information. + +## Dictionaries and Dictionary Entries + +Dictionaries and dictionary entries are both specified using the `{}` +characters. + +The dictionary syntax is more commonly used. This is what the printer elects +to use in the normal case of dictionary entries appearing in an array (AKA +"a dictionary"). The separate syntax for dictionary entries is typically +only used for when the entries appear on their own, outside of an array +(which is valid but unusual). Of course, you are free to use the dictionary +entry syntax within arrays but there is no good reason to do so (and the +printer itself will never do so). Note that, as with arrays, the type of +empty dictionaries must be established (either explicitly or through +inference). + +The dictionary syntax is the same as Python's syntax for dictionaries. Some +examples: + +`@a{sv} {}` parses as the empty dictionary of everyone's favourite type. + +`@a{sv} []` is the same as above (owing to the fact that dictionaries are +really arrays). + +`{1: "one", 2: "two", 3: "three"}` parses as a dictionary mapping integers +to strings. + +The dictionary entry syntax looks just like a pair (2-tuple) that uses +braces instead of parens. The presence of a comma immediately following the +key differentiates it from the dictionary syntax (which features a colon +after the first key). Some examples: + +`{1, "one"}` is a free-standing dictionary entry that can be parsed on its +own or as part of another container value. + +`[{1, "one"}, {2, "two"}, {3, "three"}]` is exactly equivalent to the +dictionary example given above. + +## Variants + +Variants are denoted using angle brackets (aka "XML brackets"), `<>`. They +may not be omitted. + +Using `<>` effectively disrupts the type inferencing that occurs between +array elements. This can have positive and negative effects. + +`[<"hello">, <42>]` will parse whereas `["hello", 42]` would not. + +`[<['']>, <[]>]` will fail to parse even though `[[''], []]` parses +successfully. You would need to specify `[<['']>, <@as []>]`. + +`{"title": <"frobit">, "enabled": , "width": <800>}` is an example of +perhaps the most pervasive use of both dictionaries and variants. + +## Maybe Types + +The syntax for specifying maybe types is inspired by Haskell. + +The null case is specified using the keyword nothing and the non-null case +is explicitly specified using the keyword just. GVariant allows just to be +omitted in every case that it is able to unambiguously determine the +intention of the writer. There are two cases where it must be specified: + +- when using nested maybes, in order to specify the just nothing case +- to establish the nullability of the type of a value without explicitly + specifying its full type + +Some examples: + +`just 'hello'` parses as a non-null nullable string. + +`@ms 'hello'` is the same (demonstrating how just can be dropped if the type is already known). + +`nothing` will not parse without extra type information. + +`@ms nothing` parses as a null nullable string. + +`[just 3, nothing]` is an array of nullable integers + +`[3, nothing]` is the same as the above (demonstrating another place were just can be dropped). + +`[3, just nothing]` parses as an array of maybe maybe integers (type `ammi`). + +## Type Annotations + +Type annotations allow additional type information to be given to the +parser. Depending on the context, this type information can change the +output of the parser, cause an error when parsing would otherwise have +succeeded or resolve an error when parsing would have otherwise failed. + +Type annotations come in two forms: type codes and type keywords. + +Type keywords can be seen as more verbose (and more legible) versions of a +common subset of the type codes. The type keywords `boolean`, `byte`, +`int16`, `uint16`, `int32`, `uint32`, `handle`, `int64`, `uint64`, `double`, +`string`, `objectpath` and literal signature are each exactly equivalent to +their corresponding type code. + +Type codes are an `@` ("at" sign) followed by a definite `GVariant` type +string. Some examples: + +`uint32 5` causes the number to be parsed unsigned instead of signed (the +default). + +`@u 5` is the same + +`objectpath "/org/gnome/xyz"` creates an object path instead of a normal +string + +`@au []` specifies the type of the empty array (which would not parse +otherwise) + +`@ms ""` indicates that a string value is meant to have a maybe type + +## Bytestrings + +The bytestring syntax is a piece of syntactic sugar meant to complement the +bytestring APIs in GVariant. It constructs arrays of non-`NUL` bytes (type +`ay`) with a `NUL` terminator at the end. These are normal C strings with no +particular encoding enforced, so the bytes may not be valid UTF-8. +Bytestrings are a special case of byte arrays; byte arrays (also type 'ay'), +in the general case, can contain a `NUL` byte at any position, and need not +end with a `NUL` byte. + +Bytestrings are specified with either `b""` or `b''`. As with strings, there +is no fundamental difference between the two different types of quotes. + +Bytestrings support the full range of escapes that you would expect (ie: +those supported by [`func@GLib.strcompress`]. This includes the normal control +sequence escapes (as mentioned in the section on strings) as well as octal +and hexadecimal escapes of the forms `\0nnn` and `\xnn`. + +`b'abc'` is equivalent to `[byte 0x61, 0x62, 0x63, 0]`. + +When formatting arrays of bytes, the printer will choose to display the +array as a bytestring if it contains a nul character at the end and no other +nul bytes within. Otherwise, it is formatted as a normal array. + +## Positional Parameters + +Positional parameters are not a part of the normal `GVariant` text format, +but they are mentioned here because they can be used with +[`ctor@GLib.Variant.new_parsed`]. + +A positional parameter is indicated with a `%` followed by any valid +[GVariant Format String](gvariant-format-strings.html). Variable arguments +are collected as specified by the format string and the resulting value is +inserted at the current position. + +This feature is best explained by example: + +```c +char *t = "xyz"; +gboolean en = false; +GVariant *value; + +value = g_variant_new_parsed ("{'title': <%s>, 'enabled': <%b>}", t, en); +``` + +This constructs a dictionary mapping strings to variants (type `a{sv}`) with +two items in it. The key names are parsed from the string and the values for +those keys are taken as variable arguments parameters. + +The arguments are always collected in the order that they appear in the +string to be parsed. Format strings that collect multiple arguments are +permitted, so you may require more varargs parameters than the number of `%` +signs that appear. You can also give format strings that collect no +arguments, but there's no good reason to do so. diff --git a/docs/reference/glib/gvariant-text.xml b/docs/reference/glib/gvariant-text.xml deleted file mode 100644 index 55d476e..0000000 --- a/docs/reference/glib/gvariant-text.xml +++ /dev/null @@ -1,622 +0,0 @@ - - - - - GVariant Text Format - - - GVariant Text Format - textual representation of GVariants - - - - GVariant Text Format - - - This page attempts to document the GVariant text format as produced by - g_variant_print() and parsed by the - g_variant_parse() family of functions. In most - cases the style closely resembles the formatting of literals in Python but there are some additions and - exceptions. - - - - The functions that deal with GVariant text format absolutely always deal in utf-8. Conceptually, GVariant - text format is a string of Unicode characters -- not bytes. Non-ASCII but otherwise printable Unicode - characters are not treated any differently from normal ASCII characters. - - - - The parser makes two passes. The purpose of the first pass is to determine the type of the value being - parsed. The second pass does the actual parsing. Based on the fact that all elements in an array have to - have the same type, GVariant is able to make some deductions that would not otherwise be possible. As an - example: - - [[1, 2, 3], [4, 5, 6]] - - is parsed as an array of arrays of integers (type 'aai'), but - - [[1, 2, 3], [4, 5, 6.0]] - - is parsed as an array of arrays of doubles (type 'aad'). - - - - As another example, GVariant is able to determine that - - ["hello", nothing] - - is an array of maybe strings (type 'ams'). - - - - What the parser accepts as valid input is dependent on context. The API permits for out-of-band type - information to be supplied to the parser (which will change its behaviour). This can be seen in the - GSettings and GDBus command line utilities where the type information is available from the schema or the - remote introspection information. The additional information can cause parses to succeed when they would not - otherwise have been able to (by resolving ambiguous type information) or can cause them to fail (due to - conflicting type information). Unless stated otherwise, the examples given in this section assume that no - out-of-band type data has been given to the parser. - - - - - Syntax Summary - - - The following table describes the rough meaning of symbols that may appear inside GVariant text format. - Each symbol is described in detail in its own section, including usage examples. - - - - - - - - - - - - Symbol - - - - - Meaning - - - - - - - - true, - false - - - - - Booleans. - - - - - - - - "", - '' - - - - - String literal. See Strings below. - - - - - - - - numbers - - - - - See Numbers below. - - - - - - - - () - - - - - Tuples. - - - - - - - - [] - - - - - Arrays. - - - - - - - - {} - - - - - Dictionaries and Dictionary Entries. - - - - - - - - <> - - - - - Variants. - - - - - - - - just, - nothing - - - - - Maybe Types. - - - - - - - - @ - - - - - Type Annotations. - - - - - - - - type keywords - - - - - boolean, - byte, - int16, - uint16, - int32, - uint32, - handle, - int64, - uint64, - double, - string, - objectpath, - signature - - - See Type Annotations below. - - - - - - - - b"", - b'' - - - - - Bytestrings. - - - - - - - - % - - - - - Positional Parameters. - - - - - - - - - Booleans - - The strings true and false are parsed as booleans. This is the only - way to specify a boolean value. - - - - - Strings - - Strings literals must be quoted using "" or ''. The two are - completely equivalent (except for the fact that each one is unable to contain itself unescaped). - - - Strings are Unicode strings with no particular encoding. For example, to specify the character - é, you just write 'é'. You could also give the Unicode codepoint of - that character (U+E9) as the escape sequence '\u00e9'. Since the strings are pure - Unicode, you should not attempt to encode the utf-8 byte sequence corresponding to the string using escapes; - it won't work and you'll end up with the individual characters corresponding to each byte. - - - Unicode escapes of the form \uxxxx and \Uxxxxxxxx are supported, in - hexadecimal. The usual control sequence escapes \a, \b, - \f, \n, \r, \t and - \v are supported. Additionally, a \ before a newline character causes - the newline to be ignored. Finally, any other character following \ is copied literally - (for example, \" or \\) but for forwards compatibility with future - additions you should only use this feature when necessary for escaping backslashes or quotes. - - - The usual octal and hexadecimal escapes \0nnn and \xnn are not - supported here. Those escapes are used to encode byte values and GVariant strings are Unicode. - - - Single-character strings are not interpreted as bytes. Bytes must be specified by their numerical value. - - - - - Numbers - - Numbers are given by default as decimal values. Octal and hex values can be given in the usual way (by - prefixing with 0 or 0x). Note that GVariant considers bytes to be - unsigned integers and will print them as a two digit hexadecimal number by default. - - - Floating point numbers can also be given in the usual ways, including scientific and hexadecimal notations. - - - For lack of additional information, integers will be parsed as int32 values by default. If the number has a - point or an 'e' in it, then it will be parsed as a double precision floating point number by default. If - type information is available (either explicitly or inferred) then that type will be used instead. - - - Some examples: - - - 5 parses as the int32 value five. - - - 37.5 parses as a floating point value. - - - 3.75e1 parses the same as the value above. - - - uint64 7 parses seven as a uint64. - See Type Annotations. - - - - - Tuples - - Tuples are formed using the same syntax as Python. Here are some examples: - - - () parses as the empty tuple. - - - (5,) is a tuple containing a single value. - - - ("hello", 42) is a pair. Note that values of different types are permitted. - - - - - Arrays - - Arrays are formed using the same syntax as Python uses for lists (which is arguably the term that GVariant - should have used). Note that, unlike Python lists, GVariant arrays are statically typed. This has two - implications. - - - First, all items in the array must have the same type. Second, the type of the array must be known, even in - the case that it is empty. This means that (unless there is some other way to infer it) type information - will need to be given explicitly for empty arrays. - - - The parser is able to infer some types based on the fact that all items in an array must have the same type. - See the examples below: - - - [1] parses (without additional type information) as a one-item array of signed integers. - - - [1, 2, 3] parses (similarly) as a three-item array. - - - [1, 2, 3.0] parses as an array of doubles. This is the most simple case of the type - inferencing in action. - - - [(1, 2), (3, 4.0)] causes the 2 to also be parsed as a double (but the 1 and 3 are still - integers). - - - ["", nothing] parses as an array of maybe strings. The presence of - "nothing" clearly implies that the array elements are nullable. - - - [[], [""]] will parse properly because the type of the first (empty) array can be - inferred to be equal to the type of the second array (both are arrays of strings). - - - [b'hello', []] looks odd but will parse properly. - See Bytestrings - - - And some examples of errors: - - - ["hello", 42] fails to parse due to conflicting types. - - - [] will fail to parse without additional type information. - - - - - Dictionaries and Dictionary Entries - - Dictionaries and dictionary entries are both specified using the {} characters. - - - The dictionary syntax is more commonly used. This is what the printer elects to use in the normal case of - dictionary entries appearing in an array (aka "a dictionary"). The separate syntax for dictionary entries - is typically only used for when the entries appear on their own, outside of an array (which is valid but - unusual). Of course, you are free to use the dictionary entry syntax within arrays but there is no good - reason to do so (and the printer itself will never do so). Note that, as with arrays, the type of empty - dictionaries must be established (either explicitly or through inference). - - - The dictionary syntax is the same as Python's syntax for dictionaries. Some examples: - - - @a{sv} {} parses as the empty dictionary of everyone's favourite type. - - - @a{sv} [] is the same as above (owing to the fact that dictionaries are really arrays). - - - {1: "one", 2: "two", 3: "three"} parses as a dictionary mapping integers to strings. - - - The dictionary entry syntax looks just like a pair (2-tuple) that uses braces instead of parens. The - presence of a comma immediately following the key differentiates it from the dictionary syntax (which - features a colon after the first key). Some examples: - - - {1, "one"} is a free-standing dictionary entry that can be parsed on its own or as part - of another container value. - - - [{1, "one"}, {2, "two"}, {3, "three"}] is exactly equivalent to the dictionary example - given above. - - - - - Variants - - Variants are denoted using angle brackets (aka "XML brackets"), <>. They may not - be omitted. - - - Using <> effectively disrupts the type inferencing that occurs between array - elements. This can have positive and negative effects. - - - [<"hello">, <42>] will parse whereas ["hello", 42] would - not. - - - [<['']>, <[]>] will fail to parse even though [[''], []] - parses successfully. You would need to specify [<['']>, <@as []>]. - - - {"title": <"frobit">, "enabled": <true>, "width": <800>} is an example of - perhaps the most pervasive use of both dictionaries and variants. - - - - - Maybe Types - - The syntax for specifying maybe types is inspired by Haskell. - - - The null case is specified using the keyword nothing and the non-null case is explicitly - specified using the keyword just. GVariant allows just to be omitted - in every case that it is able to unambiguously determine the intention of the writer. There are two cases - where it must be specified: - - - - when using nested maybes, in order to specify the just nothing case - - - - to establish the nullability of the type of a value without explicitly specifying its full type - - - - - Some examples: - - - just 'hello' parses as a non-null nullable string. - - - @ms 'hello' is the same (demonstrating how just can be dropped if the type is already - known). - - - nothing will not parse wtihout extra type information. - - - @ms nothing parses as a null nullable string. - - - [just 3, nothing] is an array of nullable integers - - - [3, nothing] is the same as the above (demonstrating another place were - just can be dropped). - - - [3, just nothing] parses as an array of maybe maybe integers (type - 'ammi'). - - - - - Type Annotations - - Type annotations allow additional type information to be given to the parser. Depending on the context, - this type information can change the output of the parser, cause an error when parsing would otherwise have - succeeded or resolve an error when parsing would have otherwise failed. - - - Type annotations come in two forms: type codes and type keywords. - - - Type keywords can be seen as more verbose (and more legible) versions of a common subset of the type codes. - The type keywords boolean, byte, int16, - uint16, int32, uint32, handle, - int64, uint64, double, string, - objectpath and literal signature are each exactly equivalent to their - corresponding type code. - - - Type codes are an @ ("at" sign) followed by a definite GVariant type string. Some - examples: - - - uint32 5 causes the number to be parsed unsigned instead of signed (the default). - - - @u 5 is the same - - - objectpath "/org/gnome/xyz" creates an object path instead of a normal string - - - @au [] specifies the type of the empty array (which would not parse otherwise) - - - @ms "" indicates that a string value is meant to have a maybe type - - - - - Bytestrings - - The bytestring syntax is a piece of syntactic sugar meant to complement the bytestring APIs in GVariant. It - constructs arrays of non-nul bytes (type 'ay') with a nul terminator at the end. These are - normal C strings with no particular encoding enforced, so the bytes may not be valid UTF-8. - Bytestrings are a special case of byte arrays; byte arrays (also type 'ay'), in the general - case, can contain nul at any position, and need not end with nul. - - - Bytestrings are specified with either b"" or b''. As with strings, - there is no fundamental difference between the two different types of quotes. - - - Bytestrings support the full range of escapes that you would expect (ie: those supported by - g_strcompress(). This includes the normal control - sequence escapes (as mentioned in the section on strings) as well as octal and hexadecimal escapes of the - forms \0nnn and \xnn. - - - b'abc' is equivalent to [byte 0x61, 0x62, 0x63, 0]. - - - When formatting arrays of bytes, the printer will choose to display the array as a bytestring if it contains - a nul character at the end and no other nul bytes within. Otherwise, it is formatted as a normal array. - - - - - Positional Parameters - - Positional parameters are not a part of the normal GVariant text format, but they are mentioned here because - they can be used with g_variant_new_parsed(). - - - A positional parameter is indicated with a % followed by any valid - GVariant Format String. Variable arguments are collected as - specified by the format string and the resulting value is inserted at the current position. - - - This feature is best explained by example: - - , 'enabled': <%b>}", t, en);]]> - - This constructs a dictionary mapping strings to variants (type 'a{sv}') with two items in - it. The key names are parsed from the string and the values for those keys are taken as variable arguments - parameters. - - - The arguments are always collected in the order that they appear in the string to be parsed. Format strings - that collect multiple arguments are permitted, so you may require more varargs parameters than the number of - % signs that appear. You can also give format strings that collect no arguments, but - there's no good reason to do so. - - - - diff --git a/docs/reference/glib/gvariant-varargs.xml b/docs/reference/glib/gvariant-varargs.xml deleted file mode 100644 index f60eabb..0000000 --- a/docs/reference/glib/gvariant-varargs.xml +++ /dev/null @@ -1,1178 +0,0 @@ - - - - - GVariant Format Strings - - - GVariant Format Strings - varargs conversion of GVariants - - - - Variable Argument Conversions - - - This page attempts to document how to perform variable argument - conversions with GVariant. - - - Conversions occur according to format strings. A format string is a two-way mapping between a single - GVariant value and one or more C values. - - - A conversion from C values into a GVariant value is made using the - g_variant_new() function. A conversion from a - GVariant into C values is made using the - g_variant_get() function. - - - - - Syntax - - - This section exhaustively describes all possibilities for GVariant format strings. There are no valid forms of - format strings other than those described here. Please note that the format string syntax is likely to expand in the - future. - - - Valid format strings have one of the following forms: - - - - any type string - - - - a type string prefixed with a '@' - - - - - '&s' '&o', '&g', '^as', - '^a&s', '^ao', '^a&o','^ay', - '^&ay', '^aay' or '^a&ay'. - - - - - any format string, prefixed with an 'm' - - - - - a sequence of zero or more format strings, concatenated and enclosed in parentheses - - - - - an opening brace, followed by two format strings, followed by a closing brace (subject to the constraint that the - first format string correspond to a type valid for use as the key type of a dictionary) - - - - - - Symbols - - - The following table describes the rough meaning of symbols that may appear inside a GVariant format string. Each - symbol is described in detail in its own section, including usage examples. - - - - - - - - - - - - Symbol - - - - - Meaning - - - - - - - - - b, y, n, q, i, - u, x, t, h, d - - - - - - Used for building or deconstructing boolean, byte and numeric types. See - Numeric Types below. - - - - - - - - - s, o, g - - - - - - Used for building or deconstructing string types. See - Strings below. - - - - - - - - v - - - - - Used for building or deconstructing variant types. See - Variants below. - - - - - - - - - a - - - - - - Used for building or deconstructing arrays. See - Arrays below. - - - - - - - - - m - - - - - - Used for building or deconstructing maybe types. See - Maybe Types below. - - - - - - - - - () - - - - - - Used for building or deconstructing tuples. See - Tuples below. - - - - - - - - - {} - - - - - - Used for building or deconstructing dictionary entries. See - Dictionaries below. - - - - - - - - - @ - - - - - - Used as a prefix for a GVariant type string (not a prefix for a format string, so @as is - a valid format string but @^as is not). Denotes that a pointer to a - GVariant should be used in place of the normal C type or types. For - g_variant_new() this means that you must pass a - non-NULL (GVariant - *); if it is a floating reference, ownership will be taken, as - if by using g_variant_ref_sink(). - For g_variant_get() this means that you - must pass a pointer to a (GVariant *) for the value to be returned - by reference or NULL to ignore the value. See - GVariant * below. - - - - - - - - - *, ?, r - - - - - - Exactly equivalent to @*, @? and @r. Provided only for - completeness so that all GVariant type strings can be used also as format strings. See GVariant * below. - - - - - - - - & - - - - - Used as a prefix for a GVariant type string (not a prefix for a format string, so &s is - a valid format string but &@s is not). - Denotes that a C pointer to serialized data - should be used in place of the normal C type. See - Pointers below. - - - - - - - - ^ - - - - - Used as a prefix on some specific types of format strings. See - Convenience Conversions below. - - - - - - - - - - Numeric Types - - - Characters: b, y, n, q, - i, u, x, t, h, - d - - - - - Variable argument conversions from numeric types work in the most obvious way possible. Upon encountering one of - these characters, g_variant_new() takes the equivalent C - type as an argument. g_variant_get() takes a pointer to - the equivalent C type (or NULL to ignore the value). - - - - The equivalent C types are as follows: - - - - - - - - - - Character - - - - - Equivalent C type - - - - - - - - b - - - - - - gboolean - - - - - - - - y - - - - - - guchar - - - - - - - - n - - - - - - gint16 - - - - - - - - q - - - - - - guint16 - - - - - - - - i - - - - - - gint32 - - - - - - - - u - - - - - - guint32 - - - - - - - - x - - - - - - gint64 - - - - - - - - t - - - - - - guint64 - - - - - - - - h - - - - - - gint32 - - - - - - - - d - - - - - - gdouble - - - - - - - - - - Note that in C, small integer types in variable argument lists are promoted up to int or unsigned int as appropriate, and - read back accordingly. int is 32 bits on every platform on which GLib is - currently supported. This means that you can use C expressions of type int - with g_variant_new() and format characters - 'b', 'y', 'n', 'q', - 'i', 'u' and 'h'. Specifically, you can use integer - literals with these characters. - - - - When using the 'x' and 't' characters, you must ensure that the value that you - provide is 64 bit. This means that you should use a cast or make use of the - G_GINT64_CONSTANT or - G_GUINT64_CONSTANT macros. - - - - No type promotion occurs when using g_variant_get() since - it operates with pointers. The pointers must always point to a memory region of exactly the correct size. - - - - Examples - - - - - - - Strings - - - Characters: s, o, g - - - - - String conversions occur to and from standard nul-terminated C strings. Upon encountering an - 's', 'o' or 'g' in a format string, - g_variant_new() takes a (const - gchar *) and makes a copy of it. - NULL is not a valid string; use - maybe types to encode that. If the 'o' or - 'g' characters are used, care must be taken to ensure that the passed string is a valid D-Bus - object path or D-Bus type signature, respectively. - - - Upon encounting 's', 'o' or 'g', g_variant_get() takes a pointer to a - (gchar *) (ie: (gchar **)) and - sets it to a newly-allocated copy of the string. It is appropriate to free this copy using - g_free(). - NULL may also be passed to indicate that the value of the - string should be ignored (in which case no copy is made). - - - - Examples - - - - - - - Variants - - - Characters: v - - - - - Upon encountering a 'v', - g_variant_new() takes a (GVariant *). The value of the - GVariant is used as the contents of the variant value. - - - Upon encountering a 'v', g_variant_get() takes a pointer to a - (GVariant *) (ie: (GVariant **) - ). It is set to a new reference to a GVariant instance - containing the contents of the variant value. It is appropriate to free this reference using - g_variant_unref(). - NULL may also be passed to indicate that the value should be - ignored (in which case no new reference is created). - - - - Examples - - - - - - - - Arrays - - - Characters: a - - - - - Upon encountering an 'a' character followed by a type string, - g_variant_new() will take a - (GVariantBuilder *) that has been created as an array builder - for an array of the type given in the type string. The builder will have - g_variant_builder_end() called on it and the - result will be used as the value. As a special exception, if the given type string is a definite type, then - NULL may be given to mean an empty array of that type. - - - - Upon encountering an 'a' character followed by a type string, - g_variant_get() will take a pointer to a - (GVariantIter *) (ie: - (GVariantIter **)). - A new heap-allocated iterator is created and returned, initialised for iterating over the elements of the array. - This iterator should be freed when you are done with it, using - g_variant_iter_free(). - NULL may also be given to indicate that the value of the array - should be ignored. - - - - Examples - - - - - - - Maybe Types - - - Characters: m - - - - Maybe types are handled in two separate ways depending on the format string that follows the - 'm'. The method that is used currently depends entirely on the character immediately following the - 'm'. - - - - The first way is used with format strings starting with 'a', 's', - 'o', 'g', 'v', '@', - '*', '?', 'r', '&', or - '^'. In all of these cases, for non-maybe types, - g_variant_new() takes a pointer to a - non-NULL value and - g_variant_get() returns (by reference) a - non-NULL pointer. When any of these format strings are - prefixed with an 'm', the type of arguments that are collected does not change in any way, but - NULL becomes a permissible value, to indicate the Nothing case. - - - Note that the "special exception" introduced in the array section for constructing empty arrays is ignored - here. Using a NULL pointer with the format string 'mas' constructs - the Nothing value -- not an empty array. - - - The second way is used with all other format strings. For - g_variant_new() an additional - gboolean argument is collected and for - g_variant_get() an additional - (gboolean *). Following this argument, the arguments that are normally - collected for the equivalent non-maybe type will be collected. - - - If FALSE is given to - g_variant_new() then the Nothing value is constructed and - the collected arguments are ignored. Otherwise (if TRUE was - given), the arguments are used in the normal way to create the Just value. - - - If NULL is given to - g_variant_get() then the value is ignored. If a - non-NULL pointer is given then it is used to return by reference - whether the value was Just. In the case that the value was Just, the - gboolean will be set to - TRUE and the value will be stored in the arguments in the usual - way. In the case that the value was Nothing, the gboolean will be set to - FALSE and the arguments will be collected in the normal way - but have their values set to binary zero. - - - - Examples - - - - - - - Tuples - - - Characters: () - - - - - Tuples are handled by handling each item in the tuple, in sequence. Each item is handled in the usual way. - - - - Examples - - - - - - - GVariant * - - - Characters: @, *, ?, r - - - - - Upon encountering a '@' in front of a type string, - g_variant_new() takes a - non-NULL pointer to a - GVariant and uses its value directly instead of collecting arguments to - create the value. The provided GVariant must have a type that matches the - type string following the '@'. '*' is - the same as '@*' (ie: take a GVariant of any type). - '?' is the same as '@?' (ie: take a - GVariant of any basic type). 'r' is the same as - '@r' (ie: take a GVariant of any tuple type). - - - Upon encountering a '@' in front of a type string, - g_variant_get() - takes a pointer to a (GVariant *) (ie: a - (GVariant **)) and sets it to a new reference to a - GVariant containing the value (instead of deconstructing the value into - C types in the usual way). NULL can be given to ignore the - value. '*', '?' and 'r' are handled in a way analogous to - what is stated above. - - - You can always use '*' as an alternative to '?', 'r' or any - use of '@'. Using the other characters where possible is recommended, however, due to the - improvements in type safety and code self-documentation. - - - - Examples - - - - - - - Dictionaries - - - Characters: {} - - - - - Dictionary entries are handled by handling first the key, then the value. Each is handled in the usual way. - - - - Examples - - - - - - To extract data from nested dictionaries you can go through a vardict. - - - - Examples - -, 'max': <%i>}})", - "/object/path", value, max); -{ - GVariant *params; - GVariant *p_brightness; - gchar *obj - gint p_max; - - g_variant_get (data, "(o@a{?*})", &obj, ¶ms); - g_print ("object_path: %s\n", obj); - g_free (obj); - - p_brightness = g_variant_lookup_value (params, "brightness", G_VARIANT_TYPE_VARDICT); - g_variant_lookup (p_brightness, "max", "i", &p_max); - g_print ("max: %d\n", p_max); - g_variant_unref (params); -}]]> - - - - - - Pointers - - - Characters: & - - - - - The '&' character is used to indicate that serialized data should be directly exchanged via a - pointer. - - - Currently, the only use for this character is when it is applied to a string (ie: '&s', - '&o' or '&g'). For - g_variant_new() this has absolutely no effect. The string - is collected and duplicated normally. For g_variant_get() - it means that instead of creating a newly allocated copy of the string, a pointer to the serialized data is - returned. This pointer should not be freed. Validity checks are performed to ensure that the string data will - always be properly nul-terminated. - - - - Examples - - - - - - - Convenience Conversions - - - Characters: ^ - - - - - The '^' character currently supports conversion to and from bytestrings or to and from arrays - of strings or bytestrings. It does not support byte arrays. It has a number of forms. - - - - In all forms, when used with g_variant_new() one - pointer value is collected from the variable arguments and passed to a function (as given in the table below). - The result of that function is used as the value for this position. When used with - g_variant_get() one pointer value is produced by using - the function (given in the table) and returned by reference. - - - - - - - - - - - - - Conversion - - - - - - Used with g_variant_new() - - - - - - - Used with g_variant_get() - - - - - - - - - - ^as - - - - - - equivalent to g_variant_new_strv() - - - - - equivalent to g_variant_dup_strv() - - - - - - - - - ^a&s - - - - - - equivalent to g_variant_get_strv() - - - - - - - - - ^ao - - - - - - equivalent to g_variant_new_objv() - - - - - equivalent to g_variant_dup_objv() - - - - - - - - - ^a&o - - - - - - equivalent to g_variant_get_objv() - - - - - - - - - ^ay - - - - - - equivalent to g_variant_new_bytestring() - - - - - equivalent to g_variant_dup_bytestring() - - - - - - - - - ^&ay - - - - - - equivalent to g_variant_get_bytestring() - - - - - - - - - ^aay - - - - - - equivalent to g_variant_new_bytestring_array() - - - - - equivalent to g_variant_dup_bytestring_array() - - - - - - - - - ^a&ay - - - - - - equivalent to g_variant_get_bytestring_array() - - - - - - - - - - diff --git a/docs/reference/glib/host-utils.md b/docs/reference/glib/host-utils.md new file mode 100644 index 0000000..5a86b25 --- /dev/null +++ b/docs/reference/glib/host-utils.md @@ -0,0 +1,30 @@ +Title: Hostname Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2008 Dan Winship + +# Hostname Utilities + +Functions for manipulating internet hostnames; in particular, for +converting between Unicode and ASCII-encoded forms of +Internationalized Domain Names (IDNs). + +The +[Internationalized Domain Names for Applications (IDNA)](http://www.ietf.org/rfc/rfc3490.txt) +standards allow for the use +of Unicode domain names in applications, while providing +backward-compatibility with the old ASCII-only DNS, by defining an +ASCII-Compatible Encoding of any given Unicode name, which can be +used with non-IDN-aware applications and protocols. (For example, +“Παν語.org” maps to “xn--4wa8awb4637h.org”.) + +## Hostname Conversions + + * [func@GLib.hostname_to_ascii] + * [func@GLib.hostname_to_unicode] + +## Hostname Checks + + * [func@GLib.hostname_is_non_ascii] + * [func@GLib.hostname_is_ascii_encoded] + * [func@GLib.hostname_is_ip_address] + diff --git a/docs/reference/glib/i18n.md b/docs/reference/glib/i18n.md new file mode 100644 index 0000000..7c99be4 --- /dev/null +++ b/docs/reference/glib/i18n.md @@ -0,0 +1,49 @@ +Title: Internationalization + +# Internationalization + +GLib doesn't force any particular localization method upon its users. But +since GLib itself is localized using the `gettext()` mechanism, it seems +natural to offer the de-facto standard `gettext()` support macros in an +easy-to-use form. + +In order to use these macros in an application, you must include +``. For use in a library, you must include `` +after defining the `GETTEXT_PACKAGE` macro suitably for your library: + +```c +#define GETTEXT_PACKAGE "gtk4" +#include +``` + +For an application, note that you also have to call `bindtextdomain()`, +`bind_textdomain_codeset()`, `textdomain()` and `setlocale()` early on in your +`main()` to make `gettext()` work. For example: + +```c +#include +#include + +int +main (int argc, char **argv) +{ + setlocale (LC_ALL, ""); + bindtextdomain (GETTEXT_PACKAGE, DATADIR "/locale"); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + textdomain (GETTEXT_PACKAGE); + + // Rest of your application. +} +``` + +where `DATADIR` is as typically provided by Automake or Meson. + +For a library, you only have to call `bindtextdomain()` and +`bind_textdomain_codeset()` in your initialization function. If your library +doesn't have an initialization function, you can call the functions before +the first translated message. + +The [gettext +manual](http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers) +covers details of how to integrate gettext into a project’s build system and +workflow. diff --git a/docs/reference/glib/logging.md b/docs/reference/glib/logging.md new file mode 100644 index 0000000..c4a7262 --- /dev/null +++ b/docs/reference/glib/logging.md @@ -0,0 +1,137 @@ +Title: Message Logging + +# Message Logging + +The `g_return` family of macros (`g_return_if_fail()`, +`g_return_val_if_fail()`, `g_return_if_reached()`, +`g_return_val_if_reached()`) should only be used for programming errors, a +typical use case is checking for invalid parameters at the beginning of a +public function. They should not be used if you just mean "if (error) +return", they should only be used if you mean "if (bug in program) return". +The program behavior is generally considered undefined after one of these +checks fails. They are not intended for normal control flow, only to give a +perhaps-helpful warning before giving up. + +Structured logging output is supported using `g_log_structured()`. This +differs from the traditional `g_log()` API in that log messages are handled +as a collection of key–value pairs representing individual pieces of +information, rather than as a single string containing all the information +in an arbitrary format. + +The convenience macros `g_info()`, `g_message()`, `g_debug()`, `g_warning()` +and `g_error()` will use the traditional `g_log()` API unless you define the +symbol `G_LOG_USE_STRUCTURED` before including `glib.h`. But note that even +messages logged through the traditional `g_log()` API are ultimatively +passed to `g_log_structured()`, so that all log messages end up in same +destination. If `G_LOG_USE_STRUCTURED` is defined, `g_test_expect_message()` +will become ineffective for the wrapper macros `g_warning()` and friends +(see [Testing for Messages](#testing-for-messages).) + +The support for structured logging was motivated by the following needs +(some of which were supported previously; others weren’t): + +- Support for multiple logging levels. +- Structured log support with the ability to add `MESSAGE_ID`s (see + `g_log_structured()`). +- Moving the responsibility for filtering log messages from the program to + the log viewer — instead of libraries and programs installing log handlers + (with `g_log_set_handler()`) which filter messages before output, all log + messages are outputted, and the log viewer program (such as + [`journalctl`](https://www.freedesktop.org/software/systemd/man/journalctl.html)) + must filter them. This is based on the idea that bugs are sometimes hard + to reproduce, so it is better to log everything possible and then use + tools to analyse the logs than it is to not be able to reproduce a bug to + get additional log data. Code which uses logging in performance-critical + sections should compile out the `g_log_structured()` calls in release + builds, and compile them in in debugging builds. +- A single writer function which handles all log messages in a process, from + all libraries and program code; rather than multiple log handlers with + poorly defined interactions between them. This allows a program to easily + change its logging policy by changing the writer function, for example to + log to an additional location or to change what logging output fallbacks + are used. The log writer functions provided by GLib are exposed publicly + so they can be used from programs’ log writers. This allows log writer + policy and implementation to be kept separate. +- If a library wants to add standard information to all of its log messages + (such as library state) or to redact private data (such as passwords or + network credentials), it should use a wrapper function around its + `g_log_structured()` calls or implement that in the single log writer + function. +- If a program wants to pass context data from a `g_log_structured()` call + to its log writer function so that, for example, it can use the correct + server connection to submit logs to, that user data can be passed as a + zero-length `GLogField` to `g_log_structured_array()`. +- Color output needed to be supported on the terminal, to make reading + through logs easier. + +## Using Structured Logging + +To use structured logging (rather than the old-style logging), either use +the `g_log_structured()` and `g_log_structured_array()` functions; or define +`G_LOG_USE_STRUCTURED` before including any GLib header, and use the +`g_message()`, `g_debug()`, `g_error()` (etc.) macros. + +You do not need to define `G_LOG_USE_STRUCTURED` to use +`g_log_structured()`, but it is a good idea to avoid confusion. + +## Log Domains + +Log domains may be used to broadly split up the origins of log messages. +Typically, there are one or a few log domains per application or library. +`G_LOG_DOMAIN` should be used to define the default log domain for the current +compilation unit — it is typically defined at the top of a source file, or +in the preprocessor flags for a group of source files. + +Log domains must be unique, and it is recommended that they are the +application or library name, optionally followed by a hyphen and a +sub-domain name. For example, `bloatpad` or `bloatpad-io`. + +## Debug Message Output + +The default log functions (`g_log_default_handler()` for the old-style API +and `g_log_writer_default()` for the structured API) both drop debug and +informational messages by default, unless the log domains of those messages +are listed in the `G_MESSAGES_DEBUG` environment variable (or it is set to +`all`). + +It is recommended that custom log writer functions re-use the +`G_MESSAGES_DEBUG` environment variable, rather than inventing a custom one, +so that developers can re-use the same debugging techniques and tools across +projects. Since GLib 2.68, this can be implemented by dropping messages for +which `g_log_writer_default_would_drop()` returns `TRUE`. + +## Testing for Messages + +With the old `g_log()` API, `g_test_expect_message()` and +`g_test_assert_expected_messages()` could be used in simple cases to check +whether some code under test had emitted a given log message. These +functions have been deprecated with the structured logging API, for several +reasons: + +- They relied on an internal queue which was too inflexible for many use + cases, where messages might be emitted in several orders, some messages + might not be emitted deterministically, or messages might be emitted by + unrelated log domains. +- They do not support structured log fields. +- Examining the log output of code is a bad approach to testing it, and + while it might be necessary for legacy code which uses `g_log()`, it + should be avoided for new code using `g_log_structured()`. + +They will continue to work as before if `g_log()` is in use (and +`G_LOG_USE_STRUCTURED` is not defined). They will do nothing if used with +the structured logging API. + +Examining the log output of code is discouraged: libraries should not emit +to stderr during defined behaviour, and hence this should not be tested. If +the log emissions of a library during undefined behaviour need to be tested, +they should be limited to asserting that the library aborts and prints a +suitable error message before aborting. This should be done with +`g_test_trap_assert_stderr()`. + +If it is really necessary to test the structured log messages emitted by a +particular piece of code – and the code cannot be restructured to be more +suitable to more conventional unit testing – you should write a custom log +writer function (see `g_log_set_writer_func()`) which appends all log +messages to a queue. When you want to check the log messages, examine and +clear the queue, ignoring irrelevant log messages (for example, from log +domains other than the one under test). diff --git a/docs/reference/glib/macros.md b/docs/reference/glib/macros.md new file mode 100644 index 0000000..2e5dc27 --- /dev/null +++ b/docs/reference/glib/macros.md @@ -0,0 +1,896 @@ +Title: Macros + +# Macros + +GLib provides a set of C pre-processor macros and symbols for commonly-used +language and platform features. + +## Platform + +`G_OS_WIN32` +: This macro is defined only on Windows, so you can bracket Windows-specific + code using `#ifdef G_OS_WIN32 ... #endif`. + +`G_OS_UNIX` + +: This macro is defined only on UNIX and UNIX-like systems, so you can bracket + UNIX-specific code in `#ifdef G_OS_UNIX ... #endif`. To detect whether to + compile features that require a specific kernel or operating system, check + for the appropriate OS-specific predefined macros instead, for example: + + - Linux kernel (any libc, including glibc, musl or Android): `#ifdef __linux__` + - Linux kernel and GNU user-space: `#if defined(__linux__) && defined(__GLIBC__)` + - FreeBSD kernel (any libc, including glibc): `#ifdef __FreeBSD_kernel__` + - FreeBSD kernel and user-space: `#ifdef __FreeBSD__` + - Apple operating systems (macOS, iOS, tvOS), regardless of whether + Cocoa/Carbon toolkits are available: `#ifdef __APPLE__` + + See for more. + + +`G_DIR_SEPARATOR` +: The directory separator character. This is `'/'` on UNIX machines and `'\'` under Windows. + +`G_DIR_SEPARATOR_S` +: The directory separator as a string. This is `"/"` on UNIX machines and `"\"` under Windows. + +`G_IS_DIR_SEPARATOR(ch)` +: Checks whether a character is a directory separator. It returns true for `'/'` on UNIX machines and for `'\'` or `'/'` under Windows. Available since 2.6. + +`G_SEARCHPATH_SEPARATOR` +: The search path separator character. This is `':'` on UNIX machines and `';'` under Windows. + +`G_SEARCHPATH_SEPARATOR_S` +: The search path separator as a string. This is `":"` on UNIX machines and `";"` under Windows. + +## Values + +`TRUE` +: Defines the true value for the `gboolean` type. + +`FALSE` +: Defines the false value for the `gboolean` type. + +`NULL` +: Defines the standard `NULL` pointer. + +## Maths + +`MIN(a, b)` +: Calculates the minimum of `a` and `b`. + +`MAX(a, b)` +: Calculates the maximum of `a` and `b`. + +`ABS(value)` + +: Calculates the absolute value of a given numerical value. The absolute value + is simply the number with any negative sign taken away. + + For example, + + - `ABS(-10)` is 10. + - `ABS(10)` is also 10. + + +`CLAMP(value, low, high)` + +: Ensures that a value is between the limits set by `low` and `high`. If `low` is + greater than `high` the result is undefined. + + For example, + + - `CLAMP(5, 10, 15)` is 10. + - `CLAMP(15, 5, 10)` is 10. + - `CLAMP(20, 15, 25)` is 20. + + +`G_APPROX_VALUE(a, b, epsilon)` + +: Evaluates to true if the absolute difference between the given numerical + values `a` and `b` is smaller than `epsilon`, and to false otherwise. + + For example, + + - `G_APPROX_VALUE (5, 6, 2)` evaluates to true + - `G_APPROX_VALUE (3.14, 3.15, 0.001)` evaluates to false + - `G_APPROX_VALUE (n, 0.f, FLT_EPSILON)` evaluates to true if `n` is within + the single precision floating point epsilon from zero + + Available since: 2.58 + + +## Structure Access + +`G_STRUCT_MEMBER(member_type, struct_pointer, offset)` +: Returns a member of a structure at a given offset, using the given type. + +`G_STRUCT_MEMBER_P(struct_pointer, offset)` +: Returns an untyped pointer to a given offset of a struct. + +`G_STRUCT_OFFSET(struct_type, member_name)` +: Returns the offset, in bytes, of a member of a struct. + Consider using standard C `offsetof()`, available since at least C89 + and C++98, in new code (but note that `offsetof()` returns a `size_t` + rather than a `long`). + + +## Array Utilties + +`G_N_ELEMENTS(array)` +: Determines the number of elements in an array. The array must be + declared so the compiler knows its size at compile-time; this + macro will not work on an array allocated on the heap, only static + arrays or arrays on the stack. + + +## Miscellaneous Macros + +These macros provide more specialized features which are not needed so often +by application programmers. + +`G_STMT_START` +: Starts a multi-statement macro block so that it can be used in places + where only one statement is expected by the compiler. + +`G_STMT_END` +: Ends a multi-statement macro block so that it can be used in places + where only one statement is expected by the compiler. + +`G_BEGIN_DECLS` +: Used (along with `G_END_DECLS`) to bracket C header files that may be + included by C++ sources. If the compiler in use is a C++ compiler, starts + an `extern "C"` around the header. + +`G_END_DECLS` +: Used (along with `G_BEGIN_DECLS`) to bracket C header files that may be + included by C++ sources, or compiled by a C++ compiler. If the compiler + in use is a C++ compiler, ends the `extern "C"` block around the header. + + +`G_VA_COPY(ap1, ap2)` + +: Portable way to copy `va_list` variables. + + In order to use this function, you must include `string.h` yourself, + because this macro may use `memmove()` and GLib does not include + `string.h` for you. + + Each invocation of `G_VA_COPY (ap1, ap2)` must be matched with a + corresponding `va_end (ap1)` call in the same function. + + This is equivalent to standard C `va_copy()`, available since C99 + and C++11, which should be preferred in new code. + + +`G_STRINGIFY(macro_or_string)` + +: Accepts a macro or a string and converts it into a string after + preprocessor argument expansion. For example, the following code: + + #define AGE 27 + const gchar *greeting = G_STRINGIFY (AGE) " today!"; + + is transformed by the preprocessor into (code equivalent to): + + const gchar *greeting = "27 today!"; + + +`G_PASTE(identifier1, identifier2)` + +: Yields a new preprocessor pasted identifier `identifier1identifier2` from its expanded + arguments `identifier1` and `identifier2`. For example,the following code: + + #define GET(traveller,method) G_PASTE(traveller_get_, method) (traveller) + const char *name = GET (traveller, name); + const char *quest = GET (traveller, quest); + Color *favourite = GET (traveller, favourite_colour); + + is transformed by the preprocessor into: + + const char *name = traveller_get_name (traveller); + const char *quest = traveller_get_quest (traveller); + Color *favourite = traveller_get_favourite_colour (traveller); + + Available since: 2.20 + + +`G_STATIC_ASSERT(expr)` + +: The `G_STATIC_ASSERT()` macro lets the programmer check a condition at + compile time. The condition needs to be compile time computable. The + macro can be used in any place where a `typedef` is valid. + + A `typedef` is generally allowed in exactly the same places that + a variable declaration is allowed. For this reason, you should + not use `G_STATIC_ASSERT()` in the middle of blocks of code. + + The macro should only be used once per source code line. + + Since: 2.20 + + +`G_STATIC_ASSERT_EXPR(expr)` + +: The `G_STATIC_ASSERT_EXPR()` macro lets the programmer check a condition + at compile time. The condition needs to be compile time computable. + + Unlike `G_STATIC_ASSERT()`, this macro evaluates to an expression + and, as such, can be used in the middle of other expressions. + Its value should be ignored. This can be accomplished by placing + it as the first argument of a comma expression. + + #define ADD_ONE_TO_INT(x) \ + (G_STATIC_ASSERT_EXPR(sizeof (x) == sizeof (int)), ((x) + 1)) + + Since: 2.30 + + +## Compiler + + +`G_GNUC_EXTENSION` +: Expands to `__extension__` when GCC is used as the compiler. This simply + tells GCC not to warn about the following non-standard code when compiling + with the `-pedantic` option. + + +`G_GNUC_CONST` + +: Expands to the GNU C `const` function attribute if the compiler is GCC. + Declaring a function as `const` enables better optimization of calls to + the function. A `const` function doesn't examine any values except its + parameters, and has no effects except its return value. + + Place the attribute after the declaration, just before the semicolon. + + gchar g_ascii_tolower (gchar c) G_GNUC_CONST; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute) for more details. + + A function that has pointer arguments and examines the data pointed to + must not be declared `const`. Likewise, a function that calls a non-`const` + function usually must not be `const`. It doesn't make sense for a `const` + function to return `void`. + + +`G_GNUC_PURE` + +: Expands to the GNU C `pure` function attribute if the compiler is GCC. + Declaring a function as `pure` enables better optimization of calls to + the function. A `pure` function has no effects except its return value + and the return value depends only on the parameters and/or global + variables. + + Place the attribute after the declaration, just before the semicolon. + + gboolean g_type_check_value (const GValue *value) G_GNUC_PURE; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute) for more details. + + +`G_GNUC_UNUSED` + +: Expands to the GNU C `unused` function attribute if the compiler is gcc. + It is used for declaring functions and arguments which may never be used. + It avoids possible compiler warnings. + + For functions, place the attribute after the declaration, just before the + semicolon. For arguments, place the attribute at the beginning of the + argument declaration. + + void my_unused_function (G_GNUC_UNUSED gint unused_argument, + gint other_argument) G_GNUC_UNUSED; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute) for more details. + + +`G_GNUC_MALLOC` + +: Expands to the GNU C `malloc` function attribute if the compiler is GCC. + + Declaring a function as `malloc` enables better optimization of the function, + but must only be done if the allocation behaviour of the function is fully + understood, otherwise miscompilation can result. + + A function can have the `malloc` attribute if it returns a pointer which is + guaranteed to not alias with any other pointer valid when the function + returns, and moreover no pointers to valid objects occur in any storage + addressed by the returned pointer. + + In practice, this means that `G_GNUC_MALLOC` can be used with any function + which returns unallocated or zeroed-out memory, but not with functions which + return initialised structures containing other pointers, or with functions + that reallocate memory. This definition changed in GLib 2.58 to match the + stricter definition introduced around GCC 5. + + Place the attribute after the declaration, just before the semicolon. + + gpointer g_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1); + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-functions-that-behave-like-malloc) + for more details. + + Since: 2.6 + + +`G_GNUC_DEPRECATED` + +: Expands to the GNU C `deprecated` attribute if the compiler is GCC. + It can be used to mark `typedef`s, variables and functions as deprecated. + When called with the `-Wdeprecated-declarations` option, + gcc will generate warnings when deprecated interfaces are used. + + Place the attribute after the declaration, just before the semicolon. + + int my_mistake (void) G_GNUC_DEPRECATED; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-deprecated-function-attribute) for more details. + + See also: `G_DEPRECATED` + + Since: 2.2 + + +`G_GNUC_DEPRECATED_FOR(func)` + +: Like `G_GNUC_DEPRECATED`, but names the intended replacement for the + deprecated symbol if the version of gcc in use is new enough to support + custom deprecation messages. + + Place the attribute after the declaration, just before the semicolon. + + int my_mistake (void) G_GNUC_DEPRECATED_FOR(my_replacement); + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-deprecated-function-attribute) for more details. + + Note that if `func` is a macro, it will be expanded in the warning message. + You can enclose it in quotes to prevent this. (The quotes will show up + in the warning, but it's better than showing the macro expansion.) + + Since: 2.26 + + +`G_GNUC_NORETURN` + +: Expands to the GNU C `noreturn` function attribute if the compiler is GCC. + It is used for declaring functions which never return. It enables + optimization of the function, and avoids possible compiler warnings. + + Since 2.68, it is recommended that code uses `G_NORETURN` instead of + `G_GNUC_NORETURN`, as that works on more platforms and compilers (in + particular, MSVC and C++11) than `G_GNUC_NORETURN`, which works with GCC and + Clang only. `G_GNUC_NORETURN` continues to work, so has not been deprecated + yet. + + Place the attribute after the declaration, just before the semicolon. + + void g_abort (void) G_GNUC_NORETURN; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noreturn-function-attribute) for more details. + + +`G_GNUC_FALLTHROUGH` + +: Expands to the GNU C `fallthrough` statement attribute if the compiler supports it. + This allows declaring case statement to explicitly fall through in switch + statements. To enable this feature, use `-Wimplicit-fallthrough` during + compilation. + + Put the attribute right before the case statement you want to fall through to. + + switch (foo) + { + case 1: + g_message ("it's 1"); + G_GNUC_FALLTHROUGH; + case 2: + g_message ("it's either 1 or 2"); + break; + } + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#index-fallthrough-statement-attribute) for more details. + + Since: 2.60 + + +`G_GNUC_FORMAT(idx)` + +: Expands to the GNU C `format_arg` function attribute if the compiler + is GCC. This function attribute specifies that a function takes a + format string for a `printf()`, `scanf()`, `strftime()` or `strfmon()` + style function and modifies it, so that the result can be passed to + a `printf()`, `scanf()`, `strftime()` or `strfmon()` style function + (with the remaining arguments to the format function the same as they + would have been for the unmodified string). + + Place the attribute after the function declaration, just before the + semicolon. + + gchar *g_dgettext (gchar *domain_name, gchar *msgid) G_GNUC_FORMAT (2); + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-Wformat-nonliteral-1) for more details. + + +`G_GNUC_NULL_TERMINATED` + +: Expands to the GNU C `sentinel` function attribute if the compiler is GCC. + This function attribute only applies to variadic functions and instructs + the compiler to check that the argument list is terminated with an + explicit `NULL`. + + Place the attribute after the declaration, just before the semicolon. + + gchar *g_strconcat (const gchar *string1, + ...) G_GNUC_NULL_TERMINATED; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-sentinel-function-attribute) for more details + + Since: 2.8 + + +`G_GNUC_WARN_UNUSED_RESULT` + +: Expands to the GNU C `warn_unused_result` function attribute if the compiler + is GCC. This function attribute makes the compiler emit a warning if the + result of a function call is ignored. + + Place the attribute after the declaration, just before the semicolon. + + GList *g_list_append (GList *list, + gpointer data) G_GNUC_WARN_UNUSED_RESULT; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute) for more details. + + Since: 2.10 + + +`G_GNUC_NO_INLINE` + +: Expands to the GNU C `noinline` function attribute if the compiler is GCC. + + Declaring a function as `noinline` prevents the function from being + considered for inlining. + + This macro is provided for retro-compatibility and will be eventually + deprecated; `G_NO_INLINE` should be used instead. + + The attribute may be placed before the declaration or definition, + right before the `static` keyword. + + G_GNUC_NO_INLINE + static int + do_not_inline_this (void) + { + // ... + } + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noinline-function-attribute) + for more details. + + See also: `G_NO_INLINE`, `G_ALWAYS_INLINE`. + + Since: 2.58 + + +`G_GNUC_NO_INSTRUMENT` + +: Expands to the GNU C `no_instrument_function` function attribute if the + compiler is GCC. Functions with this attribute will not be instrumented + for profiling, when the compiler is called with the + `-finstrument-functions` option. + + Place the attribute after the declaration, just before the semicolon. + + int do_uninteresting_things (void) G_GNUC_NO_INSTRUMENT; + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-no_005finstrument_005ffunction-function-attribute) for more details. + + +`G_GNUC_MAY_ALIAS` + +: Expands to the GNU C `may_alias` type attribute if the compiler is GCC. + Types with this attribute will not be subjected to type-based alias + analysis, but are assumed to alias with any other type, just like `char`. + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-may_005falias-type-attribute) for details. + + Since: 2.14 + + +`G_GNUC_FUNCTION` + +: Expands to `""` on all modern compilers, and to `__FUNCTION__` on GCC version 2.x. Don't use it. + + Deprecated: 2.16: Use `G_STRFUNC()` instead + + +`G_GNUC_PRETTY_FUNCTION` + +: Expands to `""` on all modern compilers, and to `__PRETTY_FUNCTION__` on GCC version 2.x. Don't use it. + + Deprecated: 2.16: Use `G_STRFUNC()` instead + + +`G_GNUC_CHECK_VERSION(major, minor)` + +: Expands to a check for a compiler with `__GNUC__` defined and a version + greater than or equal to the major and minor numbers provided. For example, + the following would only match on compilers such as GCC 4.8 or newer. + + #if G_GNUC_CHECK_VERSION(4, 8) + // ... + #endif + + Since: 2.42 + + +`G_GNUC_BEGIN_IGNORE_DEPRECATIONS` + +: Tells GCC (if it is a new enough version) to temporarily stop emitting + warnings when functions marked with `G_GNUC_DEPRECATED` or + `G_GNUC_DEPRECATED_FOR` are called. This is useful for when you have + one deprecated function calling another one, or when you still have + regression tests for deprecated functions. + + Use `G_GNUC_END_IGNORE_DEPRECATIONS` to resume warning again. (If you + are not compiling with `-Wdeprecated-declarations` then neither macro + has any effect.) + + This macro can be used either inside or outside of a function body, + but must appear on a line by itself. + + static void + test_deprecated_function (void) + { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + g_assert_cmpint (my_mistake (), ==, 42); + G_GNUC_END_IGNORE_DEPRECATIONS + } + + Both this macro and the corresponding `G_GNUC_END_IGNORE_DEPRECATIONS` + are considered statements, so they should not be used around branching + or loop conditions; for instance, this use is invalid: + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + if (check == some_deprecated_function ()) + G_GNUC_END_IGNORE_DEPRECATIONS + { + do_something (); + } + + and you should move the deprecated section outside the condition + + // Solution A + some_data_t *res; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + res = some_deprecated_function (); + G_GNUC_END_IGNORE_DEPRECATIONS + + if (check == res) + { + do_something (); + } + + // Solution B + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + if (check == some_deprecated_function ()) + { + do_something (); + } + G_GNUC_END_IGNORE_DEPRECATIONS + + Since: 2.32 + + +`G_GNUC_END_IGNORE_DEPRECATIONS` + +: Undoes the effect of `G_GNUC_BEGIN_IGNORE_DEPRECATIONS`, telling + GCC to resume outputting warnings again (assuming those warnings + had been enabled to begin with). + + This macro can be used either inside or outside of a function body, + but must appear on a line by itself. + + Since: 2.32 + + +`G_C_STD_VERSION` + +: The C standard version the code is compiling against, it's normally + defined with the same value of `__STDC_VERSION__` for C standard + compatible compilers, while it uses the lowest standard version + in pure MSVC, given that in such compiler the definition depends on + a compilation flag. + + This is granted to be undefined when compiling with a C++ compiler. + + See also: `G_C_STD_CHECK_VERSION` and `G_CXX_STD_VERSION` + + Since: 2.76 + + +`G_C_STD_CHECK_VERSION(version)` + +: Macro to check if the current compiler supports a specified version + of the C standard. Such value must be numeric and can be provided both + in the short form for the well-known versions (e.g. `90`, `99`...) or in + the complete form otherwise (e.g. `199000L`, `199901L`, `205503L`...). + + When a C++ compiler is used, the macro is defined and evaluates to false. + + This value is compared against `G_C_STD_VERSION`. + + #if G_C_STD_CHECK_VERSION(17) + // ... + #endif + + See also: `G_CXX_STD_CHECK_VERSION` + + Since: 2.76 + + +`G_CXX_STD_VERSION` + +: The C++ standard version the code is compiling against, it's defined + with the same value of `__cplusplus` for C++ standard compatible + compilers, while it uses `_MSVC_LANG` in MSVC, given that the + standard definition depends on a compilation flag in such compiler. + + This is granted to be undefined when not compiling with a C++ compiler. + + See also: `G_CXX_STD_CHECK_VERSION` and `G_C_STD_VERSION` + + Since: 2.76 + + +`G_CXX_STD_CHECK_VERSION(version)` + +: Macro to check if the current compiler supports a specified @version + of the C++ standard. Such value must be numeric and can be provided both + in the short form for the well-known versions (e.g. `11`, `17`...) or in + the complete form otherwise (e.g. `201103L`, `201703L`, `205503L`...). + + When a C compiler is used, the macro evaluates to false. + + This value is compared against `G_CXX_STD_VERSION`. + + #if G_CXX_STD_CHECK_VERSION(20) + // ... + #endif + + See also: `G_C_STD_CHECK_VERSION` + + Since: 2.76 + + +`G_LIKELY(expr)` + +: Hints the compiler that the expression is likely to evaluate to + a true value. The compiler may use this information for optimizations. + + if (G_LIKELY (random () != 1)) + g_print ("not one"); + + Since: 2.2 + + +`G_UNLIKELY(expr)` + +: Hints the compiler that the expression is unlikely to evaluate to + a true value. The compiler may use this information for optimizations. + + if (G_UNLIKELY (random () == 1)) + g_print ("a random one"); + + Since: 2.2 + + +`G_ALIGNOF(type)` + +: Evaluates to the minimal alignment required by the platform ABI for values + of the given type. The address of a variable or struct member of the given + type must always be a multiple of this alignment. For example, most + platforms require int variables to be aligned at a 4-byte boundary, so + `G_ALIGNOF (int)` is 4 on most platforms. + + Note this is not necessarily the same as the value returned by GCC’s + `__alignof__` operator, which returns the preferred alignment for a type. + The preferred alignment may be a stricter alignment than the minimal + alignment. + + Since: 2.60 + + +`G_SIZEOF_MEMBER(struct_type, member_name)` + +: Evaluates to the size in bytes of `member_name` in the struct definition + without having a declared instance of `struct_type`. + + Since: 2.64 + + +`G_NORETURN` + +: Expands to the GNU C or MSVC `noreturn` function attribute depending on + the compiler. It is used for declaring functions which never return. + Enables optimization of the function, and avoids possible compiler warnings. + + Note that `G_NORETURN` supersedes the previous `G_GNUC_NORETURN` macro, which + will eventually be deprecated. `G_NORETURN` supports more platforms. + + Place the attribute before the function declaration as follows: + + G_NORETURN void g_abort (void); + + Since: 2.68 + + +`G_NORETURN_FUNCPTR` + +: Expands to the GNU C or MSVC `noreturn` function attribute depending on + the compiler. It is used for declaring function pointers which never return. + Enables optimization of the function, and avoids possible compiler warnings. + + Place the attribute before the function declaration as follows: + + G_NORETURN_FUNCPTR void (*funcptr) (void); + + Note that if the function is not a function pointer, you can simply use + the `G_NORETURN` macro as follows: + + G_NORETURN void g_abort (void); + + Since: 2.68 + + +`G_ALWAYS_INLINE` + +: Expands to the GNU C `always_inline` or MSVC `__forceinline` function + attribute depending on the compiler. It is used for declaring functions + as always inlined, ignoring the compiler optimization levels. + + The attribute may be placed before the declaration or definition, + right before the `static` keyword. + + G_ALWAYS_INLINE + static int + do_inline_this (void) + { + // ... + } + + See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-always_005finline-function-attribute) + and the [MSVC documentation](https://docs.microsoft.com/en-us/visualstudio/misc/inline-inline-forceinline) + for more details. + + Since: 2.74 + + +`G_NO_INLINE` + +: Expands to the GNU C or MSVC `noinline` function attribute + depending on the compiler. It is used for declaring functions + preventing from being considered for inlining. + + Note that `G_NO_INLINE` supersedes the previous `G_GNUC_NO_INLINE` + macro, which will eventually be deprecated. `G_NO_INLINE` supports + more platforms. + + The attribute may be placed before the declaration or definition, + right before the `static` keyword. + + G_NO_INLINE + static int + do_not_inline_this (void) + { + // ... + } + + Since: 2.74 + + +`G_STRLOC` +: Expands to a string identifying the current code position. + +`G_STRFUNC` +: Expands to a string identifying the current function. Since: 2.4 + +`G_GNUC_INTERNAL` + +: This attribute can be used for marking library functions as being used + internally to the library only, which may allow the compiler to handle + function calls more efficiently. Note that static functions do not need + to be marked as internal in this way. See the GNU C documentation for + details. + + When using a compiler that supports the GNU C hidden visibility attribute, + this macro expands to `__attribute__((visibility("hidden")))`. + When using the Sun Studio compiler, it expands to `__hidden`. + + Note that for portability, the attribute should be placed before the + function declaration. While GCC allows the macro after the declaration, + Sun Studio does not. + + G_GNUC_INTERNAL + void _g_log_fallback_handler (const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer unused_data); + + Since: 2.6 + + +`G_HAVE_GNUC_VISIBILITY` +: Defined to 1 if GCC-style visibility handling is supported. + + +## Deprecation + + +`G_DEPRECATED` + +: This macro is similar to `G_GNUC_DEPRECATED`, and can be used to mark + functions declarations as deprecated. Unlike `G_GNUC_DEPRECATED`, it is + meant to be portable across different compilers and must be placed + before the function declaration. + + G_DEPRECATED + int my_mistake (void); + + Since: 2.32 + + +`G_DEPRECATED_FOR(f)` + +: This macro is similar to `G_GNUC_DEPRECATED_FOR`, and can be used to mark + functions declarations as deprecated. Unlike `G_GNUC_DEPRECATED_FOR`, it + is meant to be portable across different compilers and must be placed + before the function declaration. + + G_DEPRECATED_FOR(my_replacement) + int my_mistake (void); + + Since: 2.32 + + +`G_UNAVAILABLE(major, minor)` + +: This macro can be used to mark a function declaration as unavailable. + It must be placed before the function declaration. Use of a function + that has been annotated with this macros will produce a compiler warning. + + Since: 2.32 + + +`GLIB_DISABLE_DEPRECATION_WARNINGS` +: A macro that should be defined before including the `glib.h` header. + If it is defined, no compiler warnings will be produced for uses + of deprecated GLib APIs. + + +## Version checking + +`GLIB_MAJOR_VERSION` + +: A macro that evaluates to the major component of the version of GLib, + e.g. `1` for version `1.2.3`. + + +`GLIB_MINOR_VERSION` + +: A macro that evaluates to the minor component of the version of GLib, + e.g. `2` for version `1.2.3`. + + +`GLIB_MICRO_VERSION` + +: A macro that evaluates to the micro component of the version of GLib, + e.g. `3` for version `1.2.3`. + + +`GLIB_CHECK_VERSION (major, minor, micro)` + +: A macro that evaluates to true if the version of GLib is newer than + the given version tuple. diff --git a/docs/reference/glib/main-loop.md b/docs/reference/glib/main-loop.md new file mode 100644 index 0000000..bd63b20 --- /dev/null +++ b/docs/reference/glib/main-loop.md @@ -0,0 +1,107 @@ +Title: The Main Event Loop + +# The Main Event Loop + +The main event loop manages all the available sources of events for GLib and +GTK applications. These events can come from any number of different types +of sources such as file descriptors (plain files, pipes or sockets) and +timeouts. New types of event sources can also be added using +`g_source_attach()`. + +To allow multiple independent sets of sources to be handled in different +threads, each source is associated with a `GMainContext`. A `GMainContext` +can only be running in a single thread, but sources can be added to it and +removed from it from other threads. All functions which operate on a +`GMainContext` or a built-in `GSource` are thread-safe. + +Each event source is assigned a priority. The default priority, +`G_PRIORITY_DEFAULT`, is 0. Values less than 0 denote higher priorities. +Values greater than 0 denote lower priorities. Events from high priority +sources are always processed before events from lower priority sources. + +Idle functions can also be added, and assigned a priority. These will be run +whenever no events with a higher priority are ready to be processed. + +The `GMainLoop` data type represents a main event loop. A GMainLoop is +created with `g_main_loop_new()`. After adding the initial event sources, +`g_main_loop_run()` is called. This continuously checks for new events from +each of the event sources and dispatches them. Finally, the processing of an +event from one of the sources leads to a call to `g_main_loop_quit()` to +exit the main loop, and `g_main_loop_run()` returns. + +It is possible to create new instances of `GMainLoop` recursively. This is +often used in GTK applications when showing modal dialog boxes. Note that +event sources are associated with a particular `GMainContext`, and will be +checked and dispatched for all main loops associated with that GMainContext. + +Libraries may contain wrappers of some of these functions, e.g. +`gtk_main()`, `gtk_main_quit()` and `gtk_events_pending()`. + +## Creating new source types + +One of the unusual features of the `GMainLoop` functionality is that new +types of event source can be created and used in addition to the builtin +type of event source. A new event source type is used for handling GDK +events. A new source type is created by "deriving" from the `GSource` +structure. The derived type of source is represented by a structure that has +the `GSource` structure as a first element, and other elements specific to +the new source type. To create an instance of the new source type, call +`g_source_new()` passing in the size of the derived structure and a table of +functions. These `GSourceFuncs` determine the behavior of the new source +type. + +New source types basically interact with the main context in two ways. Their +prepare function in `GSourceFuncs` can set a timeout to determine the +maximum amount of time that the main loop will sleep before checking the +source again. In addition, or as well, the source can add file descriptors +to the set that the main context checks using `g_source_add_poll()`. + +## Customizing the main loop iteration + +Single iterations of a `GMainContext` can be run with +`g_main_context_iteration()`. In some cases, more detailed control of +exactly how the details of the main loop work is desired, for instance, when +integrating the `GMainLoop` with an external main loop. In such cases, you +can call the component functions of `g_main_context_iteration()` directly. +These functions are `g_main_context_prepare()`, `g_main_context_query()`, +`g_main_context_check()` and `g_main_context_dispatch()`. + +## State of a Main Context + +The operation of these functions can best be seen in terms of a state +diagram, as shown in this image. + +![](mainloop-states.gif) + +On UNIX, the GLib mainloop is incompatible with `fork()`. Any program using +the mainloop must either `exec()` or `exit()` from the child without +returning to the mainloop. + +## Memory management of sources + +There are two options for memory management of the user data passed to a +`GSource` to be passed to its callback on invocation. This data is provided +in calls to `g_timeout_add()`, `g_timeout_add_full()`, `g_idle_add()`, etc. +and more generally, using `g_source_set_callback()`. This data is typically +an object which ‘owns’ the timeout or idle callback, such as a widget or a +network protocol implementation. In many cases, it is an error for the +callback to be invoked after this owning object has been destroyed, as that +results in use of freed memory. + +The first, and preferred, option is to store the source ID returned by +functions such as `g_timeout_add()` or `g_source_attach()`, and explicitly +remove that source from the main context using `g_source_remove()` when the +owning object is finalized. This ensures that the callback can only be +invoked while the object is still alive. + +The second option is to hold a strong reference to the object in the +callback, and to release it in the callback’s `GDestroyNotify`. This ensures +that the object is kept alive until after the source is finalized, which is +guaranteed to be after it is invoked for the final time. The +`GDestroyNotify` is another callback passed to the ‘full’ variants of +`GSource` functions (for example, `g_timeout_add_full()`). It is called when +the source is finalized, and is designed for releasing references like this. + +One important caveat of this second approach is that it will keep the object +alive indefinitely if the main loop is stopped before the `GSource` is +invoked, which may be undesirable. diff --git a/docs/reference/glib/markup.md b/docs/reference/glib/markup.md new file mode 100644 index 0000000..edd3ec4 --- /dev/null +++ b/docs/reference/glib/markup.md @@ -0,0 +1,50 @@ +Title: Simple XML Subset Parser +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2011, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2012 David King + +# Simple XML Subset Parser + +The "GMarkup" parser is intended to parse a simple markup format +that's a subset of XML. This is a small, efficient, easy-to-use +parser. It should not be used if you expect to interoperate with +other applications generating full-scale XML, and must not be used if you +expect to parse untrusted input. However, it's very useful for application +data files, config files, etc. where you know your application will be the +only one writing the file. + +Full-scale XML parsers should be able to parse the subset used by +GMarkup, so you can easily migrate to full-scale XML at a later +time if the need arises. + +GMarkup is not guaranteed to signal an error on all invalid XML; +the parser may accept documents that an XML parser would not. +However, XML documents which are not well-formed (which is a +weaker condition than being valid. See the +[XML specification](http://www.w3.org/TR/REC-xml/) +for definitions of these terms.) are not considered valid GMarkup +documents. + +## Simplifications to XML + +The simplifications compared to full XML include: + + - Only UTF-8 encoding is allowed + - No user-defined entities + - Processing instructions, comments and the doctype declaration + are "passed through" but are not interpreted in any way + - No DTD or validation + +The markup format does support: + + - Elements + - Attributes + - 5 standard entities: `&` `<` `>` `"` `'` + - Character references + - Sections marked as CDATA + +## An example parser + +Here is an example for a markup parser: +[markup-example.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/markup-example.c) + diff --git a/docs/reference/glib/memory-slices.md b/docs/reference/glib/memory-slices.md new file mode 100644 index 0000000..63dc417 --- /dev/null +++ b/docs/reference/glib/memory-slices.md @@ -0,0 +1,58 @@ +Title: Memory Slices + +# Memory Slices + +GSlice was a space-efficient and multi-processing scalable way to allocate +equal sized pieces of memory. Since GLib 2.76, its implementation has been +removed and it calls `g_malloc()` and `g_free()`, because the performance of the +system-default allocators has improved on all platforms since GSlice was +written. + +The GSlice APIs have not been deprecated, as they are widely in use and doing +so would be very disruptive for little benefit. + +New code should be written using [`func@GLib.new`]/[`func@GLib.malloc`] and +[`func@GLib.free`]. There is no particular benefit in porting existing code away +from `g_slice_new()`/`g_slice_free()` unless it’s being rewritten anyway. + +Here is an example for using the slice allocator: + +```c +gchar *mem[10000]; +gint i; + +// Allocate 10000 blocks. +for (i = 0; i < 10000; i++) + { + mem[i] = g_slice_alloc (50); + + // Fill in the memory with some junk. + for (j = 0; j < 50; j++) + mem[i][j] = i * j; + } + +// Now free all of the blocks. +for (i = 0; i < 10000; i++) + g_slice_free1 (50, mem[i]); +``` + +And here is an example for using the using the slice allocator with data +structures: + +```c +GRealArray *array; + +// Allocate one block, using the g_slice_new() macro. +array = g_slice_new (GRealArray); + +// We can now use array just like a normal pointer to a structure. +array->data = NULL; +array->len = 0; +array->alloc = 0; +array->zero_terminated = (zero_terminated ? 1 : 0); +array->clear = (clear ? 1 : 0); +array->elt_size = elt_size; + +// We can free the block, so it can be reused. +g_slice_free (GRealArray, array); +``` diff --git a/docs/reference/glib/memory.md b/docs/reference/glib/memory.md new file mode 100644 index 0000000..d50f4f6 --- /dev/null +++ b/docs/reference/glib/memory.md @@ -0,0 +1,99 @@ +Title: Memory Allocation +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2000, 2019 Red Hat, Inc. +SPDX-FileCopyrightText: 2007 Emmanuele Bassi +SPDX-FileCopyrightText: 2018 Pavlo Solntsev +SPDX-FileCopyrightText: 2020 Endless Mobile, Inc. + +# Memory Allocation + +These functions provide support for allocating and freeing memory. + +If any call to allocate memory using functions [func@GLib.new], +[func@GLib.new0], [func@GLib.renew], [func@GLib.malloc], [func@GLib.malloc0], +[func@GLib.malloc0_n], [func@GLib.realloc] and [func@GLib.realloc_n] +fails, the application is terminated. This also means that there is no +need to check if the call succeeded. + +On the other hand, the `g_try_…()` family of functions returns `NULL` on failure +that can be used as a check for unsuccessful memory allocation. The application +is not terminated in this case. + +As all GLib functions and data structures use [func@GLib.malloc] internally, +unless otherwise specified, any allocation failure will result in the +application being terminated. + +It’s important to match [func@GLib.malloc] (and wrappers such as +[func@GLib.new]) with [func@GLib.free], [func@GLib.slice_alloc] (and wrappers +such as [func@GLib.slice_new]) with [func@GLib.slice_free], plain +[`malloc()`](man:malloc(3)) with [`free()`](man:free(3)), and (if you’re using +C++) `new` with `delete` and `new[]` with `delete[]`. Otherwise bad things can +happen, since these allocators may use different memory pools (and +`new`/`delete` call constructors and destructors). + +Since GLib 2.46, [func@GLib.malloc] is hardcoded to always use the system malloc +implementation. + +## Struct Allocations + + * [func@GLib.new] + * [func@GLib.new0] + * [func@GLib.renew] + * [func@GLib.try_new] + * [func@GLib.try_new0] + * [func@GLib.try_renew] + +## Block Allocations + + * [func@GLib.malloc] + * [func@GLib.malloc0] + * [func@GLib.realloc] + * [func@GLib.try_malloc] + * [func@GLib.try_malloc0] + * [func@GLib.try_realloc] + * [func@GLib.malloc_n] + * [func@GLib.malloc0_n] + * [func@GLib.realloc_n] + * [func@GLib.try_malloc_n] + * [func@GLib.try_malloc0_n] + * [func@GLib.try_realloc_n] + +## Free Functions + + * [func@GLib.free] + * [func@GLib.free_sized] + * [func@GLib.clear_pointer] + * [func@GLib.steal_pointer] + +In addition, the `g_mem_gc_friendly` exported variable will be true if GLib has +been [run with `G_DEBUG=gc-friendly`](running.html#environment-variables). If +so, memory to be freed will be cleared to zero before being freed. + +## Stack Allocations + + * [func@GLib.alloca] + * [func@GLib.alloca0] + * [func@GLib.newa] + * [func@GLib.newa0] + +## Aligned Allocations + + * [func@GLib.aligned_alloc] + * [func@GLib.aligned_alloc0] + * [func@GLib.aligned_free] + * [func@GLib.aligned_free_sized] + +## Copies and Moves + + * [func@GLib.memmove] + * [func@GLib.memdup2] + +## Deprecated API + + * [func@GLib.memdup] + * [struct@GLib.MemVTable] + * [func@GLib.mem_set_vtable] + * [func@GLib.mem_is_system_malloc] + * `glib_mem_profiler_table` exported variable + * [func@GLib.mem_profile] + diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build index 3cfff2f..a4197a9 100644 --- a/docs/reference/glib/meson.build +++ b/docs/reference/glib/meson.build @@ -1,124 +1,29 @@ -if get_option('gtk_doc') - subdir('xml') - ignore_headers = [ - 'gallocator.h', - 'gdatasetprivate.h', - 'glibintl.h', - 'gbsearcharray.h', - 'glib-private.h', - 'gmoduleconf.h', - 'grcboxprivate.h', - 'gstdioprivate.h', - 'gthreadprivate.h', - 'gunibreak.h', - 'gunicomp.h', - 'gunidecomp.h', - 'gunichartables.h', - 'glib_probes.h', - 'glib_trace.h', - 'libcharset.h', - 'gdebug.h', - 'gprintfint.h', - 'gmirroringtable.h', - 'gscripttable.h', - 'gtrace-private.h', - 'glib-mirroring-tab', - 'gnulib', - 'gbytesprivate.h', - 'gvariant-internal.h', - 'gvariant-serialiser.h', - 'gvariant-core.h', - 'gvarianttypeinfo.h', - 'gwakeup.h', - 'gtranslit-data.h', - 'glib-init.h', - 'gconstructor.h', - 'valgrind.h', - 'gutilsprivate.h', - 'gvalgrind.h', - 'dirent.h', - 'glib-unixprivate.h', - 'glib-visibility.h', - 'gmodule-visibility.h', - ] - - docpath = join_paths(glib_datadir, 'gtk-doc', 'html') - version_conf = configuration_data() - version_conf.set('GLIB_VERSION', meson.project_version()) - configure_file( - input: 'version.xml.in', - output: 'version.xml', - configuration: version_conf - ) - - configure_file( - input: 'glib-sections.txt.in', - output: 'glib-sections.txt', - command: [gen_visibility_macros, meson.project_version(), 'doc-sections', '@INPUT@', '@OUTPUT@'], - ) - - gnome.gtkdoc('glib', - main_xml : 'glib-docs.xml', - namespace : 'g', - mode : 'none', - src_dir : [ 'glib', 'gmodule' ], - dependencies : libglib_dep, - scan_args : [ - '--ignore-decorators=' + ignore_decorators + '|' + ignore_decorators.replace('GLIB', 'GMODULE'), - '--ignore-headers=' + ' '.join(ignore_headers), - ], - content_files : [ - 'cross.xml', - 'running.xml', - 'building.xml', - 'changes.xml', - 'compiling.xml', - 'programming.xml', - 'resources.xml', - 'regex-syntax.xml', - 'glib-gettextize.xml', - 'gtester.xml', - 'gtester-report.xml', - 'gvariant-varargs.xml', - 'gvariant-text.xml', - ], - expand_content_files : [ - 'compiling.xml', - ], - html_assets : [ - 'file-name-encodings.png', - 'mainloop-states.gif', - 'Sorted_binary_tree_breadth-first_traversal.svg', - 'Sorted_binary_tree_inorder.svg', - 'Sorted_binary_tree_postorder.svg', - 'Sorted_binary_tree_preorder.svg', - ], - fixxref_args: [ - '--html-dir=' + docpath, - ], - install: true, - check: true) -endif - -if get_option('man') +if get_option('man-pages').enabled() manpages = ['glib-gettextize', 'gtester', 'gtester-report'] foreach page : manpages custom_target(page + '-man', - input: page + '.xml', + input: page + '.rst', output: page + '.1', - command: xsltproc_command, + command: [ + rst2man, + rst2man_flags, + '@INPUT@', + ], + capture: true, install: true, - install_dir: man1_dir) + install_dir: man1_dir, + install_tag: 'doc', + ) endforeach endif -if get_option('gtk_doc') +if get_option('documentation') # GVariant specification is currently standalone rst2html5 = find_program('rst2html5', 'rst2html5.py', required: false) if rst2html5.found() - spec_path = glib_datadir / 'doc' / 'glib-2.0' + spec_path = docs_dir figures = files( 'gvariant-byte-boundaries.svg', @@ -147,3 +52,69 @@ if get_option('gtk_doc') ) endif endif + +expand_content_files = [ + 'atomic.md', + 'base64.md', + 'building.md', + 'character-set.md', + 'checked-math.md', + 'compiling.md', + 'cross-compiling.md', + 'datalist-and-dataset.md', + 'error-reporting.md', + 'file-utils.md', + 'gvariant-format-strings.md', + 'gvariant-text-format.md', + 'i18n.md', + 'logging.md', + 'main-loop.md', + 'memory.md', + 'memory-slices.md', + 'numerical.md', + 'random.md', + 'reference-counting.md', + 'running.md', + 'testing.md', + 'threads.md', + 'threads-deprecated.md', + 'markup.md', + 'misc-utils.md', + 'goption.md', + 'host-utils.md', + 'data-structures.md', + 'programming.md', + 'resources.md', + 'shell.md', + 'spawn.md', + 'string-utils.md', + 'types.md', + 'unicode.md', + 'unix.md', + 'uuid.md', + 'version.md', + 'warnings.md', + 'windows.md', +] + +glib_toml = configure_file(input: 'glib.toml.in', output: 'glib.toml', configuration: toml_conf) + +custom_target('glib-docs', + input: [ glib_toml, glib_gir[0] ], + output: 'glib', + command: [ + gidocgen, + 'generate', + gidocgen_common_args, + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--content-dir=@0@'.format(meson.current_source_dir()), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gobject'), + '@INPUT1@', + ], + build_by_default: true, + depend_files: expand_content_files, + install: true, + install_dir: docs_dir, + install_tag: 'doc', +) diff --git a/docs/reference/glib/misc-utils.md b/docs/reference/glib/misc-utils.md new file mode 100644 index 0000000..301c8d0 --- /dev/null +++ b/docs/reference/glib/misc-utils.md @@ -0,0 +1,113 @@ +Title: Miscellaneous Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2000 Red Hat, Inc. + +# Miscellaneous Utilities + +These are portable utility functions. + +## Application Name and Environment + +* [func@GLib.get_application_name] +* [func@GLib.set_application_name] +* [func@GLib.get_prgname] +* [func@GLib.set_prgname] +* [func@GLib.get_environ] +* [func@GLib.environ_getenv] +* [func@GLib.environ_setenv] +* [func@GLib.environ_unsetenv] +* [func@GLib.getenv] +* [func@GLib.setenv] +* [func@GLib.unsetenv] +* [func@GLib.listenv] +* [func@GLib.get_user_name] +* [func@GLib.get_real_name] + +## System Directories + +* [func@GLib.get_user_cache_dir] +* [func@GLib.get_user_data_dir] +* [func@GLib.get_user_config_dir] +* [func@GLib.get_user_state_dir] +* [func@GLib.get_user_runtime_dir] +* [func@GLib.get_user_special_dir] +* [func@GLib.get_system_data_dirs] +* [func@GLib.get_system_config_dirs] +* [func@GLib.reload_user_special_dirs_cache] + +## OS Info + +Information about the current OS can be retrieved by calling +[func@GLib.get_os_info] and passing it one of the following keys (this list may +grow in future): + + * `G_OS_INFO_KEY_NAME` + * `G_OS_INFO_KEY_PRETTY_NAME` + * `G_OS_INFO_KEY_VERSION` + * `G_OS_INFO_KEY_VERSION_CODENAME` + * `G_OS_INFO_KEY_VERSION_ID` + * `G_OS_INFO_KEY_ID` + * `G_OS_INFO_KEY_HOME_URL` + * `G_OS_INFO_KEY_DOCUMENTATION_URL` + * `G_OS_INFO_KEY_SUPPORT_URL` + * `G_OS_INFO_KEY_BUG_REPORT_URL` + * `G_OS_INFO_KEY_PRIVACY_POLICY_URL` + +## Paths + + * [func@GLib.get_host_name] + * [func@GLib.get_home_dir] + * [func@GLib.get_tmp_dir] + * [func@GLib.get_current_dir] + * [func@GLib.canonicalize_filename] + * [func@GLib.path_is_absolute] + * [func@GLib.path_skip_root] + * [func@GLib.path_get_basename] + * [func@GLib.path_get_dirname] + * [func@GLib.build_filename] + * [func@GLib.build_filenamev] + * [func@GLib.build_filename_valist] + * [func@GLib.build_path] + * [func@GLib.build_pathv] + +## Size Formatting + + * [func@GLib.format_size] + * [func@GLib.format_size_full] + * [func@GLib.format_size_for_display] + +## Executables + + * [func@GLib.find_program_in_path] + +## Bit Manipulation + + * [func@GLib.bit_nth_lsf] + * [func@GLib.bit_nth_msf] + * [func@GLib.bit_storage] + +## Primes + + * [func@GLib.spaced_primes_closest] + +## Process Lifetime + + * [func@GLib.abort] + +## Debug + + * [func@GLib.parse_debug_string] + +## Sorting + + * [func@GLib.qsort_with_data] + +## Pointers + + * [func@GLib.nullify_pointer] + +## Deprecated API + + * [type@GLib.VoidFunc] + * [type@GLib.FreeFunc] + * [func@GLib.atexit] diff --git a/docs/reference/glib/numerical.md b/docs/reference/glib/numerical.md new file mode 100644 index 0000000..2e389e9 --- /dev/null +++ b/docs/reference/glib/numerical.md @@ -0,0 +1,35 @@ +Title: Numerical Definitions +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2001 Havoc Pennington +SPDX-FileCopyrightText: 2010 Red Hat, Inc. + +# Numerical Definitions + +GLib offers mathematical constants such as [const@GLib.PI] for the value of pi; +many platforms have these in the C library, but some don’t. The GLib +versions always exist. + +The [type@GLib.FloatIEEE754] and [type@GLib.DoubleIEEE754] unions are used to +access the sign, mantissa and exponent of IEEE floats and doubles. These unions +are defined as appropriate for a given platform. IEEE floats and doubles are +supported (used for storage) by at least Intel, PPC and Sparc. See +[IEEE 754-2008](http://en.wikipedia.org/wiki/IEEE_float) +for more information about IEEE number formats. + +## Floating Point + + * [const@GLib.IEEE754_FLOAT_BIAS] + * [const@GLib.IEEE754_DOUBLE_BIAS] + * [type@GLib.FloatIEEE754] + * [type@GLib.DoubleIEEE754] + +## Numerical Constants + + * [const@GLib.E] + * [const@GLib.LN2] + * [const@GLib.LN10] + * [const@GLib.PI] + * [const@GLib.PI_2] + * [const@GLib.PI_4] + * [const@GLib.SQRT2] + * [const@GLib.LOG_2_BASE_10] diff --git a/docs/reference/glib/programming.md b/docs/reference/glib/programming.md new file mode 100644 index 0000000..4438ad7 --- /dev/null +++ b/docs/reference/glib/programming.md @@ -0,0 +1,71 @@ +Title: Writing GLib Applications +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2012 Red Hat, Inc. +SPDX-FileCopyrightText: 2023 Endless OS Foundation, LLC + +# Writing GLib Applications + +## Memory Allocations + +Unless otherwise specified, all functions which allocate memory in GLib will +abort the process if heap allocation fails. This is because it is too hard to +recover from allocation failures in any non-trivial program and, in particular, +to test all the allocation failure code paths. + +## UTF-8 and String Encoding + +All GLib, GObject and GIO functions accept and return strings in +[UTF-8 encoding](https://en.wikipedia.org/wiki/UTF-8) unless otherwise +specified. + +Input strings to function calls are *not* checked to see if +they are valid UTF-8: it is the application developer’s responsibility to +validate input strings at the time of input, either at the program or library +boundary, and to only use valid UTF-8 string constants in their application. +If GLib were to UTF-8 validate all string inputs to all functions, there would +be a significant drop in performance. + +Similarly, output strings from functions are guaranteed to be in UTF-8, +and this does not need to be validated by the calling function. If a function +returns invalid UTF-8 (and is not documented as doing so), that’s a bug. + +See [func@GLib.utf8_validate] and [func@GLib.utf8_make_valid] for validating +UTF-8 input. + +## Threads + +The general policy of GLib is that all functions are invisibly threadsafe +with the exception of data structure manipulation functions, where, if +you have two threads manipulating the *same* data structure, they must use a +lock to synchronize their operation. + +GLib creates a worker thread for its own purposes so GLib applications +will always have at least 2 threads. + +In particular, this means that programs must only use +[async-signal-safe functions](man:signal-safety(7)) between +calling [`fork()`](man:fork(2)) and [`exec()`](man:exec(3)), even if +they haven’t explicitly spawned another thread yet. + +See the sections on [threads](threads.html) and [struct@GLib.ThreadPool] for +GLib APIs that support multithreaded applications. + +## Security and setuid Use + +When writing code that runs with elevated privileges, it is important +to follow some basic rules of secure programming. David Wheeler has an +excellent book on this topic, +[Secure Programming for Linux and Unix HOWTO](http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/index.html). + +When it comes to GLib and its associated libraries, GLib and +GObject are generally fine to use in code that runs with elevated +privileges; they don’t load modules (executable code in shared objects) +or run other programs ‘behind your back’. GIO, however, is not designed to be +used in privileged programs, either ones which are spawned by a privileged +process, or ones which are run with a setuid bit set. + +setuid programs should always reset their environment to contain only +known-safe values before calling into non-trivial libraries such as GIO. This +reduces the risk of an attacker-controlled environment variable being used to +get a privileged GIO process to run arbitrary code via loading a GIO module or +similar. diff --git a/docs/reference/glib/programming.xml b/docs/reference/glib/programming.xml deleted file mode 100644 index 9efa19d..0000000 --- a/docs/reference/glib/programming.xml +++ /dev/null @@ -1,124 +0,0 @@ - - - - -Writing GLib Applications -3 -GLib Library - - - -Writing GLib Applications - -General considerations when programming with GLib - - - - -Writing GLib Applications - - -Memory Allocations - - -Unless otherwise specified, all functions which allocate memory in GLib will -abort the process if heap allocation fails. This is because it is too hard to -recover from allocation failures in any non-trivial program and, in particular, -to test all the allocation failure code paths. - - - - -UTF-8 and String Encoding - - -All GLib, GObject and GIO functions accept and return strings in -UTF-8 encoding -unless otherwise specified. - - - -Input strings to function calls are not checked to see if -they are valid UTF-8: it is the application developer’s responsibility to -validate input strings at the time of input, either at the program or library -boundary, and to only use valid UTF-8 string constants in their application. -If GLib were to UTF-8 validate all string inputs to all functions, there would -be a significant drop in performance. - - -Similarly, output strings from functions are guaranteed to be in UTF-8, -and this does not need to be validated by the calling function. If a function -returns invalid UTF-8 (and is not documented as doing so), that’s a bug. - - - -See g_utf8_validate() -and g_utf8_make_valid() -for validating UTF-8 input. - - - - -Threads - - -The general policy of GLib is that all functions are invisibly threadsafe -with the exception of data structure manipulation functions, where, if -you have two threads manipulating the same data -structure, they must use a lock to synchronize their operation. - - - -GLib creates a worker thread for its own purposes so GLib applications -will always have at least 2 threads. - - - -In particular, this means that programs must only use -async-signal-safe functions between -calling fork() and exec(), even if -they haven’t explicitly spawned another thread yet. - - - -See the sections on threads and -thread pools for GLib APIs that -support multithreaded applications. - - - - - -Security and setuid use - - -When writing code that runs with elevated privileges, it is important -to follow some basic rules of secure programming. David Wheeler has an -excellent book on this topic, -Secure Programming for Linux and Unix HOWTO. - - - -When it comes to GLib and its associated libraries, GLib and -GObject are generally fine to use in code that runs with elevated -privileges; they don't load modules (executable code in shared objects) -or run other programs ‘behind your back’. GIO, however, is not designed to be -used in privileged programs, either ones which are spawned by a privileged -process, or ones which are run with a setuid bit set. - - - -setuid programs should always reset their environment to contain only -known-safe values before calling into non-trivial libraries such as GIO. This -reduces the risk of an attacker-controlled environment variable being used to -get a privileged GIO process to run arbitrary code via loading a GIO module or -similar. - - - - - - - diff --git a/docs/reference/glib/random.md b/docs/reference/glib/random.md new file mode 100644 index 0000000..2f1b5e3 --- /dev/null +++ b/docs/reference/glib/random.md @@ -0,0 +1,61 @@ +Title: Random Numbers +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2000, 2002 Sebastian Wilhelmi +SPDX-FileCopyrightText: 2013 Colin Walters + +# Random Numbers + +The following functions allow you to use a portable, fast and good +pseudo-random number generator (PRNG). + +Do not use this API for cryptographic purposes such as key +generation, nonces, salts or one-time pads. + +This PRNG is suitable for non-cryptographic use such as in games +(shuffling a card deck, generating levels), generating data for +a test suite, etc. If you need random data for cryptographic +purposes, it is recommended to use platform-specific APIs such +as `/dev/random` on UNIX, or +[`CryptGenRandom()`](https://learn.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptgenrandom) +on Windows. + +[type@GLib.Rand] uses the Mersenne Twister PRNG, which was originally +developed by Makoto Matsumoto and Takuji Nishimura. Further +information can be found at +[this page](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html). + +If you just need a random number, you simply call the `g_random_*()` +functions, which will create a globally used [type@GLib.Rand] and use the +according `g_rand_*()` functions internally: + + * [func@GLib.random_int] + * [func@GLib.random_int_range] + * [func@GLib.random_double] + * [func@GLib.random_double_range] + * [func@GLib.random_set_seed] + +Whenever you need a stream of reproducible random numbers, you better create a +[type@GLib.Rand] yourself and use the `g_rand_*()` functions directly, which +will also be slightly faster. Initializing a [type@GLib.Rand] with a +certain seed will produce exactly the same series of random +numbers on all platforms. This can thus be used as a seed for +e.g. games. + +The `g_rand*_range()` functions will return high quality equally +distributed random numbers, whereas for example the +`(g_random_int () % max)` approach often +doesn’t yield equally distributed numbers. + +GLib changed the seeding algorithm for the pseudo-random number +generator Mersenne Twister, as used by [type@GLib.Rand]. This was necessary, +because some seeds would yield very bad pseudo-random streams. +Also the pseudo-random integers generated by `g_rand*_int_range()` +will have a slightly better equal distribution with the new +version of GLib. + +The original seeding and generation algorithms, as found in +GLib 2.0.x, can be used instead of the new ones by setting the +environment variable `G_RANDOM_VERSION` to the value of `2.0`. +Use the GLib-2.0 algorithms only if you have sequences of numbers +generated with Glib-2.0 that you need to reproduce exactly. + diff --git a/docs/reference/glib/reference-counting.md b/docs/reference/glib/reference-counting.md new file mode 100644 index 0000000..cb3a58d --- /dev/null +++ b/docs/reference/glib/reference-counting.md @@ -0,0 +1,164 @@ +Title: Reference Counting + +## Reference counting types + +Reference counting is a garbage collection mechanism that is based on +assigning a counter to a data type, or any memory area; the counter is +increased whenever a new reference to that data type is acquired, and +decreased whenever the reference is released. Once the last reference is +released, the resources associated to that data type are freed. + +GLib uses reference counting in many of its data types, and provides the +`grefcount` and `gatomicrefcount` types to implement safe and atomic +reference counting semantics in new data types. + +It is important to note that `grefcount` and `gatomicrefcount` should be +considered completely opaque types; you should always use the provided API +to increase and decrease the counters, and you should never check their +content directly, or compare their content with other values. + +## Reference counted data + +A "reference counted box", or "RcBox", is an opaque wrapper data type that +is guaranteed to be as big as the size of a given data type, and which +augments the given data type with reference counting semantics for its +memory management. + +RcBox is useful if you have a plain old data type, like a structure +typically placed on the stack, and you wish to provide additional API to use +it on the heap; or if you want to implement a new type to be passed around +by reference without necessarily implementing copy/free semantics or your +own reference counting. + +The typical use is: + +```c +typedef struct { + char *name; + char *address; + char *city; + char *state; + int age; +} Person; + +Person * +person_new (void) +{ + return g_rc_box_new0 (Person); +} +``` + +Every time you wish to acquire a reference on the memory, you should call +`g_rc_box_acquire()`; similarly, when you wish to release a reference you +should call `g_rc_box_release()`: + +```c +// Add a Person to the Database; the Database acquires ownership +// of the Person instance +void +add_person_to_database (Database *db, Person *p) +{ + db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p)); +} + +// Removes a Person from the Database; the reference acquired by +// add_person_to_database() is released here +void +remove_person_from_database (Database *db, Person *p) +{ + db->persons = g_list_remove (db->persons, p); + g_rc_box_release (p); +} +``` + +If you have additional memory allocated inside the structure, you can use +`g_rc_box_release_full()`, which takes a function pointer, which will be +called if the reference released was the last: + +```c +void +person_clear (Person *p) +{ + g_free (p->name); + g_free (p->address); + g_free (p->city); + g_free (p->state); +} + +void +remove_person_from_database (Database *db, Person *p) +{ + db->persons = g_list_remove (db->persons, p); + g_rc_box_release_full (p, (GDestroyNotify) person_clear); +} +``` + +If you wish to transfer the ownership of a reference counted data +type without increasing the reference count, you can use `g_steal_pointer()`: + +```c + Person *p = g_rc_box_new (Person); + + // fill_person_details() is defined elsewhere + fill_person_details (p); + + // add_person_to_database_no_ref() is defined elsewhere; it adds + // a Person to the Database without taking a reference + add_person_to_database_no_ref (db, g_steal_pointer (&p)); +``` + + +## Thread safety + +The reference counting operations on data allocated using +`g_rc_box_alloc()`, `g_rc_box_new()`, and `g_rc_box_dup()` are not thread +safe; it is your code's responsibility to ensure that references are +acquired are released on the same thread. + +If you need thread safe reference counting, you should use the +`g_atomic_rc_*` API: + +| Operation | Atomic equivalent | +|---------------------------|----------------------------------| +| `g_rc_box_alloc()` | `g_atomic_rc_box_alloc()` | +| `g_rc_box_new()` | `g_atomic_rc_box_new()` | +| `g_rc_box_dup()` | `g_atomic_rc_box_dup()` | +| `g_rc_box_acquire()` | `g_atomic_rc_box_acquire()` | +| `g_rc_box_release()` | `g_atomic_rc_box_release()` | +| `g_rc_box_release_full()` | `g_atomic_rc_box_release_full()` | + +The reference counting operations on data allocated using +`g_atomic_rc_box_alloc()`, `g_atomic_rc_box_new()`, and +`g_atomic_rc_box_dup()` are guaranteed to be atomic, and thus can be safely +be performed by different threads. It is important to note that only the +reference acquisition and release are atomic; changes to the content of the +data are your responsibility. + +It is a programmer error to mix the atomic and non-atomic reference counting +operations. + +## Automatic pointer clean up + +If you want to add `g_autoptr()` support to your plain old data type through +reference counting, you can use the `G_DEFINE_AUTOPTR_CLEANUP_FUNC()` and +`g_rc_box_release()`: + +```c +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release) +``` + +If you need to clear the contents of the data, you will need to use an +ancillary function that calls `g_rc_box_release_full()`: + +```c +static void +my_data_struct_release (MyDataStruct *data) +{ + // my_data_struct_clear() is defined elsewhere + g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear); +} + +G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release) +``` + +The `g_rc_box*` and `g_atomic_rc_box*` APIs were introduced in GLib 2.58. diff --git a/docs/reference/glib/regex-syntax.xml b/docs/reference/glib/regex-syntax.xml deleted file mode 100644 index 0b413aa..0000000 --- a/docs/reference/glib/regex-syntax.xml +++ /dev/null @@ -1,2485 +0,0 @@ - - - - - Regular expression syntax - - - - - - -Regular expression syntax - -syntax and semantics of regular expressions supported by GRegex - - - - -GRegex regular expression details - -A regular expression is a pattern that is matched against a -string from left to right. Most characters stand for themselves in a -pattern, and match the corresponding characters in the string. As a -trivial example, the pattern - - - -The quick brown fox - - - -matches a portion of a string that is identical to itself. When -caseless matching is specified (the G_REGEX_CASELESS flag), letters are -matched independently of case. - - - -The power of regular expressions comes from the ability to include -alternatives and repetitions in the pattern. These are encoded in the -pattern by the use of metacharacters, which do not stand for themselves -but instead are interpreted in some special way. - - - -There are two different sets of metacharacters: those that are recognized -anywhere in the pattern except within square brackets, and those -that are recognized in square brackets. Outside square brackets, the -metacharacters are as follows: - - - -Metacharacters outside square brackets - - - - - Character - Meaning - - - - - \ - general escape character with several uses - - - ^ - assert start of string (or line, in multiline mode) - - - $ - assert end of string (or line, in multiline mode) - - - . - match any character except newline (by default) - - - [ - start character class definition - - - | - start of alternative branch - - - ( - start subpattern - - - ) - end subpattern - - - ? - extends the meaning of (, or 0/1 quantifier, or quantifier minimizer - - - * - 0 or more quantifier - - - + - 1 or more quantifier, also "possessive quantifier" - - - { - start min/max quantifier - - - -
- - -Part of a pattern that is in square brackets is called a "character -class". In a character class the only metacharacters are: - - - -Metacharacters inside square brackets - - - - - Character - Meaning - - - - - \ - general escape character - - - ^ - negate the class, but only if the first character - - - - - indicates character range - - - [ - POSIX character class (only if followed by POSIX syntax) - - - ] - terminates the character class - - - -
-
- - -Backslash - -The backslash character has several uses. Firstly, if it is followed by -a non-alphanumeric character, it takes away any special meaning that -character may have. This use of backslash as an escape character -applies both inside and outside character classes. - - - -For example, if you want to match a * character, you write \* in the -pattern. This escaping action applies whether or not the following -character would otherwise be interpreted as a metacharacter, so it is -always safe to precede a non-alphanumeric with backslash to specify -that it stands for itself. In particular, if you want to match a -backslash, you write \\. - - - -If a pattern is compiled with the G_REGEX_EXTENDED -option, whitespace in the pattern (other than in a character class) and -characters between a # outside a character class and the next newline -are ignored. -An escaping backslash can be used to include a whitespace or # character -as part of the pattern. - - - -Note that the C compiler interprets backslash in strings itself, therefore -you need to duplicate all \ characters when you put a regular expression -in a C string, like "\\d{3}". - - - -If you want to remove the special meaning from a sequence of characters, -you can do so by putting them between \Q and \E. -The \Q...\E sequence is recognized both inside and outside character -classes. - - - -Non-printing characters - -A second use of backslash provides a way of encoding non-printing -characters in patterns in a visible manner. There is no restriction on the -appearance of non-printing characters, apart from the binary zero that -terminates a pattern, but when a pattern is being prepared by text -editing, it is usually easier to use one of the following escape -sequences than the binary character it represents: - - - -Non-printing characters - - - - - Escape - Meaning - - - - - \a - alarm, that is, the BEL character (hex 07) - - - \cx - "control-x", where x is any character - - - \e - escape (hex 1B) - - - \f - formfeed (hex 0C) - - - \n - newline (hex 0A) - - - \r - carriage return (hex 0D) - - - \t - tab (hex 09) - - - \ddd - character with octal code ddd, or backreference - - - \xhh - character with hex code hh - - - \x{hhh..} - character with hex code hhh.. - - - -
- - -The precise effect of \cx is as follows: if x is a lower case letter, -it is converted to upper case. Then bit 6 of the character (hex 40) is -inverted. Thus \cz becomes hex 1A, but \c{ becomes hex 3B, while \c; -becomes hex 7B. - - - -After \x, from zero to two hexadecimal digits are read (letters can be -in upper or lower case). Any number of hexadecimal digits may appear -between \x{ and }, but the value of the character code -must be less than 2**31 (that is, the maximum hexadecimal value is -7FFFFFFF). If characters other than hexadecimal digits appear between -\x{ and }, or if there is no terminating }, this form of escape is not -recognized. Instead, the initial \x will be interpreted as a basic hexadecimal -escape, with no following digits, giving a character whose -value is zero. - - - -Characters whose value is less than 256 can be defined by either of the -two syntaxes for \x. There is no difference -in the way they are handled. For example, \xdc is exactly the same as -\x{dc}. - - - -After \0 up to two further octal digits are read. If there are fewer -than two digits, just those that are present are used. -Thus the sequence \0\x\07 specifies two binary zeros followed by a BEL -character (code value 7). Make sure you supply two digits after the -initial zero if the pattern character that follows is itself an octal -digit. - - - -The handling of a backslash followed by a digit other than 0 is complicated. -Outside a character class, GRegex reads it and any following digits as a -decimal number. If the number is less than 10, or if there -have been at least that many previous capturing left parentheses in the -expression, the entire sequence is taken as a back reference. A -description of how this works is given later, following the discussion -of parenthesized subpatterns. - - - -Inside a character class, or if the decimal number is greater than 9 -and there have not been that many capturing subpatterns, GRegex re-reads -up to three octal digits following the backslash, and uses them to generate -a data character. Any subsequent digits stand for themselves. For example: - - - -Non-printing characters - - - - - Escape - Meaning - - - - - \040 - is another way of writing a space - - - \40 - is the same, provided there are fewer than 40 previous capturing subpatterns - - - \7 - is always a back reference - - - \11 - might be a back reference, or another way of writing a tab - - - \011 - is always a tab - - - \0113 - is a tab followed by the character "3" - - - \113 - might be a back reference, otherwise the character with octal code 113 - - - \377 - might be a back reference, otherwise the byte consisting entirely of 1 bits - - - \81 - is either a back reference, or a binary zero followed by the two characters "8" and "1" - - - -
- - -Note that octal values of 100 or greater must not be introduced by a -leading zero, because no more than three octal digits are ever read. - - - -All the sequences that define a single character can be used both inside -and outside character classes. In addition, inside a character class, the -sequence \b is interpreted as the backspace character (hex 08), and the -sequences \R and \X are interpreted as the characters "R" and "X", respectively. -Outside a character class, these sequences have different meanings (see below). - -
- - -Absolute and relative back references - -The sequence \g followed by a positive or negative number, optionally enclosed -in braces, is an absolute or relative back reference. Back references are -discussed later, following the discussion of parenthesized subpatterns. - - - - -Generic character types - - -Another use of backslash is for specifying generic character types. -The following are always recognized: - - - -Generic characters - - - - - Escape - Meaning - - - - - \d - any decimal digit - - - \D - any character that is not a decimal digit - - - \s - any whitespace character - - - \S - any character that is not a whitespace character - - - \w - any "word" character - - - \W - any "non-word" character - - - -
- - -Each pair of escape sequences partitions the complete set of characters -into two disjoint sets. Any given character matches one, and only one, -of each pair. - - - -These character type sequences can appear both inside and outside character -classes. They each match one character of the appropriate type. -If the current matching point is at the end of the passed string, all -of them fail, since there is no character to match. - - - -For compatibility with Perl, \s does not match the VT character (code -11). This makes it different from the POSIX "space" class. The \s -characters are HT (9), LF (10), FF (12), CR (13), and space (32). - - - -A "word" character is an underscore or any character less than 256 that -is a letter or digit. - - -Characters with values greater than 128 never match \d, -\s, or \w, and always match \D, \S, and \W. - -
- - -Newline sequences -Outside a character class, the escape sequence \R matches any Unicode -newline sequence. -This particular group matches either the two-character sequence CR followed by -LF, or one of the single characters LF (linefeed, U+000A), VT (vertical tab, -U+000B), FF (formfeed, U+000C), CR (carriage return, U+000D), NEL (next -line, U+0085), LS (line separator, U+2028), or PS (paragraph separator, U+2029). -The two-character sequence is treated as a single unit that -cannot be split. Inside a character class, \R matches the letter "R". - - - -Unicode character properties - -To support generic character types there are three additional escape -sequences, they are: - - - -Generic character types - - - - - Escape - Meaning - - - - - \p{xx} - a character with the xx property - - - \P{xx} - a character without the xx property - - - \X - an extended Unicode sequence - - - -
- - -The property names represented by xx above are limited to the Unicode -script names, the general category properties, and "Any", which matches -any character (including newline). Other properties such as "InMusicalSymbols" -are not currently supported. Note that \P{Any} does not match any characters, -so always causes a match failure. - - - -Sets of Unicode characters are defined as belonging to certain scripts. A -character from one of these sets can be matched using a script name. For -example, \p{Greek} or \P{Han}. - - - -Those that are not part of an identified script are lumped together as -"Common". The current list of scripts can be found in the documentation for -the #GUnicodeScript enumeration. Script names for use with \p{} can be -found by replacing all spaces with underscores, e.g. for Linear B use -\p{Linear_B}. - - - -Each character has exactly one general category property, specified by a -two-letter abbreviation. For compatibility with Perl, negation can be specified -by including a circumflex between the opening brace and the property name. For -example, \p{^Lu} is the same as \P{Lu}. - - - -If only one letter is specified with \p or \P, it includes all the general -category properties that start with that letter. In this case, in the absence -of negation, the curly brackets in the escape sequence are optional; these two -examples have the same effect: - - - -\p{L} -\pL - - - -In addition to the two-letter category codes listed in the -documentation for the #GUnicodeType enumeration, the following -general category property codes are supported: - - - -Property codes - - - - - Code - Meaning - - - - - C - Other - - - L - Letter - - - M - Mark - - - N - Number - - - P - Punctuation - - - S - Symbol - - - Z - Separator - - - -
- - -The special property L& is also supported: it matches a character that has -the Lu, Ll, or Lt property, in other words, a letter that is not classified as -a modifier or "other". - - - -The long synonyms for these properties that Perl supports (such as \ep{Letter}) -are not supported by GRegex, nor is it permitted to prefix any of these -properties with "Is". - - - -No character that is in the Unicode table has the Cn (unassigned) property. -Instead, this property is assumed for any code point that is not in the -Unicode table. - - - -Specifying caseless matching does not affect these escape sequences. -For example, \p{Lu} always matches only upper case letters. - - - -The \X escape matches any number of Unicode characters that form an -extended Unicode sequence. \X is equivalent to - - - -(?>\PM\pM*) - - - -That is, it matches a character without the "mark" property, followed -by zero or more characters with the "mark" property, and treats the -sequence as an atomic group (see below). Characters with the "mark" -property are typically accents that affect the preceding character. - - - -Matching characters by Unicode property is not fast, because GRegex has -to search a structure that contains data for over fifteen thousand -characters. That is why the traditional escape sequences such as \d and -\w do not use Unicode properties. - -
- - -Simple assertions - -The final use of backslash is for certain simple assertions. An -assertion specifies a condition that has to be met at a particular point in -a match, without consuming any characters from the string. The -use of subpatterns for more complicated assertions is described below. -The backslashed assertions are: - - - -Simple assertions - - - - - Escape - Meaning - - - - - \b - matches at a word boundary - - - \B - matches when not at a word boundary - - - \A - matches at the start of the string - - - \Z - matches at the end of the string or before a newline at the end of the string - - - \z - matches only at the end of the string - - - \G - matches at first matching position in the string - - - -
- - -These assertions may not appear in character classes (but note that \b -has a different meaning, namely the backspace character, inside a -character class). - - - -A word boundary is a position in the string where the current -character and the previous character do not both match \w or \W (i.e. -one matches \w and the other matches \W), or the start or end of the -string if the first or last character matches \w, respectively. - - - -The \A, \Z, and \z assertions differ from the traditional circumflex -and dollar (described in the next section) in that they only ever match -at the very start and end of the string, whatever options are -set. Thus, they are independent of multiline mode. These three assertions -are not affected by the G_REGEX_MATCH_NOTBOL or G_REGEX_MATCH_NOTEOL options, -which affect only the behaviour of the circumflex and dollar metacharacters. -However, if the start_position argument of a matching function is non-zero, -indicating that matching is to start at a point other than the beginning of -the string, \A can never match. The difference between \Z and \z is -that \Z matches before a newline at the end of the string as well at the -very end, whereas \z matches only at the end. - - - -The \G assertion is true only when the current matching position is at -the start point of the match, as specified by the start_position argument -to the matching functions. It differs from \A when the value of startoffset is -non-zero. - - - -Note, however, that the interpretation of \G, as the start of the -current match, is subtly different from Perl’s, which defines it as the -end of the previous match. In Perl, these can be different when the -previously matched string was empty. - - - -If all the alternatives of a pattern begin with \G, the expression is -anchored to the starting match position, and the "anchored" flag is set -in the compiled regular expression. - -
-
- - -Circumflex and dollar - -Outside a character class, in the default matching mode, the circumflex -character is an assertion that is true only if the current matching -point is at the start of the string. If the start_position argument to -the matching functions is non-zero, circumflex can never match if the -G_REGEX_MULTILINE option is unset. Inside a character class, circumflex -has an entirely different meaning (see below). - - - -Circumflex need not be the first character of the pattern if a number -of alternatives are involved, but it should be the first thing in each -alternative in which it appears if the pattern is ever to match that -branch. If all possible alternatives start with a circumflex, that is, -if the pattern is constrained to match only at the start of the string, -it is said to be an "anchored" pattern. (There are also other -constructs that can cause a pattern to be anchored.) - - - -A dollar character is an assertion that is true only if the current -matching point is at the end of the string, or immediately -before a newline at the end of the string (by default). Dollar need not -be the last character of the pattern if a number of alternatives are -involved, but it should be the last item in any branch in which it -appears. Dollar has no special meaning in a character class. - - - -The meaning of dollar can be changed so that it matches only at the -very end of the string, by setting the G_REGEX_DOLLAR_ENDONLY option at -compile time. This does not affect the \Z assertion. - - - -The meanings of the circumflex and dollar characters are changed if the -G_REGEX_MULTILINE option is set. When this is the case, -a circumflex matches immediately after internal newlines as well as at the -start of the string. It does not match after a newline that ends the string. -A dollar matches before any newlines in the string, as well as at the very -end, when G_REGEX_MULTILINE is set. When newline is -specified as the two-character sequence CRLF, isolated CR and LF characters -do not indicate newlines. - - - -For example, the pattern /^abc$/ matches the string "def\nabc" (where -\n represents a newline) in multiline mode, but not otherwise. Consequently, -patterns that are anchored in single line mode because all branches start with -^ are not anchored in multiline mode, and a match for circumflex is possible -when the start_position argument of a matching function -is non-zero. The G_REGEX_DOLLAR_ENDONLY option is ignored -if G_REGEX_MULTILINE is set. - - - -Note that the sequences \A, \Z, and \z can be used to match the start and -end of the string in both modes, and if all branches of a pattern start with -\A it is always anchored, whether or not G_REGEX_MULTILINE -is set. - - - - -Full stop (period, dot) - -Outside a character class, a dot in the pattern matches any one character -in the string, including a non-printing character, but not (by -default) newline. In UTF-8 a character might be more than one byte long. - - - -When a line ending is defined as a single character, dot never matches that -character; when the two-character sequence CRLF is used, dot does not match CR -if it is immediately followed by LF, but otherwise it matches all characters -(including isolated CRs and LFs). When any Unicode line endings are being -recognized, dot does not match CR or LF or any of the other line ending -characters. - - - -If the G_REGEX_DOTALL flag is set, dots match newlines -as well. The handling of dot is entirely independent of the handling of circumflex -and dollar, the only relationship being that they both involve newline -characters. Dot has no special meaning in a character class. - - - -The behaviour of dot with regard to newlines can be changed. If the -G_REGEX_DOTALL option is set, a dot matches any one -character, without exception. If newline is defined as the two-character -sequence CRLF, it takes two dots to match it. - - - -The handling of dot is entirely independent of the handling of circumflex and -dollar, the only relationship being that they both involve newlines. Dot has no -special meaning in a character class. - - - - -Matching a single byte - -Outside a character class, the escape sequence \C matches any one byte, -both in and out of UTF-8 mode. Unlike a dot, it always matches any line -ending characters. -The feature is provided in Perl in order to match individual bytes in -UTF-8 mode. Because it breaks up UTF-8 characters into individual -bytes, what remains in the string may be a malformed UTF-8 string. For -this reason, the \C escape sequence is best avoided. - - - -GRegex does not allow \C to appear in lookbehind assertions (described -below), because in UTF-8 mode this would make it impossible to calculate -the length of the lookbehind. - - - - -Square brackets and character classes - -An opening square bracket introduces a character class, terminated by a -closing square bracket. A closing square bracket on its own is not special. If a closing square bracket is required as a member of the class, -it should be the first data character in the class (after an initial -circumflex, if present) or escaped with a backslash. - - - -A character class matches a single character in the string. A matched character -must be in the set of characters defined by the class, unless the first -character in the class definition is a circumflex, in which case the -string character must not be in the set defined by the class. If a -circumflex is actually required as a member of the class, ensure it is -not the first character, or escape it with a backslash. - - - -For example, the character class [aeiou] matches any lower case vowel, -while [^aeiou] matches any character that is not a lower case vowel. -Note that a circumflex is just a convenient notation for specifying the -characters that are in the class by enumerating those that are not. A -class that starts with a circumflex is not an assertion: it still consumes -a character from the string, and therefore it fails if the current pointer -is at the end of the string. - - - -In UTF-8 mode, characters with values greater than 255 can be included -in a class as a literal string of bytes, or by using the \x{ escaping -mechanism. - - - -When caseless matching is set, any letters in a class represent both -their upper case and lower case versions, so for example, a caseless -[aeiou] matches "A" as well as "a", and a caseless [^aeiou] does not -match "A", whereas a caseful version would. - - - -Characters that might indicate line breaks are never treated -in any special way when matching character classes, whatever line-ending -sequence is in use, and whatever setting of the G_REGEX_DOTALL -and G_REGEX_MULTILINE options is used. A class such as [^a] -always matches one of these characters. - - - -The minus (hyphen) character can be used to specify a range of characters in -a character class. For example, [d-m] matches any letter -between d and m, inclusive. If a minus character is required in a -class, it must be escaped with a backslash or appear in a position -where it cannot be interpreted as indicating a range, typically as the -first or last character in the class. - - - -It is not possible to have the literal character "]" as the end character -of a range. A pattern such as [W-]46] is interpreted as a class of -two characters ("W" and "-") followed by a literal string "46]", so it -would match "W46]" or "-46]". However, if the "]" is escaped with a -backslash it is interpreted as the end of range, so [W-\]46] is interpreted -as a class containing a range followed by two other characters. -The octal or hexadecimal representation of "]" can also be used to end -a range. - - - -Ranges operate in the collating sequence of character values. They can -also be used for characters specified numerically, for example -[\000-\037]. In UTF-8 mode, ranges can include characters whose values -are greater than 255, for example [\x{100}-\x{2ff}]. - - - -The character types \d, \D, \p, \P, \s, \S, \w, and \W may also appear -in a character class, and add the characters that they match to the -class. For example, [\dABCDEF] matches any hexadecimal digit. A -circumflex can conveniently be used with the upper case character types to -specify a more restricted set of characters than the matching lower -case type. For example, the class [^\W_] matches any letter or digit, -but not underscore. - - - -The only metacharacters that are recognized in character classes are -backslash, hyphen (only where it can be interpreted as specifying a -range), circumflex (only at the start), opening square bracket (only -when it can be interpreted as introducing a POSIX class name - see the -next section), and the terminating closing square bracket. However, -escaping other non-alphanumeric characters does no harm. - - - - -Posix character classes - -GRegex supports the POSIX notation for character classes. This uses names -enclosed by [: and :] within the enclosing square brackets. For example, - - - -[01[:alpha:]%] - - - -matches "0", "1", any alphabetic character, or "%". The supported class -names are - - - -Posix classes - - - - - Name - Meaning - - - - - alnum - letters and digits - - - alpha - letters - - - ascii - character codes 0 - 127 - - - blank - space or tab only - - - cntrl - control characters - - - digit - decimal digits (same as \d) - - - graph - printing characters, excluding space - - - lower - lower case letters - - - print - printing characters, including space - - - punct - printing characters, excluding letters and digits - - - space - white space (not quite the same as \s) - - - upper - upper case letters - - - word - "word" characters (same as \w) - - - xdigit - hexadecimal digits - - - -
- - -The "space" characters are HT (9), LF (10), VT (11), FF (12), CR (13), -and space (32). Notice that this list includes the VT character (code -11). This makes "space" different to \s, which does not include VT (for -Perl compatibility). - - - -The name "word" is a Perl extension, and "blank" is a GNU extension. -Another Perl extension is negation, which is indicated by a ^ character -after the colon. For example, - - - -[12[:^digit:]] - - - -matches "1", "2", or any non-digit. GRegex also recognize the -POSIX syntax [.ch.] and [=ch=] where "ch" is a "collating element", but -these are not supported, and an error is given if they are encountered. - - - -In UTF-8 mode, characters with values greater than 128 do not match any -of the POSIX character classes. - -
- - -Vertical bar - -Vertical bar characters are used to separate alternative patterns. For -example, the pattern - - - - gilbert|sullivan - - - -matches either "gilbert" or "sullivan". Any number of alternatives may -appear, and an empty alternative is permitted (matching the empty -string). The matching process tries each alternative in turn, from -left to right, and the first one that succeeds is used. If the alternatives are within a subpattern (defined below), "succeeds" means matching the rest of the main pattern as well as the alternative in the subpattern. - - - - -Internal option setting - -The settings of the G_REGEX_CASELESS, G_REGEX_MULTILINE, G_REGEX_MULTILINE, -and G_REGEX_EXTENDED options can be changed from within the pattern by a -sequence of Perl-style option letters enclosed between "(?" and ")". The -option letters are - - - -Option settings - - - - - Option - Flag - - - - - i - G_REGEX_CASELESS - - - m - G_REGEX_MULTILINE - - - s - G_REGEX_DOTALL - - - x - G_REGEX_EXTENDED - - - -
- - -For example, (?im) sets caseless, multiline matching. It is also -possible to unset these options by preceding the letter with a hyphen, and a -combined setting and unsetting such as (?im-sx), which sets G_REGEX_CASELESS -and G_REGEX_MULTILINE while unsetting G_REGEX_DOTALL and G_REGEX_EXTENDED, -is also permitted. If a letter appears both before and after the -hyphen, the option is unset. - - - -When an option change occurs at top level (that is, not inside subpattern -parentheses), the change applies to the remainder of the pattern -that follows. - - - -An option change within a subpattern (see below for a description of subpatterns) -affects only that part of the current pattern that follows it, so - - - -(a(?i)b)c - - - -matches abc and aBc and no other strings (assuming G_REGEX_CASELESS is not -used). By this means, options can be made to have different settings -in different parts of the pattern. Any changes made in one alternative -do carry on into subsequent branches within the same subpattern. For -example, - - - -(a(?i)b|c) - - - -matches "ab", "aB", "c", and "C", even though when matching "C" the -first branch is abandoned before the option setting. This is because -the effects of option settings happen at compile time. There would be -some very weird behaviour otherwise. - - - -The options G_REGEX_UNGREEDY and -G_REGEX_EXTRA and G_REGEX_DUPNAMES -can be changed in the same way as the Perl-compatible options by using -the characters U, X and J respectively. - -
- - -Subpatterns - -Subpatterns are delimited by parentheses (round brackets), which can be -nested. Turning part of a pattern into a subpattern does two things: - - - - -It localizes a set of alternatives. For example, the pattern -cat(aract|erpillar|) matches one of the words "cat", "cataract", or -"caterpillar". Without the parentheses, it would match "cataract", -"erpillar" or an empty string. - - -It sets up the subpattern as a capturing subpattern. This means -that, when the whole pattern matches, that portion of the -string that matched the subpattern can be obtained using g_match_info_fetch(). -Opening parentheses are counted from left to right (starting from 1, as -subpattern 0 is the whole matched string) to obtain numbers for the -capturing subpatterns. - - - - -For example, if the string "the red king" is matched against the pattern - - - -the ((red|white) (king|queen)) - - - -the captured substrings are "red king", "red", and "king", and are numbered 1, 2, and 3, respectively. - - - -The fact that plain parentheses fulfil two functions is not always -helpful. There are often times when a grouping subpattern is required -without a capturing requirement. If an opening parenthesis is followed -by a question mark and a colon, the subpattern does not do any capturing, -and is not counted when computing the number of any subsequent -capturing subpatterns. For example, if the string "the white queen" is -matched against the pattern - - - -the ((?:red|white) (king|queen)) - - - -the captured substrings are "white queen" and "queen", and are numbered -1 and 2. The maximum number of capturing subpatterns is 65535. - - - -As a convenient shorthand, if any option settings are required at the -start of a non-capturing subpattern, the option letters may appear -between the "?" and the ":". Thus the two patterns - - - -(?i:saturday|sunday) -(?:(?i)saturday|sunday) - - - -match exactly the same set of strings. Because alternative branches are -tried from left to right, and options are not reset until the end of -the subpattern is reached, an option setting in one branch does affect -subsequent branches, so the above patterns match "SUNDAY" as well as -"Saturday". - - - - -Named subpatterns - -Identifying capturing parentheses by number is simple, but it can be -very hard to keep track of the numbers in complicated regular expressions. -Furthermore, if an expression is modified, the numbers may -change. To help with this difficulty, GRegex supports the naming of -subpatterns. A subpattern can be named in one of three ways: (?<name>...) or -(?'name'...) as in Perl, or (?P<name>...) as in Python. -References to capturing parentheses from other -parts of the pattern, such as backreferences, recursion, and conditions, -can be made by name as well as by number. - - - -Names consist of up to 32 alphanumeric characters and underscores. Named -capturing parentheses are still allocated numbers as well as names, exactly as -if the names were not present. -By default, a name must be unique within a pattern, but it is possible to relax -this constraint by setting the G_REGEX_DUPNAMES option at -compile time. This can be useful for patterns where only one instance of the -named parentheses can match. Suppose you want to match the name of a weekday, -either as a 3-letter abbreviation or as the full name, and in both cases you -want to extract the abbreviation. This pattern (ignoring the line breaks) does -the job: - - - -(?<DN>Mon|Fri|Sun)(?:day)?| -(?<DN>Tue)(?:sday)?| -(?<DN>Wed)(?:nesday)?| -(?<DN>Thu)(?:rsday)?| -(?<DN>Sat)(?:urday)? - - - -There are five capturing substrings, but only one is ever set after a match. -The function for extracting the data by name returns the substring -for the first (and in this example, the only) subpattern of that name that -matched. This saves searching to find which numbered subpattern it was. If you -make a reference to a non-unique named subpattern from elsewhere in the -pattern, the one that corresponds to the lowest number is used. - - - - -Repetition - -Repetition is specified by quantifiers, which can follow any of the -following items: - - - -a literal data character -the dot metacharacter -the \C escape sequence -the \X escape sequence (in UTF-8 mode) -the \R escape sequence -an escape such as \d that matches a single character -a character class -a back reference (see next section) -a parenthesized subpattern (unless it is an assertion) - - - -The general repetition quantifier specifies a minimum and maximum number -of permitted matches, by giving the two numbers in curly brackets -(braces), separated by a comma. The numbers must be less than 65536, -and the first must be less than or equal to the second. For example: - - - -z{2,4} - - - -matches "zz", "zzz", or "zzzz". A closing brace on its own is not a -special character. If the second number is omitted, but the comma is -present, there is no upper limit; if the second number and the comma -are both omitted, the quantifier specifies an exact number of required -matches. Thus - - - -[aeiou]{3,} - - - -matches at least 3 successive vowels, but may match many more, while - - - -\d{8} - - - -matches exactly 8 digits. An opening curly bracket that appears in a -position where a quantifier is not allowed, or one that does not match -the syntax of a quantifier, is taken as a literal character. For example, -{,6} is not a quantifier, but a literal string of four characters. - - - -In UTF-8 mode, quantifiers apply to UTF-8 characters rather than to -individual bytes. Thus, for example, \x{100}{2} matches two UTF-8 -characters, each of which is represented by a two-byte sequence. Similarly, -\X{3} matches three Unicode extended sequences, each of which may be -several bytes long (and they may be of different lengths). - - - -The quantifier {0} is permitted, causing the expression to behave as if -the previous item and the quantifier were not present. - - - -For convenience, the three most common quantifiers have single-character -abbreviations: - - - -Abbreviations for quantifiers - - - - - Abbreviation - Meaning - - - - - * - is equivalent to {0,} - - - + - is equivalent to {1,} - - - ? - is equivalent to {0,1} - - - -
- - -It is possible to construct infinite loops by following a subpattern -that can match no characters with a quantifier that has no upper limit, -for example: - - - -(a?)* - - - -Because there are cases where this can be useful, such patterns are -accepted, but if any repetition of the subpattern does in fact match -no characters, the loop is forcibly broken. - - - -By default, the quantifiers are "greedy", that is, they match as much -as possible (up to the maximum number of permitted times), without -causing the rest of the pattern to fail. The classic example of where -this gives problems is in trying to match comments in C programs. These -appear between /* and */ and within the comment, individual * and / -characters may appear. An attempt to match C comments by applying the -pattern - - - -/\*.*\*/ - - - -to the string - - - -/* first comment */ not comment /* second comment */ - - - -fails, because it matches the entire string owing to the greediness of -the .* item. - - - -However, if a quantifier is followed by a question mark, it ceases to -be greedy, and instead matches the minimum number of times possible, so -the pattern - - - -/\*.*?\*/ - - - -does the right thing with the C comments. The meaning of the various -quantifiers is not otherwise changed, just the preferred number of -matches. Do not confuse this use of question mark with its use as a -quantifier in its own right. Because it has two uses, it can sometimes -appear doubled, as in - - - -\d??\d - - - -which matches one digit by preference, but can match two if that is the -only way the rest of the pattern matches. - - - -If the G_REGEX_UNGREEDY flag is set, the quantifiers are not greedy -by default, but individual ones can be made greedy by following them with -a question mark. In other words, it inverts the default behaviour. - - - -When a parenthesized subpattern is quantified with a minimum repeat -count that is greater than 1 or with a limited maximum, more memory is -required for the compiled pattern, in proportion to the size of the -minimum or maximum. - - - -If a pattern starts with .* or .{0,} and the G_REGEX_DOTALL flag -is set, thus allowing the dot to match newlines, the -pattern is implicitly anchored, because whatever follows will be tried -against every character position in the string, so there is no -point in retrying the overall match at any position after the first. -GRegex normally treats such a pattern as though it were preceded by \A. - - - -In cases where it is known that the string contains no newlines, it -is worth setting G_REGEX_DOTALL in order to obtain this optimization, -or alternatively using ^ to indicate anchoring explicitly. - - - -However, there is one situation where the optimization cannot be used. -When .* is inside capturing parentheses that are the subject of a -backreference elsewhere in the pattern, a match at the start may fail -where a later one succeeds. Consider, for example: - - - -(.*)abc\1 - - - -If the string is "xyz123abc123" the match point is the fourth character. -For this reason, such a pattern is not implicitly anchored. - - - -When a capturing subpattern is repeated, the value captured is the -substring that matched the final iteration. For example, after - - - -(tweedle[dume]{3}\s*)+ - - - -has matched "tweedledum tweedledee" the value of the captured substring -is "tweedledee". However, if there are nested capturing subpatterns, -the corresponding captured values may have been set in previous iterations. -For example, after - - - -/(a|(b))+/ - - - -matches "aba" the value of the second captured substring is "b". - -
- - -Atomic grouping and possessive quantifiers - -With both maximizing ("greedy") and minimizing ("ungreedy" or "lazy") -repetition, failure of what follows normally causes the repeated -item to be re-evaluated to see if a different number -of repeats allows the rest of the pattern to match. Sometimes it -is useful to prevent this, either to change the nature of the -match, or to cause it fail earlier than it otherwise might, when the -author of the pattern knows there is no point in carrying on. - - - -Consider, for example, the pattern \d+foo when applied to the string - - - -123456bar - - - -After matching all 6 digits and then failing to match "foo", the normal -action of the matcher is to try again with only 5 digits matching the -\d+ item, and then with 4, and so on, before ultimately failing. -"Atomic grouping" (a term taken from Jeffrey Friedl’s book) provides -the means for specifying that once a subpattern has matched, it is not -to be re-evaluated in this way. - - - -If we use atomic grouping for the previous example, the matcher -give up immediately on failing to match "foo" the first time. The notation -is a kind of special parenthesis, starting with (?> as in this -example: - - - -(?>\d+)foo - - - -This kind of parenthesis "locks up" the part of the pattern it contains -once it has matched, and a failure further into the pattern is -prevented from backtracking into it. Backtracking past it to previous -items, however, works as normal. - - - -An alternative description is that a subpattern of this type matches -the string of characters that an identical standalone pattern would -match, if anchored at the current point in the string. - - - -Atomic grouping subpatterns are not capturing subpatterns. Simple cases -such as the above example can be thought of as a maximizing repeat that -must swallow everything it can. So, while both \d+ and \d+? are prepared -to adjust the number of digits they match in order to make the -rest of the pattern match, (?>\d+) can only match an entire sequence of -digits. - - - -Atomic groups in general can of course contain arbitrarily complicated -subpatterns, and can be nested. However, when the subpattern for an -atomic group is just a single repeated item, as in the example above, a -simpler notation, called a "possessive quantifier" can be used. This -consists of an additional + character following a quantifier. Using -this notation, the previous example can be rewritten as - - - -\d++foo - - - -Possessive quantifiers are always greedy; the setting of the -G_REGEX_UNGREEDY option is ignored. They are a convenient notation for the -simpler forms of atomic group. However, there is no difference in the -meaning of a possessive quantifier and the equivalent -atomic group, though there may be a performance difference; -possessive quantifiers should be slightly faster. - - - -The possessive quantifier syntax is an extension to the Perl syntax. -It was invented by Jeffrey Friedl in the first edition of his book and -then implemented by Mike McCloskey in Sun's Java package. -It ultimately found its way into Perl at release 5.10. - - - -GRegex has an optimization that automatically "possessifies" certain simple -pattern constructs. For example, the sequence A+B is treated as A++B because -there is no point in backtracking into a sequence of A's when B must follow. - - - -When a pattern contains an unlimited repeat inside a subpattern that -can itself be repeated an unlimited number of times, the use of an -atomic group is the only way to avoid some failing matches taking a -very long time indeed. The pattern - - - -(\D+|<\d+>)*[!?] - - - -matches an unlimited number of substrings that either consist of non- -digits, or digits enclosed in <>, followed by either ! or ?. When it -matches, it runs quickly. However, if it is applied to - - - -aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa - - - -it takes a long time before reporting failure. This is because the -string can be divided between the internal \D+ repeat and the external -* repeat in a large number of ways, and all have to be tried. (The -example uses [!?] rather than a single character at the end, because -GRegex has an optimization that allows for fast failure -when a single character is used. It remember the last single character -that is required for a match, and fail early if it is not present -in the string.) If the pattern is changed so that it uses an atomic -group, like this: - - - -((?>\D+)|<\d+>)*[!?] - - - -sequences of non-digits cannot be broken, and failure happens quickly. - - - - -Back references - -Outside a character class, a backslash followed by a digit greater than -0 (and possibly further digits) is a back reference to a capturing subpattern -earlier (that is, to its left) in the pattern, provided there have been that -many previous capturing left parentheses. - - - -However, if the decimal number following the backslash is less than 10, -it is always taken as a back reference, and causes an error only if -there are not that many capturing left parentheses in the entire pattern. -In other words, the parentheses that are referenced need not be -to the left of the reference for numbers less than 10. A "forward back -reference" of this type can make sense when a repetition is involved and -the subpattern to the right has participated in an earlier iteration. - - - -It is not possible to have a numerical "forward back reference" to subpattern -whose number is 10 or more using this syntax because a sequence such as \e50 is -interpreted as a character defined in octal. See the subsection entitled -"Non-printing characters" above for further details of the handling of digits -following a backslash. There is no such problem when named parentheses are used. -A back reference to any subpattern is possible using named parentheses (see below). - - - -Another way of avoiding the ambiguity inherent in the use of digits following a -backslash is to use the \g escape sequence (introduced in Perl 5.10.) -This escape must be followed by a positive or a negative number, -optionally enclosed in braces. - - - -A positive number specifies an absolute reference without the ambiguity that is -present in the older syntax. It is also useful when literal digits follow the -reference. A negative number is a relative reference. Consider "(abc(def)ghi)\g{-1}", -the sequence \g{-1} is a reference to the most recently started capturing -subpattern before \g, that is, is it equivalent to \2. Similarly, \g{-2} -would be equivalent to \1. The use of relative references can be helpful in -long patterns, and also in patterns that are created by joining together -fragments that contain references within themselves. - - - -A back reference matches whatever actually matched the capturing subpattern -in the current string, rather than anything matching -the subpattern itself (see "Subpatterns as subroutines" below for a way -of doing that). So the pattern - - - -(sens|respons)e and \1ibility - - - -matches "sense and sensibility" and "response and responsibility", but -not "sense and responsibility". If caseful matching is in force at the -time of the back reference, the case of letters is relevant. For example, - - - -((?i)rah)\s+\1 - - - -matches "rah rah" and "RAH RAH", but not "RAH rah", even though the -original capturing subpattern is matched caselessly. - - - -Back references to named subpatterns use the Perl syntax \k<name> or \k'name' -or the Python syntax (?P=name). We could rewrite the above example in either of -the following ways: - - - -(?<p1>(?i)rah)\s+\k<p1> -(?P<p1>(?i)rah)\s+(?P=p1) - - - -A subpattern that is referenced by name may appear in the pattern before or -after the reference. - - - -There may be more than one back reference to the same subpattern. If a -subpattern has not actually been used in a particular match, any back -references to it always fail. For example, the pattern - - - -(a|(bc))\2 - - - -always fails if it starts to match "a" rather than "bc". Because there -may be many capturing parentheses in a pattern, all digits following -the backslash are taken as part of a potential back reference number. -If the pattern continues with a digit character, some delimiter must be -used to terminate the back reference. If the G_REGEX_EXTENDED flag is -set, this can be whitespace. Otherwise an empty comment (see "Comments" below) can be used. - - - -A back reference that occurs inside the parentheses to which it refers -fails when the subpattern is first used, so, for example, (a\1) never -matches. However, such references can be useful inside repeated subpatterns. -For example, the pattern - - - -(a|b\1)+ - - - -matches any number of "a"s and also "aba", "ababbaa" etc. At each iteration -of the subpattern, the back reference matches the character -string corresponding to the previous iteration. In order for this to -work, the pattern must be such that the first iteration does not need -to match the back reference. This can be done using alternation, as in -the example above, or by a quantifier with a minimum of zero. - - - - -Assertions - -An assertion is a test on the characters following or preceding the -current matching point that does not actually consume any characters. -The simple assertions coded as \b, \B, \A, \G, \Z, \z, ^ and $ are -described above. - - - -More complicated assertions are coded as subpatterns. There are two -kinds: those that look ahead of the current position in the -string, and those that look behind it. An assertion subpattern is -matched in the normal way, except that it does not cause the current -matching position to be changed. - - - -Assertion subpatterns are not capturing subpatterns, and may not be -repeated, because it makes no sense to assert the same thing several -times. If any kind of assertion contains capturing subpatterns within -it, these are counted for the purposes of numbering the capturing -subpatterns in the whole pattern. However, substring capturing is carried -out only for positive assertions, because it does not make sense for -negative assertions. - - - -Lookahead assertions - -Lookahead assertions start with (?= for positive assertions and (?! for -negative assertions. For example, - - - -\w+(?=;) - - - -matches a word followed by a semicolon, but does not include the semicolon -in the match, and - - - -foo(?!bar) - - - -matches any occurrence of "foo" that is not followed by "bar". Note -that the apparently similar pattern - - - -(?!foo)bar - - - -does not find an occurrence of "bar" that is preceded by something -other than "foo"; it finds any occurrence of "bar" whatsoever, because -the assertion (?!foo) is always true when the next three characters are -"bar". A lookbehind assertion is needed to achieve the other effect. - - - -If you want to force a matching failure at some point in a pattern, the -most convenient way to do it is with (?!) because an empty string -always matches, so an assertion that requires there not to be an empty -string must always fail. - - - - -Lookbehind assertions - -Lookbehind assertions start with (?<= for positive assertions and (?<! -for negative assertions. For example, - - - -(?<!foo)bar - - - -does find an occurrence of "bar" that is not preceded by "foo". The -contents of a lookbehind assertion are restricted such that all the -strings it matches must have a fixed length. However, if there are -several top-level alternatives, they do not all have to have the same -fixed length. Thus - - - -(?<=bullock|donkey) - - - -is permitted, but - - - -(?<!dogs?|cats?) - - - -causes an error at compile time. Branches that match different length -strings are permitted only at the top level of a lookbehind assertion. -An assertion such as - - - -(?<=ab(c|de)) - - - -is not permitted, because its single top-level branch can match two -different lengths, but it is acceptable if rewritten to use two top- -level branches: - - - -(?<=abc|abde) - - - -The implementation of lookbehind assertions is, for each alternative, -to temporarily move the current position back by the fixed length and -then try to match. If there are insufficient characters before the -current position, the assertion fails. - - - -GRegex does not allow the \C escape (which matches a single byte in UTF-8 -mode) to appear in lookbehind assertions, because it makes it impossible -to calculate the length of the lookbehind. The \X and \R escapes, which can -match different numbers of bytes, are also not permitted. - - - -Possessive quantifiers can be used in conjunction with lookbehind assertions to -specify efficient matching at the end of the subject string. Consider a simple -pattern such as - - - -abcd$ - - - -when applied to a long string that does not match. Because matching -proceeds from left to right, GRegex will look for each "a" in the string -and then see if what follows matches the rest of the pattern. If the -pattern is specified as - - - -^.*abcd$ - - - -the initial .* matches the entire string at first, but when this fails -(because there is no following "a"), it backtracks to match all but the -last character, then all but the last two characters, and so on. Once -again the search for "a" covers the entire string, from right to left, -so we are no better off. However, if the pattern is written as - - - -^.*+(?<=abcd) - - - -there can be no backtracking for the .*+ item; it can match only the -entire string. The subsequent lookbehind assertion does a single test -on the last four characters. If it fails, the match fails immediately. -For long strings, this approach makes a significant difference to the -processing time. - - - - -Using multiple assertions - -Several assertions (of any sort) may occur in succession. For example, - - - -(?<=\d{3})(?<!999)foo - - - -matches "foo" preceded by three digits that are not "999". Notice that -each of the assertions is applied independently at the same point in -the string. First there is a check that the previous three -characters are all digits, and then there is a check that the same -three characters are not "999". This pattern does not match "foo" preceded -by six characters, the first of which are digits and the last -three of which are not "999". For example, it doesn’t match "123abcfoo". -A pattern to do that is - - - -(?<=\d{3}...)(?<!999)foo - - - -This time the first assertion looks at the preceding six characters, -checking that the first three are digits, and then the second assertion -checks that the preceding three characters are not "999". - - - -Assertions can be nested in any combination. For example, - - - -(?<=(?<!foo)bar)baz - - - -matches an occurrence of "baz" that is preceded by "bar" which in turn -is not preceded by "foo", while - - - -(?<=\d{3}(?!999)...)foo - - - -is another pattern that matches "foo" preceded by three digits and any -three characters that are not "999". - - - - - -Conditional subpatterns - -It is possible to cause the matching process to obey a subpattern -conditionally or to choose between two alternative subpatterns, depending -on the result of an assertion, or whether a previous capturing subpattern -matched or not. The two possible forms of conditional subpattern are - - - -(?(condition)yes-pattern) -(?(condition)yes-pattern|no-pattern) - - - -If the condition is satisfied, the yes-pattern is used; otherwise the -no-pattern (if present) is used. If there are more than two alternatives -in the subpattern, a compile-time error occurs. - - - -There are four kinds of condition: references to subpatterns, references to -recursion, a pseudo-condition called DEFINE, and assertions. - - - -Checking for a used subpattern by number - -If the text between the parentheses consists of a sequence of digits, the -condition is true if the capturing subpattern of that number has previously -matched. - - - -Consider the following pattern, which contains non-significant white space -to make it more readable (assume the G_REGEX_EXTENDED) -and to divide it into three parts for ease of discussion: - - - -( \( )? [^()]+ (?(1) \) ) - - - -The first part matches an optional opening parenthesis, and if that -character is present, sets it as the first captured substring. The second -part matches one or more characters that are not parentheses. The -third part is a conditional subpattern that tests whether the first set -of parentheses matched or not. If they did, that is, if string started -with an opening parenthesis, the condition is true, and so the yes-pattern -is executed and a closing parenthesis is required. Otherwise, -since no-pattern is not present, the subpattern matches nothing. In -other words, this pattern matches a sequence of non-parentheses, -optionally enclosed in parentheses. - - - - -Checking for a used subpattern by name - -Perl uses the syntax (?(<name>)...) or (?('name')...) to test for a used -subpattern by name, the Python syntax (?(name)...) is also recognized. However, -there is a possible ambiguity with this syntax, because subpattern names may -consist entirely of digits. GRegex looks first for a named subpattern; if it -cannot find one and the name consists entirely of digits, GRegex looks for a -subpattern of that number, which must be greater than zero. Using subpattern -names that consist entirely of digits is not recommended. - - - -Rewriting the above example to use a named subpattern gives this: - - - -(?<OPEN> \( )? [^()]+ (?(<OPEN>) \) ) - - - - -Checking for pattern recursion - -If the condition is the string (R), and there is no subpattern with the name R, -the condition is true if a recursive call to the whole pattern or any -subpattern has been made. If digits or a name preceded by ampersand follow the -letter R, for example: - - - -(?(R3)...) -(?(R&name)...) - - - -the condition is true if the most recent recursion is into the subpattern whose -number or name is given. This condition does not check the entire recursion -stack. - - - -At "top level", all these recursion test conditions are false. Recursive -patterns are described below. - - - - -Defining subpatterns for use by reference only - -If the condition is the string (DEFINE), and there is no subpattern with the -name DEFINE, the condition is always false. In this case, there may be only one -alternative in the subpattern. It is always skipped if control reaches this -point in the pattern; the idea of DEFINE is that it can be used to define -"subroutines" that can be referenced from elsewhere. (The use of "subroutines" -is described below.) For example, a pattern to match an IPv4 address could be -written like this (ignore whitespace and line breaks): - - - -(?(DEFINE) (?<byte> 2[0-4]\d | 25[0-5] | 1\d\d | [1-9]?\d) ) -\b (?&byte) (\.(?&byte)){3} \b - - - -The first part of the pattern is a DEFINE group inside which another group -named "byte" is defined. This matches an individual component of an IPv4 -address (a number less than 256). When matching takes place, this part of the -pattern is skipped because DEFINE acts like a false condition. - - - -The rest of the pattern uses references to the named group to match the four -dot-separated components of an IPv4 address, insisting on a word boundary at -each end. - - - - -Assertion conditions - -If the condition is not in any of the above formats, it must be an -assertion. This may be a positive or negative lookahead or lookbehind -assertion. Consider this pattern, again containing non-significant -white space, and with the two alternatives on the second line: - - - -(?(?=[^a-z]*[a-z]) -\d{2}-[a-z]{3}-\d{2} | \d{2}-\d{2}-\d{2} ) - - - -The condition is a positive lookahead assertion that matches an -optional sequence of non-letters followed by a letter. In other words, -it tests for the presence of at least one letter in the string. If a -letter is found, the string is matched against the first alternative; -otherwise it is matched against the second. This pattern matches -strings in one of the two forms dd-aaa-dd or dd-dd-dd, where aaa are -letters and dd are digits. - - - - - -Comments - -The sequence (?# marks the start of a comment that continues up to the -next closing parenthesis. Nested parentheses are not permitted. The -characters that make up a comment play no part in the pattern matching -at all. - - - -If the G_REGEX_EXTENDED option is set, an unescaped # -character outside a character class introduces a comment that continues to -immediately after the next newline in the pattern. - - - - -Recursive patterns - -Consider the problem of matching a string in parentheses, allowing for -unlimited nested parentheses. Without the use of recursion, the best -that can be done is to use a pattern that matches up to some fixed -depth of nesting. It is not possible to handle an arbitrary nesting -depth. - - - -For some time, Perl has provided a facility that allows regular expressions to -recurse (amongst other things). It does this by interpolating Perl code in the -expression at run time, and the code can refer to the expression itself. A Perl -pattern using code interpolation to solve the parentheses problem can be -created like this: - - - -$re = qr{\( (?: (?>[^()]+) | (?p{$re}) )* \)}x; - - - -The (?p{...}) item interpolates Perl code at run time, and in this case refers -recursively to the pattern in which it appears. - - - -Obviously, GRegex cannot support the interpolation of Perl code. Instead, it -supports special syntax for recursion of the entire pattern, and also for -individual subpattern recursion. This kind of recursion was introduced into -Perl at release 5.10. - - - -A special item that consists of (? followed by a number greater than zero and a -closing parenthesis is a recursive call of the subpattern of the given number, -provided that it occurs inside that subpattern. (If not, it is a "subroutine" -call, which is described in the next section.) The special item (?R) or (?0) is -a recursive call of the entire regular expression. - - - -In GRegex (like Python, but unlike Perl), a recursive subpattern call is always -treated as an atomic group. That is, once it has matched some of the subject -string, it is never re-entered, even if it contains untried alternatives and -there is a subsequent matching failure. - - - -This pattern solves the nested parentheses problem (assume the -G_REGEX_EXTENDED option is set so that white space is -ignored): - - - -\( ( (?>[^()]+) | (?R) )* \) - - - -First it matches an opening parenthesis. Then it matches any number of -substrings which can either be a sequence of non-parentheses, or a -recursive match of the pattern itself (that is, a correctly parenthesized -substring). Finally there is a closing parenthesis. - - - -If this were part of a larger pattern, you would not want to recurse -the entire pattern, so instead you could use this: - - - -( \( ( (?>[^()]+) | (?1) )* \) ) - - - -We have put the pattern into parentheses, and caused the recursion to -refer to them instead of the whole pattern. In a larger pattern, keeping -track of parenthesis numbers can be tricky. It may be more convenient to -use named parentheses instead. -The Perl syntax for this is (?&name); GRegex also supports the(?P>name) -syntax. We could rewrite the above example as follows: - - - -(?<pn> \( ( (?>[^()]+) | (?&pn) )* \) ) - - - -If there is more than one subpattern with the same name, the earliest one is -used. This particular example pattern contains nested unlimited repeats, and so -the use of atomic grouping for matching strings of non-parentheses is important -when applying the pattern to strings that do not match. -For example, when this pattern is applied to - - - -(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa() - - - -it yields "no match" quickly. However, if atomic grouping is not used, -the match runs for a very long time indeed because there are so many -different ways the + and * repeats can carve up the string, and all -have to be tested before failure can be reported. - - - -At the end of a match, the values set for any capturing subpatterns are -those from the outermost level of the recursion at which the subpattern -value is set. - - - -If the pattern above is matched against - - - -(ab(cd)ef) - - - -the value for the capturing parentheses is "ef", which is the last -value taken on at the top level. If additional parentheses are added, -giving - - - -\( ( ( (?>[^()]+) | (?R) )* ) \) - ^ ^ - ^ ^ - - - -the string they capture is "ab(cd)ef", the contents of the top level -parentheses. - - - -Do not confuse the (?R) item with the condition (R), which tests for -recursion. Consider this pattern, which matches text in angle brackets, -allowing for arbitrary nesting. Only digits are allowed in nested -brackets (that is, when recursing), whereas any characters are permitted -at the outer level. - - - -< (?: (?(R) \d++ | [^<>]*+) | (?R)) * > - - - -In this pattern, (?(R) is the start of a conditional subpattern, with -two different alternatives for the recursive and non-recursive cases. -The (?R) item is the actual recursive call. - - - - -Subpatterns as subroutines - -If the syntax for a recursive subpattern reference (either by number or -by name) is used outside the parentheses to which it refers, it operates -like a subroutine in a programming language. The "called" subpattern may -be defined before or after the reference. An earlier example pointed out -that the pattern - - - -(sens|respons)e and \1ibility - - - -matches "sense and sensibility" and "response and responsibility", but -not "sense and responsibility". If instead the pattern - - - -(sens|respons)e and (?1)ibility - - - -is used, it does match "sense and responsibility" as well as the other -two strings. Another example is given in the discussion of DEFINE above. - - - -Like recursive subpatterns, a "subroutine" call is always treated as an atomic -group. That is, once it has matched some of the string, it is never -re-entered, even if it contains untried alternatives and there is a subsequent -matching failure. - - - -When a subpattern is used as a subroutine, processing options such as -case-independence are fixed when the subpattern is defined. They cannot be -changed for different calls. For example, consider this pattern: - - - -(abc)(?i:(?1)) - - - -It matches "abcabc". It does not match "abcABC" because the change of -processing option does not affect the called subpattern. - - - - -Copyright - -This document was copied and adapted from the PCRE documentation, -specifically from the man page for pcrepattern. -The original copyright note is: - - - -Copyright (c) 1997-2006 University of Cambridge. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - - * Neither the name of the University of Cambridge nor the name of Google - Inc. nor the names of their contributors may be used to endorse or - promote products derived from this software without specific prior - written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" -AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE -IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE -ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE -LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR -CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF -SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS -INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN -CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) -ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE -POSSIBILITY OF SUCH DAMAGE. - - - -
diff --git a/docs/reference/glib/resources.md b/docs/reference/glib/resources.md new file mode 100644 index 0000000..fbac645 --- /dev/null +++ b/docs/reference/glib/resources.md @@ -0,0 +1,43 @@ +Title: Support and Bug Reports +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2002 Matthias Clasen +SPDX-FileCopyrightText: 2018 Collabora, Ltd. +SPDX-FileCopyrightText: 2019 Emmanuele Bassi + +# Support and Bug Reports + +## Filing a Bug Report or Feature Request + +If you encounter a bug, misfeature, or missing feature in GLib, please +file a bug report on the issue tracker at +[https://gitlab.gnome.org/GNOME/glib/issues/new](https://gitlab.gnome.org/GNOME/glib/issues/new). +We’d also appreciate reports of incomplete or misleading information in +the GLib documentation; file those with the ‘Documentation’ label. + +Don’t hesitate to file a bug report, even if you think we may know +about it already, or aren’t sure of the details. Just give us as much +information as you have, and if it’s already fixed or has already been +discussed, we’ll add a note to that effect in the report. + +The issue tracker should definitely be used for feature requests, it’s +not only for bugs. We track all GLib development in GitLab, so it’s +the way to be sure the GLib developers won’t forget about an issue. + +## Code Contributions + +If you develop a bugfix or enhancement for GLib, please open a merge request +for that in GitLab as well. All branches must be offered under the terms of +the GNU LGPL license, so be sure you are authorized to give us the branch +under those terms. + +If you want to discuss your branch before or after developing it, open a +topic on [Discourse](https://discourse.gnome.org/tags/glib). +But be sure to create the GitLab merge request as well; if the branch is only +on the list and not in GitLab, it’s likely to slip through the cracks. + +## Discussions and User Questions + +The [GLib issue tracker](https://gitlab.gnome.org/GNOME/glib/issues) +is meant for discussions with actionable topics. If you want to ask a question +about using GLib, or discuss new features, you should use +[the `glib` tag on Discourse](https://discourse.gnome.org/tags/glib). diff --git a/docs/reference/glib/resources.xml b/docs/reference/glib/resources.xml deleted file mode 100644 index c5cfa78..0000000 --- a/docs/reference/glib/resources.xml +++ /dev/null @@ -1,77 +0,0 @@ - - - - -Mailing lists and bug reports -3 -Mailing lists and bug reports - - - -Mailing lists and bug reports - -Getting help with GLib - - - - -Filing a bug report or feature request - - -If you encounter a bug, misfeature, or missing feature in GLib, please -file a bug report on the issue tracker at -https://gitlab.gnome.org/GNOME/glib/issues/new. -We'd also appreciate reports of incomplete or misleading information in -the GLib documentation; file those with the ‘Documentation’ label. - - - -Don't hesitate to file a bug report, even if you think we may know -about it already, or aren't sure of the details. Just give us as much -information as you have, and if it's already fixed or has already been -discussed, we'll add a note to that effect in the report. - - - -The issue tracker should definitely be used for feature requests, it's -not only for bugs. We track all GLib development in GitLab, so it's -the way to be sure the GLib developers won't forget about an issue. - - - - - -Code Contributions - - -If you develop a bugfix or enhancement for GLib, please open a merge request -for that in GitLab as well. All branches must be offered under the terms of -the GNU LGPL license, so be sure you are authorized to give us the branch -under those terms. - - - -If you want to discuss your branch before or after developing it, open a -topic on Discourse. -But be sure to create the GitLab merge request as well; if the branch is only -on the list and not in GitLab, it's likely to slip through the cracks. - - - - - -Discussions and user questions - - -The GLib issue tracker -is meant for discussions with actionable topics. If you want to ask a question -about using GLib, or discuss new features, you should use -the glib tag on Discourse. - - - - - - diff --git a/docs/reference/glib/running.md b/docs/reference/glib/running.md new file mode 100644 index 0000000..687ca75 --- /dev/null +++ b/docs/reference/glib/running.md @@ -0,0 +1,295 @@ +Title: Running GLib Applications + +# Running GLib Applications + +## Environment variables + +The runtime behaviour of GLib applications can be influenced by a number of +environment variables. + +Standard variables +: GLib reads standard environment variables like `LANG`, `PATH`, `HOME`, + `TMPDIR`, `TZ` and `LOGNAME`. + +XDG directories +: GLib consults the environment variables `XDG_DATA_HOME`, + `XDG_DATA_DIRS`, `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`, `XDG_CACHE_HOME` and + `XDG_RUNTIME_DIR` for the various XDG directories. For more information, see + the [XDG basedir specification](https://specifications.freedesktop.org/basedir-spec/latest/). + +`G_FILENAME_ENCODING` +: This environment variable can be set to a comma-separated list of character + set names. GLib assumes that filenames are encoded in the first character + set from that list rather than in UTF-8. The special token "@locale" can be + used to specify the character set for the current locale. + +`G_BROKEN_FILENAMES` +: If this environment variable is set, GLib assumes that filenames are in the + locale encoding rather than in UTF-8. `G_FILENAME_ENCODING` takes priority + over `G_BROKEN_FILENAMES`. + +`G_MESSAGES_PREFIXED` +: A list of log levels for which messages should be prefixed by the program + name and PID of the application. The default is to prefix everything except + `G_LOG_LEVEL_MESSAGE` and `G_LOG_LEVEL_INFO`. The possible values are error, + warning, critical, message, info and debug. You can also use the special + values all and help. This environment variable only affects the default log + handler, `g_log_default_handler()`. + +`G_MESSAGES_DEBUG` +: A space-separated list of log domains for which informational and debug + messages should be printed. By default, these messages are not printed. You + can also use the special value all. This environment variable only affects + the default log handler, `g_log_default_handler()`. + +`G_DEBUG` +: This environment variable can be set to a list of debug options, which cause + GLib to print out different types of debugging information. + + - `fatal-warnings`: Causes GLib to abort the program at the first call to + `g_warning()` or `g_critical()`. Use of this flag is not recommended + except when debugging. + - `fatal-criticals`: Causes GLib to abort the program at the first call + to `g_critical()`. This flag can be useful during debugging and + testing. + - `gc-friendly`: Newly allocated memory that isn't directly initialized, + as well as memory being freed will be reset to 0. The point here is to + allow memory checkers and similar programs that use Boehm GC alike + algorithms to produce more accurate results. + - `resident-modules`: All modules loaded by GModule will be made + resident. This can be useful for tracking memory leaks in modules which + are later unloaded; but it can also hide bugs where code is accessed + after the module would have normally been unloaded. + - `bind-now-modules`: All modules loaded by GModule will bind their + symbols at load time, even when the code uses `G_MODULE_BIND_LAZY`. + + The special value `all` can be used to turn on all debug options. The special + value `help` can be used to print all available options. + +`G_SLICE` +: This environment variable allowed reconfiguration of the GSlice memory + allocator. Since GLib 2.76, GSlice uses the system `malloc()` implementation + internally, so this variable is ignored. + +`G_RANDOM_VERSION` +: If this environment variable is set to '2.0', the outdated pseudo-random + number seeding and generation algorithms from GLib 2.0 are used instead of + the newer, better ones. You should only set this variable if you have + sequences of numbers that were generated with Glib 2.0 that you need to + reproduce exactly. + +`LIBCHARSET_ALIAS_DIR` +: Allows to specify a nonstandard location for the `charset.aliases` file + that is used by the character set conversion routines. The default + location is the `libdir` specified at compilation time. + +`TZDIR` +: Allows to specify a nonstandard location for the timezone data files that + are used by the `GDateTime` API. The default location is under + `/usr/share/zoneinfo`. For more information, also look at the `tzset` manual + page. + +`G_ENABLE_DIAGNOSTIC` +: If set to a non-zero value, this environment variable enables diagnostic + messages, like deprecation messages for GObject properties and signals. + +`G_DEBUGGER` +: When running on Windows, if set to a non-empty string, GLib will try to + interpret the contents of this environment variable as a command line to a + debugger, and run it if the process crashes. The debugger command line + should contain `%p` and `%e` substitution tokens, which GLib will replace + with the process ID of the crashing process and a handle to an event that + the debugger should signal to let GLib know that the debugger successfully + attached to the process. If `%e` is absent, or if the debugger is not able + to signal events, GLib will resume execution after 60 seconds. If `%p` is + absent, the debugger won't know which process to attach to, and GLib will + also resume execution after 60 seconds. Additionally, even if `G_DEBUGGER` + is not set, GLib would still try to print basic exception information (code + and address) into `stderr`. By default the debugger gets a new console + allocated for it. Set the `G_DEBUGGER_OLD_CONSOLE` environment variable to + any non-empty string to make the debugger inherit the console of the + crashing process. Normally this is only used by the GLib testsuite. The + exception handler is written with the aim of making it as simple as + possible, to minimize the risk of it invoking buggy functions or running + buggy code, which would result in exceptions being raised recursively. + Because of that it lacks most of the amenities that one would expect of + GLib. Namely, it does not support Unicode, so it is highly advisable to + only use ASCII characters in `G_DEBUGGER`. See also `G_VEH_CATCH`. + +`G_VEH_CATCH` +: Catching some exceptions can break the program, since Windows will + sometimes use exceptions for execution flow control and other purposes + other than signalling a crash. The `G_VEH_CATCH` environment variable + augments Vectored Exception Handling on Windows (see `G_DEBUGGER`), + allowing GLib to catch more exceptions. Set this variable to a + comma-separated list of hexadecimal exception codes that should + additionally be caught. By default GLib will only catch Access Violation, + Stack Overflow and Illegal Instruction exceptions. + +## Locale + +A number of interfaces in GLib depend on the current locale in which an +application is running. Therefore, most GLib-using applications should call +`setlocale (LC_ALL, "")` to set up the current locale. + +On Windows, in a C program there are several locale concepts that not +necessarily are synchronized. On one hand, there is the system default ANSI +code-page, which determines what encoding is used for file names handled by +the C library's functions and the Win32 API. (We are talking about the +"narrow" functions here that take character pointers, not the "wide" ones.) + +On the other hand, there is the C library's current locale. The character +set (code-page) used by that is not necessarily the same as the system +default ANSI code-page. Strings in this character set are returned by +functions like `strftime()`. + +## Debugging with GDB + +GLib ships with a set of Python macros for the GDB debugger. These +macros make it easier to debug applications written using GLib. + +To use this you need to install GLib in the same prefix as GDB so that +the Python GDB autoloaded files get installed in the right place for +GDB to pick up. + +You can check if gdb has picked up the GLib gdb scripts correctly by +running the following command in your gdb session. + +``` +(gdb) info auto-load python-scripts +Loaded Script +Yes /usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libglib-2.0.so.0.7800.0-gdb.py +Yes /usr/share/gdb/auto-load/usr/lib/x86_64-linux-gnu/libgobject-2.0.so.0.7800.0-gdb.py +``` + +The version numbers and paths might differ based on the OS +distribution, but if you see the entries listed for libglib and +libgobject, then the gdb scripts should work. + +GLib Python macros provide the following benefits while debugging +applications written using GLib. + +1. Pretty printing GLib types +2. Iterating lists using `gforeach` command +3. Backtrace decorations + +### 1. Pretty printing GLib types: + +General pretty printing GLib types should work without having to do +anything special. + +For example, printing a hash table with string keys will display the hash +contents in the following format. + +``` +(gdb) print my_string_hash_variable +$1 = 0x5555556d9660 = { + [0x7ffff76f6592 "GdkWaylandPopup"] = 0x555555768a50, + [0x7ffff76e67e8 "GtkStyleProvider"] = 0x5555557a19c0, + [0x7ffff7db7151 "GHttpProxy"] = 0x5555556f5bc0 +} +``` + +Printing a hash table with pointer keys will display the hash contents +in the following format. + +``` +(gdb) print my_pointer_hash_variable +$2 = 0x5555556dcb50 = { + [0x555555b59ec0] = 0x555555b59770, + [0x555555c79f80] = 0x555555c86b00, + [0x555555c68f40] = 0x555555c69630 +} +``` + +Printing a list will display the list contents in the following +format. + +``` +(gdb) p my_appname_list +$3 = 0x55c4582deef0 = {0x7f16ab85dc90, 0x7f16abb02700, 0x7f16a80066e0} +``` + +It's not possible for us to decode and print string entries even if +the list has string entries, as GLib stores list entries as +`gpointer`s internally. But, that can be achieved using the `gforeach` +command. + +### 2. Iterating lists using "gforeach" command: + +The `gforeach` command can be used to apply a command on each item in +a list (`GList`/`GSList`). We can also type cast the `gpointer`s in the +list to desired type. + +For example, to print all strings in a string list named `my_appname_list`, +you can do the following. + +``` +(gdb) gforeach appname in my_appname_list: print (gchar*) $appname +$4 = (gchar *) 0x7f16ab85dc90 "Boxes" +$5 = (gchar *) 0x7f16abb02700 "GNOME Application Platform version 45" +$6 = (gchar *) 0x7f16a80066e0 "Firefox ESR" +``` + +You can also call functions on each entry in the list, as below: + +``` +(gdb) gforeach appname in my_appname_list: call (int) strlen($appname) +$7 = 5 +$8 = 37 +$9 = 11 +``` + +### 3. Backtrace decorations: + +Backtraces are decorated with GLib type names and signal names. + +E.g. From the below backtrace, we can say that +`gs_updates_page_button_refresh_cb ()` callback function was called +when a button (via the `GtkButton` type decoration) was clicked (via +the `clicked` signal decoration) + +``` +#0 gs_updates_page_button_refresh_cb (widget=0x5602f986b670 [GtkButton], self=0x5602f93aeb80 [GsUpdatesPage]) at ../src/gs-updates-page.c:826 +#1 0x00007f09da7651de in (instance=0x5602f986b670, signal_id=158, detail=0) at ../gobject/gsignal.c:3675 +#2 0x00007f09da747bad in g_cclosure_marshal_VOID__VOIDv (closure=0x5602f986c6a0, return_value=0x0, instance=0x5602f986b670, ...) + at ../gobject/gmarshal.c:165 +… +#20 0x00007f09da52c250 in g_application_run (application=0x5602f9068ae0 [GsApplication], argc=1, argv=0x7ffcfb3bb468) at ../gio/gapplication.c:2577 +#21 0x00005602f8b53ccd in main (argc=1, argv=0x7ffcfb3bb468) at ../src/gs-main.c:49 +``` + +Following is the same backtrace without any GLib decorations, which is +not very useful. + +``` +#0 gs_updates_page_button_refresh_cb (widget=0x5602f986b670, self=0x5602f93aeb80) at ../src/gs-updates-page.c:826 +#1 0x00007f09da747bad in g_cclosure_marshal_VOID__VOIDv (closure=0x5602f986c6a0, return_value=0x0, instance=0x5602f986b670, ...) + at ../gobject/gmarshal.c:165 +… +#20 0x00007f09da52c250 in g_application_run (application=0x5602f9068ae0, argc=1, argv=0x7ffcfb3bb468) at ../gio/gapplication.c:2577 +#21 0x00005602f8b53ccd in main (argc=1, argv=0x7ffcfb3bb468) at ../src/gs-main.c:49 +``` + +## SystemTap + +SystemTap is a dynamic whole-system analysis toolkit. GLib ships with a file +`libglib-2.0.so.*.stp` which defines a set of probe points, which you can hook +into with custom SystemTap scripts. See the files `libglib-2.0.so.*.stp`, +`libgobject-2.0.so.*.stp` and `libgio-2.0.so.*.stp` which are in your shared +SystemTap scripts directory. + +## Memory statistics + +`g_mem_profile()` will output a summary `g_malloc()` memory usage, if memory +profiling has been enabled by calling: + +``` +g_mem_set_vtable (glib_mem_profiler_table); +``` + +upon startup. + +If GLib has been configured with full debugging support, then +`g_slice_debug_tree_statistics()` can be called in a debugger to output details +about the memory usage of the slice allocator. diff --git a/docs/reference/glib/running.xml b/docs/reference/glib/running.xml deleted file mode 100644 index dbf22ad..0000000 --- a/docs/reference/glib/running.xml +++ /dev/null @@ -1,371 +0,0 @@ - - - - -Running GLib Applications -3 -GLib Library - - - -Running GLib Applications - -How to run and debug your GLib application - - - - -Running and debugging GLib Applications - - -Environment variables - - - The runtime behaviour of GLib applications can be influenced by a - number of environment variables. - - - - Standard variables - - - GLib reads standard environment variables like LANG, - PATH, HOME, TMPDIR, - TZ and LOGNAME. - - - - - XDG directories - - - GLib consults the environment variables XDG_DATA_HOME, - XDG_DATA_DIRS, XDG_CONFIG_HOME, - XDG_CONFIG_DIRS, XDG_CACHE_HOME and - XDG_RUNTIME_DIR for the various XDG directories. - For more information, see the XDG basedir spec. - - - - - <envar>G_FILENAME_ENCODING</envar> - - - This environment variable can be set to a comma-separated list of character - set names. GLib assumes that filenames are encoded in the first character - set from that list rather than in UTF-8. The special token "@locale" can be - used to specify the character set for the current locale. - - - - - <envar>G_BROKEN_FILENAMES</envar> - - - If this environment variable is set, GLib assumes that filenames are in - the locale encoding rather than in UTF-8. G_FILENAME_ENCODING takes - priority over G_BROKEN_FILENAMES. - - - - - <envar>G_MESSAGES_PREFIXED</envar> - - - A list of log levels for which messages should be prefixed by the - program name and PID of the application. The default is to prefix - everything except G_LOG_LEVEL_MESSAGE and - G_LOG_LEVEL_INFO. - The possible values are - error, - warning, - critical, - message, - info and - debug. - You can also use the special values - all and - help. - - - This environment variable only affects the default log handler, - g_log_default_handler(). - - - - - <envar>G_MESSAGES_DEBUG</envar> - - - A space-separated list of log domains for which informational - and debug messages should be printed. By default, these - messages are not printed. - - - You can also use the special value all. - - - This environment variable only affects the default log handler, - g_log_default_handler(). - - - - - <envar>G_DEBUG</envar> - - - This environment variable can be set to a list of debug options, - which cause GLib to print out different types of debugging information. - - - fatal-warnings - Causes GLib to abort the program at the first call - to g_warning() or g_critical(). Use of this flag is not - recommended except when debugging. - - - - fatal-criticals - Causes GLib to abort the program at the first call - to g_critical(). This flag can be useful during debugging and - testing. - - - - gc-friendly - Newly allocated memory that isn't directly initialized, - as well as memory being freed will be reset to 0. The point here is - to allow memory checkers and similar programs that use Boehm GC alike - algorithms to produce more accurate results. - - - - resident-modules - All modules loaded by GModule will be made resident. - This can be useful for tracking memory leaks in modules which are - later unloaded; but it can also hide bugs where code is accessed - after the module would have normally been unloaded. - - - - bind-now-modules - All modules loaded by GModule will bind their symbols - at load time, even when the code uses %G_MODULE_BIND_LAZY. - - - - The special value all can be used to turn on all debug options. - The special value help can be used to print all available options. - - - - - <envar>G_SLICE</envar> - - - This environment variable allowed reconfiguration of the GSlice - memory allocator. Since GLib 2.76, GSlice uses the system - malloc() implementation internally, so this variable is - ignored. - - - - - <envar>G_RANDOM_VERSION</envar> - - - If this environment variable is set to '2.0', the outdated - pseudo-random number seeding and generation algorithms from - GLib 2.0 are used instead of the newer, better ones. You should - only set this variable if you have sequences of numbers that were - generated with Glib 2.0 that you need to reproduce exactly. - - - - - <envar>LIBCHARSET_ALIAS_DIR</envar> - - - Allows to specify a nonstandard location for the - charset.aliases file that is used by the - character set conversion routines. The default location is the - libdir specified at compilation time. - - - - - <envar>TZDIR</envar> - - - Allows to specify a nonstandard location for the timezone data files - that are used by the #GDateTime API. The default location is under - /usr/share/zoneinfo. For more information, - also look at the tzset manual page. - - - - - <envar>G_ENABLE_DIAGNOSTIC</envar> - - - If set to a non-zero value, this environment variable enables - diagnostic messages, like deprecation messages for GObject properties - and signals. - - - - - <envar>G_DEBUGGER</envar> - - - When running on Windows, if set to a non-empty string, GLib will - try to interpret the contents of this environment variable as - a command line to a debugger, and run it if the process crashes. - The debugger command line should contain %p and %e substitution - tokens, which GLib will replace with the process ID of the crashing - process and a handle to an event that the debugger should signal - to let GLib know that the debugger successfully attached to the - process. If %e is absent, or if the debugger is not able to - signal events, GLib will resume execution after 60 seconds. - If %p is absent, the debugger won't know which process to attach to, - and GLib will also resume execution after 60 seconds. - - - Additionally, even if G_DEBUGGER is not set, GLib would still - try to print basic exception information (code and address) into - stderr. - - - By default the debugger gets a new console allocated for it. - Set the G_DEBUGGER_OLD_CONSOLE environment variable to any - non-empty string to make the debugger inherit the console of - the crashing process. Normally this is only used by the GLib - testsuite. - - - The exception handler is written with the aim of making it as - simple as possible, to minimize the risk of it invoking - buggy functions or running buggy code, which would result - in exceptions being raised recursively. Because of that - it lacks most of the amenities that one would expect of GLib. - Namely, it does not support Unicode, so it is highly advisable - to only use ASCII characters in G_DEBUGGER. - - - See also G_VEH_CATCH. - - - - - <envar>G_VEH_CATCH</envar> - - - Catching some exceptions can break the program, since Windows - will sometimes use exceptions for execution flow control and - other purposes other than signalling a crash. - - - The G_VEH_CATCH environment variable augments - Vectored Exception Handling - on Windows (see G_DEBUGGER), allowing GLib to catch more - exceptions. Set this variable to a comma-separated list of - hexadecimal exception codes that should additionally be caught. - - - By default GLib will only catch Access Violation, Stack Overflow and - Illegal Instruction exceptions. - - - - - - -Locale - - -A number of interfaces in GLib depend on the current locale in which -an application is running. Therefore, most GLib-using applications should -call setlocale (LC_ALL, "") to set up the current -locale. - - - -On Windows, in a C program there are several locale concepts -that not necessarily are synchronized. On one hand, there is the -system default ANSI code-page, which determines what encoding is used -for file names handled by the C library's functions and the Win32 -API. (We are talking about the "narrow" functions here that take -character pointers, not the "wide" ones.) - - - -On the other hand, there is the C library's current locale. The -character set (code-page) used by that is not necessarily the same as -the system default ANSI code-page. Strings in this character set are -returned by functions like strftime(). - - - - - -GLib ships with a set of Python macros for the GDB debugger. These includes pretty -printers for lists, hashtables and GObject types. It also has a backtrace filter -that makes backtraces with signal emissions easier to read. - - - -To use this you need a version of GDB that supports Python scripting; anything -from 7.0 should be fine. You then need to install GLib in the same prefix as -GDB so that the Python GDB autoloaded files get installed in the right place -for GDB to pick up. - - - -General pretty printing should just happen without having to do anything special. -To get the signal emission filtered backtrace you must use the "new-backtrace" command -instead of the standard one. - - - -There is also a new command called gforeach that can be used to apply a command -on each item in a list. E.g. you can do - -gforeach i in some_list_variable: print *(GtkWidget *)l - -Which would print the contents of each widget in a list of widgets. - - - -SystemTap - - -SystemTap is a dynamic whole-system -analysis toolkit. GLib ships with a file libglib-2.0.so.*.stp which defines a -set of probe points, which you can hook into with custom SystemTap scripts. -See the files libglib-2.0.so.*.stp, libgobject-2.0.so.*.stp -and libgio-2.0.so.*.stp which -are in your shared SystemTap scripts directory. - - - - - -Memory statistics - - -g_mem_profile() will output a summary g_malloc() memory usage, if memory -profiling has been enabled by calling -g_mem_set_vtable (glib_mem_profiler_table) upon startup. - - - -If GLib has been configured with , -then g_slice_debug_tree_statistics() can be called in a debugger to -output details about the memory usage of the slice allocator. - - - - - diff --git a/docs/reference/glib/shell.md b/docs/reference/glib/shell.md new file mode 100644 index 0000000..3be3a2b --- /dev/null +++ b/docs/reference/glib/shell.md @@ -0,0 +1,15 @@ +Title: Shell Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2014 Matthias Clasen + +# Shell Utilities + +GLib provides the functions [func@GLib.shell_quote] and +[func@GLib.shell_unquote] to handle shell-like quoting in strings. The function +[func@GLib.shell_parse_argv] parses a string similar to the way a POSIX shell +(`/bin/sh`) would. + +Note that string handling in shells has many obscure and historical +corner-cases which these functions do not necessarily reproduce. They +are good enough in practice, though. + diff --git a/docs/reference/glib/spawn.md b/docs/reference/glib/spawn.md new file mode 100644 index 0000000..f45c276 --- /dev/null +++ b/docs/reference/glib/spawn.md @@ -0,0 +1,76 @@ +Title: Spawning Processes +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2014 Red Hat, Inc. +SPDX-FileCopyrightText: 2017 Philip Withnall + +# Spawning Processes + +GLib supports spawning of processes with an API that is more +convenient than the bare UNIX [`fork()`](man:fork(2)) and +[`exec()`](man:exec(3)). + +The `g_spawn_…()` family of functions has synchronous ([func@GLib.spawn_sync]) +and asynchronous variants ([func@GLib.spawn_async], +[func@GLib.spawn_async_with_pipes]), as well as convenience variants that take a +complete shell-like command line ([func@GLib.spawn_command_line_sync], +[func@GLib.spawn_command_line_async]). + +See [class@Gio.Subprocess] in GIO for a higher-level API that provides +stream interfaces for communication with child processes. + +An example of using [func@GLib.spawn_async_with_pipes]: +```c +const gchar * const argv[] = { "my-favourite-program", "--args", NULL }; +gint child_stdout, child_stderr; +GPid child_pid; +g_autoptr(GError) error = NULL; + +// Spawn child process. +g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, + NULL, &child_pid, NULL, &child_stdout, + &child_stderr, &error); +if (error != NULL) + { + g_error ("Spawning child failed: %s", error->message); + return; + } + +// Add a child watch function which will be called when the child process +// exits. +g_child_watch_add (child_pid, child_watch_cb, NULL); + +// You could watch for output on @child_stdout and @child_stderr using +// #GUnixInputStream or #GIOChannel here. + +static void +child_watch_cb (GPid pid, + gint status, + gpointer user_data) +{ + g_message ("Child %" G_PID_FORMAT " exited %s", pid, + g_spawn_check_wait_status (status, NULL) ? "normally" : "abnormally"); + + // Free any resources associated with the child here, such as I/O channels + // on its stdout and stderr FDs. If you have no code to put in the + // child_watch_cb() callback, you can remove it and the g_child_watch_add() + // call, but you must also remove the G_SPAWN_DO_NOT_REAP_CHILD flag, + // otherwise the child process will stay around as a zombie until this + // process exits. + + g_spawn_close_pid (pid); +} +``` + +## Spawn Functions + + * [func@GLib.spawn_async_with_fds] + * [func@GLib.spawn_async_with_pipes] + * [func@GLib.spawn_async_with_pipes_and_fds] + * [func@GLib.spawn_async] + * [func@GLib.spawn_sync] + * [func@GLib.spawn_check_wait_status] + * [func@GLib.spawn_check_exit_status] + * [func@GLib.spawn_command_line_async] + * [func@GLib.spawn_command_line_sync] + * [func@GLib.spawn_close_pid] + diff --git a/docs/reference/glib/string-utils.md b/docs/reference/glib/string-utils.md new file mode 100644 index 0000000..977af4b --- /dev/null +++ b/docs/reference/glib/string-utils.md @@ -0,0 +1,187 @@ +Title: String Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 1999 Owen Taylor +SPDX-FileCopyrightText: 2000 Red Hat, Inc. +SPDX-FileCopyrightText: 2002, 2003, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2015 Collabora, Ltd. + +# String Utilities + +This section describes a number of utility functions for creating, +duplicating, and manipulating strings. + +Note that the functions [func@GLib.printf], [func@GLib.fprintf], +[func@GLib.sprintf], [func@GLib.vprintf], [func@GLib.vfprintf], +[func@GLib.vsprintf] and [func@GLib.vasprintf] are declared in the header +`gprintf.h` which is not included in `glib.h` +(otherwise using `glib.h` would drag in `stdio.h`), so you'll have to +explicitly include `` in order to use the GLib +`printf()` functions. + +## String precision pitfalls # {#string-precision} + +While you may use the `printf()` functions to format UTF-8 strings, +notice that the precision of a `%Ns` parameter is interpreted +as the number of bytes, not characters to print. On top of that, +the GNU libc implementation of the `printf()` functions has the +‘feature’ that it checks that the string given for the `%Ns` +parameter consists of a whole number of characters in the current +encoding. So, unless you are sure you are always going to be in an +UTF-8 locale or your know your text is restricted to ASCII, avoid +using `%Ns`. If your intention is to format strings for a +certain number of columns, then `%Ns` is not a correct solution +anyway, since it fails to take wide characters (see [func@GLib.unichar_iswide]) +into account. + +Note also that there are various `printf()` parameters which are platform +dependent. GLib provides platform independent macros for these parameters +which should be used instead. A common example is [const@GLib.GUINT64_FORMAT], +which should be used instead of `%llu` or similar parameters for formatting +64-bit integers. These macros are all named `G_*_FORMAT`; see +[Basic Types](types.html). + +## General String Manipulation + + * [func@GLib.strdup] + * [func@GLib.strndup] + * [func@GLib.strdupv] + * [func@GLib.strnfill] + * [func@GLib.stpcpy] + * [func@GLib.strstr_len] + * [func@GLib.strrstr] + * [func@GLib.strrstr_len] + * [func@GLib.str_has_prefix] + * [func@GLib.str_has_suffix] + * [func@GLib.strcmp0] + * [func@GLib.str_to_ascii] + * [func@GLib.str_tokenize_and_fold] + * [func@GLib.str_match_string] + +For users of GLib in C, the `g_set_str()` inline function also exists to set a +string and handle copying the new value and freeing the old one. + +## String Copying + + * [func@GLib.strlcpy] + * [func@GLib.strlcat] + +## Printing + + * [func@GLib.strdup_printf] + * [func@GLib.strdup_vprintf] + * [func@GLib.printf] + * [func@GLib.vprintf] + * [func@GLib.fprintf] + * [func@GLib.vfprintf] + * [func@GLib.sprintf] + * [func@GLib.vsprintf] + * [func@GLib.snprintf] + * [func@GLib.vsnprintf] + * [func@GLib.vasprintf] + * [func@GLib.printf_string_upper_bound] + +## ASCII + + * [func@GLib.str_is_ascii] + * [func@GLib.ascii_isalnum] + * [func@GLib.ascii_isalpha] + * [func@GLib.ascii_iscntrl] + * [func@GLib.ascii_isdigit] + * [func@GLib.ascii_isgraph] + * [func@GLib.ascii_islower] + * [func@GLib.ascii_isprint] + * [func@GLib.ascii_ispunct] + * [func@GLib.ascii_isspace] + * [func@GLib.ascii_isupper] + * [func@GLib.ascii_isxdigit] + +## ASCII Parsing + + * [func@GLib.ascii_digit_value] + * [func@GLib.ascii_xdigit_value] + +## ASCII Comparisons + + * [func@GLib.ascii_strcasecmp] + * [func@GLib.ascii_strncasecmp] + +## ASCII Case Manipulation + + * [func@GLib.ascii_strup] + * [func@GLib.ascii_strdown] + * [func@GLib.ascii_tolower] + * [func@GLib.ascii_toupper + +## ASCII String Manipulation + + * [func@GLib.strreverse] + +## ASCII Number Manipulation + + * [func@GLib.ascii_strtoll] + * [func@GLib.ascii_strtoull] + * [const@GLib.ASCII_DTOSTR_BUF_SIZE] + * [func@GLib.ascii_strtod] + * [func@GLib.ascii_dtostr] + * [func@GLib.ascii_formatd] + * [func@GLib.strtod] + +## ASCII Number Parsing + + * [type@GLib.NumberParserError] + * [func@GLib.ascii_string_to_signed] + * [func@GLib.ascii_string_to_unsigned] + +## Whitespace Removal + + * [func@GLib.strchug] + * [func@GLib.strchomp] + * [func@GLib.strstrip] + +## Find and Replace + + * [func@GLib.strdelimit] + * [const@GLib.STR_DELIMITERS] + * [func@GLib.strescape] + * [func@GLib.strcompress] + * [func@GLib.strcanon] + +## Splitting and Joining + + * [func@GLib.strsplit] + * [func@GLib.strsplit_set] + * [func@GLib.strconcat] + * [func@GLib.strjoin] + * [func@GLib.strjoinv] + +## String Arrays + + * [type@GLib.Strv] + * [func@GLib.strfreev] + * [func@GLib.strv_length] + * [func@GLib.strv_contains] + * [func@GLib.strv_equal] + +## String Array Builder + + * [type@GLib.StrvBuilder] + * [ctor@GLib.StrvBuilder.new] + * [method@GLib.StrvBuilder.ref] + * [method@GLib.StrvBuilder.unref] + * [method@GLib.StrvBuilder.add] + * [method@GLib.StrvBuilder.addv] + * [method@GLib.StrvBuilder.add_many] + * [method@GLib.StrvBuilder.take] + * [method@GLib.StrvBuilder.end] + +## POSIX Errors + + * [func@GLib.strerror] + * [func@GLib.strsignal] + +## Deprecated API + + * [func@GLib.strup] + * [func@GLib.strdown] + * [func@GLib.strcasecmp] + * [func@GLib.strncasecmp] diff --git a/docs/reference/glib/testing.md b/docs/reference/glib/testing.md new file mode 100644 index 0000000..a0f1d12 --- /dev/null +++ b/docs/reference/glib/testing.md @@ -0,0 +1,183 @@ +Title: Testing Framework + +# Testing Framework + +GLib provides a framework for writing and maintaining unit tests in parallel +to the code they are testing. The API is designed according to established +concepts found in the other test frameworks (JUnit, NUnit, RUnit), which in +turn is based on smalltalk unit testing concepts. + +- Test case: Tests (test methods) are grouped together with their fixture + into test cases. +- Fixture: A test fixture consists of fixture data and setup and teardown + methods to establish the environment for the test functions. We use fresh + fixtures, i.e. fixtures are newly set up and torn down around each test + invocation to avoid dependencies between tests. +- Test suite: Test cases can be grouped into test suites, to allow subsets + of the available tests to be run. Test suites can be grouped into other + test suites as well. + +The API is designed to handle creation and registration of test suites and +test cases implicitly. A simple call like: + +```c +g_test_add_func ("/misc/assertions", test_assertions); +``` + +creates a test suite called "misc" with a single test case named +"assertions", which consists of running the `test_assertions` function. + +In addition to the traditional `g_assert_true()`, the test framework +provides an extended set of assertions for comparisons: +`g_assert_cmpfloat()`, `g_assert_cmpfloat_with_epsilon()`, +`g_assert_cmpint()`, `g_assert_cmpuint()`, `g_assert_cmphex()`, +`g_assert_cmpstr()`, `g_assert_cmpmem()` and `g_assert_cmpvariant()`. The +advantage of these variants over plain `g_assert_true()` is that the +assertion messages can be more elaborate, and include the values of the +compared entities. + +Note that `g_assert()` should **not** be used in unit tests, since it is a +no-op when compiling with `G_DISABLE_ASSERT`. Use `g_assert()` in production +code, and `g_assert_true()` in unit tests. + +A full example of creating a test suite with two tests using fixtures: + +```c +#include +#include + +typedef struct { + MyObject *obj; + OtherObject *helper; +} MyObjectFixture; + +static void +my_object_fixture_set_up (MyObjectFixture *fixture, + gconstpointer user_data) +{ + fixture->obj = my_object_new (); + my_object_set_prop1 (fixture->obj, "some-value"); + my_object_do_some_complex_setup (fixture->obj, user_data); + + fixture->helper = other_object_new (); +} + +static void +my_object_fixture_tear_down (MyObjectFixture *fixture, + gconstpointer user_data) +{ + g_clear_object (&fixture->helper); + g_clear_object (&fixture->obj); +} + +static void +test_my_object_test1 (MyObjectFixture *fixture, + gconstpointer user_data) +{ + g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "initial-value"); +} + +static void +test_my_object_test2 (MyObjectFixture *fixture, + gconstpointer user_data) +{ + my_object_do_some_work_using_helper (fixture->obj, fixture->helper); + g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "updated-value"); +} + +int +main (int argc, char *argv[]) +{ + setlocale (LC_ALL, ""); + + g_test_init (&argc, &argv, NULL); + + // Define the tests. + g_test_add ("/my-object/test1", MyObjectFixture, "some-user-data", + my_object_fixture_set_up, test_my_object_test1, + my_object_fixture_tear_down); + g_test_add ("/my-object/test2", MyObjectFixture, "some-user-data", + my_object_fixture_set_up, test_my_object_test2, + my_object_fixture_tear_down); + + return g_test_run (); +} +``` + +### Integrating GTest in your project + +#### Using Meson + +If you are using the Meson build system, you will typically use the provided +`test()` primitive to call the test binaries, e.g.: + +``` +test( + 'foo', + executable('foo', 'foo.c', dependencies: deps), + env: [ + 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), + ], + protocol: 'tap', +) + +test( + 'bar', + executable('bar', 'bar.c', dependencies: deps), + env: [ + 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), + 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), + ], + protocol: 'tap', +) +``` + +#### Using Autotools + +If you are using Autotools, you're strongly encouraged to use the Automake +TAP harness; GLib provides template files for easily integrating with it: + +- [`glib-tap.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk) +- [`tap-test`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test) +- [`tap-driver.sh`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh) + +You can copy these files in your own project's root directory, and then set +up your `Makefile.am` file to reference them, for instance: + +``` +include $(top_srcdir)/glib-tap.mk + +# test binaries +test_programs = \ + foo \ + bar + +# data distributed in the tarball +dist_test_data = \ + foo.data.txt \ + bar.data.txt + +# data not distributed in the tarball +test_data = \ + blah.data.txt +``` + +Make sure to distribute the TAP files, using something like the following in +your top-level `Makefile.am`: + +``` +EXTRA_DIST += \ + tap-driver.sh \ + tap-test +``` + +`glib-tap.mk` will be distributed implicitly due to being included in a +`Makefile.am`. All three files should be added to version control. + +If you don't have access to the Autotools TAP harness, you can use the +gtester and gtester-report tools, and use the +[`glib.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk) +Automake template provided by GLib. Note, however, that since GLib 2.62, +gtester and gtester-report have been deprecated in favour of using TAP. The +`--tap` argument to tests is enabled by default as of GLib 2.62. diff --git a/docs/reference/glib/threads-deprecated.md b/docs/reference/glib/threads-deprecated.md new file mode 100644 index 0000000..4198a63 --- /dev/null +++ b/docs/reference/glib/threads-deprecated.md @@ -0,0 +1,37 @@ +Title: Deprecated Thread API +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2011 Allison Lortie + +# Deprecated Thread API + +These APIs are deprecated. You should not use them in new code. +This section remains only to assist with understanding code that was +written to use these APIs at some point in the past. + +Deprecated thread creation/configuration functions: + + * [type@GLib.ThreadPriority] + * [type@GLib.ThreadFunctions] + * [func@GLib.Thread.init] + * [func@GLib.Thread.get_initialized] + * [method@GLib.Thread.set_priority] + * [func@GLib.Thread.foreach] + * [func@GLib.Thread.create] + * [func@GLib.Thread.create_full] + +Deprecated static variants of locking primitives: + + * [type@GLib.StaticMutex] + * [type@GLib.StaticRecMutex] + * [type@GLib.StaticRWLock] + * [type@GLib.StaticPrivate] + +Deprecated dynamic allocation of locking primitives: + + * [func@GLib.Private.new] + * [func@GLib.Mutex.new] + * [method@GLib.Mutex.free] + * [func@GLib.Cond.new] + * [method@GLib.Cond.free] + * [method@GLib.Cond.timed_wait] + diff --git a/docs/reference/glib/threads.md b/docs/reference/glib/threads.md new file mode 100644 index 0000000..d01689b --- /dev/null +++ b/docs/reference/glib/threads.md @@ -0,0 +1,91 @@ +Title: Threads +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2010 Allison Lortie +SPDX-FileCopyrightText: 2011, 2012, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2014 Collabora, Ltd. + +# Threads + +Threads act almost like processes, but unlike processes all threads of one +process share the same memory. This is good, as it provides easy +communication between the involved threads via this shared memory, and it is +bad, because strange things (so called "Heisenbugs") might happen if the +program is not carefully designed. In particular, due to the concurrent +nature of threads, no assumptions on the order of execution of code running +in different threads can be made, unless order is explicitly forced by the +programmer through synchronization primitives. + +The aim of the thread-related functions in GLib is to provide a portable +means for writing multi-threaded software. There are primitives for mutexes +to protect the access to portions of memory (`GMutex`, `GRecMutex` and +`GRWLock`). There is a facility to use individual bits for locks +(`g_bit_lock()`). There are primitives for condition variables to allow +synchronization of threads (`GCond`). There are primitives for +thread-private data - data that every thread has a private instance of +(`GPrivate`). There are facilities for one-time initialization (`GOnce`, +`g_once_init_enter_pointer()`, `g_once_init_enter()`). Finally, there are +primitives to create and manage threads (`GThread`). + +The GLib threading system used to be initialized with `g_thread_init()`. +This is no longer necessary. Since version 2.32, the GLib threading system +is automatically initialized at the start of your program, and all +thread-creation functions and synchronization primitives are available right +away. + +Note that it is not safe to assume that your program has no threads even if +you don't call `g_thread_new()` yourself. GLib and GIO can and will create +threads for their own purposes in some cases, such as when using +`g_unix_signal_source_new()` or when using GDBus. + +Originally, UNIX did not have threads, and therefore some traditional UNIX +APIs are problematic in threaded programs. Some notable examples are + +- C library functions that return data in statically allocated buffers, such + as `strtok()` or `strerror()`. For many of these, there are thread-safe + variants with a `_r` suffix, or you can look at corresponding GLib APIs + (`like g_strsplit()` or `g_strerror()`). +- The functions `setenv()` and `unsetenv()` manipulate the process + environment in a not thread-safe way, and may interfere with `getenv()` + calls in other threads. Note that `getenv()` calls may be hidden behind + other APIs. For example, GNU `gettext()` calls `getenv()` under the + covers. In general, it is best to treat the environment as readonly. If + you absolutely have to modify the environment, do it early in `main()`, + when no other threads are around yet. +- The `setlocale()` function changes the locale for the entire process, + affecting all threads. Temporary changes to the locale are often made to + change the behavior of string scanning or formatting functions like + `scanf()` or `printf()`. GLib offers a number of string APIs (like + `g_ascii_formatd()` or `g_ascii_strtod()`) that can often be used as an + alternative. Or you can use the `uselocale()` function to change the + locale only for the current thread. +- The `fork()` function only takes the calling thread into the child's copy + of the process image. If other threads were executing in critical sections + they could have left mutexes locked which could easily cause deadlocks in + the new child. For this reason, you should call `exit()` or `exec()` as + soon as possible in the child and only make signal-safe library calls + before that. +- The `daemon()` function uses `fork()` in a way contrary to what is + described above. It should not be used with GLib programs. + +GLib itself is internally completely thread-safe (all global data is +automatically locked), but individual data structure instances are not +automatically locked for performance reasons. For example, you must +coordinate accesses to the same `GHashTable` from multiple threads. The two +notable exceptions from this rule are `GMainLoop` and `GAsyncQueue`, which are +thread-safe and need no further application-level locking to be accessed +from multiple threads. Most refcounting functions such as `g_object_ref()` are +also thread-safe. + +A common use for GThreads is to move a long-running blocking operation out +of the main thread and into a worker thread. For GLib functions, such as +single GIO operations, this is not necessary, and complicates the code. +Instead, the `…_async()` version of the function should be used from the main +thread, eliminating the need for locking and synchronisation between +multiple threads. If an operation does need to be moved to a worker thread, +consider using `g_task_run_in_thread()`, or a `GThreadPool`. `GThreadPool` is +often a better choice than `GThread`, as it handles thread reuse and task +queueing; `GTask` uses this internally. + +However, if multiple blocking operations need to be performed in sequence, +and it is not possible to use `GTask` for them, moving them to a worker thread +can clarify the code. diff --git a/docs/reference/glib/types.md b/docs/reference/glib/types.md new file mode 100644 index 0000000..aab0bd0 --- /dev/null +++ b/docs/reference/glib/types.md @@ -0,0 +1,882 @@ +Title: Basic Types +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 1999 Owen Taylor +SPDX-FileCopyrightText: 2000 Red Hat, Inc. +SPDX-FileCopyrightText: 2000 Sebastian Wilhelmi +SPDX-FileCopyrightText: 2008 Matthias Clasen +SPDX-FileCopyrightText: 2008, 2010 Behdad Esfahbod +SPDX-FileCopyrightText: 2009 Christian Persch +SPDX-FileCopyrightText: 2014, 2022 Collabora, Ltd. +SPDX-FileCopyrightText: 2017, 2018 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2018 Christoph Reiter +SPDX-FileCopyrightText: 2019 Alistair Thomas + +# Basic Types + +GLib defines a number of commonly used types, which can be divided +into several groups: + + - New types which are not part of standard C (but are defined in + various C standard library header files) — [`gboolean`](#gboolean), + [`gssize`](#gssize). + - Integer types which are guaranteed to be the same size across + all platforms — [`gint8`](#gint8), [`guint8`](#guint8), [`gint16`](#gint16), + [`guint16`](#guint16), [`gint32`](#gint32), [`guint32`](#guint32), + [`gint64`](#gint64), [`guint64`](#guint64). + - Types which are easier to use than their standard C counterparts — + [`gpointer`](#gpointer), [`gconstpointer`](#gconstpointer), + [`guchar`](#guchar), [`guint`](#guint), [`gushort`](#gushort), + [`gulong`](#gulong). + - Types which correspond exactly to standard C types, but are + included for completeness — [`gchar`](#gchar), [`gint`](#gint), + [`gshort`](#gshort), [`glong`](#glong), [`gfloat`](#gfloat), + [`gdouble`](#gdouble). + - Types which correspond exactly to standard C99 types, but are available + to use even if your compiler does not support C99 — [`gsize`](#gsize), + [`goffset`](#goffset), [`gintptr`](#gintptr), [`guintptr`](#guintptr). + +GLib also defines macros for the limits of some of the standard +integer and floating point types, as well as macros for suitable +[`printf()`](man:printf(3)) formats for these types. + +Note that depending on the platform and build configuration, the format +macros might not be compatible with the system provided +[`printf()`](man:printf(3)) function, because GLib might use a different +`printf()` implementation internally. The format macros will always work with +GLib API (like [func@GLib.print]), and with any C99 compatible `printf()` +implementation. + +## Basic Types + +### `gboolean` + +A standard boolean type. Variables of this type should only contain the value +`TRUE` or `FALSE`. + +Never directly compare the contents of a `gboolean` variable with the values +`TRUE` or `FALSE`. Use `if (condition)` to check a `gboolean` is ‘true’, instead +of `if (condition == TRUE)`. Likewise use `if (!condition)` to check a +`gboolean` is ‘false’. + +There is no validation when assigning to a `gboolean` variable and so it could +contain any value represented by a `gint`. This is why the use of `if +(condition)` is recommended. All non-zero values in C evaluate to ‘true’. + +### `gpointer` + +An untyped pointer, exactly equivalent to `void *`. + +The standard C `void *` type should usually be preferred in +new code, but `gpointer` can be used in contexts where a type name +must be a single word, such as in the [method@GObject.Type.name] of +[const@GObject.TYPE_POINTER] or when generating a family of function names for +multiple types using macros. + +### `gconstpointer` + +An untyped pointer to constant data, exactly equivalent to `const void *`. + +The data pointed to should not be changed. + +This is typically used in function prototypes to indicate +that the data pointed to will not be altered by the function. + +The standard C `const void *` type should usually be preferred in +new code, but `gconstpointer` can be used in contexts where a type name +must be a single word. + +### `gchar` + +Equivalent to the standard C `char` type. + +This type only exists for symmetry with `guchar`. +The standard C `char` type should be preferred in new code. + +### `guchar` + +Equivalent to the standard C `unsigned char` type. + +The standard C `unsigned char` type should usually be preferred in +new code, but `guchar` can be used in contexts where a type name +must be a single word, such as in the [method@GObject.Type.name] of +[const@GObject.TYPE_UCHAR] or when generating a family of function names for +multiple types using macros. + +## Naturally Sized Integers + +### `gint` + +Equivalent to the standard C `int` type. + +Values of this type can range from `INT_MIN` to `INT_MAX`, +or equivalently from `G_MININT` to `G_MAXINT`. + +This type only exists for symmetry with [`guint`](#guint). +The standard C `int` type should be preferred in new code. + +`G_MININT` +: The minimum value which can be held in a `gint`. + + This is the same as standard C `INT_MIN`, which is available since C99 + and should be preferred in new code. + +`G_MAXINT` +: The maximum value which can be held in a `gint`. + + This is the same as standard C `INT_MAX`, which is available since C99 + and should be preferred in new code. + +### `guint` + +Equivalent to the standard C `unsigned int` type. + +Values of this type can range from `0` to `UINT_MAX`, +or equivalently `0` to `G_MAXUINT`. + +The standard C `unsigned int` type should usually be preferred in +new code, but `guint` can be used in contexts where a type name +must be a single word, such as in the [method@GObject.Type.name] of +[const@GObject.TYPE_UINT] or when generating a family of function names for +multiple types using macros. + +`G_MAXUINT` +: The maximum value which can be held in a `guint`. + + This is the same as standard C `UINT_MAX`, which is available since C99 + and should be preferred in new code. + +### `gshort` + +Equivalent to the standard C `short` type. + +Values of this type can range from `SHRT_MIN` to `SHRT_MAX`, +or equivalently `G_MINSHORT` to `G_MAXSHORT`. + +This type only exists for symmetry with `gushort`. +The standard C `short` type should be preferred in new code. + +`G_MINSHORT` +: The minimum value which can be held in a `gshort`. + + This is the same as standard C `SHRT_MIN`, which is available since C99 + and should be preferred in new code. + +`G_MAXSHORT` +: The maximum value which can be held in a `gshort`. + + This is the same as standard C `SHRT_MAX`, which is available since C99 + and should be preferred in new code. + +### `gushort` + +Equivalent to the standard C `unsigned short` type. + +Values of this type can range from `0` to `USHRT_MAX`, +or equivalently from `0` to `G_MAXUSHORT`. + +The standard C `unsigned short` type should usually be preferred in +new code, but `gushort` can be used in contexts where a type name +must be a single word, such as when generating a family of function +names for multiple types using macros. + + +`G_MAXUSHORT` +: The maximum value which can be held in a `gushort`. + + This is the same as standard C `USHRT_MAX`, which is available since C99 + and should be preferred in new code. + +### `glong` + +Equivalent to the standard C `long` type. + +Values of this type can range from `LONG_MIN` to `LONG_MAX`, +or equivalently `G_MINLONG` to `G_MAXLONG`. + +This type only exists for symmetry with `gulong`. +The standard C `long` type should be preferred in new code. + +`G_MINLONG` +: The minimum value which can be held in a `glong`. + + This is the same as standard C `LONG_MIN`, which is available since C99 + and should be preferred in new code. + +`G_MAXLONG` +: The maximum value which can be held in a `glong`. + + This is the same as standard C `ULONG_MAX`, which is available since C99 + and should be preferred in new code. + +### `gulong` + +Equivalent to the standard C `unsigned long` type. + +Values of this type can range from `0` to `G_MAXULONG`. + +The standard C `unsigned long` type should usually be preferred in +new code, but `gulong` can be used in contexts where a type name +must be a single word, such as in the [method@GObject.Type.name] of +[const@GObject.TYPE_ULONG] or when generating a family of function names for +multiple types using macros. + +`G_MAXULONG` +: The maximum value which can be held in a `gulong`. + + This is the same as standard C `ULONG_MAX`, which is available since C99 + and should be preferred in new code. + +## Fixed Width Integers + +### `gint8` + +A signed integer guaranteed to be 8 bits on all platforms, +similar to the standard C `int8_t`. + +The `int8_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `gint8` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `G_MININT8` (= -128) to +`G_MAXINT8` (= 127). + +`G_MININT8` +: The minimum value which can be held in a `gint8`. + + Since: 2.4 + +`G_MAXINT8` +: The maximum value which can be held in a `gint8`. + + This is the same as standard C `INT8_MAX`, which should be + preferred in new code. + + Since: 2.4 + +### `guint8` + +An unsigned integer guaranteed to be 8 bits on all platforms, +similar to the standard C `uint8_t`. + +The `uint8_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `guint8` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `0` to `G_MAXUINT8` (= 255). + +`G_MAXUINT8` +: The maximum value which can be held in a `guint8`. + + This is the same as standard C `UINT8_MAX`, which should be + preferred in new code. + + Since: 2.4 + +### `gint16` + +A signed integer guaranteed to be 16 bits on all platforms, +similar to the standard C `int16_t`. + +The `int16_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `gint16` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `G_MININT16` (= -32,768) to +`G_MAXINT16` (= 32,767). + +To print or scan values of this type, use +`G_GINT16_MODIFIER` and/or `G_GINT16_FORMAT`. + +`G_MININT16` +: The minimum value which can be held in a `gint16`. + + Since: 2.4 + +`G_MAXINT16` +: The maximum value which can be held in a `gint16`. + + This is the same as standard C `INT16_MAX`, which should be + preferred in new code. + + Since: 2.4 + +`G_GINT16_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gint16` or `guint16`. It + is a string literal, but doesn’t include the percent-sign, such + that you can add precision and length modifiers between percent-sign + and conversion specifier and append a conversion specifier. + + The following example prints `0x7b`; + ```c + gint16 value = 123; + g_print ("%#" G_GINT16_MODIFIER "x", value); + ``` + + This is not necessarily the correct modifier for printing and scanning + `int16_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId16` and `SCNd16` should be used for `int16_t`. + + Since: 2.4 + +`G_GINT16_FORMAT` +: This is the platform dependent conversion specifier for scanning and + printing values of type `gint16`. It is a string literal, but doesn’t + include the percent-sign, such that you can add precision and length + modifiers between percent-sign and conversion specifier. + + ```c + gint16 in; + gint32 out; + sscanf ("42", "%" G_GINT16_FORMAT, &in) + out = in * 1000; + g_print ("%" G_GINT32_FORMAT, out); + ``` + + This is not necessarily the correct format for printing and scanning + `int16_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId16` and `SCNd16` should be used for `int16_t`. + +### `guint16` + +An unsigned integer guaranteed to be 16 bits on all platforms, +similar to the standard C `uint16_t`. + +The `uint16_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `guint16` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `0` to `G_MAXUINT16` (= 65,535). + +To print or scan values of this type, use +`G_GINT16_MODIFIER` and/or `G_GUINT16_FORMAT`. + +`G_MAXUINT16` +: The maximum value which can be held in a `guint16`. + + This is the same as standard C `UINT16_MAX`, which should be + preferred in new code. + + Since: 2.4 + +`G_GUINT16_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `guint16`. See also `G_GINT16_FORMAT` + + This is not necessarily the correct modifier for printing and scanning + `uint16_t` values, even though the in-memory representation is the same. + Standard C macros like `PRIu16` and `SCNu16` should be used for `uint16_t`. + +### `gint32` + +A signed integer guaranteed to be 32 bits on all platforms. + +The `int32_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `gint16` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `G_MININT32` (= -2,147,483,648) +to `G_MAXINT32` (= 2,147,483,647). + +To print or scan values of this type, use +`G_GINT32_MODIFIER` and/or `G_GINT32_FORMAT`. + +Note that on platforms with more than one 32-bit standard integer type, +`gint32` and `int32_t` are not necessarily implemented by the same +32-bit integer type. +For example, on an ILP32 platform where `int` and `long` are both 32-bit, +it might be the case that one of these types is `int` and the other +is `long`. +See [`gsize`](#gsize) for more details of what this implies. + +`G_MININT32` +: The minimum value which can be held in a `gint32`. + + Since: 2.4 + +`G_MAXINT32` +: The maximum value which can be held in a `gint32`. + + This is the same as standard C `INT32_MAX`, which should be + preferred in new code. + + Since: 2.4 + +`G_GINT32_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gint32` or `guint32`. It + is a string literal. See also `G_GINT16_MODIFIER`. + + This is not necessarily the correct modifier for printing and scanning + `int32_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId32` and `SCNd32` should be used for `int32_t`. + + Since: 2.4 + +`G_GINT32_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `gint32`. See also `G_GINT16_FORMAT`. + + This is not necessarily the correct modifier for printing and scanning + `int32_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId32` and `SCNd32` should be used for `int32_t`. + +### `guint32` + +An unsigned integer guaranteed to be 32 bits on all platforms, +similar to the standard C `uint32_t`. + +The `uint32_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `guint32` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `0` to `G_MAXUINT32` (= 4,294,967,295). + +To print or scan values of this type, use +`G_GINT32_MODIFIER` and/or `G_GUINT32_FORMAT`. + +Note that on platforms with more than one 32-bit standard integer type, +`guint32` and `uint32_t` are not necessarily implemented by the same +32-bit integer type. +See [`gsize`](#gsize) for more details of what this implies. + +`G_MAXUINT32` +: The maximum value which can be held in a `guint32`. + + This is the same as standard C `UINT32_MAX`, which should be + preferred in new code. + + Since: 2.4 + +`G_GUINT32_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `guint32`. See also `G_GINT16_FORMAT`. + + This is not necessarily the correct modifier for printing and scanning + `uint32_t` values, even though the in-memory representation is the same. + Standard C macros like `PRIu32` and `SCNu32` should be used for `uint32_t`. + +### `gint64` + +A signed integer guaranteed to be 64 bits on all platforms, +similar to the standard C `int64_t`. + +The `int64_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `gint64` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `G_MININT64` +(= -9,223,372,036,854,775,808) to `G_MAXINT64` +(= 9,223,372,036,854,775,807). + +To print or scan values of this type, use +`G_GINT64_MODIFIER` and/or `G_GINT64_FORMAT`. + +Note that on platforms with more than one 64-bit standard integer type, +`gint64` and `int64_t` are not necessarily implemented by the same +64-bit integer type. +For example, on a platform where both `long` and `long long` are 64-bit, +it might be the case that one of those types is used for `gint64` +and the other is used for `int64_t`. +See [`gsize`](#gsize) for more details of what this implies. + +`G_MININT64` +: The minimum value which can be held in a `gint64`. + +`G_MAXINT64` +: The maximum value which can be held in a `gint64`. + +`G_GINT64_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gint64` or `guint64`. + It is a string literal. + + Some platforms do not support printing 64-bit integers, even + though the types are supported. On such platforms `G_GINT64_MODIFIER` + is not defined. + + This is not necessarily the correct modifier for printing and scanning + `int64_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId64` and `SCNd64` should be used for `int64_t`. + + Since: 2.4 + +`G_GINT64_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `gint64`. See also `G_GINT16_FORMAT`. + + Some platforms do not support scanning and printing 64-bit integers, + even though the types are supported. On such platforms `G_GINT64_FORMAT` + is not defined. Note that [`scanf()`](man:scanf(3)) may not support 64-bit + integers, even if `G_GINT64_FORMAT` is defined. Due to its weak error + handling, `scanf()` is not recommended for parsing anyway; consider using + [func@GLib.ascii_strtoull] instead. + + This is not necessarily the correct format for printing and scanning + `int64_t` values, even though the in-memory representation is the same. + Standard C macros like `PRId64` and `SCNd64` should be used for `int64_t`. + +`G_GINT64_CONSTANT(val)` +: This macro is used to insert 64-bit integer literals + into the source code. + + It is similar to the standard C `INT64_C` macro, + which should be preferred in new code. + +### `guint64` + +An unsigned integer guaranteed to be 64-bits on all platforms, +similar to the standard C `uint64_t` type. + +The `uint64_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires use of `guint64` +(see [`gsize`](#gsize) for more details). + +Values of this type can range from `0` to `G_MAXUINT64` +(= 18,446,744,073,709,551,615). + +To print or scan values of this type, use +`G_GINT64_MODIFIER` and/or `G_GUINT64_FORMAT`. + +Note that on platforms with more than one 64-bit standard integer type, +`guint64` and `uint64_t` are not necessarily implemented by the same +64-bit integer type. +See [`gsize`](#gsize) for more details of what this implies. + +`G_MAXUINT64` +: The maximum value which can be held in a `guint64`. + + This is the same as standard C `UINT64_MAX`, which should be + preferred in new code. + +`G_GUINT64_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `guint64`. See also `G_GINT16_FORMAT`. + + Some platforms do not support scanning and printing 64-bit integers, + even though the types are supported. On such platforms `G_GUINT64_FORMAT` + is not defined. Note that [`scanf()`](man:scanf(3)) may not support 64-bit + integers, even if `G_GINT64_FORMAT` is defined. Due to its weak error + handling, `scanf()` is not recommended for parsing anyway; consider using + [func@GLib.ascii_strtoull] instead. + + This is not necessarily the correct modifier for printing and scanning + `uint64_t` values, even though the in-memory representation is the same. + Standard C macros like `PRIu64` and `SCNu64` should be used for `uint64_t`. + +`G_GUINT64_CONSTANT(val)` +: This macro is used to insert 64-bit unsigned integer + literals into the source code. + + It is similar to the standard C `UINT64_C` macro, + which should be preferred in new code. + + Since: 2.10 + +## Floating Point + +### `gfloat` + +Equivalent to the standard C `float` type. + +Values of this type can range from `-FLT_MAX` to `FLT_MAX`, +or equivalently from `-G_MAXFLOAT` to `G_MAXFLOAT`. + +`G_MINFLOAT` +: The minimum positive value which can be held in a `gfloat`. + + If you are interested in the smallest value which can be held + in a `gfloat`, use `-G_MAXFLOAT`. + + This is the same as standard C `FLT_MIN`, which is available since C99 + and should be preferred in new code. + +`G_MAXFLOAT` +: The maximum value which can be held in a `gfloat`. + + This is the same as standard C `FLT_MAX`, which is available since C99 + and should be preferred in new code. + +### `gdouble` + +Equivalent to the standard C `double` type. + +Values of this type can range from `-DBL_MAX` to `DBL_MAX`, +or equivalently from `-G_MAXDOUBLE` to `G_MAXDOUBLE`. + +`G_MINDOUBLE` +: The minimum positive value which can be held in a `gdouble`. + + If you are interested in the smallest value which can be held + in a `gdouble`, use `-G_MAXDOUBLE`. + + This is the same as standard C `DBL_MIN`, which is available since C99 + and should be preferred in new code. + +`G_MAXDOUBLE` +: The maximum value which can be held in a `gdouble`. + + This is the same as standard C `DBL_MAX`, which is available since C99 + and should be preferred in new code. + +## Architecture Sized Integers + +### `gsize` + +An unsigned integer type of the result of the `sizeof` operator, +corresponding to the `size_t` type defined in C99. + +The standard `size_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires `gsize` +(see below for more details). + +`gsize` is usually 32 bit wide on a 32-bit platform and 64 bit wide +on a 64-bit platform. Values of this type can range from `0` to +`G_MAXSIZE`. + +This type is wide enough to hold the size of the largest possible +memory allocation, but is not guaranteed to be wide enough to hold +the numeric value of a pointer: on platforms that use tagged pointers, +such as [CHERI](https://cheri-cpu.org/), pointers can be numerically +larger than the size of the address space. +If the numeric value of a pointer needs to be stored in an integer +without information loss, use the standard C types `intptr_t` or +`uintptr_t`, or the similar GLib types [`gintptr`](#gintptr) or +[`guintptr`](#guintptr). + +To print or scan values of this type, use +`G_GSIZE_MODIFIER` and/or `G_GSIZE_FORMAT`. + +Note that on platforms where more than one standard integer type is +the same size, `size_t` and `gsize` are always the same size but are +not necessarily implemented by the same standard integer type. +For example, on an ILP32 platform where `int`, `long` and pointers +are all 32-bit, `size_t` might be `unsigned long` while `gsize` +might be `unsigned int`. +This can result in compiler warnings or unexpected C++ name-mangling +if the two types are used inconsistently. + +As a result, changing a type from `gsize` to `size_t` in existing APIs +might be an incompatible API or ABI change, especially if C++ +is involved. The safe option is to leave existing APIs using the same type +that they have historically used, and only use the standard C types in +new APIs. + +Similar considerations apply to all the fixed-size types +([`gint8`](#gint8), [`guint8`](#guint8), [`gint16`](#gint16), +[`guint16`](#guint16), [`gint32`](#gint32), [`guint32`](#guint32), +[`gint64`](#gint64), [`guint64`](#guint64) and [`goffset`](#goffset)), as well +as [`gintptr`](#gintptr) and [`guintptr`](#guintptr). +Types that are 32 bits or larger are particularly likely to be +affected by this. + +`G_MAXSIZE` +: The maximum value which can be held in a `gsize`. + + This is the same as standard C `SIZE_MAX` (available since C99), + which should be preferred in new code. + + Since: 2.4 + +`G_GSIZE_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gsize`. It + is a string literal. + + Note that this is not necessarily the correct modifier to scan or + print a `size_t`, even though the in-memory representation is the + same. The Standard C `"z"` modifier should be used for `size_t`, + assuming a C99-compliant `printf` implementation is available. + + Since: 2.6 + +`G_GSIZE_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `gsize`. See also `G_GINT16_FORMAT`. + + Note that this is not necessarily the correct format to scan or + print a `size_t`, even though the in-memory representation is the + same. The standard C `"zu"` format should be used for `size_t`, + assuming a C99-compliant `printf` implementation is available. + + Since: 2.6 + +### `gssize` + +A signed variant of [`gsize`](#gsize), corresponding to the +`ssize_t` defined in POSIX or the similar `SSIZE_T` in Windows. + +In new platform-specific code, consider using `ssize_t` or `SSIZE_T` +directly. + +Values of this type can range from `G_MINSSIZE` to `G_MAXSSIZE`. + +Note that on platforms where `ssize_t` is implemented, `ssize_t` and +`gssize` might be implemented by different standard integer types +of the same size. Similarly, on Windows, `SSIZE_T` and `gssize` +might be implemented by different standard integer types of the same +size. See [`gsize`](#gsize) for more details. + +This type is also not guaranteed to be the same as standard C +`ptrdiff_t`, although they are the same on many platforms. + +To print or scan values of this type, use +`G_GSSIZE_MODIFIER` and/or `G_GSSIZE_FORMAT`. + +`G_MINSSIZE` +: The minimum value which can be held in a `gssize`. + + Since: 2.14 + +`G_MAXSSIZE` +: The maximum value which can be held in a `gssize`. + + Since: 2.14 + +`G_GSSIZE_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `gssize`. See also `G_GINT16_FORMAT`. + + Note that this is not necessarily the correct format to scan or print + a POSIX `ssize_t` or a Windows `SSIZE_T`, even though the in-memory + representation is the same. + On POSIX platforms, the `"zd"` format should be used for `ssize_t`. + + Since: 2.6 + +`G_GSSIZE_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gssize`. It + is a string literal. + + Note that this is not necessarily the correct modifier to scan or print + a POSIX `ssize_t` or a Windows `SSIZE_T`, even though the in-memory + representation is the same. + On POSIX platforms, the `"z"` modifier should be used for `ssize_t`. + + Since: 2.6 + +### `goffset` + +A signed integer type that is used for file offsets, +corresponding to the POSIX type `off_t` as if compiling with +`_FILE_OFFSET_BITS` set to 64. `goffset` is always 64 bits wide, even on +32-bit architectures, and even if `off_t` is only 32 bits. +Values of this type can range from `G_MINOFFSET` to +`G_MAXOFFSET`. + +To print or scan values of this type, use +`G_GOFFSET_MODIFIER` and/or `G_GOFFSET_FORMAT`. + +On platforms with more than one 64-bit standard integer type, +even if `off_t` is also 64 bits in size, `goffset` and `off_t` are not +necessarily implemented by the same 64-bit integer type. +See [`gsize`](#gsize) for more details of what this implies. + +Since: 2.14 + +`G_MINOFFSET` +: The minimum value which can be held in a `goffset`. + +`G_MAXOFFSET` +: The maximum value which can be held in a `goffset`. + +`G_GOFFSET_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `goffset`. It is a string + literal. See also `G_GINT64_MODIFIER`. + + This modifier should only be used with `goffset` values, and not + with `off_t`, which is not necessarily the same type or even the same size. + + Since: 2.20 + +`G_GOFFSET_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `goffset`. See also `G_GINT64_FORMAT`. + + This format should only be used with `goffset` values, and not + with `off_t`, which is not necessarily the same type or even the same size. + + Since: 2.20 + +`G_GOFFSET_CONSTANT(val)` +: This macro is used to insert `goffset` 64-bit integer literals + into the source code. + + See also `G_GINT64_CONSTANT()`. + + Since: 2.20 + +### `gintptr` + +Corresponds to the C99 type `intptr_t`, +a signed integer type that can hold any pointer. + +The standard `intptr_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires `gintptr`. +Note that `intptr_t` and `gintptr` might be implemented by different +standard integer types of the same size. See [`gsize`](#gsize) for more details. + +`gintptr` is not guaranteed to be the same type or the same size as +[`gssize`](#gssize), even though they are the same on many CPU architectures. + +To print or scan values of this type, use +`G_GINTPTR_MODIFIER` and/or `G_GINTPTR_FORMAT`. + +Since: 2.18 + +`G_GINTPTR_MODIFIER` +: The platform dependent length modifier for conversion specifiers + for scanning and printing values of type `gintptr` or `guintptr`. + It is a string literal. + + Note that this is not necessarily the correct modifier to scan or + print an `intptr_t`, even though the in-memory representation is the + same. + Standard C macros like `PRIdPTR` and `SCNdPTR` should be used for + `intptr_t`. + + Since: 2.22 + +`G_GINTPTR_FORMAT` +: This is the platform dependent conversion specifier for scanning + and printing values of type `gintptr`. + + Note that this is not necessarily the correct format to scan or + print an `intptr_t`, even though the in-memory representation is the + same. + Standard C macros like `PRIdPTR` and `SCNdPTR` should be used for + `intptr_t`. + + Since: 2.22 + +### `guintptr` + +Corresponds to the C99 type `uintptr_t`, +an unsigned integer type that can hold any pointer. + +The standard `uintptr_t` type should be preferred in new code, unless +consistency with pre-existing APIs requires `guintptr`. +Note that `uintptr_t` and `guintptr` might be implemented by different +standard integer types of the same size. See [`gsize`](#gsize) for more details. + +`guintptr` is not guaranteed to be the same type or the same size as +[`gsize`](#gsize), even though they are the same on many CPU architectures. + +To print or scan values of this type, use +`G_GINTPTR_MODIFIER` and/or `G_GUINTPTR_FORMAT`. + +Since: 2.18 + +`G_GUINTPTR_FORMAT` +: This is the platform dependent conversion specifier + for scanning and printing values of type `guintptr`. + + Note that this is not necessarily the correct format to scan or + print a `uintptr_t`, even though the in-memory representation is the + same. + Standard C macros like `PRIuPTR` and `SCNuPTR` should be used for + `uintptr_t`. + + Since: 2.22 diff --git a/docs/reference/glib/unicode.md b/docs/reference/glib/unicode.md new file mode 100644 index 0000000..da4ed96 --- /dev/null +++ b/docs/reference/glib/unicode.md @@ -0,0 +1,37 @@ +Title: Unicode +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2011, 2014, 2023 Matthias Clasen +SPDX-FileCopyrightText: 2020 Endless OS Foundation, LLC + +# Unicode support + +GLib has support for various aspects of Unicode, and provides a number of APIs for dealing +with Unicode characters and strings. + +There are analogues of the traditional `ctype.h` character classification and case conversion +functions, UTF-8 analogues of some string utility functions, functions to perform normalization, +case conversion and collation on UTF-8 strings and finally functions to convert between the UTF-8, +UTF-16 and UCS-4 encodings of Unicode. + +The implementations of the Unicode functions in GLib are based on the Unicode Character Data tables, +which are available from [www.unicode.org](http://www.unicode.org/). + + - Unicode 4.0 was added in GLib 2.8 + - Unicode 4.1 was added in GLib 2.10 + - Unicode 5.0 was added in GLib 2.12 + - Unicode 5.1 was added in GLib 2.16.3 + - Unicode 6.0 was added in GLib 2.30 + - Unicode 6.1 was added in GLib 2.32 + - Unicode 6.2 was added in GLib 2.36 + - Unicode 6.3 was added in GLib 2.40 + - Unicode 7.0 was added in GLib 2.42 + - Unicode 8.0 was added in GLib 2.48 + - Unicode 9.0 was added in GLib 2.50.1 + - Unicode 10.0 was added in GLib 2.54 + - Unicode 11.10 was added in GLib 2.58 + - Unicode 12.0 was added in GLib 2.62 + - Unicode 12.1 was added in GLib 2.62 + - Unicode 13.0 was added in GLib 2.66 + - Unicode 14.0 was added in GLib 2.71 + - Unicode 15.0 was added in GLib 2.76 + diff --git a/docs/reference/glib/unix.md b/docs/reference/glib/unix.md new file mode 100644 index 0000000..fa446c5 --- /dev/null +++ b/docs/reference/glib/unix.md @@ -0,0 +1,48 @@ +Title: Unix-specific Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2011 Colin Walters + +# Unix-specific Utilities + +Most of GLib is intended to be portable; in contrast, this set of +functions is designed for programs which explicitly target Unix, +or are using it to build higher level abstractions which would be +conditionally compiled if the platform matches `G_OS_UNIX`. + +To use these functions, you must explicitly include the +`glib-unix.h` header. + +## File Descriptors + + * [func@GLib.unix_open_pipe] + * [func@GLib.unix_set_fd_nonblocking] + +## Pipes + +The [struct@GLib.UnixPipe] structure can be used to conveniently open and +manipulate a Unix pipe. + + +The methods for it are all static inline for efficiency. They are: + + * `g_unix_pipe_open()` + * `g_unix_pipe_get()` + * `g_unix_pipe_steal()` + * `g_unix_pipe_close()` + * `g_unix_pipe_clear()` + +## Signals + + * [func@GLib.unix_signal_add] + * [func@GLib.unix_signal_add_full] + * [func@GLib.unix_signal_source_new] + +## Polling + + * [func@GLib.unix_fd_add] + * [func@GLib.unix_fd_add_full] + * [func@GLib.unix_fd_source_new] + +## User Database + + * [func@GLib.unix_get_passwd_entry] diff --git a/docs/reference/glib/urlmap.js b/docs/reference/glib/urlmap.js new file mode 100644 index 0000000..b1f0962 --- /dev/null +++ b/docs/reference/glib/urlmap.js @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Matthias Clasen +var baseURLs = [ + [ 'GLib', 'https://docs.gtk.org/glib/' ], + [ 'GModule', 'https://docs.gtk.org/gmodule/' ], + [ 'GObject', 'https://docs.gtk.org/gobject/' ], + [ 'Gio', 'https://docs.gtk.org/gio/' ], + [ 'Gtk', 'https://docs.gtk.org/gtk4/' ], +]; diff --git a/docs/reference/glib/uuid.md b/docs/reference/glib/uuid.md new file mode 100644 index 0000000..3abebe3 --- /dev/null +++ b/docs/reference/glib/uuid.md @@ -0,0 +1,25 @@ +Title: GUuid +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2017 Bastien Nocera +SPDX-FileCopyrightText: 2017 Marc-André Lureau + +# GUuid + +A UUID, or Universally unique identifier, is intended to uniquely +identify information in a distributed environment. For the +definition of UUID, see [RFC 4122](https://tools.ietf.org/html/rfc4122.html). + +The creation of UUIDs does not require a centralized authority. + +UUIDs are of relatively small size (128 bits, or 16 bytes). The +common string representation (ex: +`1d6c0810-2bd6-45f3-9890-0268422a6f14`) needs 37 bytes. +[func@GLib.uuid_string_is_valid] can be used to check whether a string is a +valid UUID. + +The UUID specification defines 5 versions, and calling +[func@GLib.uuid_string_random] will generate a unique (or rather random) +UUID of the most common version, version 4. + +UUID support was added to GLib in version 2.52. + diff --git a/docs/reference/glib/version.md b/docs/reference/glib/version.md new file mode 100644 index 0000000..4d9ddcf --- /dev/null +++ b/docs/reference/glib/version.md @@ -0,0 +1,46 @@ +Title: Version Information +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2004 Matthias Clasen +SPDX-FileCopyrightText: 2012 Emmanuele Bassi + +# Version Information + +GLib provides version information, primarily useful in configure +checks for builds that have a configure script. Applications will +not typically use the features described here. + +## Run-time Version Numbers + +The variables `glib_major_version`, `glib_minor_version`, `glib_micro_version`, +`glib_binary_age` and `glib_interface_age` are all available to check. + +They can be compared using the function [func@GLib.check_version]. + +## Compile-time Version Numbers + + * [const@GLib.MAJOR_VERSION] + * [const@GLib.MINOR_VERSION] + * [const@GLib.MICRO_VERSION] + * [func@GLib.CHECK_VERSION] + +## Version Numbers + +The GLib headers annotate deprecated APIs in a way that produces +compiler warnings if these deprecated APIs are used. The warnings +can be turned off by defining the macro `GLIB_DISABLE_DEPRECATION_WARNINGS` +before including the `glib.h` header. + +GLib also provides support for building applications against +defined subsets of deprecated or new GLib APIs. Define the macro +`GLIB_VERSION_MIN_REQUIRED` to specify up to what version of GLib +you want to receive warnings about deprecated APIs. Define the +macro `GLIB_VERSION_MAX_ALLOWED` to specify the newest version of +GLib whose API you want to use. + +The macros `GLIB_VERSION_2_2`, `GLIB_VERSION_2_4`, …, `GLIB_VERSION_2_80`, etc. +are defined automatically in each release, and can be used to set the value +of macros like `GLIB_VERSION_MIN_REQUIRED`. + +The macros `GLIB_VERSION_CUR_STABLE` and `GLIB_VERSION_PREV_STABLE` are also +automatically defined to point to the right version definitions. + diff --git a/docs/reference/glib/version.xml.in b/docs/reference/glib/version.xml.in deleted file mode 100644 index af9b9c4..0000000 --- a/docs/reference/glib/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@GLIB_VERSION@ diff --git a/docs/reference/glib/warnings.md b/docs/reference/glib/warnings.md new file mode 100644 index 0000000..bb05656 --- /dev/null +++ b/docs/reference/glib/warnings.md @@ -0,0 +1,73 @@ +Title: Warnings and Assertions +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2018 Endless Mobile, Inc. +SPDX-FileCopyrightText: 2023 Daniel Carpenter + +# Warnings and Assertions + +GLib defines several warning functions and assertions which can be used to +warn of programmer errors when calling functions, and print error messages +from command line programs. + +## Pre-condition Assertions + +The [func@GLib.return_if_fail], [func@GLib.return_val_if_fail], +[func@GLib.return_if_reached] and [func@GLib.return_val_if_reached] macros are +intended as pre-condition assertions, to be used at the top of a public function +to check that the function’s arguments are acceptable. Any failure of such a +pre-condition assertion is considered a programming error on the part of the +caller of the public API, and the program is considered to be in an undefined +state afterwards. They are similar to the libc [`assert()`](man:assert(3)) +function, but provide more context on failures. + +For example: +```c +gboolean +g_dtls_connection_shutdown (GDtlsConnection *conn, + gboolean shutdown_read, + gboolean shutdown_write, + GCancellable *cancellable, + GError **error) +{ + // local variable declarations + + g_return_val_if_fail (G_IS_DTLS_CONNECTION (conn), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + // function body + + return return_val; +} +``` + +[func@GLib.warn_if_fail] and [func@GLib.warn_if_reached] behave similarly, but +they will not abort the program on failure. The program should be considered to +be in an undefined state if they fail, however. + +## Messages + +[func@GLib.print] and [func@GLib.printerr] are intended to be used for +output from command line applications, since they output to standard output +and standard error by default — whereas functions like [func@GLib.message] and +[func@GLib.log] may be redirected to special purpose message windows, files, or +the system journal. + +The default print handlers may be overridden with [func@GLib.set_print_handler] +and [func@GLib.set_printerr_handler]. + +### Encoding + +If the console encoding is not UTF-8 (as specified by +[func@GLib.get_console_charset]) then these functions convert the message first. +Any Unicode characters not defined by that charset are replaced by `'?'`. On +Linux, [`setlocale()`](man:setlocale(3)) must be called early in `main()` to +load the encoding. This behaviour can be changed by providing custom handlers to +[func@GLib.set_print_handler], [func@GLib.set_printerr_handler] and +[func@GLib.log_set_handler]. + +## Debugging Utilities + + * [func@GLib.on_error_query] + * [func@GLib.on_error_stack_trace] + * [func@GLib.BREAKPOINT] diff --git a/docs/reference/glib/windows.md b/docs/reference/glib/windows.md new file mode 100644 index 0000000..c6a1080 --- /dev/null +++ b/docs/reference/glib/windows.md @@ -0,0 +1,26 @@ +Title: Windows-specific Utilities +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2005 Ross Burton + +# Windows-specific Utilities + +These functions provide some level of Unix emulation on the +Windows platform. If your application really needs the POSIX +APIs, we suggest you try the [Cygwin project](https://cygwin.com/). + + * [type@GLib.Win32OSType] + * [func@GLib.win32_check_windows_version] + * [func@GLib.win32_get_command_line] + * [func@GLib.win32_error_message] + * [func@GLib.win32_getlocale] + * [func@GLib.win32_get_package_installation_directory] + * [func@GLib.win32_get_package_installation_directory_of_module] + * [func@GLib.win32_get_package_installation_subdirectory] + * [func@GLib.win32_get_windows_version] + * [func@GLib.win32_locale_filename_from_utf8] + * [func@GLib.WIN32_HAVE_WIDECHAR_API] + * [func@GLib.WIN32_IS_NT_BASED] + +## Deprecated API + + * [func@GLib.WIN32_DLLMAIN_FOR_DLL_NAME] diff --git a/docs/reference/glib/xml/gtkdocentities.ent.in b/docs/reference/glib/xml/gtkdocentities.ent.in deleted file mode 100644 index f12c9ff..0000000 --- a/docs/reference/glib/xml/gtkdocentities.ent.in +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/reference/glib/xml/meson.build b/docs/reference/glib/xml/meson.build deleted file mode 100644 index 6aeb745..0000000 --- a/docs/reference/glib/xml/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -ent_conf = configuration_data() -ent_conf.set('PACKAGE', 'glib') -ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.gnome.org/GNOME/glib/issues/new') -ent_conf.set('PACKAGE_NAME', 'glib') -ent_conf.set('PACKAGE_STRING', 'glib') -ent_conf.set('PACKAGE_TARNAME', 'glib') -ent_conf.set('PACKAGE_URL', 'FIXME') -ent_conf.set('PACKAGE_VERSION', glib_version) -ent_conf.set('PACKAGE_API_VERSION', glib_api_version) -configure_file( - input: 'gtkdocentities.ent.in', - output: 'gtkdocentities.ent', - configuration: ent_conf -) diff --git a/docs/reference/gmodule/gmodule.toml.in b/docs/reference/gmodule/gmodule.toml.in new file mode 100644 index 0000000..46f1efd --- /dev/null +++ b/docs/reference/gmodule/gmodule.toml.in @@ -0,0 +1,49 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2023 Matthias Clasen +# Copyright 2023 Philip Withnall + +[library] +name = "GModule" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/glib/" +repository_url = "https://gitlab.gnome.org/GNOME/glib.git" +website_url = "https://www.gtk.org" +docs_url = "https://docs.gtk.org/gmodule/" +authors = "GLib Development Team" +license = "LGPL-2.1-or-later" +description = "Portable API for dynamically loading modules" +dependencies = [ "GLib-2.0", "GObject-2.0", "Gio-2.0" ] +devhelp = true +search_index = true + + [dependencies."GLib-2.0"] + name = "GLib" + description = "The base utility library" + docs_url = "https://docs.gtk.org/glib/" + + [dependencies."GObject-2.0"] + name = "GObject" + description = "The base type system library" + docs_url = "https://docs.gtk.org/gobject/" + + [dependencies."Gio-2.0"] + name = "GIO" + description = "GObject Interfaces and Objects, Networking, IPC, and I/O" + docs_url = "https://docs.gtk.org/gio/" + +[theme] +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +[source-location] +base_url = "https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/" + +[extra] +urlmap_file = "urlmap.js" +# The same order will be used when generating the index +content_files = [ + "modules.md", +] +content_images = [ +] diff --git a/docs/reference/gmodule/meson.build b/docs/reference/gmodule/meson.build new file mode 100644 index 0000000..eb75a05 --- /dev/null +++ b/docs/reference/gmodule/meson.build @@ -0,0 +1,26 @@ +expand_content_files = [ + 'modules.md', +] + +gmodule_toml = configure_file(input: 'gmodule.toml.in', output: 'gmodule.toml', configuration: toml_conf) + +custom_target('gmodule-docs', + input: [ gmodule_toml, gmodule_gir[0] ], + output: 'gmodule', + command: [ + gidocgen, + 'generate', + gidocgen_common_args, + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--content-dir=@0@'.format(meson.current_source_dir()), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gobject'), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gmodule'), + '@INPUT1@', + ], + build_by_default: true, + depend_files: expand_content_files, + install: true, + install_dir: docs_dir, + install_tag: 'doc', +) diff --git a/docs/reference/gmodule/modules.md b/docs/reference/gmodule/modules.md new file mode 100644 index 0000000..8f0eeeb --- /dev/null +++ b/docs/reference/gmodule/modules.md @@ -0,0 +1,92 @@ +Title: Dynamic Loading of Modules + +## Dynamic Loading of Modules + +These functions provide a portable way to dynamically load object files +(commonly known as 'plug-ins'). The current implementation supports all +systems that provide an implementation of `dlopen()` (e.g. Linux/Sun), as +well as Windows platforms via DLLs. + +A program which wants to use these functions must be linked to the libraries +output by the command: + + pkg-config --libs gmodule-2.0 + +To use them you must first determine whether dynamic loading is supported on +the platform by calling [`func@GModule.Module.supported`]. If it is, you can +open a module with [`func@GModule.Module.open`], find the module's symbols +(e.g. function names) with [`method@GModule.Module.symbol`], and later close +the module with [`method@GModule.Module.close`]. +[`method@GModule.Module.name`] will return the file name of a currently +opened module. + +If any of the above functions fail, the error status can be found with +[`func@GModule.Module.error`]. + +The `GModule` implementation features reference counting for opened modules, +and supports hook functions within a module which are called when the module +is loaded and unloaded (see [callback@GModule.ModuleCheckInit] and +[callback@GModule.ModuleUnload]). + +If your module introduces static data to common subsystems in the running +program, e.g. through calling API like: + +```c +static GQuark my_module_quark = + g_quark_from_static_string ("my-module-stuff"); +``` + +it must ensure that it is never unloaded, by calling +[`method@GModule.Module.make_resident`]. + +### Calling a function defined in a GModule + +```c +// the function signature for 'say_hello' +typedef void (* SayHelloFunc) (const char *message); + +gboolean +just_say_hello (const char *filename, GError **error) +{ + SayHelloFunc say_hello; + GModule *module; + + module = g_module_open (filename, G_MODULE_BIND_LAZY); + if (module == NULL) + { + g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH, + "%s", g_module_error ()); + return FALSE; + } + + if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello)) + { + g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, + "%s: %s", filename, g_module_error ()); + + if (!g_module_close (module)) + g_warning ("%s: %s", filename, g_module_error ()); + + return FALSE; + } + + if (say_hello == NULL) + { + g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, + "symbol say_hello is NULL"); + + if (!g_module_close (module)) + g_warning ("%s: %s", filename, g_module_error ()); + + return FALSE; + } + + // call our function in the module + say_hello ("Hello world!"); + + if (!g_module_close (module)) + g_warning ("%s: %s", filename, g_module_error ()); + + return TRUE; + } +``` diff --git a/docs/reference/gmodule/urlmap.js b/docs/reference/gmodule/urlmap.js new file mode 100644 index 0000000..b1f0962 --- /dev/null +++ b/docs/reference/gmodule/urlmap.js @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Matthias Clasen +var baseURLs = [ + [ 'GLib', 'https://docs.gtk.org/glib/' ], + [ 'GModule', 'https://docs.gtk.org/gmodule/' ], + [ 'GObject', 'https://docs.gtk.org/gobject/' ], + [ 'Gio', 'https://docs.gtk.org/gio/' ], + [ 'Gtk', 'https://docs.gtk.org/gtk4/' ], +]; diff --git a/docs/reference/gobject/boxed.md b/docs/reference/gobject/boxed.md new file mode 100644 index 0000000..d311221 --- /dev/null +++ b/docs/reference/gobject/boxed.md @@ -0,0 +1,113 @@ +Title: Boxed Types + +# Boxed Types + +A "boxed type" is a generic wrapper mechanism for arbitrary C structures. +The only thing the type system needs to know about the structures is how to +copy them (a [`callback@GObject.BoxedCopyFunc`]) and how to free them (a +[`callback@GObject.BoxedFreeFunc`])—beyond that they are treated as opaque +chunks of memory. + +Boxed types are useful for simple value-holder structures like rectangles or +points. They can also be used for wrapping structures defined in non-GObject +based libraries. They allow arbitrary structures to be handled in a uniform +way, allowing uniform copying (or referencing) and freeing (or +unreferencing) of them, and uniform representation of the type of the +contained structure. In turn, this allows any type which can be boxed to be +set as the data in a `GValue`, which allows for polymorphic handling of a much +wider range of data types, and hence usage of such types as `GObject` property +values. + +All boxed types inherit from the `G_TYPE_BOXED` fundamental type. + +It is very important to note that boxed types are **not** deeply +inheritable: you cannot register a boxed type that inherits from another +boxed type. This means you cannot create your own custom, parallel type +hierarchy and map it to GType using boxed types. If you want to have deeply +inheritable types without using GObject, you will need to use +`GTypeInstance`. + +## Registering a new boxed type + +The recommended way to register a new boxed type is to use the +[`func@GObject.DEFINE_BOXED_TYPE`] macro: + +```c +// In the header + +#define EXAMPLE_TYPE_RECTANGLE (example_rectangle_get_type()) + +typedef struct { + double x, y; + double width, height; +} ExampleRectangle; + +GType +example_rectangle_get_type (void); + +ExampleRectangle * +example_rectangle_copy (ExampleRectangle *r); + +void +example_rectangle_free (ExampleRectangle *r); + +// In the source +G_DEFINE_BOXED_TYPE (ExampleRectangle, example_rectangle, + example_rectangle_copy, + example_rectangle_free) +``` + +Just like `G_DEFINE_TYPE` and `G_DEFINE_INTERFACE_TYPE`, the +`G_DEFINE_BOXED_TYPE` macro will provide the definition of the `get_type()` +function, which will call [`func@GObject.boxed_type_register_static`] with +the given type name as well as the `GBoxedCopyFunc` and `GBoxedFreeFunc` +functions. + +## Using boxed types + +### Object properties + +In order to use a boxed type with GObject properties you will need to +register the property using [`func@GObject.param_spec_boxed`], e.g. + +```c +obj_props[PROP_BOUNDS] = + g_param_spec_boxed ("bounds", NULL, NULL, + EXAMPLE_TYPE_RECTANGLE, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); +``` + +In the `set_property` implementation you can use `g_value_get_boxed()` to +retrieve a pointer to the boxed type: + +```c +switch (prop_id) + { + // ... + case PROP_BOUNDS: + example_object_set_bounds (self, g_value_get_boxed (value)); + break; + // ... + } +``` + +Similarly, you can use `g_value_set_boxed()` in the implementation of the +`get_property` virtual function: + +```c +switch (prop_id) + { + // ... + case PROP_BOUNDS: + g_value_set_boxed (self, &self->bounds); + break; + // ... + } +``` + +## Reference counting + +Boxed types are designed so that reference counted types can be boxed. Use +the type’s ‘ref’ function as the `GBoxedCopyFunc`, and its ‘unref’ function as +the `GBoxedFreeFunc`. For example, for `GBytes`, the `GBoxedCopyFunc` is +`g_bytes_ref()`, and the GBoxedFreeFunc is `g_bytes_unref()`. diff --git a/docs/reference/gobject/concepts.md b/docs/reference/gobject/concepts.md new file mode 100644 index 0000000..62bdf95 --- /dev/null +++ b/docs/reference/gobject/concepts.md @@ -0,0 +1,1847 @@ +Title: Type System Concepts + +# Type System Concepts + +## Introduction + +Most modern programming languages come with their own native object systems +and additional fundamental algorithmic language constructs. Just as GLib +serves as an implementation of such fundamental types and algorithms (linked +lists, hash tables and so forth), the GLib Object System provides the +required implementations of a flexible, extensible, and intentionally easy +to map (into other languages) object-oriented framework for C. The +substantial elements that are provided can be summarized as: + +- A generic type system to register arbitrary single-inherited flat and deep + derived types as well as interfaces for structured types. It takes care of + creation, initialization and memory management of the assorted object and + class structures, maintains parent/child relationships and deals with + dynamic implementations of such types. That is, their type specific + implementations are relocatable/unloadable during runtime. +- A collection of fundamental type implementations, such as integers, + doubles, enums and structured types, to name a few. +- A sample fundamental type implementation to base object hierarchies upon - + the GObject fundamental type. +- A signal system that allows very flexible user customization of + virtual/overridable object methods and can serve as a powerful + notification mechanism. +- An extensible parameter/value system, supporting all the provided + fundamental types that can be used to generically handle object properties + or otherwise parameterized types. + +## Background + +GObject, and its lower-level type system, GType, are used by GTK and most +GNOME libraries to provide: + +- object-oriented C-based APIs and +- automatic transparent API bindings to other compiled or interpreted + languages. + +A lot of programmers are used to working with compiled-only or dynamically +interpreted-only languages and do not understand the challenges associated +with cross-language interoperability. This introduction tries to provide an +insight into these challenges and briefly describes the solution chosen by +GLib. + +The following chapters go into greater detail into how GType and GObject +work and how you can use them as a C programmer. It is useful to keep in +mind that allowing access to C objects from other interpreted languages was +one of the major design goals: this can often explain the sometimes rather +convoluted APIs and features present in this library. + +### Data types and programming + +One could say that a programming language is merely a way to create data +types and manipulate them. Most languages provide a number of +language-native types and a few primitives to create more complex types +based on these primitive types. + +In C, the language provides types such as char, long, pointer. During +compilation of C code, the compiler maps these language types to the +compiler's target architecture machine types. If you are using a C +interpreter (assuming one exists), the interpreter (the program which +interprets the source code and executes it) maps the language types to the +machine types of the target machine at runtime, during the program execution +(or just before execution if it uses a Just In Time compiler engine). + +Perl and Python are interpreted languages which do not really provide type +definitions similar to those used by C. Perl and Python programmers +manipulate variables and the type of the variables is decided only upon the +first assignment or upon the first use which forces a type on the variable. +The interpreter also often provides a lot of automatic conversions from one +type to the other. For example, in Perl, a variable which holds an integer +can be automatically converted to a string given the required context: + +```perl +my $tmp = 10; +print "this is an integer converted to a string:" . $tmp . "\n"; +``` + +Of course, it is also often possible to explicitly specify conversions when +the default conversions provided by the language are not intuitive. + +### Exporting a C API + +C APIs are defined by a set of functions and global variables which are +usually exported from a binary. C functions have an arbitrary number of +arguments and one return value. Each function is thus uniquely identified by +the function name and the set of C types which describe the function +arguments and return value. The global variables exported by the API are +similarly identified by their name and their type. + +A C API is thus merely defined by a set of names to which a set of types are +associated. If you know the function calling convention and the mapping of +the C types to the machine types used by the platform you are on, you can +resolve the name of each function to find where the code associated to this +function is located in memory, and then construct a valid argument list for +the function. Finally, all you have to do is trigger a call to the target C +function with the argument list. + +For the sake of discussion, here is a sample C function and the associated +32 bit x86 assembly code generated by GCC on a Linux computer: + +```c +static void +function_foo (int foo) +{ +} + +int +main (int argc, + char *argv[]) +{ + function_foo (10); + + return 0; +} +``` + +```asm +push $0xa +call 0x80482f4 +``` + +The assembly code shown above is pretty straightforward: the first +instruction pushes the hexadecimal value 0xa (decimal value 10) as a 32-bit +integer on the stack and calls `function_foo`. As you can see, C function +calls are implemented by GCC as native function calls (this is probably the +fastest implementation possible). + +Now, let's say we want to call the C function `function_foo` from a Python +program. To do this, the Python interpreter needs to: + +- Find where the function is located. This probably means finding the binary + generated by the C compiler which exports this function. +- Load the code of the function in executable memory. +- Convert the Python parameters to C-compatible parameters before calling + the function. +- Call the function with the right calling convention. +- Convert the return values of the C function to Python-compatible variables + to return them to the Python code. + +The process described above is pretty complex and there are a lot of ways to +make it entirely automatic and transparent to C and Python programmers: + +- The first solution is to write by hand a lot of glue code, once for each + function exported or imported, which does the Python-to-C parameter + conversion and the C-to-Python return value conversion. This glue code is + then linked with the interpreter which allows Python programs to call + Python functions which delegate work to C functions. +- Another, nicer solution is to automatically generate the glue code, once + for each function exported or imported, with a special compiler which + reads the original function signature. + +The solution used by GLib is to use the GType library which holds at runtime +a description of all the objects manipulated by the programmer. This +so-called dynamic type library is then used by special generic glue code to +automatically convert function parameters and function calling conventions +between different runtime domains. + +The greatest advantage of the solution implemented by GType is that the glue +code sitting at the runtime domain boundaries is written once: the figure +below states this more clearly. + +![](./glue.png) + +Currently, there exist multiple generic glue code which makes it possible to +use C objects written with GType directly in a variety of languages, with a +minimum amount of work: there is no need to generate huge amounts of glue +code either automatically or by hand. + +Although that goal was arguably laudable, its pursuit has had a major +influence on the whole GType/GObject library. C programmers are likely to be +puzzled at the complexity of the features exposed in the following chapters +if they forget that the GType/GObject library was not only designed to offer +OO-like features to C programmers but also transparent cross-language +interoperability. + +## The GLib Dynamic Type System + +A type, as manipulated by the GLib type system, is much more generic than what is usually understood as an Object type. It is best explained by looking at the structure and the functions used to register new types in the type system. + +```c +typedef struct _GTypeInfo GTypeInfo; +struct _GTypeInfo +{ + /* interface types, classed types, instantiated types */ + guint16 class_size; + + GBaseInitFunc base_init; + GBaseFinalizeFunc base_finalize; + + /* classed types, instantiated types */ + GClassInitFunc class_init; + GClassFinalizeFunc class_finalize; + gconstpointer class_data; + + /* instantiated types */ + guint16 instance_size; + guint16 n_preallocs; + GInstanceInitFunc instance_init; + + /* value handling */ + const GTypeValueTable *value_table; +}; + +GType +g_type_register_static (GType parent_type, + const gchar *type_name, + const GTypeInfo *info, + GTypeFlags flags); + +GType +g_type_register_fundamental (GType type_id, + const gchar *type_name, + const GTypeInfo *info, + const GTypeFundamentalInfo *finfo, + GTypeFlags flags); +``` + +`g_type_register_static()`, `g_type_register_dynamic()` and +`g_type_register_fundamental()` are the C functions, defined in `gtype.h` +and implemented in `gtype.c` which you should use to register a new GType in +the program's type system. It is not likely you will ever need to use +`g_type_register_fundamental()` but in case you want to, the last chapter +explains how to create new fundamental types. + +Fundamental types are top-level types which do not derive from any other +type while other non-fundamental types derive from other types. Upon +initialization, the type system not only initializes its internal data +structures but it also registers a number of core types: some of these are +fundamental types. Others are types derived from these fundamental types. + +Fundamental and non-fundamental types are defined by: + +- class size: the `class_size` field in `GTypeInfo`. +- class initialization functions (C++ constructor): the `base_init` and + `class_init` fields in `GTypeInfo`. +- class destruction functions (C++ destructor): the `base_finalize` and + `class_finalize` fields in `GTypeInfo`. +- instance size (C++ parameter to new): the `instance_size` field in + `GTypeInfo`. +- instantiation policy (C++ type of new operator): the `n_preallocs` field + in `GTypeInfo`. +- copy functions (C++ copy operators): the `value_table` field in + `GTypeInfo`. +- type characteristic flags: `GTypeFlags`. + +Fundamental types are also defined by a set of `GTypeFundamentalFlags` which +are stored in a `GTypeFundamentalInfo`. Non-fundamental types are +furthermore defined by the type of their parent which is passed as the +`parent_type` parameter to `g_type_register_static()` and +`g_type_register_dynamic()`. + +## Copy functions + +The major common point between all GLib types (fundamental and +non-fundamental, classed and non-classed, instantiatable and +non-instantiatable) is that they can all be manipulated through a single API +to copy/assign them. + +The `GValue` structure is used as an abstract container for all of these +types. Its simplistic API (defined in `gobject/gvalue.h`) can be used to +invoke the `value_table` functions registered during type registration: for +example `g_value_copy()` copies the content of a `GValue` to another +`GValue`. This is similar to a C++ assignment which invokes the C++ copy +operator to modify the default bit-by-bit copy semantics of C++/C +structures/classes. + +The following code shows how you can copy around a 64 bit integer, as well +as a `GObject` instance pointer: + +```c +static void test_int (void) +{ + GValue a_value = G_VALUE_INIT; + GValue b_value = G_VALUE_INIT; + guint64 a, b; + + a = 0xdeadbeef; + + g_value_init (&a_value, G_TYPE_UINT64); + g_value_set_uint64 (&a_value, a); + + g_value_init (&b_value, G_TYPE_UINT64); + g_value_copy (&a_value, &b_value); + + b = g_value_get_uint64 (&b_value); + + if (a == b) { + g_print ("Yay !! 10 lines of code to copy around a uint64.\n"); + } else { + g_print ("Are you sure this is not a Z80 ?\n"); + } +} + +static void test_object (void) +{ + GObject *obj; + GValue obj_vala = G_VALUE_INIT; + GValue obj_valb = G_VALUE_INIT; + obj = g_object_new (VIEWER_TYPE_FILE, NULL); + + g_value_init (&obj_vala, VIEWER_TYPE_FILE); + g_value_set_object (&obj_vala, obj); + + g_value_init (&obj_valb, G_TYPE_OBJECT); + + /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. + * This function thus calls g_object_ref. + * It is interesting to note that the assignment works here because + * VIEWER_TYPE_FILE is a G_TYPE_OBJECT. + */ + g_value_copy (&obj_vala, &obj_valb); + + g_object_unref (G_OBJECT (obj)); + g_object_unref (G_OBJECT (obj)); +} +``` + +The important point about the above code is that the exact semantics of the +copy calls is undefined since they depend on the implementation of the copy +function. Certain copy functions might decide to allocate a new chunk of +memory and then to copy the data from the source to the destination. Others +might want to simply increment the reference count of the instance and copy +the reference to the new `GValue`. + +The value table used to specify these assignment functions is documented in +`GTypeValueTable`. + +Interestingly, it is also very unlikely you will ever need to specify a +`value_table` during type registration because these `value_tables` are +inherited from the parent types for non-fundamental types. + +## Conventions + +There are a number of conventions users are expected to follow when creating +new types which are to be exported in a header file: + +- Type names (including object names) must be at least three characters long + and start with "a–z", "A–Z" or "\_". +- Use the `object_method` pattern for function names: to invoke the method + named save on an instance of object type file, call `file_save`. +- Use prefixing to avoid namespace conflicts with other projects. If your + library (or application) is named `Viewer`, prefix all your function names + with viewer_. For example: `viewer_object_method`. +- Create a macro named `PREFIX_TYPE_OBJECT` which always returns the GType + for the associated object type. For an object of type `File` in the + `Viewer` namespace, use: `VIEWER_TYPE_FILE`. This macro is implemented + using a function named `prefix_object_get_type`; for example, + `viewer_file_get_type`. +- Use `G_DECLARE_FINAL_TYPE` or `G_DECLARE_DERIVABLE_TYPE` to define various + other conventional macros for your object: + - `PREFIX_OBJECT (obj)`, which returns a pointer of type `PrefixObject`. + This macro is used to enforce static type safety by doing explicit casts + wherever needed. It also enforces dynamic type safety by doing runtime + checks. It is possible to disable the dynamic type checks in production + builds (see "Building GLib" section in the GLib API reference). For + example, we would create `VIEWER_FILE (obj)` to keep the previous + example. + - `PREFIX_OBJECT_CLASS (klass)`, which is strictly equivalent to the + previous casting macro: it does static casting with dynamic type + checking of class structures. It is expected to return a pointer to a + class structure of type `PrefixObjectClass`. An example is: + `VIEWER_FILE_CLASS`. + - `PREFIX_IS_OBJECT (obj)`, which returns a gboolean which indicates + whether the input object instance pointer is non-`NULL` and of type + `OBJECT`. For example, `VIEWER_IS_FILE`. + - `PREFIX_IS_OBJECT_CLASS (klass)`, which returns a boolean if the input + class pointer is a pointer to a class of type `OBJECT`. For example, + `VIEWER_IS_FILE_CLASS`. + - `PREFIX_OBJECT_GET_CLASS (obj)`, which returns the class pointer + associated to an instance of a given type. This macro is used for static + and dynamic type safety purposes (just like the previous casting + macros). For example, `VIEWER_FILE_GET_CLASS`. + +The implementation of these macros is pretty straightforward: a number of +simple-to-use macros are provided in `gtype.h`. For the example we used above, +we would write the following trivial code to declare the macros: + +```c +#define VIEWER_TYPE_FILE viewer_file_get_type() +G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) +``` + +Unless your code has special requirements, you can use the `G_DEFINE_TYPE` +macro to define a class: + +```c +G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) +``` + +Otherwise, the `viewer_file_get_type` function must be implemented manually: + +```c +GType viewer_file_get_type (void) +{ + static GType type = 0; + if (type == 0) { + const GTypeInfo info = { + /* You fill this structure. */ + }; + type = g_type_register_static (G_TYPE_OBJECT, + "ViewerFile", + &info, 0); + } + return type; +} +``` + +## Non-instantiatable non-classed fundamental types + +A lot of types are not instantiatable by the type system and do not have a class. Most of these types are fundamental trivial types such as `gchar`, and are already registered by GLib. + +In the rare case of needing to register such a type in the type system, fill a `GTypeInfo` structure with zeros since these types are also most of the time fundamental: + +```c +GTypeInfo info = { + .class_size = 0, + + .base_init = NULL, + .base_finalize = NULL, + + .class_init = NULL, + .class_finalize = NULL, + .class_data = NULL, + + .instance_size = 0, + .n_preallocs = 0, + .instance_init = NULL, + + .value_table = NULL, +}; + +static const GTypeValueTable value_table = { + .value_init = value_init_long0, + .value_free = NULL, + .value_copy = value_copy_long0, + .value_peek_pointer = NULL, + + .collect_format = "i", + .collect_value = value_collect_int, + .lcopy_format = "p", + .lcopy_value = value_lcopy_char, +}; + +info.value_table = &value_table; + +type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0); +``` + +Having non-instantiatable types might seem a bit useless: what good is a +type if you cannot instantiate an instance of that type? Most of these types +are used in conjunction with `GValue`s: a `GValue` is initialized with an +integer or a string and it is passed around by using the registered type's +`value_table`. `GValue`s (and by extension these trivial fundamental types) +are most useful when used in conjunction with object properties and signals. + +## Instantiatable classed types: objects + +Types which are registered with a class and are declared instantiatable are +what most closely resembles an object. Although `GObject`s are the most well +known type of instantiatable classed types, other kinds of similar objects +used as the base of an inheritance hierarchy have been externally developed +and they are all built on the fundamental features described below. + +For example, the code below shows how you could register such a fundamental +object type in the type system (using none of the GObject convenience API): + +```c +typedef struct { + GObject parent_instance; + + /* instance members */ + char *filename; +} ViewerFile; + +typedef struct { + GObjectClass parent_class; + + /* class members */ + + /* the first is public, pure and virtual */ + void (*open) (ViewerFile *self, + GError **error); + + /* the second is public and virtual */ + void (*close) (ViewerFile *self, + GError **error); +} ViewerFileClass; + +#define VIEWER_TYPE_FILE (viewer_file_get_type ()) + +GType +viewer_file_get_type (void) +{ + static GType type = 0; + if (type == 0) { + const GTypeInfo info = { + .class_size = sizeof (ViewerFileClass), + .base_init = NULL, + .base_finalize = NULL, + .class_init = (GClassInitFunc) viewer_file_class_init, + .class_finalize = NULL, + .class_data = NULL, + .instance_size = sizeof (ViewerFile), + .n_preallocs = 0, + .instance_init = (GInstanceInitFunc) viewer_file_init, + }; + type = g_type_register_static (G_TYPE_OBJECT, + "ViewerFile", + &info, 0); + } + return type; +} +``` + +Upon the first call to `viewer_file_get_type`, the type named `ViewerFile` will be registered in the type system as inheriting from the type `G_TYPE_OBJECT`. + +Every object must define two structures: its class structure and its instance structure. All class structures must contain as first member a `GTypeClass` structure. All instance structures must contain as first member a `GTypeInstance` structure. The declaration of these C types, coming from `gtype.h` is shown below: + +``` +struct _GTypeClass +{ + GType g_type; +}; + +struct _GTypeInstance +{ + GTypeClass *g_class; +}; +``` + +These constraints allow the type system to make sure that every object instance (identified by a pointer to the object's instance structure) contains in its first bytes a pointer to the object's class structure. + +This relationship is best explained by an example: let's take object B which inherits from object A: + +```c +/* A definitions */ +typedef struct { + GTypeInstance parent; + int field_a; + int field_b; +} A; + +typedef struct { + GTypeClass parent_class; + void (*method_a) (void); + void (*method_b) (void); +} AClass; + +/* B definitions. */ +typedef struct { + A parent; + int field_c; + int field_d; +} B; + +typedef struct { + AClass parent_class; + void (*method_c) (void); + void (*method_d) (void); +} BClass; +``` + +The C standard mandates that the first field of a C structure is stored starting in the first byte of the buffer used to hold the structure's fields in memory. This means that the first field of an instance of an object B is A's first field which in turn is `GTypeInstance`'s first field which in turn is `g_class`, a pointer to B's class structure. + +Thanks to these simple conditions, it is possible to detect the type of every object instance by doing: + +```c +B *b; +b->parent.parent.g_class->g_type +``` + +or, more compactly: + +```c +B *b; +((GTypeInstance *) b)->g_class->g_type +``` + +### Initialization and destruction + +Instantiation of these types can be done with `g_type_create_instance()`, which +will look up the type information structure associated with the type +requested. Then, the instance size and instantiation policy (if the +`n_preallocs` field is set to a non-zero value, the type system allocates the +object's instance structures in chunks rather than mallocing for every +instance) declared by the user are used to get a buffer to hold the object's +instance structure. + +If this is the first instance of the object ever created, the type system +must create a class structure. It allocates a buffer to hold the object's +class structure and initializes it. The first part of the class structure +(ie: the embedded parent class structure) is initialized by copying the +contents from the class structure of the parent class. The rest of class +structure is initialized to zero. If there is no parent, the entire class +structure is initialized to zero. The type system then invokes the +`base_init` functions `(GBaseInitFunc)` from topmost fundamental +object to bottom-most most derived object. The object's `class_init` +`(GClassInitFunc)` function is invoked afterwards to complete initialization +of the class structure. Finally, the object's interfaces are initialized (we +will discuss interface initialization in more detail later). + +Once the type system has a pointer to an initialized class structure, it +sets the object's instance class pointer to the object's class structure and +invokes the object's `instance_init` `(GInstanceInitFunc)` functions, from +top-most fundamental type to bottom-most most-derived type. + +Object instance destruction through `g_type_free_instance()` is very simple: +the instance structure is returned to the instance pool if there is one and +if this was the last living instance of the object, the class is destroyed. + +Class destruction (the concept of destruction is sometimes partly referred +to as finalization in GType) is the symmetric process of the initialization: +interfaces are destroyed first. Then, the most derived `class_finalize` +`(GClassFinalizeFunc)` function is invoked. Finally, the `base_finalize` +`(GBaseFinalizeFunc)` functions are invoked from bottom-most most-derived type +to top-most fundamental type and the class structure is freed. + +The base initialization/finalization process is very similar to the C++ +constructor/destructor paradigm. The practical details are different though +and it is important not to get confused by superficial similarities. GTypes +have no instance destruction mechanism. It is the user's responsibility to +implement correct destruction semantics on top of the existing GType code. +(This is what `GObject` does) Furthermore, C++ +code equivalent to the `base_init` and `class_init` callbacks of GType is +usually not needed because C++ cannot really create object types at runtime. + +The instantiation/finalization process can be summarized as follows: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Invocation timeFunction invokedFunction's parameters
First call to g_type_create_instance() for target typetype's base_init functionOn the inheritance tree of classes from fundamental type to target type. base_init is invoked once for each class structure.
target type's class_init functionOn target type's class structure
interface initialization, see the section called “Interface Initialization”
Each call to g_type_create_instance() for target typetarget type's instance_init functionOn object's instance
Last call to g_type_free_instance() for target typeinterface destruction, see the section called “Interface Destruction”
target type's class_finalize functionOn target type's class structure
type's base_finalize functionOn the inheritance tree of classes from fundamental type to target type. base_finalize is invoked once for each class structure.
+ +## Non-instantiatable classed types: interfaces + +GType's interfaces are very similar to Java's interfaces. They allow to +describe a common API that several classes will adhere to. Imagine the play, +pause and stop buttons on hi-fi equipment—those can be seen as a playback +interface. Once you know what they do, you can control your CD player, MP3 +player or anything that uses these symbols. + +To declare an interface you have to register a non-instantiatable classed +type which derives from `GTypeInterface`. The following piece of code declares +such an interface: + +```c +#define VIEWER_TYPE_EDITABLE viewer_editable_get_type () +G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject) + +struct _ViewerEditableInterface { + GTypeInterface parent; + + void (*save) (ViewerEditable *self, + GError **error); +}; + +void viewer_editable_save (ViewerEditable *self, + GError **error); +``` + +The interface function, `viewer_editable_save` is implemented in a pretty +simple way: + +```c +void +viewer_editable_save (ViewerEditable *self, + GError **error) +{ + ViewerEditableinterface *iface; + + g_return_if_fail (VIEWER_IS_EDITABLE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + iface = VIEWER_EDITABLE_GET_IFACE (self); + g_return_if_fail (iface->save != NULL); + iface->save (self); +} +``` + +`viewer_editable_get_type` registers a type named `ViewerEditable` which +inherits from `G_TYPE_INTERFACE`. All interfaces must be children of +`G_TYPE_INTERFACE` in the inheritance tree. + +An interface is defined by only one structure which must contain as first +member a `GTypeInterface` structure. The interface structure is expected to +contain the function pointers of the interface methods. It is good style to +define helper functions for each of the interface methods which simply call +the interface's method directly: `viewer_editable_save` is one of these. + +If you have no special requirements you can use the `G_IMPLEMENT_INTERFACE` +macro to implement an interface: + +```c +static void +viewer_file_save (ViewerEditable *self) +{ + g_print ("File implementation of editable interface save method.\n"); +} + +static void +viewer_file_editable_interface_init (ViewerEditableInterface *iface) +{ + iface->save = viewer_file_save; +} + +G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, VIEWER_TYPE_FILE, + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_file_editable_interface_init)) +``` + +If your code does have special requirements, you must write a custom +`get_type` function to register your GType which inherits from some GObject +and which implements the interface `ViewerEditable`. For example, this code +registers a new `ViewerFile` class which implements `ViewerEditable`: + +```c +static void +viewer_file_save (ViewerEditable *editable) +{ + g_print ("File implementation of editable interface save method.\n"); +} + +static void +viewer_file_editable_interface_init (gpointer g_iface, + gpointer iface_data) +{ + ViewerEditableInterface *iface = g_iface; + + iface->save = viewer_file_save; +} + +GType +viewer_file_get_type (void) +{ + static GType type = 0; + if (type == 0) { + const GTypeInfo info = { + .class_size = sizeof (ViewerFileClass), + .base_init = NULL, + .base_finalize = NULL, + .class_init = (GClassInitFunc) viewer_file_class_init, + .class_finalize = NULL, + .class_data = NULL, + .instance_size = sizeof (ViewerFile), + .n_preallocs = 0, + .instance_init = (GInstanceInitFunc) viewer_file_init + }; + + const GInterfaceInfo editable_info = { + .interface_init = (GInterfaceInitFunc) viewer_file_editable_interface_init, + .interface_finalize = NULL, + .interface_data = NULL, + }; + + type = g_type_register_static (VIEWER_TYPE_FILE, + "ViewerFile", + &info, 0); + + g_type_add_interface_static (type, + VIEWER_TYPE_EDITABLE, + &editable_info); + } + return type; +} +``` + +`g_type_add_interface_static()` records in the type system that the given +`ViewerFile` type implements also `ViewerEditable` +(`viewer_editable_get_type()` returns the type of `ViewerEditable`). The +`GInterfaceInfo` structure holds information about the implementation of the +interface: + +```c +struct _GInterfaceInfo +{ + GInterfaceInitFunc interface_init; + GInterfaceFinalizeFunc interface_finalize; + gpointer interface_data; +}; +``` + +### Interface initialization + +When an instantiatable classed type which implements an interface (either +directly or by inheriting an implementation from a superclass) is created +for the first time, its class structure is initialized following the process +described in the section called "Instantiatable classed types: objects". +After that, the interface implementations associated with the type are +initialized. + +First a memory buffer is allocated to hold the interface structure. The +parent's interface structure is then copied over to the new interface +structure (the parent interface is already initialized at that point). If +there is no parent interface, the interface structure is initialized with +zeros. The `g_type` and the `g_instance_type` fields are then initialized: +`g_type` is set to the type of the most-derived interface and `g_instance_type` +is set to the type of the most derived type which implements this interface. + +The interface's `base_init` function is called, and then the interface's +`default_init` is invoked. Finally if the type has registered an +implementation of the interface, the implementation's `interface_init` +function is invoked. If there are multiple implementations of an interface +the `base_init` and `interface_init` functions will be invoked once for each +implementation initialized. + +It is thus recommended to use a `default_init` function to initialize an +interface. This function is called only once for the interface no matter how +many implementations there are. The `default_init` function is declared by +`G_DEFINE_INTERFACE` which can be used to define the interface: + +```c +G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT) + +static void +viewer_editable_default_init (ViewerEditableInterface *iface) +{ + /* add properties and signals here, will only be called once */ +} +``` + +Or you can do that yourself in a GType function for your interface: + +```c +GType +viewer_editable_get_type (void) +{ + static gsize type_id = 0; + if (g_once_init_enter (&type_id)) { + const GTypeInfo info = { + sizeof (ViewerEditableInterface), + NULL, /* base_init */ + NULL, /* base_finalize */ + viewer_editable_default_init, /* class_init */ + NULL, /* class_finalize */ + NULL, /* class_data */ + 0, /* instance_size */ + 0, /* n_preallocs */ + NULL /* instance_init */ + }; + GType type = g_type_register_static (G_TYPE_INTERFACE, + "ViewerEditable", + &info, 0); + g_once_init_leave (&type_id, type); + } + return type_id; +} + +static void +viewer_editable_default_init (ViewerEditableInterface *iface) +{ + /* add properties and signals here, will only called once */ +} +``` + +In summary, interface initialization uses the following functions: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Invocation timeFunction InvokedFunction's parametersRemark
First call to g_type_create_instance() for any type implementing interfaceinterface's base_init functionOn interface's vtableRarely necessary to use this. Called once per instantiated classed type implementing the interface.
First call to g_type_create_instance() for each type implementing interfaceinterface's default_init functionOn interface's vtableRegister interface's signals, properties, etc. here. Will be called once.
First call to g_type_create_instance() for any type implementing interfaceimplementation's interface_init functionOn interface's vtableInitialize interface implementation. Called for each class that that implements the interface. Initialize the interface method pointers in the interface structure to the implementing class's implementation.
+ +### Interface Destruction + +When the last instance of an instantiatable type which registered an +interface implementation is destroyed, the interface's implementations +associated to the type are destroyed. + +To destroy an interface implementation, GType first calls the +implementation's `interface_finalize` function and then the interface's +most-derived `base_finalize` function. + +Again, it is important to understand, as in the section called "Interface +Initialization", that both `interface_finalize` and `base_finalize` are +invoked exactly once for the destruction of each implementation of an +interface. Thus, if you were to use one of these functions, you would need +to use a static integer variable which would hold the number of instances of +implementations of an interface such that the interface's class is destroyed +only once (when the integer variable reaches zero). + +The above process can be summarized as follows: + + + + + + + + + + + + + + + + + + + + + + + +
Invocation timeFunction InvokedFunction's parameters
Last call to g_type_free_instance() for type implementing interfaceinterface's interface_finalize functionOn interface's vtable
interface's base_finalize functionOn interface's vtable
+ +## The GObject base class + +The previous chapter discussed the details of GLib's Dynamic Type System. +The GObject library also contains an implementation for a base fundamental +type named `GObject`. + +`GObject` is a fundamental classed instantiatable type. It implements: + +- memory management with reference counting +- construction/Destruction of instances +- generic per-object properties with set/get function pairs +- easy use of signals + +All the GNOME libraries which use the GLib type system (like GTK and +GStreamer) inherit from `GObject` which is why it is important to understand +the details of how it works. + +### Object instantiation + +The `g_object_new()` family of functions can be used to instantiate any +GType which inherits from the GObject base type. All these functions make +sure the class and instance structures have been correctly initialized by +GLib's type system and then invoke at one point or another the constructor +class method which is used to: + +- allocate and clear memory through `g_type_create_instance()` +- initialize the object's instance with the construction properties. + +GObject explicitly guarantees that all class and instance members (except +the fields pointing to the parents) to be set to zero. + +Once all construction operations have been completed and constructor +properties set, the constructed class method is called. + +Objects which inherit from `GObject` are allowed to override this +constructed class method. The example below shows how `ViewerFile` overrides +the parent's construction process: + +```c +#define VIEWER_TYPE_FILE viewer_file_get_type () +G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) + +struct _ViewerFile +{ + GObject parent_instance; + + /* instance members */ + char *filename; + guint zoom_level; +}; + +/* will create viewer_file_get_type and set viewer_file_parent_class */ +G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) + +static void +viewer_file_constructed (GObject *obj) +{ + /* update the object state depending on constructor properties */ + + /* Always chain up to the parent constructed function to complete object + * initialisation. */ + G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj); +} + +static void +viewer_file_finalize (GObject *obj) +{ + ViewerFile *self = VIEWER_FILE (obj); + + g_free (self->filename); + + /* Always chain up to the parent finalize function to complete object + * destruction. */ + G_OBJECT_CLASS (viewer_file_parent_class)->finalize (obj); +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->constructed = viewer_file_constructed; + object_class->finalize = viewer_file_finalize; +} + +static void +viewer_file_init (ViewerFile *self) +{ + /* initialize the object */ +} +``` + +If the user instantiates an object `ViewerFile` with: + +```c +ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL); +``` + +If this is the first instantiation of such an object, the +`viewer_file_class_init` function will be invoked after any +`viewer_file_base_class_init` function. This will make sure the class +structure of this new object is correctly initialized. Here, +`viewer_file_class_init` is expected to override the object's class methods +and setup the class' own methods. In the example above, the constructed +method is the only overridden method: it is set to +`viewer_file_constructed`. + +Once `g_object_new()` has obtained a reference to an initialized class +structure, it invokes its constructor method to create an instance of the +new object, if the constructor has been overridden in +`viewer_file_class_init`. Overridden constructors must chain up to their +parent’s constructor. In order to find the parent class and chain up to the +parent class constructor, we can use the `viewer_file_parent_class` pointer +that has been set up for us by the `G_DEFINE_TYPE` macro. + +Finally, at one point or another, `g_object_constructor` is invoked by the +last constructor in the chain. This function allocates the object's instance +buffer through `g_type_create_instance()` which means that the +`instance_init` function is invoked at this point if one was registered. +After `instance_init` returns, the object is fully initialized and should be +ready to have its methods called by the user. When +`g_type_create_instance()` returns, `g_object_constructor` sets the +construction properties (i.e. the properties which were given to +`g_object_new()`) and returns to the user's constructor. + +The process described above might seem a bit complicated, but it can be +summarized easily by the table below which lists the functions invoked by +`g_object_new()` and their order of invocation: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Invocation timeFunction invokedFunction's parametersRemark
First call to g_object_new() for target typetarget type's base_init functionOn the inheritance tree of classes from fundamental type to target type. base_init is invoked once for each class structure.Never used in practice. Unlikely you will need it.
target type's class_init functionOn target type's class structureHere, you should make sure to initialize or override class methods (that is, assign to each class' method its function pointer) and create the signals and the properties associated to your object.
interface's base_init functionOn interface's vtable
interface's interface_init functionOn interface's vtable
Each call to g_object_new() for target typetarget type's class constructor method: GObjectClass->constructor + On object's instanceIf you need to handle construct properties in a custom way, or implement a singleton class, override the constructor method and make sure to chain up to the object's parent class before doing your own initialization. In doubt, do not override the constructor method.
type's instance_init functionOn the inheritance tree of classes from fundamental type to target type. The instance_init provided for each type is invoked once for each instance structure.Provide an instance_init function to initialize your object before its construction properties are set. This is the preferred way to initialize a GObject instance. This function is equivalent to C++ constructors.
target type's class constructed method: GObjectClass->constructedOn object's instanceIf you need to perform object initialization steps after all construct properties have been set. This is the final step in the object initialization process, and is only called if the constructor method returned a new object instance (rather than, for example, an existing singleton).
+ +Readers should feel concerned about one little twist in the order in which +functions are invoked: while, technically, the class' constructor method is +called before the GType's `instance_init` function (since +`g_type_create_instance()` which calls `instance_init` is called by +`g_object_constructor` which is the top-level class constructor method and +to which users are expected to chain to), the user's code which runs in a +user-provided constructor will always run after GType's `instance_init` +function since the user-provided constructor must (you've been warned) chain +up before doing anything useful. + +### Object memory management + +The memory-management API for GObjects is a bit complicated but the idea +behind it is pretty simple: the goal is to provide a flexible model based on +reference counting which can be integrated in applications which use or +require different memory management models (such as garbage collection). The +methods which are used to manipulate this reference count are described +below. + +#### Reference count + +The functions `g_object_ref()` and `g_object_unref()` increase and decrease +the reference count, respectively. These functions are thread-safe. +`g_clear_object()` is a convenience wrapper around `g_object_unref()` which +also clears the pointer passed to it. + +The reference count is initialized to one by `g_object_new()` which means +that the caller is currently the sole owner of the newly-created reference. +(If the object is derived from `GInitiallyUnowned`, this reference is +"floating", and must be "sunk", i.e. transformed into a real reference.) +When the reference count reaches zero, that is, when `g_object_unref()` is +called by the last owner of a reference to the object, the `dispose()` and +the `finalize()` class methods are invoked. + +Finally, after `finalize()` is invoked, `g_type_free_instance()` is called +to free the object instance. Depending on the memory allocation policy +decided when the type was registered (through one of the `g_type_register_*` +functions), the object's instance memory will be freed or returned to the +object pool for this type. Once the object has been freed, if it was the +last instance of the type, the type's class will be destroyed as described +in the section called "Instantiatable classed types: objects" and the +section called "Non-instantiatable classed types: interfaces". + +The table below summarizes the destruction process of a `GObject`: + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Invocation timeFunction invokedFunction's parametersRemark
Last call to g_object_unref() for an instance of target typetarget type's dispose class functionGObject instanceWhen dispose ends, the object should not hold any reference to any other member object. The object is also expected to be able to answer client method invocations (with possibly an error code but no memory violation) until finalize is executed. dispose can be executed more than once. dispose should chain up to its parent implementation just before returning to the caller.
target type's finalize class functionGObject instanceFinalize is expected to complete the destruction process initiated by dispose. It should complete the object's destruction. finalize will be executed only once. finalize should chain up to its parent implementation just before returning to the caller. See the section on "Reference counts and cycles" for more information.
Last call to g_object_unref() for the last instance of target typeinterface's interface_finalize functionOn interface's vtableNever used in practice. Unlikely you will need it.
interface's base_finalize functionOn interface's vtableNever used in practice. Unlikely you will need it.
target type's class_finalize functionOn target type's class structureNever used in practice. Unlikely you will need it.
type's base_finalize functionOn the inheritance tree of classes from fundamental type to target type. base_init is invoked once for each class structure.Never used in practice. Unlikely you will need it.
+ +#### Weak References + +Weak references are used to monitor object finalization: +`g_object_weak_ref()` adds a monitoring callback which does not hold a +reference to the object but which is invoked when the object runs its +dispose method. Weak references on the object are automatically dropped when +the instance is disposed, so there is no need to invoke `g_object_weak_unref()` +from the `GWeakNotify` callback. Remember that the object instance is not +passed to the `GWeakNotify` callback because the object has already been +disposed. Instead, the callback receives a pointer to where the object +previously was. + +Weak references are also used to implement `g_object_add_weak_pointer()` and +`g_object_remove_weak_pointer()`. These functions add a weak reference to +the object they are applied to which makes sure to nullify the pointer given +by the user when object is finalized. + +Similarly, `GWeakRef` can be used to implement weak references if thread +safety is required. + +#### Reference counts and cycles + +GObject's memory management model was designed to be easily integrated in +existing code using garbage collection. This is why the destruction process +is split in two phases: the first phase, executed in the `dispose()` handler is +supposed to release all references to other member objects. The second +phase, executed by the `finalize()` handler is supposed to complete the object's +destruction process. Object methods should be able to run without program +error in-between the two phases. + +This two-step destruction process is very useful to break reference counting +cycles. While the detection of the cycles is up to the external code, once +the cycles have been detected, the external code can invoke +`g_object_run_dispose()` which will indeed break any existing cycles since +it will run the dispose handler associated to the object and thus release +all references to other objects. + +This explains one of the rules about the `dispose()` handler stated earlier: +the `dispose()` handler can be invoked multiple times. Let's say we have a +reference count cycle: object A references B which itself references object +A. Let's say we have detected the cycle and we want to destroy the two +objects. One way to do this would be to invoke `g_object_run_dispose()` on one +of the objects. + +If object A releases all its references to all objects, this means it +releases its reference to object B. If object B was not owned by anyone +else, this is its last reference count which means this last unref runs B's +dispose handler which, in turn, releases B's reference on object A. If this +is A's last reference count, this last unref runs A's dispose handler which +is running for the second time before A's finalize handler is invoked! + +The above example, which might seem a bit contrived, can really happen if +GObjects are being handled by language bindings—hence the rules for object +destruction should be closely followed. + +### Object properties + +One of GObject's nice features is its generic get/set mechanism for object +properties. When an object is instantiated, the object's `class_init` +handler should be used to register the object's properties with +`g_object_class_install_properties()`. + +The best way to understand how object properties work is by looking at a +real example of how it is used: + +```c +// Implementation + +typedef enum +{ + PROP_FILENAME = 1, + PROP_ZOOM_LEVEL, + N_PROPERTIES +} ViewerFileProperty; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void +viewer_file_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ViewerFile *self = VIEWER_FILE (object); + + switch ((ViewerFileProperty) property_id) + { + case PROP_FILENAME: + g_free (self->filename); + self->filename = g_value_dup_string (value); + g_print ("filename: %s\n", self->filename); + break; + + case PROP_ZOOM_LEVEL: + self->zoom_level = g_value_get_uint (value); + g_print ("zoom level: %u\n", self->zoom_level); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +viewer_file_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ViewerFile *self = VIEWER_FILE (object); + + switch ((ViewerFileProperty) property_id) + { + case PROP_FILENAME: + g_value_set_string (value, self->filename); + break; + + case PROP_ZOOM_LEVEL: + g_value_set_uint (value, self->zoom_level); + break; + + default: + /* We don't have any other property... */ + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = viewer_file_set_property; + object_class->get_property = viewer_file_get_property; + + obj_properties[PROP_FILENAME] = + g_param_spec_string ("filename", + "Filename", + "Name of the file to load and display from.", + NULL /* default value */, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_ZOOM_LEVEL] = + g_param_spec_uint ("zoom-level", + "Zoom level", + "Zoom level to view the file at.", + 0 /* minimum value */, + 10 /* maximum value */, + 2 /* default value */, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} +``` + +```c +// Use + +ViewerFile *file; +GValue val = G_VALUE_INIT; + +file = g_object_new (VIEWER_TYPE_FILE, NULL); + +g_value_init (&val, G_TYPE_UINT); +g_value_set_char (&val, 11); + +g_object_set_property (G_OBJECT (file), "zoom-level", &val); + +g_value_unset (&val); +``` + +The client code above looks simple but a lot of things happen under the hood: + +`g_object_set_property()` first ensures a property with this name was +registered in file's `class_init` handler. If so it walks the class +hierarchy, from bottom-most most-derived type, to top-most fundamental type +to find the class which registered that property. It then tries to convert +the user-provided GValue into a GValue whose type is that of the associated +property. + +If the user provides a signed char GValue, as is shown here, and if the +object's property was registered as an `unsigned int`, `g_value_transform()` +will try to transform the input signed char into an unsigned int. Of course, +the success of the transformation depends on the availability of the +required transform function. In practice, there will almost always be a +transformation which matches and conversion will be carried out if needed. + +After transformation, the GValue is validated by `g_param_value_validate()` +which makes sure the user's data stored in the GValue matches the +characteristics specified by the property's GParamSpec. Here, the GParamSpec +we provided in `class_init` has a validation function which makes sure that +the GValue contains a value which respects the minimum and maximum bounds of +the GParamSpec. In the example above, the client's GValue does not respect +these constraints (it is set to 11, while the maximum is 10). As such, the +`g_object_set_property()` function will return with an error. + +If the user's GValue had been set to a valid value, +`g_object_set_property()` would have proceeded with calling the object's +`set_property` class method. Here, since our implementation of ViewerFile +did override this method, execution would jump to `viewer_file_set_property` +after having retrieved from the GParamSpec the `param_id` which had been +stored by `g_object_class_install_property()`. + +Once the property has been set by the object's `set_property` class method, +execution returns to `g_object_set_property()` which makes sure that the +"notify" signal is emitted on the object's instance with the changed +property as parameter unless notifications were frozen by +`g_object_freeze_notify()`. + +`g_object_thaw_notify()` can be used to re-enable notification of property +modifications through the “notify” signal. It is important to remember that +even if properties are changed while property change notification is frozen, +the "notify" signal will be emitted once for each of these changed +properties as soon as the property change notification is thawed: no +property change is lost for the "notify" signal, although multiple +notifications for a single property are compressed. Signals can only be +delayed by the notification freezing mechanism. + +It sounds like a tedious task to set up GValues every time when one wants to +modify a property. In practice one will rarely do this. The functions +`g_object_set_property()` and `g_object_get_property()` are meant to be used +by language bindings. For application there is an easier way and that is +described next. + +### Accessing multiple properties at once + +It is interesting to note that the `g_object_set()` and +`g_object_set_valist()` (variadic version) functions can be used to set +multiple properties at once. The client code shown above can then be +re-written as: + +```c +ViewerFile *file; +file = /* */; +g_object_set (G_OBJECT (file), + "zoom-level", 6, + "filename", "~/some-file.txt", + NULL); +``` + +This saves us from managing the GValues that we were needing to handle when +using `g_object_set_property()`. The code above will trigger one notify +signal emission for each property modified. + +Equivalent `_get` versions are also available: `g_object_get()` and +`g_object_get_valist()` (variadic version) can be used to get numerous +properties at once. + +These high level functions have one drawback — they don't provide a return +value. One should pay attention to the argument types and ranges when using +them. A known source of errors is to pass a different type from what the +property expects; for instance, passing an integer when the property expects +a floating point value and thus shifting all subsequent parameters by some +number of bytes. Also forgetting the terminating NULL will lead to undefined +behaviour. + +This explains how `g_object_new()`, `g_object_newv()` and +`g_object_new_valist()` work: they parse the user-provided variable number +of parameters and invoke `g_object_set()` on the parameters only after the +object has been successfully constructed. The "notify" signal will be +emitted for each property set. + +## The GObject messaging system + +### Closures + +Closures are central to the concept of asynchronous signal delivery which is +widely used throughout GTK and GNOME applications. A closure is an +abstraction, a generic representation of a callback. It is a small structure +which contains three objects: + +- a function pointer (the callback itself) whose prototype looks like: + `return_type function_callback (... , gpointer user_data);` +- the `user_data` pointer which is passed to the callback upon invocation of + the closure +- a function pointer which represents the destructor of the closure: + whenever the closure's refcount reaches zero, this function will be called + before the closure structure is freed + +The `GClosure` structure represents the common functionality of all closure +implementations: there exists a different closure implementation for each +separate runtime which wants to use the GObject type system. The GObject +library provides a simple GCClosure type which is a specific implementation +of closures to be used with C/C++ callbacks. + +A `GClosure` provides simple services: + +- invocation (`g_closure_invoke()`): this is what closures were created for; + they hide the details of callback invocation from the callback invoker. +- notification: the closure notifies listeners of certain events such as + closure invocation, closure invalidation and closure finalization. + Listeners can be registered with `g_closure_add_finalize_notifier()` + (finalization notification), `g_closure_add_invalidate_notifier()` + (invalidation notification) and `g_closure_add_marshal_guards()` + (invocation notification). There exist symmetric deregistration functions + for finalization and invalidation events + (`g_closure_remove_finalize_notifier()` and + `g_closure_remove_invalidate_notifier()`) but not for the invocation + process + +#### C Closures + +If you are using C or C++ to connect a callback to a given event, you will +either use simple `GCClosures` which have a pretty minimal API or the even +simpler `g_signal_connect()` functions (which will be presented a bit later). + +`g_cclosure_new()` will create a new closure which can invoke the +user-provided `callback_func` with the user-provided `user_data` as its last +parameter. When the closure is finalized (second stage of the destruction +process), it will invoke the `destroy_data` function if the user has +supplied one. + +`g_cclosure_new_swap()` will create a new closure which can invoke the +user-provided `callback_func` with the user-provided `user_data` as its +first parameter (instead of being the last parameter as with +`g_cclosure_new()`). When the closure is finalized (second stage of the +destruction process), it will invoke the `destroy_data` function if the user +has supplied one. + +#### Non-C closures (for the fearless) + +As was explained above, closures hide the details of callback invocation. In +C, callback invocation is just like function invocation: it is a matter of +creating the correct stack frame for the called function and executing a +call assembly instruction. + +C closure marshallers transform the array of GValues which represent the +parameters to the target function into a C-style function parameter list, +invoke the user-supplied C function with this new parameter list, get the +return value of the function, transform it into a GValue and return this +GValue to the marshaller caller. + +A generic C closure marshaller is available as +`g_cclosure_marshal_generic()` which implements marshalling for all function +types using libffi. Custom marshallers for different types are not needed +apart from performance critical code where the libffi-based marshaller may +be too slow. + +An example of a custom marshaller is given below, illustrating how GValues +can be converted to a C function call. The marshaller is for a C function +which takes an integer as its first parameter and returns `void`. + +```c +g_cclosure_marshal_VOID__INT (GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef void (*GMarshalFunc_VOID__INT) (gpointer data1, + gint arg_1, + gpointer data2); + register GMarshalFunc_VOID__INT callback; + register GCClosure *cc = (GCClosure*) closure; + register gpointer data1, data2; + + g_return_if_fail (n_param_values == 2); + + data1 = g_value_peek_pointer (param_values + 0); + data2 = closure->data; + + callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback); + + callback (data1, + g_marshal_value_peek_int (param_values + 1), + data2); +} +``` + +There exist other kinds of marshallers, for example there is a generic +Python marshaller which is used by all Python closures (a Python closure is +used to invoke a callback written in Python). This Python marshaller +transforms the input GValue list representing the function parameters into a +Python tuple which is the equivalent structure in Python. + +### Signals + +GObject's signals have nothing to do with standard UNIX signals: they +connect arbitrary application-specific events with any number of listeners. +For example, in GTK, every user event (keystroke or mouse move) is received +from the windowing system and generates a GTK event in the form of a signal +emission on the widget object instance. + +Each signal is registered in the type system together with the type on which +it can be emitted: users of the type are said to connect to the signal on a +given type instance when they register a closure to be invoked upon the +signal emission. Users can also emit the signal by themselves or stop the +emission of the signal from within one of the closures connected to the +signal. + +When a signal is emitted on a given type instance, all the closures +connected to this signal on this type instance will be invoked. All the +closures connected to such a signal represent callbacks whose signature +looks like: + +```c +return_type +function_callback (gpointer instance, + ..., + gpointer user_data); +``` + +#### Signal registration + +To register a new signal on an existing type, we can use any of +`g_signal_newv()`, `g_signal_new_valist()` or `g_signal_new()` functions: + +```c +guint +g_signal_newv (const gchar *signal_name, + GType itype, + GSignalFlags signal_flags, + GClosure *class_closure, + GSignalAccumulator accumulator, + gpointer accu_data, + GSignalCMarshaller c_marshaller, + GType return_type, + guint n_params, + GType *param_types); +``` + +The number of parameters to these functions is a bit intimidating but they are relatively simple: + +- `signal_name`: is a string which can be used to uniquely identify a given + signal +- `itype`: is the instance type on which this signal can be emitted +- `signal_flags`: partly defines the order in which closures which were + connected to the signal are invoked +- `class_closure`: this is the default closure for the signal: if it is not + `NULL` upon the signal emission, it will be invoked upon this emission of + the signal. The moment where this closure is invoked compared to other + closures connected to that signal depends partly on the `signal_flags` +- `accumulator`: this is a function pointer which is invoked after each + closure has been invoked. If it returns `FALSE`, signal emission is stopped. + If it returns `TRUE`, signal emission proceeds normally. It is also used to + compute the return value of the signal based on the return value of all + the invoked closures. For example, an accumulator could ignore `NULL` + returns from closures; or it could build a list of the values returned by + the closures +- `accu_data`: this pointer will be passed down to each invocation of the + accumulator during emission +- `c_marshaller`: this is the default C marshaller for any closure which is + connected to this signal +- `return_type`: this is the type of the return value of the signal +- `n_params`: this is the number of parameters this signal takes +- `param_types`: this is an array of GTypes which indicate the type of each + parameter of the signal. The length of this array is indicated by + `n_params`. + +As you can see from the above definition, a signal is basically a +description of the closures which can be connected to this signal and a +description of the order in which the closures connected to this signal will +be invoked. + +#### Signal connection + +If you want to connect to a signal with a closure, you have three possibilities: + +- you can register a class closure at signal registration: this is a + system-wide operation. i.e.: the class closure will be invoked during each + emission of a given signal on any of the instances of the type which + supports that signal +- tou can use `g_signal_override_class_closure()` which overrides the class + closure of a given type. It is possible to call this function only on a + derived type of the type on which the signal was registered. This function + is of use only to language bindings +- you can register a closure with the `g_signal_connect()` family of + functions. This is an instance-specific operation: the closure will be + invoked only during emission of a given signal on a given instance + +It is also possible to connect a different kind of callback on a given +signal: emission hooks are invoked whenever a given signal is emitted +whatever the instance on which it is emitted. Emission hooks are connected +with `g_signal_add_emission_hook()` and removed with +`g_signal_remove_emission_hook()`. + +#### Signal emission + +Signal emission is done through the use of the `g_signal_emit()` family of functions. + +```c +void +g_signal_emitv (const GValue instance_and_params[], + guint signal_id, + GQuark detail, + GValue *return_value); +``` + +- the `instance_and_params` array of GValues contains the list of input + parameters to the signal. The first element of the array is the instance + pointer on which to invoke the signal. The following elements of the array + contain the list of parameters to the signal +- `signal_id` identifies the signal to invoke +- `detail` identifies the specific detail of the signal to invoke. A detail + is a kind of magic token/argument which is passed around during signal + emission and which is used by closures connected to the signal to filter + out unwanted signal emissions. In most cases, you can safely set this + value to zero. See the section called "The detail argument" for more + information about this parameter +- `return_value` holds the return value of the last closure invoked during + emission if no accumulator was specified. If an accumulator was specified + during signal creation, this accumulator is used to calculate the return + value as a function of the return values of all the closures invoked + during emission. If no closure is invoked during emission, the + `return_value` is nonetheless initialized to zero/`NULL` + +Signal emission can be decomposed in 6 steps: + +1. `RUN_FIRST`: if the `G_SIGNAL_RUN_FIRST` flag was used during signal + registration and if there exists a class closure for this signal, the + class closure is invoked. +2. `EMISSION_HOOK`: if any emission hook was added to the signal, they are + invoked from first to last added. Accumulate return values. +3. `HANDLER_RUN_FIRST`: if any closure were connected with the + `g_signal_connect()` family of functions, and if they are not blocked + (with the `g_signal_handler_block()` family of functions) they are run + here, from first to last connected. +4. `RUN_LAST`: if the `G_SIGNAL_RUN_LAST` flag was set during registration + and if a class closure was set, it is invoked here. +5. `HANDLER_RUN_LAST`: if any closure were connected with the + `g_signal_connect_after()` family of functions, if they were not invoked + during `HANDLER_RUN_FIRST` and if they are not blocked, they are run + here, from first to last connected. +6. `RUN_CLEANUP`: if the `G_SIGNAL_RUN_CLEANUP` flag was set during + registration and if a class closure was set, it is invoked here. Signal + emission is completed here. + +If, at any point during the emission (except in the `RUN_CLEANUP` or +`EMISSION_HOOK` states), one of the closures stops the signal emission with +`g_signal_stop_emission()`, the emission jumps to the `RUN_CLEANUP` state. + +If, at any point during emission, one of the closures or emission hook emits +the same signal on the same instance, emission is restarted from the +`RUN_FIRST` state. + +The accumulator function is invoked in all states, after invocation of each +closure (except in `RUN_EMISSION_HOOK` and `RUN_CLEANUP`). It accumulates +the closure return value into the signal return value and returns `TRUE` or +`FALSE`. If, at any point, it does not return `TRUE`, emission jumps to +`RUN_CLEANUP` state. + +If no accumulator function was provided, the value returned by the last +handler run will be returned by `g_signal_emit()`. + +#### The detail argument + +All the functions related to signal emission or signal connection have a +parameter named the detail. Sometimes, this parameter is hidden by the API +but it is always there, in one form or another. + +Of the three main connection functions, only one has an explicit detail +parameter as a GQuark: `g_signal_connect_closure_by_id()`. + +The two other functions, `g_signal_connect_closure()` and +`g_signal_connect_data()` hide the detail parameter in the signal name +identification. Their `detailed_signal` parameter is a string which +identifies the name of the signal to connect to. The format of this string +should match `signal_name::detail_name`. For example, connecting to the +signal named `notify::cursor_position` will actually connect to the signal +named `notify` with the `cursor_position` detail. Internally, the detail +string is transformed to a GQuark if it is present. + +Of the four main signal emission functions, one hides it in its signal name +parameter: `g_signal_emit_by_name()`. The other three have an explicit +detail parameter as a GQuark again: `g_signal_emit()`, `g_signal_emitv()` +and `g_signal_emit_valist()`. + +If a detail is provided by the user to the emission function, it is used +during emission to match against the closures which also provide a detail. +If a closure's detail does not match the detail provided by the user, it +will not be invoked (even though it is connected to a signal which is being +emitted). + +This completely optional filtering mechanism is mainly used as an +optimization for signals which are often emitted for many different reasons: +the clients can filter out which events they are interested in before the +closure's marshalling code runs. For example, this is used extensively by +the notify signal of GObject: whenever a property is modified on a GObject, +instead of just emitting the notify signal, GObject associates as a detail +to this signal emission the name of the property modified. This allows +clients who wish to be notified of changes to only one property to filter +most events before receiving them. + +As a simple rule, users can and should set the detail parameter to zero: +this will disable completely this optional filtering for that signal. diff --git a/docs/reference/gobject/enum-types.md b/docs/reference/gobject/enum-types.md new file mode 100644 index 0000000..a9dee87 --- /dev/null +++ b/docs/reference/gobject/enum-types.md @@ -0,0 +1,36 @@ +Title: Enumeration Types + +# Enumeration Types + +The GLib type system provides fundamental types for enumeration and flags +types. Enumerations types are collection of identifiers associated with a +numeric value; flags types are like enumerations, but allow their values to +be combined by bitwise or. + +A registered enumeration or flags type associates a name and a nickname with +each allowed value, and the methods [`func@GObject.enum_get_value_by_name`], +[`func@GObject.enum_get_value_by_nick`], [`func@GObject.flags_get_value_by_name`] and +[`func@GObject.flags_get_value_by_nick`] can look up values by their name or nickname. + +When an enumeration or flags type is registered with the GLib type system, +it can be used as value type for object properties, using +[`func@GObject.param_spec_enum`] or [`func@GObject.param_spec_flags`]. + +GObject ships with a utility called `glib-mkenums`, that can construct +suitable type registration functions from C enumeration definitions. + +Example of how to get a string representation of an enum value: + +```c +GEnumClass *enum_class; +GEnumValue *enum_value; + +enum_class = g_type_class_ref (EXAMPLE_TYPE_ENUM); +enum_value = g_enum_get_value (enum_class, EXAMPLE_ENUM_FOO); + +g_print ("Name: %s\n", enum_value->value_name); + +g_type_class_unref (enum_class); +``` + +Alternatively, you can use [`func@GObject.enum_to_string`]. diff --git a/docs/reference/gobject/floating-refs.md b/docs/reference/gobject/floating-refs.md new file mode 100644 index 0000000..9d044e2 --- /dev/null +++ b/docs/reference/gobject/floating-refs.md @@ -0,0 +1,128 @@ +Title: Floating References + +# Floating References + +**Note**: Floating references are a C convenience API and should not be used +in modern GObject code. Language bindings in particular find the concept +highly problematic, as floating references are not identifiable through +annotations, and neither are deviations from the floating reference +behavior, like types that inherit from [class@GObject.InitiallyUnowned] and +still return a full reference from [`id@g_object_new`]. + +[class@GObject.InitiallyUnowned] is derived from [class@GObject.Object]. The +only difference between the two is that the initial reference of a +`GInitiallyUnowned` is flagged as a "floating" reference. This means that it +is not specifically claimed to be "owned" by any code portion. The main +motivation for providing floating references is C convenience. In +particular, it allows code to be written as: + +```c +container = create_container (); +container_add_child (container, create_child()); +``` + +If `container_add_child()` calls [`method@GObject.Object.ref_sink`] on the +passed-in child, no reference of the newly created child is leaked. Without +floating references, `container_add_child()` can only acquire a reference +the new child, so to implement this code without reference leaks, it would +have to be written as: + +```c +Child *child; +container = create_container (); +child = create_child (); +container_add_child (container, child); +g_object_unref (child); +``` + +The floating reference can be converted into an ordinary reference by +calling `g_object_ref_sink()`. For already sunken objects (objects that +don't have a floating reference anymore), `g_object_ref_sink()` is +equivalent to [`method@GObject.Object.ref`] and returns a new reference. + +Since floating references are useful almost exclusively for C convenience, +language bindings that provide automated reference and memory ownership +maintenance (such as smart pointers or garbage collection) should not expose +floating references in their API. The best practice for handling types that +have initially floating references is to immediately sink those references +after `g_object_new()` returns, by checking if the `GType` inherits from +`GInitiallyUnowned`. For instance: + +```c +GObject *res = g_object_new_with_properties (gtype, + n_props, + prop_names, + prop_values); + +// or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED)) +if (G_IS_INITIALLY_UNOWNED (res)) + g_object_ref_sink (res); + +return res; +``` + +Some object implementations may need to save an object's floating state +across certain code portions (an example is `GtkMenu` in GTK3), to achieve +this, the following sequence can be used: + +```c +// save floating state +gboolean was_floating = g_object_is_floating (object); +g_object_ref_sink (object); +// protected code portion + +... + +// restore floating state +if (was_floating) + g_object_force_floating (object); +else + g_object_unref (object); // release previously acquired reference +``` + +## Replacing floating references with annotations + +You should avoid basing your object hierarchy on floating references, as +they are hard to understand even in C, and introduce additional limitations +when consuming a GObject-based API in other languages. + +One way to express the ownership transfer between ‘container’ and ‘child’ +instances is to use ownership transfer annotations in your documentation and +introspection data. For instance, you can implement this pattern: + +```c +container_add_child (container, create_child ()); +``` + +without leaking by having `container_add_child()` defined as: + +```c +/** + * container_add_child: + * @self: a container + * @child: (transfer full): the child to add to the container + * + * ... + */ +void +container_add_child (Container *container, + Child *child) +{ + container->children = g_list_append (container->children, child); +} +``` + +The container does not explicitly acquire a reference on the child; instead, +the ownership of the child is transferred to the container. The transfer +annotation will be used by language bindings to ensure that there are no +leaks; and documentation tools will explicitly note that the callee now owns +the value passed by the caller. + +## Replacing floating references with weak references + +Another option for replacing floating references is to use weak references +in place of strong ones. A ‘container’ can acquire a weak reference on the +‘child’ instance by using [`method@GObject.Object.weak_ref`]. Once the +child instance loses its last strong reference, the container holding a +weak reference is notified, and it can either remove the child from its +internal list, or turn a weak reference into a strong one. diff --git a/docs/reference/gobject/glib-genmarshal.rst b/docs/reference/gobject/glib-genmarshal.rst new file mode 100644 index 0000000..0e50348 --- /dev/null +++ b/docs/reference/gobject/glib-genmarshal.rst @@ -0,0 +1,390 @@ +.. _glib-genmarshal(1): +.. meta:: + :copyright: Copyright 2003 Matthias Clasen + :copyright: Copyright 2005, 2012, 2013, 2016 Red Hat, Inc. + :copyright: Copyright 2010 Christian Persch + :copyright: Copyright 2017, 2019, 2020 Emmanuele Bassi + :copyright: Copyright 2020 Centricular + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2003 Matthias Clasen + SPDX-FileCopyrightText: 2005, 2012, 2013, 2016 Red Hat, Inc. + SPDX-FileCopyrightText: 2010 Christian Persch + SPDX-FileCopyrightText: 2017, 2019, 2020 Emmanuele Bassi + SPDX-FileCopyrightText: 2020 Centricular + SPDX-License-Identifier: LGPL-2.1-or-later + +=============== +glib-genmarshal +=============== + +------------------------------------------------------ +C code marshaller generation utility for GLib closures +------------------------------------------------------ + +SYNOPSIS +-------- + +| **glib-genmarshal** [OPTION…] [FILE…] + +DESCRIPTION +----------- + +``glib-genmarshal`` is a small utility that generates C code marshallers for +callback functions of the GClosure mechanism in the GObject sublibrary of GLib. +The marshaller functions have a standard signature, they get passed in the +invoking closure, an array of value structures holding the callback function +parameters and a value structure for the return value of the callback. The +marshaller is then responsible to call the respective C code function of the +closure with all the parameters on the stack and to collect its return value. + +``glib-genmarshal`` takes a list of marshallers to generate as input. The +marshaller list is either read from files passed as additional arguments +on the command line; or from standard input, by using ``-`` as the input file. + +MARSHALLER LIST FORMAT +^^^^^^^^^^^^^^^^^^^^^^ + +The marshaller lists are processed line by line, a line can contain a comment in +the form of:: + + # this is a comment + +or a marshaller specification of the form:: + + RTYPE:PTYPE + RTYPE:PTYPE,PTYPE + RTYPE:PTYPE,PTYPE,PTYPE + … + +The ``RTYPE`` part specifies the callback’s return type and the ``PTYPE`` +instances right of the colon specify the callback’s parameter list, except for +the first and the last arguments which are always pointers. + +PARAMETER TYPES +^^^^^^^^^^^^^^^ + +Currently, the following types are supported: + +``VOID`` + + Indicates no return type, or no extra parameters. If ``VOID`` is used as the + parameter list, no additional parameters may be present. + +``BOOLEAN`` + + For boolean types (``gboolean``). + +``CHAR`` + + For signed char types (``gchar``). + +``UCHAR`` + + For unsigned char types (``guchar``). + +``INT`` + + For signed integer types (``gint``). + +``UINT`` + + For unsigned integer types (``guint``). + +``LONG`` + + For signed long integer types (``glong``). + +``ULONG`` + + For unsigned long integer types (``gulong``). + +``INT64`` + + For signed 64-bit integer types (``gint64``). + +``UINT64`` + + For unsigned 64-bit integer types (``guint64``). + +``ENUM`` + + For enumeration types (``gint``). + +``FLAGS`` + + For flag enumeration types (``guint``). + +``FLOAT`` + + For single-precision float types (``gfloat``). + +``DOUBLE`` + + For double-precision float types (``gdouble``). + +``STRING`` + + For string types (``gchar*``). + +``BOXED`` + + For boxed (anonymous but reference counted) types (``GBoxed*``). + +``PARAM`` + + For ``GParamSpec`` or derived types (``GParamSpec*``). + +``POINTER`` + + For anonymous pointer types (``gpointer``). + +``OBJECT`` + + For ``GObject`` or derived types (``GObject*``). + +``VARIANT`` + + For ``GVariant`` types (``GVariant*``). + +``NONE`` + + Deprecated alias for ``VOID``. + +``BOOL`` + + Deprecated alias for ``BOOLEAN``. + +OPTIONS +------- + +``--header`` + + Generate header file contents of the marshallers. This option is mutually + exclusive with the ``--body`` option. + +``--body`` + + Generate C code file contents of the marshallers. This option is mutually + exclusive with the ``--header`` option. + +``--prefix `` + + Specify marshaller prefix. The default prefix is ``g_cclosure_user_marshal``. + +``--skip-source`` + + Skip source location remarks in generated comments. + +``--stdinc`` + + Use the standard marshallers of the GObject library, and include + ``glib-object.h`` in generated header files. This option is mutually exclusive + with the ``--nostdinc`` option. + +``--nostdinc`` + + Do not use the standard marshallers of the GObject library, and skip the + ``glib-object.h`` include directive in generated header files. + This option is mutually exclusive with the ``--stdinc`` option. + +``--internal`` + + Mark generated functions as internal, using ``G_GNUC_INTERNAL``. + +``-valist-marshallers`` + + Generate ``valist`` marshallers, for use with + ``g_signal_set_va_marshaller()``. + +``-v``, ``--version`` + + Print version information and exit. + +``--g-fatal-warnings`` + + Make warnings fatal. That is, exit immediately once a warning occurs. + +``-h``, ``--help`` + + Print brief help and exit. + +``--output `` + + Write output to ``FILE`` instead of the standard output. + +``--prototypes`` + + Generate function prototypes before the function definition in the C source + file, in order to avoid a ``missing-prototypes`` compiler warning. This option + is only useful when using the ``--body`` option. + +``--pragma-once`` + + Use the ``once`` pragma instead of an old style header guard + when generating the C header file. This option is only useful when using the + ``--header`` option. + +``--include-header
`` + + Adds a ``#include`` directive for the given file in the C source file. This + option is only useful when using the ``--body`` option. + +``-D [=]`` + + Adds a ``#define`` C pre-processor directive for ``SYMBOL`` and its given + ``VALUE``, or ``"1"`` if the value is unset. You can use this option multiple + times; if you do, all the symbols will be defined in the same order given on + the command line, before the symbols undefined using the ``-U`` option. This + option is only useful when using the ``--body`` option. + +``-U `` + + Adds a ``#undef`` C pre-processor directive to undefine the given ``SYMBOL``. + You can use this option multiple times; if you do, all the symbols will be + undefined in the same order given on the command line, after the symbols + defined using the ``-D`` option. This option is only useful when using the + ``--body`` option. + +``--quiet`` + + Minimizes the output of ``glib-genmarshal``, by printing only warnings and + errors. This option is mutually exclusive with the ``--verbose`` option. + +``--verbose`` + + Increases the verbosity of ``glib-genmarshal``, by printing debugging + information. This option is mutually exclusive with the ``--quiet`` option. + +USING GLIB-GENMARSHAL WITH MESON +-------------------------------- + +Meson supports generating closure marshallers using ``glib-genmarshal`` out of +the box in its ``gnome`` module. + +In your ``meson.build`` file you will typically call the ``gnome.genmarshal()`` +method with the source list of marshallers to generate:: + + gnome = import('gnome') + marshal_files = gnome.genmarshal('marshal', + sources: 'marshal.list', + internal: true, + ) + +The ``marshal_files`` variable will contain an array of two elements in the +following order: + +* a build target for the source file +* a build target for the header file + +You should use the returned objects to provide a dependency on every other +build target that references the source or header file; for instance, if you +are using the source to build a library:: + + mainlib = library('project', + sources: project_sources + marshal_files, + … + ) + +Additionally, if you are including the generated header file inside a build +target that depends on the library you just built, you must ensure that the +internal dependency includes the generated header as a required source file:: + + mainlib_dep = declare_dependency(sources: marshal_files[1], link_with: mainlib) + +You should not include the generated source file as well, otherwise it will +be built separately for every target that depends on it, causing build +failures. To know more about why all this is required, please refer to the +`corresponding Meson FAQ entry `_. + +For more information on how to use the method, see the +`Meson documentation `_ +for ``gnome.genmarshal()``. + +USING GLIB-GENMARSHAL WITH AUTOTOOLS +------------------------------------ + +In order to use ``glib-genmarshal`` in your project when using Autotools as the +build system, you will first need to modify your ``configure.ac`` file to ensure +you find the appropriate command using ``pkg-config``, similarly as to how you +discover the compiler and linker flags for GLib:: + + PKG_PROG_PKG_CONFIG([0.28]) + + PKG_CHECK_VAR([GLIB_GENMARSHAL], [glib-2.0], [glib_genmarshal]) + +In your ``Makefile.am`` file you will typically need very simple rules to +generate the C files needed for the build:: + + marshal.h: marshal.list + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --header \ + --output=$@ \ + $< + + marshal.c: marshal.list marshal.h + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --include-header=marshal.h \ + --body \ + --output=$@ \ + $< + + BUILT_SOURCES += marshal.h marshal.c + CLEANFILES += marshal.h marshal.c + EXTRA_DIST += marshal.list + +In the example above, the first rule generates the header file and depends on +a ``marshal.list`` file in order to regenerate the result in case the +marshallers list is updated. The second rule generates the source file for the +same ``marshal.list``, and includes the file generated by the header rule. + +EXAMPLE +------- + +To generate marshallers for the following callback functions:: + + void foo (gpointer data1, + gpointer data2); + void bar (gpointer data1, + gint param1, + gpointer data2); + gfloat baz (gpointer data1, + gboolean param1, + guchar param2, + gpointer data2); + +The ``marshaller.list`` file has to look like this:: + + VOID:VOID + VOID:INT + FLOAT:BOOLEAN,UCHAR + +and you call ``glib-genmarshal`` like this:: + + glib-genmarshal --header marshaller.list > marshaller.h + glib-genmarshal --body marshaller.list > marshaller.c + +The generated marshallers have the arguments encoded in their function name. +For this particular list, they are:: + + g_cclosure_user_marshal_VOID__VOID(...), + g_cclosure_user_marshal_VOID__INT(...), + g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR(...). + +They can be used directly for GClosures or be passed in as the +``GSignalCMarshaller c_marshaller`` argument upon creation of signals:: + + GClosure *cc_foo, *cc_bar, *cc_baz; + + cc_foo = g_cclosure_new (NULL, foo, NULL); + g_closure_set_marshal (cc_foo, g_cclosure_user_marshal_VOID__VOID); + cc_bar = g_cclosure_new (NULL, bar, NULL); + g_closure_set_marshal (cc_bar, g_cclosure_user_marshal_VOID__INT); + cc_baz = g_cclosure_new (NULL, baz, NULL); + g_closure_set_marshal (cc_baz, g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR); + +SEE ALSO +-------- + +`glib-mkenums(1) `_ \ No newline at end of file diff --git a/docs/reference/gobject/glib-genmarshal.xml b/docs/reference/gobject/glib-genmarshal.xml deleted file mode 100644 index 2b3e86f..0000000 --- a/docs/reference/gobject/glib-genmarshal.xml +++ /dev/null @@ -1,579 +0,0 @@ - - - - glib-genmarshal - GObject - - - Developer - Emmanuele - Bassi - - - Original developer - Tim - Janik - - - - - -glib-genmarshal -1 -User Commands - - - -glib-genmarshal -C code marshaller generation utility for GLib closures - - - - -glib-genmarshal -OPTION -FILE - - - -Description -glib-genmarshal is a small utility that generates C code -marshallers for callback functions of the GClosure mechanism in the GObject -sublibrary of GLib. The marshaller functions have a standard signature, -they get passed in the invoking closure, an array of value structures holding -the callback function parameters and a value structure for the return value -of the callback. The marshaller is then responsible to call the respective C -code function of the closure with all the parameters on the stack and to -collect its return value. - - -glib-genmarshal takes a list of marshallers to generate as -input. The marshaller list is either read from files passed as additional arguments -on the command line; or from standard input, by using - as the -input file. - - -Marshaller list format - -The marshaller lists are processed line by line, a line can contain a -comment in the form of - -# this is a comment - -or a marshaller specification of the form - -RTYPE:PTYPE -RTYPE:PTYPE,PTYPE -RTYPE:PTYPE,PTYPE,PTYPE - - - -The RTYPE part specifies the callback's return -type and the PTYPEs right to the colon specify -the callback's parameter list, except for the first and the last arguments -which are always pointers. - - -Parameter types - -Currently, the following types are supported: - - -VOID - -indicates no return type, or no extra parameters. -If VOID is used as the parameter list, no -additional parameters may be present. - - - - -BOOLEAN - -for boolean types (gboolean) - - - - -CHAR - -for signed char types (gchar) - - - - -UCHAR - -for unsigned char types (guchar) - - - - -INT - -for signed integer types (gint) - - - - -UINT - -for unsigned integer types (guint) - - - - -LONG - -for signed long integer types (glong) - - - - -ULONG - -for unsigned long integer types (gulong) - - - - -INT64 - -for signed 64bit integer types (gint64) - - - - -UINT64 - -for unsigned 64bit integer types (guint64) - - - - -ENUM - -for enumeration types (gint) - - - - -FLAGS - -for flag enumeration types (guint) - - - - -FLOAT - -for single-precision float types (gfloat) - - - - -DOUBLE - -for double-precision float types (gdouble) - - - - -STRING - -for string types (gchar*) - - - - -BOXED - -for boxed (anonymous but reference counted) types (GBoxed*) - - - - -PARAM - -for GParamSpec or derived types (GParamSpec*) - - - - -POINTER - -for anonymous pointer types (gpointer) - - - - -OBJECT - -for GObject or derived types (GObject*) - - - - -VARIANT - -for GVariant types (GVariant*) - - - - -NONE - -deprecated alias for VOID - - - - -BOOL - -deprecated alias for BOOLEAN - - - - - - - -Options - - - - - -Generate header file contents of the marshallers. This option is mutually -exclusive with the option. - - - - - - -Generate C code file contents of the marshallers. This option is mutually -exclusive with the option. - - - - - - -Specify marshaller prefix. The default prefix is `g_cclosure_user_marshal'. - - - - - - -Skip source location remarks in generated comments. - - - - - - -Use the standard marshallers of the GObject library, and include -glib-object.h in generated header files. This -option is mutually exclusive with the -option. - - - - - - -Do not use the standard marshallers of the GObject library, and skip -glib-object.h include directive in generated header files. -This option is mutually exclusive with the option. - - - - - - -Mark generated functions as internal, using G_GNUC_INTERNAL. - - - - - - -Generate valist marshallers, for use with g_signal_set_va_marshaller(). - - - - -, - -Print version information. - - - - - - -Make warnings fatal, that is, exit immediately once a warning occurs. - - - - -, - -Print brief help and exit. - - - - -, - -Print version and exit. - - - - - - -Write output to FILE instead of the standard output. - - - - - - -Generate function prototypes before the function definition in the C source -file, in order to avoid a missing-prototypes compiler -warning. This option is only useful when using the -option. - - - - - - -Use the once pragma instead of an old style header guard -when generating the C header file. This option is only useful when using the - option. - - - - - - -Adds a #include directive for the given file in the C -source file. This option is only useful when using the -option. - - - - - - -Adds a #define C pre-processor directive for -SYMBOL and its given VALUE, -or "1" if the value is unset. You can use this option multiple times; if you do, -all the symbols will be defined in the same order given on the command line, before -the symbols undefined using the option. This option is only -useful when using the option. - - - - - - -Adds a #undef C pre-processor directive to undefine the -given SYMBOL. You can use this option multiple times; -if you do, all the symbols will be undefined in the same order given on the -command line, after the symbols defined using the option. -This option is only useful when using the option. - - - - - - -Minimizes the output of glib-genmarshal, by printing only -warnings and errors. This option is mutually exclusive with the - option. - - - - - - -Increases the verbosity of glib-genmarshal, by printing -debugging information. This option is mutually exclusive with the - option. - - - - - - -Using <command>glib-genmarshal</command> with Meson - -Meson supports generating closure marshallers using glib-genmarshal -out of the box in its "gnome" module. - - - -In your meson.build file you will typically call the -gnome.genmarshal() method with the source list of marshallers -to generate: - - -gnome = import('gnome') -marshal_files = gnome.genmarshal('marshal', - sources: 'marshal.list', - internal: true, -) - - -The marshal_files variable will contain an array of two elements -in the following order: - - - a build target for the source file - a build target for the header file - - -You should use the returned objects to provide a dependency on every other -build target that references the source or header file; for instance, if you -are using the source to build a library: - - -mainlib = library('project', - sources: project_sources + marshal_files, - ... -) - - -Additionally, if you are including the generated header file inside a build -target that depends on the library you just built, you must ensure that the -internal dependency includes the generated header as a required source file: - - -mainlib_dep = declare_dependency(sources: marshal_files[1], link_with: mainlib) - - -You should not include the generated source file as well, otherwise it will -be built separately for every target that depends on it, causing build -failures. To know more about why all this is required, please refer to the - -corresponding Meson FAQ entry. - - -For more information on how to use the method, see the -Meson -documentation for gnome.genmarshal(). - - - -Using <command>glib-genmarshal</command> with Autotools - -In order to use glib-genmarshal in your project when using -Autotools as the build system, you will first need to modify your -configure.ac file to ensure you find the appropriate -command using pkg-config, similarly as to how you discover -the compiler and linker flags for GLib. - - -PKG_PROG_PKG_CONFIG([0.28]) - -PKG_CHECK_VAR([GLIB_GENMARSHAL], [glib-2.0], [glib_genmarshal]) - - -In your Makefile.am file you will typically need very -simple rules to generate the C files needed for the build. - - -marshal.h: marshal.list - $(AM_V_GEN)$(GLIB_GENMARSHAL) \ - --header \ - --output=$@ \ - $< - -marshal.c: marshal.list marshal.h - $(AM_V_GEN)$(GLIB_GENMARSHAL) \ - --include-header=marshal.h \ - --body \ - --output=$@ \ - $< - -BUILT_SOURCES += marshal.h marshal.c -CLEANFILES += marshal.h marshal.c -EXTRA_DIST += marshal.list - - -In the example above, the first rule generates the header file and depends on -a marshal.list file in order to regenerate the result in -case the marshallers list is updated. The second rule generates the source file -for the same marshal.list, and includes the file generated -by the header rule. - - - -Example - -To generate marshallers for the following callback functions: - - -void foo (gpointer data1, - gpointer data2); -void bar (gpointer data1, - gint param1, - gpointer data2); -gfloat baz (gpointer data1, - gboolean param1, - guchar param2, - gpointer data2); - - -The marshaller.list file has to look like this: - - -VOID:VOID -VOID:INT -FLOAT:BOOLEAN,UCHAR - - -and you call glib-genmarshal like this: - - -glib-genmarshal --header marshaller.list > marshaller.h -glib-genmarshal --body marshaller.list > marshaller.c - - -The generated marshallers have the arguments encoded in their function name. -For this particular list, they are - - -g_cclosure_user_marshal_VOID__VOID(...), -g_cclosure_user_marshal_VOID__INT(...), -g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR(...). - - -They can be used directly for GClosures or be passed in as the -GSignalCMarshaller c_marshaller; argument upon creation of signals: - - -GClosure *cc_foo, *cc_bar, *cc_baz; - -cc_foo = g_cclosure_new (NULL, foo, NULL); -g_closure_set_marshal (cc_foo, g_cclosure_user_marshal_VOID__VOID); -cc_bar = g_cclosure_new (NULL, bar, NULL); -g_closure_set_marshal (cc_bar, g_cclosure_user_marshal_VOID__INT); -cc_baz = g_cclosure_new (NULL, baz, NULL); -g_closure_set_marshal (cc_baz, g_cclosure_user_marshal_FLOAT__BOOLEAN_UCHAR); - - -See also - - -glib-mkenums -1 - - - - diff --git a/docs/reference/gobject/glib-mkenums.rst b/docs/reference/gobject/glib-mkenums.rst new file mode 100644 index 0000000..d6a5cce --- /dev/null +++ b/docs/reference/gobject/glib-mkenums.rst @@ -0,0 +1,491 @@ +.. _glib-mkenums(1): +.. meta:: + :copyright: Copyright 2003 Matthias Clasen + :copyright: Copyright 2009 Christian Persch + :copyright: Copyright 2010 Allison Karlitskaya + :copyright: Copyright 2012, 2013, 2016 Red Hat, Inc. + :copyright: Copyright 2017, 2019, 2022 Emmanuele Bassi + :copyright: Copyright 2018, 2020 Centricular + :copyright: Copyright 2020 Aleksander Morgado + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2003 Matthias Clasen + SPDX-FileCopyrightText: 2009 Christian Persch + SPDX-FileCopyrightText: 2010 Allison Karlitskaya + SPDX-FileCopyrightText: 2012, 2013, 2016 Red Hat, Inc. + SPDX-FileCopyrightText: 2017, 2019, 2022 Emmanuele Bassi + SPDX-FileCopyrightText: 2018, 2020 Centricular + SPDX-FileCopyrightText: 2020 Aleksander Morgado + SPDX-License-Identifier: LGPL-2.1-or-later + +============ +glib-mkenums +============ + +---------------------------------------------- +C language enum description generation utility +---------------------------------------------- + +SYNOPSIS +-------- + +| **glib-mkenums** [OPTION…] [FILE…] + +DESCRIPTION +----------- + +``glib-mkenums`` is a small utility that parses C code to extract enum +definitions and produces enum descriptions based on text templates specified by +the user. Typically, you can use this tool to generate enumeration +types for the GType type system, for GObject properties and signal marshalling; +additionally, you can use it to generate enumeration values of GSettings +schemas. + +``glib-mkenums`` takes a list of valid C code files as input. The options +specified control the text that generated, substituting various keywords +enclosed in ``@`` characters in the templates. + +Since version 2.74, GLib provides the ``G_DEFINE_ENUM_TYPE`` and +``G_DEFINE_FLAGS_TYPE`` C pre-processor macros. These macros can be used to +define a GType for projects that have few, small enumeration types without going +through the complexities of generating code at build time. + +PRODUCTION TEXT SUBSTITUTIONS +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +Certain keywords enclosed in ``@`` characters will be substituted in the +emitted text. For the substitution examples of the keywords below, +the following example enum definition is assumed:: + + typedef enum + { + PREFIX_THE_XVALUE = 1 << 3, + PREFIX_ANOTHER_VALUE = 1 << 4 + } PrefixTheXEnum; + +``@EnumName@`` + + The name of the enum currently being processed, enum names are assumed to be + properly namespaced and to use mixed capitalization to separate + words (e.g. ``PrefixTheXEnum``). + +``@enum_name@`` + + The enum name with words lowercase and word-separated by underscores + (e.g. ``prefix_the_xenum``). + +``@ENUMNAME@`` + + The enum name with words uppercase and word-separated by underscores + (e.g. ``PREFIX_THE_XENUM``). + +``@ENUMSHORT@`` + + The enum name with words uppercase and word-separated by underscores, + prefix stripped (e.g. ``THE_XENUM``). + +``@ENUMPREFIX@`` + + The prefix of the enum name (e.g. ``PREFIX``). + +``@VALUENAME@`` + + The enum value name currently being processed with words uppercase and + word-separated by underscores, this is the assumed literal notation of enum + values in the C sources (e.g. ``PREFIX_THE_XVALUE``). + +``@valuenick@`` + + A nick name for the enum value currently being processed, this is usually + generated by stripping common prefix words of all the enum values of the + current enum, the words are lowercase and underscores are substituted by a + minus (e.g. ``the-xvalue``). + +``@valuenum@`` + + The integer value for the enum value currently being processed. If the + evaluation fails then ``glib-mkenums`` will exit with an + error status, but this only happens if ``@valuenum@`` + appears in your value production template. (Since: 2.26) + +``@type@`` + + This is substituted either by ‘enum’ or ‘flags’, depending on whether the + enum value definitions contained bit-shift operators (e.g. ``flags``). + +``@Type@`` + + The same as ``@type@`` with the first letter capitalized (e.g. ``Flags``). + +``@TYPE@`` + + The same as ``@type@`` with all letters uppercased (e.g. ``FLAGS``). + +``@filename@`` + + The full path of the input file currently being processed + (e.g. ``/build/environment/project/src/foo.h``). + +``@basename@`` + + The base name of the input file currently being processed (e.g. ``foo.h``). + Typically you want to use ``@basename@`` in place of ``@filename@`` + in your templates, to improve the reproducibility of the build. (Since: 2.22) + +TRIGRAPH EXTENSIONS +^^^^^^^^^^^^^^^^^^^ + +Some C comments are treated specially in the parsed enum definitions, such +comments start out with the trigraph sequence ``/*<`` and end with the trigraph +sequence ``>*/``. + +The following options can be specified per enum definition: + +``skip`` + + Indicates this enum definition should be skipped. + +``flags`` + + Indicates this enum should be treated as a flags definition. + +``underscore_name`` + + Specifies the word separation used in the ``*_get_type()`` + function. For instance, + ``/*< underscore_name=gnome_vfs_uri_hide_options >*/``. + +``since`` + + Specifies the version tag that will be used to substitute the ``@enumsince@`` + keyword in the template, useful when documenting methods generated from the + enums (e.g. ``Since: @enumsince@``). (Since: 2.66) + +The following options can be specified per value definition: + +``skip`` + + Indicates the value should be skipped. + +``nick`` + + Specifies the otherwise auto-generated nickname. + +Examples:: + + typedef enum /*< skip >*/ + { + PREFIX_FOO + } PrefixThisEnumWillBeSkipped; + typedef enum /*< flags,prefix=PREFIX,since=1.0 >*/ + { + PREFIX_THE_ZEROTH_VALUE, /*< skip >*/ + PREFIX_THE_FIRST_VALUE, + PREFIX_THE_SECOND_VALUE, + PREFIX_THE_THIRD_VALUE, /*< nick=the-last-value >*/ + } PrefixTheFlagsEnum; + +OPTIONS +------- + +``--fhead `` + + Emits ``TEXT`` prior to processing input files. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be prepended to the + template’s ``file-header`` section. + +``--fprod `` + + Emits ``TEXT`` every time a new input file is being processed. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be appended to the + template’s ``file-production`` section. + +``--ftail `` + + Emits ``TEXT`` after all input files have been processed. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be appended to the + template’s ``file-tail`` section. + +``--eprod `` + + Emits ``TEXT`` every time an enum is encountered in the input files. + +``--vhead `` + + Emits ``TEXT`` before iterating over the set of values of an enum. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be prepended to the + template’s ``value-header`` section. + +``--vprod `` + + Emits ``TEXT`` for every value of an enum. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be appended to the + template’s ``value-production`` section. + +``--vtail `` + + Emits ``TEXT`` after iterating over all values of an enum. + + You can specify this option multiple times, and the ``TEXT`` will be + concatenated. + + When used along with a template file, ``TEXT`` will be appended to the + template’s ``value-tail`` section. + +``--comments `` + + Template for auto-generated comments, the default (for C code generations) is + ``"/* @comment@ */"``. + +``--template `` + + Read templates from the given file. The templates are enclosed in + specially-formatted C comments:: + + /*** BEGIN section ***/ + /*** END section ***/ + + ``section`` may be ``file-header``, ``file-production``, ``file-tail``, + ``enumeration-production``, ``value-header``, ``value-production``, + ``value-tail`` or ``comment``. + +``--identifier-prefix `` + + Indicates what portion of the enum name should be interpreted as the prefix + (e.g. the ``Gtk`` in ``GtkDirectionType``). Normally this will be figured out + automatically, but you may need to override the default if your namespace is + capitalized oddly. + +``--symbol-prefix `` + + Indicates what prefix should be used to correspond to the identifier prefix in + related C function names (e.g. the ``gtk`` in + ``gtk_direction_type_get_type``). Equivalently, this is the lowercase version + of the prefix component of the enum value names (e.g. the ``GTK`` in + ``GTK_DIR_UP``). The default value is the identifier prefix, converted to + lowercase. + +``--help`` + + Print brief help and exit. + +``--version`` + + Print version and exit. + +``--output `` + + Write output to ``FILE`` instead of stdout. + +``@RSPFILE`` + + When passed as the sole argument, read and parse the actual arguments from + ``RSPFILE``. Useful on systems with a low command-line length limit. For + example, Windows has a limit of 8191 characters. + +USING TEMPLATES +--------------- + +Instead of passing the various sections of the generated file to the command +line of ``glib-mkenums``, it’s strongly recommended to use a template file, +especially for generating C sources. + +A C header template file will typically look like this:: + + /*** BEGIN file-header ***/ + #pragma once + + /* Include the main project header */ + #include "project.h" + + G_BEGIN_DECLS + /*** END file-header ***/ + + /*** BEGIN file-production ***/ + + /* enumerations from "@basename@" */ + /*** END file-production ***/ + + /*** BEGIN value-header ***/ + GType @enum_name@_get_type (void) G_GNUC_CONST; + #define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) + /*** END value-header ***/ + + /*** BEGIN file-tail ***/ + G_END_DECLS + /*** END file-tail ***/ + +A C source template file will typically look like this:: + + /*** BEGIN file-header ***/ + #include "config.h" + #include "enum-types.h" + + /*** END file-header ***/ + + /*** BEGIN file-production ***/ + /* enumerations from "@basename@" */ + /*** END file-production ***/ + + /*** BEGIN value-header ***/ + GType + @enum_name@_get_type (void) + { + static GType static_g_@type@_type_id = 0; + + if (g_once_init_enter_pointer (&static_g_@type@_type_id)) + { + static const G@Type@Value values[] = { + /*** END value-header ***/ + + /*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, + /*** END value-production ***/ + + /*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + GType g_@type@_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + + g_once_init_leave_pointer (&static_g_@type@_type_id, g_@type@_type_id); + } + + return static_g_@type@_type_id; + } + + /*** END value-tail ***/ + +Template files are easier to modify and update, and can be used to generate +various types of outputs using the same command line or tools during the build. + +USING GLIB-MKENUMS WITH MESON +----------------------------- + +Meson supports generating enumeration types using ``glib-mkenums`` out of the +box in its ``gnome`` module. + +In your ``meson.build`` file you will typically call the +``gnome.mkenums_simple()`` method to generate idiomatic enumeration types from a +list of headers to inspect:: + + project_headers = [ + 'project-foo.h', + 'project-bar.h', + 'project-baz.h', + ] + + gnome = import('gnome') + enum_files = gnome.mkenums_simple('enum-types', + sources: project_headers, + ) + +The ``enum_files`` variable will contain an array of two elements +in the following order: + +1. a build target for the source file +2. a build target for the header file + +You should use the returned objects to provide a dependency on every other +build target that references the source or header file; for instance, if you +are using the source to build a library:: + + mainlib = library('project', + sources: project_sources + enum_files, + … + ) + +Additionally, if you are including the generated header file inside a build +target that depends on the library you just built, you must ensure that the +internal dependency includes the generated header as a required source file:: + + mainlib_dep = declare_dependency(sources: enum_files[1], link_with: mainlib) + +You should not include the generated source file as well, otherwise it will +be built separately for every target that depends on it, causing build +failures. To know more about why all this is required, please refer to the +`corresponding Meson FAQ entry `_. + +If you are generating C header and source files that require special templates, +you can use ``gnome.mkenums()`` to provide those headers, for instance:: + + enum_files = gnome.mkenums('enum-types', + sources: project_headers, + h_template: 'enum-types.h.in', + c_template: 'enum-types.c.in', + install_header: true, + ) + +For more information, see the +`Meson documentation `_ +for ``gnome.mkenums()``. + +USING GLIB-MKENUMS WITH AUTOTOOLS +--------------------------------- + +In order to use ``glib-mkenums`` in your project when using Autotools as the +build system, you will first need to modify your ``configure.ac`` file to ensure +you find the appropriate command using ``pkg-config``, similarly as to how you +discover the compiler and linker flags for GLib:: + + PKG_PROG_PKG_CONFIG([0.28]) + + PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums]) + +In your ``Makefile.am`` file you will typically use rules like these:: + + # A list of headers to inspect + project_headers = \ + project-foo.h \ + project-bar.h \ + project-baz.h + + enum-types.h: $(project_headers) enum-types.h.in + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template=enum-types.h.in \ + --output=$@ \ + $(project_headers) + + enum-types.c: $(project_headers) enum-types.c.in enum-types.h + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template=enum-types.c.in \ + --output=$@ \ + $(project_headers) + + # Build the enum types files before every other target + BUILT_SOURCES += enum-types.h enum-types.c + CLEANFILES += enum-types.h enum-types.c + EXTRA_DIST += enum-types.h.in enum-types.c.in + +In the example above, we have a variable called ``project_headers`` where we +reference all header files we want to inspect for generating enumeration GTypes. +In the ``enum-types.h`` rule we use ``glib-mkenums`` with a template called +``enum-types.h.in`` in order to generate the header file; similarly, in the +``enum-types.c`` rule we use a template called ``enum-types.c.in``. + +SEE ALSO +-------- + +`glib-genmarshal(1) `_ \ No newline at end of file diff --git a/docs/reference/gobject/glib-mkenums.xml b/docs/reference/gobject/glib-mkenums.xml deleted file mode 100644 index f290fe0..0000000 --- a/docs/reference/gobject/glib-mkenums.xml +++ /dev/null @@ -1,659 +0,0 @@ - - - - gdbus - GObject - - - Developer - Owen - Taylor - - - - - -glib-mkenums -1 -User Commands - - - -glib-mkenums -C language enum description generation utility - - - - -glib-mkenums -OPTION -FILE - - - -Description -glib-mkenums is a small utility that parses C code to -extract enum definitions and produces enum descriptions based on text templates -specified by the user. Typically, you can use this tool to generate enumeration -types for the GType type system, for GObject properties and signal marshalling; -additionally, you can use it to generate enumeration values of GSettings schemas. - - -glib-mkenums takes a list of valid C code files as -input. The options specified control the text that generated, substituting various -keywords enclosed in @ characters in the templates. - - -Since version 2.74, GLib provides the G_DEFINE_ENUM_TYPE -and G_DEFINE_FLAGS_TYPE C pre-processor macros. These macros -can be used to define a GType for projects that have few, small enumeration -types without going through the complexities of generating code at build -time. - -Production text substitutions - -Certain keywords enclosed in @ characters will be substituted in the -emitted text. For the substitution examples of the keywords below, -the following example enum definition is assumed: - - -typedef enum -{ - PREFIX_THE_XVALUE = 1 << 3, - PREFIX_ANOTHER_VALUE = 1 << 4 -} PrefixTheXEnum; - - - -@EnumName@ - -The name of the enum currently being processed, enum names are assumed to be -properly namespaced and to use mixed capitalization to separate -words (e.g. PrefixTheXEnum). - - - - -@enum_name@ - -The enum name with words lowercase and word-separated by underscores -(e.g. prefix_the_xenum). - - - - -@ENUMNAME@ - -The enum name with words uppercase and word-separated by underscores -(e.g. PREFIX_THE_XENUM). - - - - -@ENUMSHORT@ - -The enum name with words uppercase and word-separated by underscores, -prefix stripped (e.g. THE_XENUM). - - - - -@ENUMPREFIX@ - -The prefix of the enum name (e.g. PREFIX). - - - - -@VALUENAME@ - -The enum value name currently being processed with words uppercase and -word-separated by underscores, -this is the assumed literal notation of enum values in the C sources -(e.g. PREFIX_THE_XVALUE). - - - - -@valuenick@ - -A nick name for the enum value currently being processed, this is usually -generated by stripping common prefix words of all the enum values of the -current enum, the words are lowercase and underscores are substituted by a -minus (e.g. the-xvalue). - - - - -@valuenum@ - -The integer value for the enum value currently being processed. If the -evaluation fails then glib-mkenums will exit with an -error status, but this only happens if @valuenum@ -appears in your value production template. (Since: 2.26) - - - - -@type@ - -This is substituted either by "enum" or "flags", depending on whether the -enum value definitions contained bit-shift operators or not (e.g. flags). - - - - -@Type@ - -The same as @type@ with the first letter capitalized (e.g. Flags). - - - - -@TYPE@ - -The same as @type@ with all letters uppercased (e.g. FLAGS). - - - - -@filename@ - -The full path of the input file currently being processed (e.g. /build/environment/project/src/foo.h). - - - - -@basename@ - -The base name of the input file currently being processed (e.g. foo.h). -Typically you want to use @basename@ in place of @filename@ -in your templates, to improve the reproducibility of the build. (Since: 2.22) - - - - -Trigraph extensions - -Some C comments are treated specially in the parsed enum definitions, -such comments start out with the trigraph sequence /*< -and end with the trigraph sequence >*/. - - -The following options can be specified per enum definition: - - -skip - -Indicates this enum definition should be skipped. - - - -flags - -Indicates this enum should be treated as a flags definition. - - - -underscore_name - -Specifies the word separation used in the *_get_type() -function. For instance, /*< underscore_name=gnome_vfs_uri_hide_options >*/. - - - -since - -Specifies the version tag that will be used to substitute the @enumsince@ -keyword in the template, useful when documenting methods generated from the enums -(e.g. Since: @enumsince@). (Since: 2.66) - - - - -The following options can be specified per value definition: - - -skip - -Indicates the value should be skipped. - - - -nick - -Specifies the otherwise auto-generated nickname. - - - - -Examples: - -typedef enum /*< skip >*/ -{ - PREFIX_FOO -} PrefixThisEnumWillBeSkipped; -typedef enum /*< flags,prefix=PREFIX,since=1.0 >*/ -{ - PREFIX_THE_ZEROTH_VALUE, /*< skip >*/ - PREFIX_THE_FIRST_VALUE, - PREFIX_THE_SECOND_VALUE, - PREFIX_THE_THIRD_VALUE, /*< nick=the-last-value >*/ -} PrefixTheFlagsEnum; - - - - -Options - - - - TEXT - -Emits TEXT prior to processing input files. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be prepended to the template's file-header section. - - - - - TEXT - -Emits TEXT every time a new input file -is being processed. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be appended to the template's file-production section. - - - - - TEXT - -Emits TEXT after all input files have been -processed. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be appended to the template's file-tail section. - - - - - TEXT - -Emits TEXT every time an enum is encountered -in the input files. - - - - - TEXT - -Emits TEXT before iterating over the set of -values of an enum. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be prepended to the template's value-header section. - - - - - TEXT - -Emits TEXT for every value of an enum. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be appended to the template's value-production section. - - - - - TEXT - -Emits TEXT after iterating over all values -of an enum. - - -You can specify this option multiple times, and the TEXT -will be concatenated. - - -When used along with a template file, TEXT -will be appended to the template's value-tail section. - - - - - TEXT - -Template for auto-generated comments, the default (for C code generations) is -"/* @comment@ */". - - - - - FILE - -Read templates from the given file. The templates are enclosed in -specially-formatted C comments: - - -/*** BEGIN section ***/ -/*** END section ***/ - - -section may be file-header, -file-production, file-tail, -enumeration-production, value-header, -value-production, value-tail or -comment. - - - - - PREFIX - -Indicates what portion of the enum name should be interpreted as the -prefix (eg, the "Gtk" in -"GtkDirectionType"). Normally this will be figured -out automatically, but you may need to override the default if your -namespace is capitalized oddly. - - - - - PREFIX - -Indicates what prefix should be used to correspond to the identifier -prefix in related C function names (eg, the "gtk" -in "gtk_direction_type_get_type". Equivalently, -this is the lowercase version of the prefix component of the enum -value names (eg, the "GTK" in -"GTK_DIR_UP". The default value is the identifier -prefix, converted to lowercase. - - - - - - -Print brief help and exit. - - - - - - -Print version and exit. - - - - - - -Write output to FILE instead of stdout. - - - - - - -When passed as the sole argument, read and parse the actual arguments from -RSPFILE. Useful on systems with a low command-line length -limit. For example, Windows has a limit of 8191 characters. - - - - - - -Using templates - -Instead of passing the various sections of the generated file to the command -line of glib-mkenums, it's strongly recommended to use a -template file, especially for generating C sources. - - - -A C header template file will typically look like this: - - -/*** BEGIN file-header ***/ -#pragma once - -/* Include the main project header */ -#include "project.h" - -G_BEGIN_DECLS -/*** END file-header ***/ - -/*** BEGIN file-production ***/ - -/* enumerations from "@basename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType @enum_name@_get_type (void) G_GNUC_CONST; -#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) -/*** END value-header ***/ - -/*** BEGIN file-tail ***/ -G_END_DECLS -/*** END file-tail ***/ - - - -A C source template file will typically look like this: - - -/*** BEGIN file-header ***/ -#include "config.h" -#include "enum-types.h" - -/*** END file-header ***/ - -/*** BEGIN file-production ***/ -/* enumerations from "@basename@" */ -/*** END file-production ***/ - -/*** BEGIN value-header ***/ -GType -@enum_name@_get_type (void) -{ - static gsize static_g_@type@_type_id; - - if (g_once_init_enter (&static_g_@type@_type_id)) - { - static const G@Type@Value values[] = { -/*** END value-header ***/ - -/*** BEGIN value-production ***/ - { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, -/*** END value-production ***/ - -/*** BEGIN value-tail ***/ - { 0, NULL, NULL } - }; - - GType g_@type@_type_id = - g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - - g_once_init_leave (&static_g_@type@_type_id, g_@type@_type_id); - } - return static_g_@type@_type_id; -} - -/*** END value-tail ***/ - - - -Template files are easier to modify and update, and can be used -to generate various types of outputs using the same command line -or tools during the build. - - - -Using glib-mkenums with Meson - -Meson supports generating enumeration types using glib-mkenums -out of the box in its "gnome" module. - - - -In your meson.build file you will typically call the -gnome.mkenums_simple() method to generate idiomatic enumeration -types from a list of headers to inspect: - - -project_headers = [ - 'project-foo.h', - 'project-bar.h', - 'project-baz.h', -] - -gnome = import('gnome') -enum_files = gnome.mkenums_simple('enum-types', - sources: project_headers, -) - - - -The enum_files variable will contain an array of two elements -in the following order: - - - a build target for the source file - a build target for the header file - - -You should use the returned objects to provide a dependency on every other -build target that references the source or header file; for instance, if you -are using the source to build a library: - - -mainlib = library('project', - sources: project_sources + enum_files, - ... -) - - -Additionally, if you are including the generated header file inside a build -target that depends on the library you just built, you must ensure that the -internal dependency includes the generated header as a required source file: - - -mainlib_dep = declare_dependency(sources: enum_files[1], link_with: mainlib) - - -You should not include the generated source file as well, otherwise it will -be built separately for every target that depends on it, causing build -failures. To know more about why all this is required, please refer to the - -corresponding Meson FAQ entry. - - - -If you are generating C header and source files that require special -templates, you can use gnome.mkenums() to provide those -headers, for instance: - - -enum_files = gnome.mkenums('enum-types', - sources: project_headers, - h_template: 'enum-types.h.in', - c_template: 'enum-types.c.in', - install_header: true, -) - - -For more information, see the Meson -documentation for gnome.mkenums(). - - - -Using glib-mkenums with Autotools - -In order to use glib-mkenums in your project when using -Autotools as the build system, you will first need to modify your -configure.ac file to ensure you find the appropriate -command using pkg-config, similarly as to how you discover -the compiler and linker flags for GLib. - - -PKG_PROG_PKG_CONFIG([0.28]) - -PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums]) - - -In your Makefile.am file you will typically use rules -like these: - - -# A list of headers to inspect -project_headers = \ - project-foo.h \ - project-bar.h \ - project-baz.h - -enum-types.h: $(project_headers) enum-types.h.in - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template=enum-types.h.in \ - --output=$@ \ - $(project_headers) - -enum-types.c: $(project_headers) enum-types.c.in enum-types.h - $(AM_V_GEN)$(GLIB_MKENUMS) \ - --template=enum-types.c.in \ - --output=$@ \ - $(project_headers) - -# Build the enum types files before every other target -BUILT_SOURCES += enum-types.h enum-types.c -CLEANFILES += enum-types.h enum-types.c -EXTRA_DIST += enum-types.h.in enum-types.c.in - - -In the example above, we have a variable called project_headers -where we reference all header files we want to inspect for generating enumeration -GTypes. In the enum-types.h rule we use glib-mkenums -with a template called enum-types.h.in in order to generate the -header file; similarly, in the enum-types.c rule we use a -template called enum-types.c.in. - - - -See also - - -glib-genmarshal -1 - - - - diff --git a/docs/reference/gobject/gobject-docs.xml b/docs/reference/gobject/gobject-docs.xml deleted file mode 100644 index 69147e2..0000000 --- a/docs/reference/gobject/gobject-docs.xml +++ /dev/null @@ -1,236 +0,0 @@ - - - -]> - - - GObject Reference Manual - - for GObject &version; - The latest version of this documentation can be found on-line at - https://developer.gnome.org/gobject/unstable/. - - - - - Introduction - - Most modern programming languages come with their own native object - systems and additional fundamental algorithmic language constructs. - Just as GLib serves as an implementation of such fundamental - types and algorithms (linked lists, hash tables and so forth), the - GLib Object System provides the required implementations of a - flexible, extensible, and intentionally easy to map (into other - languages) object-oriented framework for C. - The substantial elements that are provided can be summarized as: - - - A generic type system to register arbitrary single-inherited - flat and deep derived types as well as interfaces for - structured types. - It takes care of creation, initialization and memory management - of the assorted object and class structures, maintains - parent/child relationships and deals with dynamic implementations - of such types. That is, their type specific implementations are - relocatable/unloadable during runtime. - - - A collection of fundamental type implementations, such as integers, - doubles, enums and structured types, to name a few. - - - A sample fundamental type implementation to base object hierarchies - upon - the GObject fundamental type. - - - A signal system that allows very flexible user customization of - virtual/overridable object methods and can serve as a powerful - notification mechanism. - - - An extensible parameter/value system, supporting all the provided - fundamental types that can be used to generically handle object - properties or otherwise parameterized types. - - - - - - - Concepts - - - - - - - - API Reference - - - - - - - - - - - - - - - - - - - - Tools Reference - - - - - - - - - - - Index - - - - Index of deprecated symbols - - - - Index of new symbols in 2.2 - - - - Index of new symbols in 2.4 - - - - Index of new symbols in 2.6 - - - - Index of new symbols in 2.8 - - - - Index of new symbols in 2.10 - - - - Index of new symbols in 2.12 - - - - Index of new symbols in 2.14 - - - - Index of new symbols in 2.18 - - - - Index of new symbols in 2.22 - - - - Index of new symbols in 2.24 - - - - Index of new symbols in 2.26 - - - - Index of new symbols in 2.28 - - - - Index of new symbols in 2.30 - - - - Index of new symbols in 2.32 - - - - Index of new symbols in 2.34 - - - - Index of new symbols in 2.36 - - - - Index of new symbols in 2.38 - - - - Index of new symbols in 2.40 - - - - Index of new symbols in 2.42 - - - - Index of new symbols in 2.44 - - - - Index of new symbols in 2.46 - - - - Index of new symbols in 2.54 - - - - Index of new symbols in 2.56 - - - - Index of new symbols in 2.62 - - - - Index of new symbols in 2.66 - - - - Index of new symbols in 2.68 - - - - Index of new symbols in 2.70 - - - - Index of new symbols in 2.72 - - - - Index of new symbols in 2.74 - - - - Index of new symbols in 2.76 - - - - Index of new symbols in 2.78 - - - - - - diff --git a/docs/reference/gobject/gobject-overrides.txt b/docs/reference/gobject/gobject-overrides.txt deleted file mode 100644 index e69de29..0000000 diff --git a/docs/reference/gobject/gobject-query.rst b/docs/reference/gobject/gobject-query.rst new file mode 100644 index 0000000..4aa4d0c --- /dev/null +++ b/docs/reference/gobject/gobject-query.rst @@ -0,0 +1,74 @@ +.. _gobject-query(1): +.. meta:: + :copyright: Copyright 2003 Matthias Clasen + :copyright: Copyright 2012 Red Hat, Inc. + :license: LGPL-2.1-or-later +.. + This has to be duplicated from above to make it machine-readable by `reuse`: + SPDX-FileCopyrightText: 2003 Matthias Clasen + SPDX-FileCopyrightText: 2012 Red Hat, Inc. + SPDX-License-Identifier: LGPL-2.1-or-later + +============= +gobject-query +============= + +----------------------- +display a tree of types +----------------------- + +SYNOPSIS +-------- + +| **gobject-query** froots [*OPTION*…] +| **gobject-query** tree [*OPTION*…] + +DESCRIPTION +----------- + +``gobject-query`` is a small utility that draws a tree of types. + +It takes a mandatory argument that specifies whether it should iterate over the +fundamental types or print a type tree. + +COMMANDS +-------- + +``froots`` + + Iterate over fundamental roots. + +``tree`` + + Print type tree. + +OPTIONS +------- + +``-r `` + + Specify the root type. + +``-n`` + + Don’t descend type tree. + +``-b `` + + Specify indent string. + +``-i `` + + Specify incremental indent string. + +``-s `` + + Specify line spacing. + +``-h``, ``--help`` + + Print brief help and exit. + +``-v``, ``--version`` + + Print version and exit. \ No newline at end of file diff --git a/docs/reference/gobject/gobject-query.xml b/docs/reference/gobject/gobject-query.xml deleted file mode 100644 index 437d714..0000000 --- a/docs/reference/gobject/gobject-query.xml +++ /dev/null @@ -1,123 +0,0 @@ - - - - gobject-query - GObject - - - Developer - Tim - Janik - - - - - -gobject-query -1 -User Commands - - - -gobject-query -display a tree of types - - - - -gobject-query -froots -OPTION - - -gobject-query -tree -OPTION - - - -Description - -gobject-query is a small utility that draws a tree of -types. - - - -gobject-query takes a mandatory argument that specifies -whether it should iterate over the fundamental types or print a type tree. - - - -Commands - - - - -iterate over fundamental roots - - - - - -print type tree - - - - - -Options - - - - TYPE - -specify the root type - - - - - - -don't descend type tree - - - - - STRING - -specify indent string - - - - - STRING - -specify incremental indent string - - - - - - NUMBER - -specify line spacing - - - - -, - -Print brief help and exit. - - - - -, - -Print version and exit. - - - - - - diff --git a/docs/reference/gobject/gobject-sections.txt b/docs/reference/gobject/gobject-sections.txt deleted file mode 100644 index 8b0d330..0000000 --- a/docs/reference/gobject/gobject-sections.txt +++ /dev/null @@ -1,1060 +0,0 @@ -glib-object.h - -
-gtype -Type Information -GType -G_TYPE_FUNDAMENTAL -G_TYPE_FUNDAMENTAL_MAX -G_TYPE_MAKE_FUNDAMENTAL -G_TYPE_IS_ABSTRACT -G_TYPE_IS_DERIVED -G_TYPE_IS_FUNDAMENTAL -G_TYPE_IS_VALUE_TYPE -G_TYPE_HAS_VALUE_TABLE -G_TYPE_IS_CLASSED -G_TYPE_IS_INSTANTIATABLE -G_TYPE_IS_DERIVABLE -G_TYPE_IS_DEEP_DERIVABLE -G_TYPE_IS_INTERFACE -G_TYPE_IS_FINAL -G_TYPE_IS_DEPRECATED -GTypeInterface -GTypeInstance -GTypeClass -GTypeInfo -GTypeFundamentalInfo -GInterfaceInfo -GTypeValueInitFunc -GTypeValueFreeFunc -GTypeValueCopyFunc -GTypeValuePeekPointerFunc -GTypeValueCollectFunc -GTypeValueLCopyFunc -GTypeValueTable -G_TYPE_FROM_INSTANCE -G_TYPE_FROM_CLASS -G_TYPE_FROM_INTERFACE -G_TYPE_INSTANCE_GET_CLASS -G_TYPE_INSTANCE_GET_INTERFACE -G_TYPE_INSTANCE_GET_PRIVATE -G_TYPE_CLASS_GET_PRIVATE -G_TYPE_CHECK_INSTANCE -G_TYPE_CHECK_INSTANCE_CAST -G_TYPE_CHECK_INSTANCE_TYPE -G_TYPE_CHECK_INSTANCE_FUNDAMENTAL_TYPE -G_TYPE_CHECK_CLASS_CAST -G_TYPE_CHECK_CLASS_TYPE -G_TYPE_CHECK_VALUE -G_TYPE_CHECK_VALUE_TYPE -G_TYPE_FLAG_RESERVED_ID_BIT -g_type_init -GTypeDebugFlags -g_type_init_with_debug_flags -g_type_name -g_type_qname -g_type_from_name -g_type_parent -g_type_depth -g_type_next_base -g_type_is_a -g_type_class_ref -g_type_class_peek -g_type_class_peek_static -g_type_class_unref -g_type_class_peek_parent -g_type_class_add_private -g_type_add_class_private -g_type_interface_peek -g_type_interface_peek_parent -g_type_default_interface_ref -g_type_default_interface_peek -g_type_default_interface_unref -g_type_children -g_type_interfaces -g_type_interface_prerequisites -g_type_interface_instantiatable_prerequisite -g_type_set_qdata -g_type_get_qdata -g_type_query -GTypeQuery -GBaseInitFunc -GBaseFinalizeFunc -GClassInitFunc -GClassFinalizeFunc -GInstanceInitFunc -GInterfaceInitFunc -GInterfaceFinalizeFunc -GTypeClassCacheFunc -GTypeFlags -GTypeFundamentalFlags -g_type_register_static -g_type_register_static_simple -g_type_register_dynamic -g_type_register_fundamental -g_type_add_interface_static -g_type_add_interface_dynamic -g_type_interface_add_prerequisite -g_type_get_plugin -g_type_interface_get_plugin -g_type_fundamental_next -g_type_fundamental -g_type_create_instance -g_type_free_instance -g_type_add_class_cache_func -g_type_remove_class_cache_func -g_type_class_unref_uncached -g_type_add_interface_check -g_type_remove_interface_check -GTypeInterfaceCheckFunc -g_type_value_table_peek -g_type_ensure -g_type_get_type_registration_serial -g_type_get_instance_count - -G_DECLARE_FINAL_TYPE -G_DECLARE_DERIVABLE_TYPE -G_DECLARE_INTERFACE -G_DEFINE_TYPE -G_DEFINE_TYPE_WITH_PRIVATE -G_DEFINE_TYPE_WITH_CODE -G_DEFINE_ABSTRACT_TYPE -G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE -G_DEFINE_ABSTRACT_TYPE_WITH_CODE -G_DEFINE_FINAL_TYPE -G_DEFINE_FINAL_TYPE_WITH_PRIVATE -G_DEFINE_FINAL_TYPE_WITH_CODE -G_ADD_PRIVATE -G_PRIVATE_OFFSET -G_PRIVATE_FIELD -G_PRIVATE_FIELD_P -G_DEFINE_INTERFACE -G_DEFINE_INTERFACE_WITH_CODE -G_IMPLEMENT_INTERFACE -G_DEFINE_TYPE_EXTENDED -G_DEFINE_BOXED_TYPE -G_DEFINE_BOXED_TYPE_WITH_CODE -G_DEFINE_POINTER_TYPE -G_DEFINE_POINTER_TYPE_WITH_CODE -G_DEFINE_ENUM_VALUE -G_DEFINE_ENUM_TYPE -G_DEFINE_FLAGS_TYPE - - -G_TYPE_FUNDAMENTAL_SHIFT -g_type_check_instance -g_type_check_instance_cast -g_type_check_instance_is_a -g_type_check_instance_is_fundamentally_a -g_type_check_class_cast -g_type_check_class_is_a -g_type_check_is_value_type -g_type_check_value -g_type_check_value_holds -g_type_class_adjust_private_offset -g_type_add_instance_private -g_type_instance_get_private -g_type_class_get_instance_private_offset -g_type_class_get_private -g_type_test_flags -g_type_name_from_instance -g_type_name_from_class - - -G_TYPE_INVALID -G_TYPE_NONE -G_TYPE_INTERFACE -G_TYPE_CHAR -G_TYPE_UCHAR -G_TYPE_BOOLEAN -G_TYPE_INT -G_TYPE_UINT -G_TYPE_LONG -G_TYPE_ULONG -G_TYPE_INT64 -G_TYPE_UINT64 -G_TYPE_ENUM -G_TYPE_FLAGS -G_TYPE_FLOAT -G_TYPE_DOUBLE -G_TYPE_STRING -G_TYPE_POINTER -G_TYPE_BOXED -G_TYPE_PARAM -G_TYPE_OBJECT -G_TYPE_GTYPE -G_TYPE_VARIANT -G_TYPE_CHECKSUM - - -G_TYPE_RESERVED_GLIB_FIRST -G_TYPE_RESERVED_GLIB_LAST -G_TYPE_RESERVED_BSE_FIRST -G_TYPE_RESERVED_BSE_LAST -G_TYPE_RESERVED_USER_FIRST -
- -
-gtypeplugin -GTypePlugin -GTypePlugin -GTypePluginClass -GTypePluginUse -GTypePluginUnuse -GTypePluginCompleteTypeInfo -GTypePluginCompleteInterfaceInfo -g_type_plugin_use -g_type_plugin_unuse -g_type_plugin_complete_type_info -g_type_plugin_complete_interface_info - -G_TYPE_PLUGIN -G_IS_TYPE_PLUGIN -G_TYPE_TYPE_PLUGIN -g_type_plugin_get_type -G_TYPE_PLUGIN_CLASS -G_IS_TYPE_PLUGIN_CLASS -G_TYPE_PLUGIN_GET_CLASS -
- -
-gtypemodule -GTypeModule -GTypeModule -GTypeModuleClass -g_type_module_use -g_type_module_unuse -g_type_module_set_name -g_type_module_register_type -g_type_module_add_interface -g_type_module_register_enum -g_type_module_register_flags - -G_DEFINE_DYNAMIC_TYPE -G_DEFINE_DYNAMIC_TYPE_EXTENDED -G_IMPLEMENT_INTERFACE_DYNAMIC -G_ADD_PRIVATE_DYNAMIC - - -G_TYPE_MODULE -G_IS_TYPE_MODULE -G_TYPE_TYPE_MODULE -g_type_module_get_type -G_TYPE_MODULE_CLASS -G_IS_TYPE_MODULE_CLASS -G_TYPE_MODULE_GET_CLASS -
- -
-The Base Object Type -objects -GObject -GObjectClass -GObjectConstructParam -GObjectGetPropertyFunc -GObjectSetPropertyFunc -GObjectFinalizeFunc -G_TYPE_IS_OBJECT -G_OBJECT -G_IS_OBJECT -G_OBJECT_CLASS -G_IS_OBJECT_CLASS -G_OBJECT_GET_CLASS -G_OBJECT_TYPE -G_OBJECT_TYPE_NAME -G_OBJECT_CLASS_TYPE -G_OBJECT_CLASS_NAME -g_object_class_install_property -g_object_class_install_properties -g_object_class_find_property -g_object_class_list_properties -g_object_class_override_property -g_object_interface_install_property -g_object_interface_find_property -g_object_interface_list_properties -g_object_new -g_object_new_with_properties -g_object_newv -GParameter -g_object_ref -g_object_unref -g_object_ref_sink -g_object_take_ref -g_set_object -g_clear_object -GInitiallyUnowned -GInitiallyUnownedClass -G_TYPE_INITIALLY_UNOWNED -g_object_is_floating -g_object_force_floating -GWeakNotify -g_object_weak_ref -g_object_weak_unref -g_object_add_weak_pointer -g_object_remove_weak_pointer -g_set_weak_pointer -g_clear_weak_pointer -GToggleNotify -g_object_add_toggle_ref -g_object_remove_toggle_ref -g_object_connect -g_object_disconnect -g_object_set -g_object_setv -g_object_get -g_object_getv -g_object_notify -g_object_notify_by_pspec -g_object_freeze_notify -g_object_thaw_notify -g_object_get_data -g_object_set_data -g_object_set_data_full -g_object_steal_data -g_object_dup_data -g_object_replace_data -g_object_get_qdata -g_object_set_qdata -g_object_set_qdata_full -g_object_steal_qdata -g_object_dup_qdata -g_object_replace_qdata -g_object_set_property -g_object_get_property -g_object_new_valist -g_object_set_valist -g_object_get_valist -g_object_watch_closure -g_object_run_dispose -G_OBJECT_WARN_INVALID_PROPERTY_ID - - -GWeakRef -g_weak_ref_init -g_weak_ref_clear -g_weak_ref_get -g_weak_ref_set - - -g_assert_finalize_object - - -G_INITIALLY_UNOWNED -G_INITIALLY_UNOWNED_CLASS -G_INITIALLY_UNOWNED_GET_CLASS -G_IS_INITIALLY_UNOWNED -G_IS_INITIALLY_UNOWNED_CLASS - - -G_OBJECT_WARN_INVALID_PSPEC -g_initially_unowned_get_type -g_object_compat_control -g_object_get_type -
- -
-Enumeration and Flag Types -enumerations_flags -GEnumClass -GFlagsClass -G_ENUM_CLASS_TYPE -G_ENUM_CLASS_TYPE_NAME -G_TYPE_IS_ENUM -G_ENUM_CLASS -G_IS_ENUM_CLASS -G_TYPE_IS_FLAGS -G_FLAGS_CLASS -G_IS_FLAGS_CLASS -G_FLAGS_CLASS_TYPE -G_FLAGS_CLASS_TYPE_NAME -GEnumValue -GFlagsValue -g_enum_get_value -g_enum_get_value_by_name -g_enum_get_value_by_nick -g_enum_to_string -g_flags_get_first_value -g_flags_get_value_by_name -g_flags_get_value_by_nick -g_flags_to_string -g_enum_register_static -g_flags_register_static -g_enum_complete_type_info -g_flags_complete_type_info -
- -
-gboxed -Boxed Types -GBoxedCopyFunc -GBoxedFreeFunc -g_boxed_copy -g_boxed_free -g_boxed_type_register_static -g_pointer_type_register_static - - -G_TYPE_HASH_TABLE -G_TYPE_DATE -G_TYPE_GSTRING -G_TYPE_STRV -G_TYPE_REGEX -G_TYPE_MATCH_INFO -G_TYPE_ARRAY -G_TYPE_BYTE_ARRAY -G_TYPE_PTR_ARRAY -G_TYPE_BYTES -G_TYPE_VARIANT_TYPE -G_TYPE_ERROR -G_TYPE_DATE_TIME -G_TYPE_TIME_ZONE -G_TYPE_IO_CHANNEL -G_TYPE_IO_CONDITION -G_TYPE_VARIANT_BUILDER -G_TYPE_VARIANT_DICT -G_TYPE_KEY_FILE -G_TYPE_MAIN_CONTEXT -G_TYPE_MAIN_LOOP -G_TYPE_MAPPED_FILE -G_TYPE_MARKUP_PARSE_CONTEXT -G_TYPE_SOURCE -G_TYPE_POLLFD -G_TYPE_THREAD -G_TYPE_OPTION_GROUP -G_TYPE_URI -G_TYPE_TREE -G_TYPE_PATTERN_SPEC -G_TYPE_BOOKMARK_FILE - - -G_TYPE_IS_BOXED - - -g_gstring_get_type -g_strv_get_type -g_date_get_type -g_hash_table_get_type -g_regex_get_type -g_match_info_get_type -g_array_get_type -g_byte_array_get_type -g_ptr_array_get_type -g_error_get_type -g_date_time_get_type -g_time_zone_get_type -g_variant_get_gtype -g_variant_type_get_gtype -g_variant_builder_get_type -g_variant_dict_get_type -g_gtype_get_type -g_main_context_get_type -g_main_loop_get_type -g_source_get_type -g_pollfd_get_type -g_bytes_get_type -g_key_file_get_type -g_checksum_get_type -g_mapped_file_get_type -g_markup_parse_context_get_type -g_thread_get_type -g_option_group_get_type -g_uri_get_type -g_tree_get_type -g_pattern_spec_get_type -g_bookmark_file_get_type -
- -
-Generic values -generic_values -G_VALUE_INIT -G_VALUE_HOLDS -G_VALUE_TYPE -G_VALUE_TYPE_NAME -G_TYPE_IS_VALUE -G_TYPE_IS_VALUE_ABSTRACT -G_IS_VALUE -GValue -G_TYPE_VALUE -G_TYPE_VALUE_ARRAY -g_value_init -g_value_copy -g_value_reset -g_value_unset -g_value_init_from_instance -g_value_set_instance -g_value_fits_pointer -g_value_peek_pointer -g_value_type_compatible -g_value_type_transformable -g_value_transform -GValueTransform -g_value_register_transform_func -g_strdup_value_contents - - -G_VALUE_NOCOPY_CONTENTS -g_value_get_type -g_value_array_get_type -
- -
-Value arrays -value_arrays -GValueArray -g_value_array_get_nth -g_value_array_new -g_value_array_copy -g_value_array_free -g_value_array_append -g_value_array_prepend -g_value_array_insert -g_value_array_remove -g_value_array_sort -g_value_array_sort_with_data -
- -
-GParamSpec -gparamspec -G_TYPE_IS_PARAM -G_PARAM_SPEC -G_IS_PARAM_SPEC -G_PARAM_SPEC_CLASS -G_IS_PARAM_SPEC_CLASS -G_PARAM_SPEC_GET_CLASS -G_PARAM_SPEC_TYPE -G_PARAM_SPEC_TYPE_NAME -G_PARAM_SPEC_VALUE_TYPE -GParamSpec -GParamSpecClass -GParamFlags -G_PARAM_STATIC_STRINGS -G_PARAM_MASK -G_PARAM_USER_SHIFT -g_param_spec_ref -g_param_spec_unref -g_param_spec_sink -g_param_spec_ref_sink -g_param_spec_get_default_value -g_param_value_set_default -g_param_value_defaults -g_param_value_validate -g_param_value_is_valid -g_param_value_convert -g_param_values_cmp -g_param_spec_is_valid_name -g_param_spec_get_name -g_param_spec_get_name_quark -g_param_spec_get_nick -g_param_spec_get_blurb -g_param_spec_get_qdata -g_param_spec_set_qdata -g_param_spec_set_qdata_full -g_param_spec_steal_qdata -g_param_spec_get_redirect_target -g_param_spec_internal -GParamSpecTypeInfo -g_param_type_register_static -GParamSpecPool -g_param_spec_pool_new -g_param_spec_pool_insert -g_param_spec_pool_remove -g_param_spec_pool_lookup -g_param_spec_pool_list -g_param_spec_pool_list_owned -
- -
-Standard Parameter and Value Types -param_value_types - - -G_IS_PARAM_SPEC_BOOLEAN -G_PARAM_SPEC_BOOLEAN -G_VALUE_HOLDS_BOOLEAN -G_TYPE_PARAM_BOOLEAN -GParamSpecBoolean -g_param_spec_boolean -g_value_set_boolean -g_value_get_boolean - - -G_IS_PARAM_SPEC_CHAR -G_PARAM_SPEC_CHAR -G_VALUE_HOLDS_CHAR -G_TYPE_PARAM_CHAR -GParamSpecChar -g_param_spec_char -g_value_set_char -g_value_get_char -g_value_get_schar -g_value_set_schar - - -G_IS_PARAM_SPEC_UCHAR -G_PARAM_SPEC_UCHAR -G_VALUE_HOLDS_UCHAR -G_TYPE_PARAM_UCHAR -GParamSpecUChar -g_param_spec_uchar -g_value_set_uchar -g_value_get_uchar - - -G_IS_PARAM_SPEC_INT -G_PARAM_SPEC_INT -G_VALUE_HOLDS_INT -G_TYPE_PARAM_INT -GParamSpecInt -g_param_spec_int -g_value_set_int -g_value_get_int - - -G_IS_PARAM_SPEC_UINT -G_PARAM_SPEC_UINT -G_VALUE_HOLDS_UINT -G_TYPE_PARAM_UINT -GParamSpecUInt -g_param_spec_uint -g_value_set_uint -g_value_get_uint - - -G_IS_PARAM_SPEC_LONG -G_PARAM_SPEC_LONG -G_VALUE_HOLDS_LONG -G_TYPE_PARAM_LONG -GParamSpecLong -g_param_spec_long -g_value_set_long -g_value_get_long - - -G_IS_PARAM_SPEC_ULONG -G_PARAM_SPEC_ULONG -G_VALUE_HOLDS_ULONG -G_TYPE_PARAM_ULONG -GParamSpecULong -g_param_spec_ulong -g_value_set_ulong -g_value_get_ulong - - -G_IS_PARAM_SPEC_INT64 -G_PARAM_SPEC_INT64 -G_VALUE_HOLDS_INT64 -G_TYPE_PARAM_INT64 -GParamSpecInt64 -g_param_spec_int64 -g_value_set_int64 -g_value_get_int64 - - -G_IS_PARAM_SPEC_UINT64 -G_PARAM_SPEC_UINT64 -G_VALUE_HOLDS_UINT64 -G_TYPE_PARAM_UINT64 -GParamSpecUInt64 -g_param_spec_uint64 -g_value_set_uint64 -g_value_get_uint64 - - -G_IS_PARAM_SPEC_FLOAT -G_PARAM_SPEC_FLOAT -G_VALUE_HOLDS_FLOAT -G_TYPE_PARAM_FLOAT -GParamSpecFloat -g_param_spec_float -g_value_set_float -g_value_get_float - - -G_IS_PARAM_SPEC_DOUBLE -G_PARAM_SPEC_DOUBLE -G_VALUE_HOLDS_DOUBLE -G_TYPE_PARAM_DOUBLE -GParamSpecDouble -g_param_spec_double -g_value_set_double -g_value_get_double - - -G_IS_PARAM_SPEC_ENUM -G_PARAM_SPEC_ENUM -G_VALUE_HOLDS_ENUM -G_TYPE_PARAM_ENUM -GParamSpecEnum -g_param_spec_enum -g_value_set_enum -g_value_get_enum - - -G_IS_PARAM_SPEC_FLAGS -G_PARAM_SPEC_FLAGS -G_VALUE_HOLDS_FLAGS -G_TYPE_PARAM_FLAGS -GParamSpecFlags -g_param_spec_flags -g_value_set_flags -g_value_get_flags - - -G_IS_PARAM_SPEC_STRING -G_PARAM_SPEC_STRING -G_VALUE_HOLDS_STRING -G_TYPE_PARAM_STRING -G_VALUE_IS_INTERNED_STRING -G_VALUE_INTERNED_STRING -GParamSpecString -gchararray -g_param_spec_string -g_value_set_string -g_value_set_static_string -g_value_take_string -g_value_set_string_take_ownership -g_value_get_string -g_value_dup_string -g_value_set_interned_string - - -G_IS_PARAM_SPEC_PARAM -G_PARAM_SPEC_PARAM -G_VALUE_HOLDS_PARAM -G_TYPE_PARAM_PARAM -GParamSpecParam -g_param_spec_param -g_value_set_param -g_value_take_param -g_value_set_param_take_ownership -g_value_get_param -g_value_dup_param - - -G_IS_PARAM_SPEC_BOXED -G_PARAM_SPEC_BOXED -G_VALUE_HOLDS_BOXED -G_TYPE_PARAM_BOXED -GParamSpecBoxed -g_param_spec_boxed -g_value_set_boxed -g_value_set_static_boxed -g_value_take_boxed -g_value_set_boxed_take_ownership -g_value_get_boxed -g_value_dup_boxed - - -G_IS_PARAM_SPEC_POINTER -G_PARAM_SPEC_POINTER -G_VALUE_HOLDS_POINTER -G_TYPE_PARAM_POINTER -GParamSpecPointer -g_param_spec_pointer -g_value_set_pointer -g_value_get_pointer - - -G_IS_PARAM_SPEC_OBJECT -G_PARAM_SPEC_OBJECT -G_VALUE_HOLDS_OBJECT -G_TYPE_PARAM_OBJECT -GParamSpecObject -g_param_spec_object -g_value_set_object -g_value_take_object -g_value_set_object_take_ownership -g_value_get_object -g_value_dup_object - - -G_IS_PARAM_SPEC_UNICHAR -G_PARAM_SPEC_UNICHAR -G_TYPE_PARAM_UNICHAR -GParamSpecUnichar -g_param_spec_unichar - - -G_IS_PARAM_SPEC_VALUE_ARRAY -G_PARAM_SPEC_VALUE_ARRAY -G_TYPE_PARAM_VALUE_ARRAY -GParamSpecValueArray -g_param_spec_value_array - - -G_IS_PARAM_SPEC_OVERRIDE -G_PARAM_SPEC_OVERRIDE -G_TYPE_PARAM_OVERRIDE -GParamSpecOverride -g_param_spec_override - - -G_IS_PARAM_SPEC_GTYPE -G_PARAM_SPEC_GTYPE -G_VALUE_HOLDS_GTYPE -G_TYPE_PARAM_GTYPE -GParamSpecGType -g_param_spec_gtype -g_value_get_gtype -g_value_set_gtype - - -G_IS_PARAM_SPEC_VARIANT -G_PARAM_SPEC_VARIANT -G_VALUE_HOLDS_VARIANT -G_TYPE_PARAM_VARIANT -GParamSpecVariant -g_param_spec_variant -g_value_get_variant -g_value_dup_variant -g_value_set_variant -g_value_take_variant - - -g_value_set_instance -g_param_spec_types -
- -
-Varargs Value Collection -value_collection -glib-object.h,gobject/gvaluecollector.h -GTypeCValue -G_VALUE_COLLECT_INIT -G_VALUE_COLLECT_INIT2 -G_VALUE_COLLECT -G_VALUE_COLLECT_SKIP -G_VALUE_LCOPY -G_VALUE_COLLECT_FORMAT_MAX_LENGTH -
- -
-Signals -signals -GSignalInvocationHint -GSignalAccumulator -GSignalCMarshaller -GSignalCVaMarshaller -GSignalEmissionHook -GSignalFlags -GSignalMatchType -GSignalQuery -G_SIGNAL_TYPE_STATIC_SCOPE -G_SIGNAL_MATCH_MASK -G_SIGNAL_FLAGS_MASK -g_signal_new -g_signal_newv -g_signal_new_valist -g_signal_set_va_marshaller -g_signal_query -g_signal_lookup -g_signal_name -g_signal_list_ids -g_signal_emit -g_signal_emit_by_name -g_signal_emitv -g_signal_emit_valist -g_signal_connect -g_signal_connect_after -g_signal_connect_swapped -g_signal_connect_object -GConnectFlags -g_signal_connect_data -g_signal_connect_closure -g_signal_connect_closure_by_id -g_signal_handler_block -g_signal_handler_unblock -g_signal_handler_disconnect -g_signal_handler_find -g_signal_handlers_block_matched -g_signal_handlers_unblock_matched -g_signal_handlers_disconnect_matched -g_signal_handler_is_connected -g_signal_handlers_block_by_func -g_signal_handlers_unblock_by_func -g_signal_handlers_disconnect_by_func -g_signal_handlers_disconnect_by_data -g_signal_has_handler_pending -g_signal_stop_emission -g_signal_stop_emission_by_name -g_signal_override_class_closure -g_signal_chain_from_overridden -g_signal_new_class_handler -g_signal_override_class_handler -g_signal_chain_from_overridden_handler -g_signal_add_emission_hook -g_signal_remove_emission_hook -g_signal_is_valid_name -g_signal_parse_name -g_signal_get_invocation_hint -g_signal_type_cclosure_new -g_signal_accumulator_first_wins -g_signal_accumulator_true_handled -g_clear_signal_handler - -g_signal_handlers_destroy -
- -
-gclosure -Closures -G_CLOSURE_NEEDS_MARSHAL -G_CLOSURE_N_NOTIFIERS -G_CCLOSURE_SWAP_DATA -G_CALLBACK -GCallback -GClosure -G_TYPE_CLOSURE -GCClosure -GClosureMarshal -GVaClosureMarshal -GClosureNotify -g_cclosure_new -g_cclosure_new_swap -g_cclosure_new_object -g_cclosure_new_object_swap -g_cclosure_marshal_generic -g_closure_new_object -g_closure_ref -g_closure_sink -g_closure_unref -g_closure_invoke -g_closure_invalidate -g_closure_add_finalize_notifier -g_closure_add_invalidate_notifier -g_closure_remove_finalize_notifier -g_closure_remove_invalidate_notifier -g_closure_new_simple -g_closure_set_marshal -g_closure_add_marshal_guards -g_closure_set_meta_marshal -g_source_set_closure -g_source_set_dummy_callback - - -g_cclosure_marshal_VOID__VOID -g_cclosure_marshal_VOID__BOOLEAN -g_cclosure_marshal_VOID__CHAR -g_cclosure_marshal_VOID__UCHAR -g_cclosure_marshal_VOID__INT -g_cclosure_marshal_VOID__UINT -g_cclosure_marshal_VOID__LONG -g_cclosure_marshal_VOID__ULONG -g_cclosure_marshal_VOID__ENUM -g_cclosure_marshal_VOID__FLAGS -g_cclosure_marshal_VOID__FLOAT -g_cclosure_marshal_VOID__DOUBLE -g_cclosure_marshal_VOID__STRING -g_cclosure_marshal_VOID__PARAM -g_cclosure_marshal_VOID__BOXED -g_cclosure_marshal_VOID__POINTER -g_cclosure_marshal_VOID__OBJECT -g_cclosure_marshal_VOID__VARIANT -g_cclosure_marshal_STRING__OBJECT_POINTER -g_cclosure_marshal_VOID__UINT_POINTER -g_cclosure_marshal_BOOLEAN__FLAGS -g_cclosure_marshal_BOOL__FLAGS -g_cclosure_marshal_BOOLEAN__BOXED_BOXED -g_cclosure_marshal_BOOL__BOXED_BOXED - - -g_cclosure_marshal_generic_va -g_cclosure_marshal_VOID__VOIDv -g_cclosure_marshal_VOID__BOOLEANv -g_cclosure_marshal_VOID__CHARv -g_cclosure_marshal_VOID__UCHARv -g_cclosure_marshal_VOID__INTv -g_cclosure_marshal_VOID__UINTv -g_cclosure_marshal_VOID__LONGv -g_cclosure_marshal_VOID__ULONGv -g_cclosure_marshal_VOID__ENUMv -g_cclosure_marshal_VOID__FLAGSv -g_cclosure_marshal_VOID__FLOATv -g_cclosure_marshal_VOID__DOUBLEv -g_cclosure_marshal_VOID__STRINGv -g_cclosure_marshal_VOID__PARAMv -g_cclosure_marshal_VOID__BOXEDv -g_cclosure_marshal_VOID__POINTERv -g_cclosure_marshal_VOID__OBJECTv -g_cclosure_marshal_VOID__VARIANTv -g_cclosure_marshal_STRING__OBJECT_POINTERv -g_cclosure_marshal_VOID__UINT_POINTERv -g_cclosure_marshal_BOOLEAN__FLAGSv -g_cclosure_marshal_BOOLEAN__BOXED_BOXEDv - - -GClosureNotifyData -g_closure_get_type -g_io_channel_get_type -g_io_condition_get_type -
- -
-gbinding -GBinding -GBindingFlags -g_binding_get_source -g_binding_dup_source -g_binding_get_source_property -g_binding_get_target -g_binding_dup_target -g_binding_get_target_property -g_binding_get_flags -g_binding_unbind - -g_object_bind_property -GBindingTransformFunc -g_object_bind_property_full -g_object_bind_property_with_closures - -G_TYPE_BINDING -G_TYPE_BINDING_FLAGS -G_BINDING -G_IS_BINDING - -g_binding_flags_get_type -g_binding_get_type -
- -
-gbindinggroup -GBindingGroup -g_binding_group_new -g_binding_group_dup_source -g_binding_group_set_source -g_binding_group_bind -g_binding_group_bind_full -g_binding_group_bind_with_closures - -G_TYPE_BINDING_GROUP -G_TYPE_BINDING_GROUP_CLASS -G_BINDING_GROUP -G_IS_BINDING_GROUP - -g_binding_group_get_type -
- -
-gsignalgroup -GSignalGroup -g_signal_group_block -g_signal_group_connect -g_signal_group_connect_after -g_signal_group_connect_data -g_signal_group_connect_object -g_signal_group_connect_swapped -g_signal_group_connect_closure -g_signal_group_dup_target -g_signal_group_get_type -g_signal_group_new -g_signal_group_set_target -g_signal_group_unblock - -G_IS_SIGNAL_GROUP -G_SIGNAL_GROUP -G_TYPE_SIGNAL_GROUP - -g_signal_group_get_type -
diff --git a/docs/reference/gobject/gobject.toml.in b/docs/reference/gobject/gobject.toml.in new file mode 100644 index 0000000..de39bc4 --- /dev/null +++ b/docs/reference/gobject/gobject.toml.in @@ -0,0 +1,64 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# Copyright 2023 Matthias Clasen +# Copyright 2023 Philip Withnall + +[library] +name = "GObject" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/glib/" +repository_url = "https://gitlab.gnome.org/GNOME/glib.git" +website_url = "https://www.gtk.org" +docs_url = "https://docs.gtk.org/gobject/" +authors = "GLib Development Team" +license = "LGPL-2.1-or-later" +description = "The base type system and object class" +devhelp = true +search_index = true +dependencies = ["GLib-2.0"] + + [dependencies."GLib-2.0"] + name = "GLib" + description = "The base utility library" + docs_url = "https://docs.gtk.org/glib/" + +related = ["GModule-2.0", "Gio-2.0"] + + [related."GModule-2.0"] + name = "GModule" + description = "Portable API for dynamically loading modules" + docs_url = "https://docs.gtk.org/gmodule/" + + [related."Gio-2.0"] + name = "GIO" + description = "GObject Interfaces and Objects, Networking, IPC, and I/O" + docs_url = "https://docs.gtk.org/gio/" + +[theme] +name = "basic" +show_index_summary = true +show_class_hierarchy = true + +[extra] +urlmap_file = "urlmap.js" +# The same order will be used when generating the index +content_files = [ + "concepts.md", + "tutorial.md", + "types.md", + "signals.md", + "floating-refs.md", + "boxed.md", + "enum-types.md", + "gvalue.md", + "value-collection.md", +] +content_images = [ + "images/glue.png", +] + +# This is the anonymous union inside GValue; we don't need it +# as a type, and including it just generates a dummy union +# definition +[[object]] +name = "_Value__data__union" +hidden = true diff --git a/docs/reference/gobject/gvalue.md b/docs/reference/gobject/gvalue.md new file mode 100644 index 0000000..e2af92b --- /dev/null +++ b/docs/reference/gobject/gvalue.md @@ -0,0 +1,108 @@ +Title: Generic Value Container + +# Generic Value Container + +The [`struct@GObject.Value`] structure is basically a variable container +that consists of a type identifier and a specific value of that type. The +type identifier within a `GValue` structure always determines the type of the +associated value. + +To create an undefined `GValue` structure, simply create a zero-filled +GValue structure. To initialize the `GValue`, use the +[`method@GObject.Value.init`] function. A `GValue` cannot be used until it +is initialized. + +Once you have finished using a `GValue`, you must call +[`method@GObject.Value.unset`] to ensure that all the resources associated +with the `GValue` are freed. + +The basic type operations (such as freeing and copying) are determined by +the [`struct@GObject.TypeValueTable`] associated with the type ID stored in +the `GValue`. Other `GValue` operations (such as converting values between +types) are provided by this interface. + +The code in the example program below demonstrates `GValue`'s features: + +```c +#include + +static void +int2string (const GValue *src_value, + GValue *dest_value) +{ + if (g_value_get_int (src_value) == 42) + g_value_set_static_string (dest_value, "An important number"); + else + g_value_set_static_string (dest_value, "What's that?"); +} + +int +main (int argc, + char *argv[]) +{ + // GValues must be initialized + GValue a = G_VALUE_INIT; + GValue b = G_VALUE_INIT; + const char *message; + + // The GValue starts empty + g_assert (!G_VALUE_HOLDS_STRING (&a)); + + // Put a string in it + g_value_init (&a, G_TYPE_STRING); + g_assert (G_VALUE_HOLDS_STRING (&a)); + g_value_set_static_string (&a, "Hello, world!"); + g_printf ("%s\n", g_value_get_string (&a)); + + // Reset it to its pristine state + g_value_unset (&a); + + // It can then be reused for another type + g_value_init (&a, G_TYPE_INT); + g_value_set_int (&a, 42); + + // Attempt to transform it into a GValue of type STRING + g_value_init (&b, G_TYPE_STRING); + + // An INT is transformable to a STRING + g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING)); + + g_value_transform (&a, &b); + g_printf ("%s\n", g_value_get_string (&b)); + + // Attempt to transform it again using a custom transform function + g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string); + g_value_transform (&a, &b); + g_printf ("%s\n", g_value_get_string (&b)); + + g_value_unset (&b); + g_value_unset (&a); + + return 0; +} +``` + +For letting a `GValue` own (and memory manage) arbitrary types or pointers, +they need to become a [boxed type](boxed.html). The example below shows how +the pointer `mystruct` of type `MyStruct` is used as a [boxed type](boxed.html). + +```c +typedef struct { ... } MyStruct; +G_DEFINE_BOXED_TYPE (MyStruct, my_struct, my_struct_copy, my_struct_free) + +// These two lines normally go in a public header. By GObject convention, +// the naming scheme is NAMESPACE_TYPE_NAME: +#define MY_TYPE_STRUCT (my_struct_get_type ()) +GType my_struct_get_type (void); + +void +foo (void) +{ + GValue *value = g_new0 (GValue, 1); + g_value_init (value, MY_TYPE_STRUCT); + g_value_set_boxed (value, mystruct); + // [... your code ....] + g_value_unset (value); + g_free (value); +} +``` diff --git a/docs/reference/gobject/meson.build b/docs/reference/gobject/meson.build index dd3e53d..03355b7 100644 --- a/docs/reference/gobject/meson.build +++ b/docs/reference/gobject/meson.build @@ -1,70 +1,52 @@ -if get_option('gtk_doc') - subdir('xml') - - ignore_headers = [ - 'tests', - 'gatomicarray.h', - 'gobject_probes.h', - 'gobject_trace.h', - 'gtype-private.h', - 'glib-enumtypes.h', - 'gobject-visibility.h', - ] - - docpath = join_paths(glib_datadir, 'gtk-doc', 'html') - version_conf = configuration_data() - version_conf.set('GLIB_VERSION', meson.project_version()) - configure_file( - input: 'version.xml.in', - output: 'version.xml', - configuration: version_conf - ) - - gtkdocincl = include_directories('.') - - gnome.gtkdoc('gobject', - main_xml : 'gobject-docs.xml', - namespace : 'g', - mode : 'none', - dependencies : [libgobject_dep, libglib_dep], - include_directories : [gtkdocincl], - src_dir : 'gobject', - scan_args : [ - '--ignore-decorators=' + '|'.join(ignore_decorators.replace('GLIB', 'GOBJECT')), - '--rebuild-types', - '--ignore-headers=' + ' '.join(ignore_headers), - ], - content_files : [ - 'glib-mkenums.xml', - 'glib-genmarshal.xml', - 'gobject-query.xml', - 'tut_gobject.xml', - 'tut_gsignal.xml', - 'tut_gtype.xml', - 'tut_howto.xml', - 'tut_intro.xml', - 'tut_tools.xml' - ], - html_assets : [ - 'images/glue.png' - ], - fixxref_args: [ - '--html-dir=' + docpath, - '--extra-dir=' + join_paths('gobject', '..', 'glib', 'html'), - ], - install: true, - check: true, - ) -endif - -if get_option('man') +if get_option('man-pages').enabled() manpages = ['glib-mkenums', 'glib-genmarshal', 'gobject-query'] foreach page : manpages custom_target(page + '-man', - input: page + '.xml', + input: page + '.rst', output: page + '.1', - command: xsltproc_command, + command: [ + rst2man, + rst2man_flags, + '@INPUT@', + ], + capture: true, install: true, - install_dir: man1_dir) + install_dir: man1_dir, + install_tag: 'doc', + ) endforeach endif + +expand_content_files = [ + 'boxed.md', + 'concepts.md', + 'enum-types.md', + 'floating-refs.md', + 'gvalue.md', + 'tutorial.md', + 'types.md', + 'signals.md', + 'value-collection.md', +] + +gobject_toml = configure_file(input: 'gobject.toml.in', output: 'gobject.toml', configuration: toml_conf) + +custom_target('gobject-docs', + input: [ gobject_toml, gobject_gir[0] ], + output: 'gobject', + command: [ + gidocgen, + 'generate', + gidocgen_common_args, + '--config=@INPUT0@', + '--output-dir=@OUTPUT@', + '--content-dir=@0@'.format(meson.current_source_dir()), + '--add-include-path=@0@'.format(meson.current_build_dir() / '../../../gobject'), + '@INPUT1@', + ], + build_by_default: true, + depend_files: expand_content_files, + install: true, + install_dir: docs_dir, + install_tag: 'doc', +) diff --git a/docs/reference/gobject/signals.md b/docs/reference/gobject/signals.md new file mode 100644 index 0000000..0486cd9 --- /dev/null +++ b/docs/reference/gobject/signals.md @@ -0,0 +1,95 @@ +Title: Signals +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2000, 2001 Tim Janik +SPDX-FileCopyrightText: 2000 Owen Taylor +SPDX-FileCopyrightText: 2002, 2014 Matthias Clasen +SPDX-FileCopyrightText: 2014 Collabora, Ltd. +SPDX-FileCopyrightText: 2019 Endless Mobile, Inc. + +# Signals + +The basic concept of the signal system is that of the emission +of a signal. Signals are introduced per-type and are identified +through strings. Signals introduced for a parent type are available +in derived types as well, so basically they are a per-type facility +that is inherited. + +A signal emission mainly involves invocation of a certain set of +callbacks in precisely defined manner. There are two main categories +of such callbacks, per-object ones and user provided ones. +(Although signals can deal with any kind of instantiatable type, I'm +referring to those types as "object types" in the following, simply +because that is the context most users will encounter signals in.) +The per-object callbacks are most often referred to as "object method +handler" or "default (signal) handler", while user provided callbacks are +usually just called "signal handler". + +The object method handler is provided at signal creation time (this most +frequently happens at the end of an object class' creation), while user +provided handlers are frequently connected and disconnected to/from a +certain signal on certain object instances. + +A signal emission consists of five stages, unless prematurely stopped: + +1. Invocation of the object method handler for `G_SIGNAL_RUN_FIRST` signals + +2. Invocation of normal user-provided signal handlers (where the @after + flag is not set) + +3. Invocation of the object method handler for `G_SIGNAL_RUN_LAST` signals + +4. Invocation of user provided signal handlers (where the @after flag is set) + +5. Invocation of the object method handler for `G_SIGNAL_RUN_CLEANUP` signals + +The user-provided signal handlers are called in the order they were +connected in. + +All handlers may prematurely stop a signal emission, and any number of +handlers may be connected, disconnected, blocked or unblocked during +a signal emission. + +There are certain criteria for skipping user handlers in stages 2 and 4 +of a signal emission. + +First, user handlers may be blocked. Blocked handlers are omitted during +callback invocation, to return from the blocked state, a handler has to +get unblocked exactly the same amount of times it has been blocked before. + +Second, upon emission of a `G_SIGNAL_DETAILED` signal, an additional +`detail` argument passed in to [func@GObject.signal_emit] has to match +the detail argument of the signal handler currently subject to invocation. +Specification of no detail argument for signal handlers (omission of the +detail part of the signal specification upon connection) serves as a +wildcard and matches any detail argument passed in to emission. + +While the `detail` argument is typically used to pass an object property name +(as with `GObject::notify`), no specific format is mandated for the detail +string, other than that it must be non-empty. + +## Memory management of signal handlers + +If you are connecting handlers to signals and using a `GObject` instance as +your signal handler user data, you should remember to pair calls to +[func@GObject.signal_connect] with calls to [func@GObject.signal_handler_disconnect] +or [func@GObject.signal_handlers_disconnect_by_func]. While signal handlers are +automatically disconnected when the object emitting the signal is finalised, +they are not automatically disconnected when the signal handler user data is +destroyed. If this user data is a `GObject` instance, using it from a +signal handler after it has been finalised is an error. + +There are two strategies for managing such user data. The first is to +disconnect the signal handler (using [func@GObject.signal_handler_disconnect] +or [func@GObject.signal_handlers_disconnect_by_func]) when the user data (object) +is finalised; this has to be implemented manually. For non-threaded programs, +[func@GObject.signal_connect_object] can be used to implement this automatically. +Currently, however, it is unsafe to use in threaded programs. + +The second is to hold a strong reference on the user data until after the +signal is disconnected for other reasons. This can be implemented +automatically using [func@GObject.signal_connect_data]. + +The first approach is recommended, as the second approach can result in +effective memory leaks of the user data if the signal handler is never +disconnected for some reason. + diff --git a/docs/reference/gobject/tut_gobject.xml b/docs/reference/gobject/tut_gobject.xml deleted file mode 100644 index 53f38ab..0000000 --- a/docs/reference/gobject/tut_gobject.xml +++ /dev/null @@ -1,728 +0,0 @@ - - - - The GObject base class - - - The previous chapter discussed the details of GLib's Dynamic Type System. - The GObject library also contains an implementation for a base fundamental - type named GObject. - - - - GObject is a fundamental classed instantiatable type. It implements: - - Memory management with reference counting - Construction/Destruction of instances - Generic per-object properties with set/get function pairs - Easy use of signals - - All the GNOME libraries which use the GLib type system (like GTK and GStreamer) - inherit from GObject which is why it is important to understand - the details of how it works. - - - - Object instantiation - - - The g_object_new - family of functions can be used to instantiate any GType which inherits - from the GObject base type. All these functions make sure the class and - instance structures have been correctly initialized by GLib's type system - and then invoke at one point or another the constructor class method - which is used to: - - - Allocate and clear memory through g_type_create_instance, - - - Initialize the object's instance with the construction properties. - - - Although one can expect all class and instance members (except the fields - pointing to the parents) to be set to zero, some consider it good practice - to explicitly set them. - - - - Once all construction operations have been completed and constructor - properties set, the constructed class method is called. - - - - Objects which inherit from GObject are allowed to override this - constructed class method. - The example below shows how ViewerFile overrides the parent's construction process: - -#define VIEWER_TYPE_FILE viewer_file_get_type () -G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) - -struct _ViewerFile -{ - GObject parent_instance; - - /* instance members */ - gchar *filename; - guint zoom_level; -}; - -/* will create viewer_file_get_type and set viewer_file_parent_class */ -G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) - -static void -viewer_file_constructed (GObject *obj) -{ - /* update the object state depending on constructor properties */ - - /* Always chain up to the parent constructed function to complete object - * initialisation. */ - G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj); -} - -static void -viewer_file_finalize (GObject *obj) -{ - ViewerFile *self = VIEWER_FILE (obj); - - g_free (self->filename); - - /* Always chain up to the parent finalize function to complete object - * destruction. */ - G_OBJECT_CLASS (viewer_file_parent_class)->finalize (obj); -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->constructed = viewer_file_constructed; - object_class->finalize = viewer_file_finalize; -} - -static void -viewer_file_init (ViewerFile *self) -{ - /* initialize the object */ -} - - - If the user instantiates an object ViewerFile with: - -ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL); - - If this is the first instantiation of such an object, the - viewer_file_class_init function will be invoked - after any viewer_file_base_class_init function. - This will make sure the class structure of this new object is - correctly initialized. Here, viewer_file_class_init - is expected to override the object's class methods and setup the - class' own methods. In the example above, the constructed - method is the only overridden method: it is set to - viewer_file_constructed. - - - - Once g_object_new has obtained a reference to an initialized - class structure, it invokes its constructor method to create an instance of the new - object, if the constructor has been overridden in viewer_file_class_init. - Overridden constructors must chain up to their parent’s constructor. In - order to find the parent class and chain up to the parent class - constructor, we can use the viewer_file_parent_class - pointer that has been set up for us by the - G_DEFINE_TYPE - macro. - - - - Finally, at one point or another, g_object_constructor is invoked - by the last constructor in the chain. This function allocates the object's instance buffer - through g_type_create_instance - which means that the instance_init function is invoked at this point if one - was registered. After instance_init returns, the object is fully initialized and should be - ready to have its methods called by the user. When - g_type_create_instance - returns, g_object_constructor sets the construction properties - (i.e. the properties which were given to g_object_new) and returns - to the user's constructor. - - - - The process described above might seem a bit complicated, but it can be - summarized easily by the table below which lists the functions invoked - by g_object_new - and their order of invocation: - - - - - <function><link linkend="g-object-new">g_object_new</link></function> - - - - - - - - Invocation time - Function invoked - Function's parameters - Remark - - - - - First call to g_object_new for target type - target type's base_init function - On the inheritance tree of classes from fundamental type to target type. - base_init is invoked once for each class structure. - Never used in practice. Unlikely you will need it. - - - - target type's class_init function - On target type's class structure - - Here, you should make sure to initialize or override class methods (that is, - assign to each class' method its function pointer) and create the signals and - the properties associated to your object. - - - - - interface's base_init function - On interface's vtable - - - - - interface's interface_init function - On interface's vtable - - - - Each call to g_object_new for target type - target type's class constructor method: GObjectClass->constructor - On object's instance - - If you need to handle construct properties in a custom way, or implement a singleton class, override the constructor - method and make sure to chain up to the object's - parent class before doing your own initialization. - In doubt, do not override the constructor method. - - - - - type's instance_init function - On the inheritance tree of classes from fundamental type to target type. - the instance_init provided for each type is invoked once for each instance - structure. - - Provide an instance_init function to initialize your object before its construction - properties are set. This is the preferred way to initialize a GObject instance. - This function is equivalent to C++ constructors. - - - - - target type's class constructed method: GObjectClass->constructed - On object's instance - - If you need to perform object initialization steps after all construct properties have been set. - This is the final step in the object initialization process, and is only called if the constructor - method returned a new object instance (rather than, for example, an existing singleton). - - - - -
-
- - - Readers should feel concerned about one little twist in the order in - which functions are invoked: while, technically, the class' constructor - method is called before the GType's instance_init - function (since g_type_create_instance which calls instance_init is called by - g_object_constructor which is the top-level class - constructor method and to which users are expected to chain to), the - user's code which runs in a user-provided constructor will always - run after GType's instance_init function since the - user-provided constructor must (you've been warned) - chain up before doing anything useful. - -
- - - Object memory management - - - The memory-management API for GObjects is a bit complicated but the idea behind it - is pretty simple: the goal is to provide a flexible model based on reference counting - which can be integrated in applications which use or require different memory management - models (such as garbage collection). The methods which are used to - manipulate this reference count are described below. - - - - Reference count - - - The functions g_object_ref/g_object_unref respectively - increase and decrease the reference count. These functions are - thread-safe. - g_clear_object - is a convenience wrapper around g_object_unref - which also clears the pointer passed to it. - - - The reference count is initialized to one by - g_object_new which means that the caller - is currently the sole owner of the newly-created reference. (If the object is derived from GInitiallyUnowned, this reference count is floating.) - When the reference count reaches zero, that is, - when g_object_unref is called by the last client holding - a reference to the object, the dispose and the - finalize class methods are invoked. - - - Finally, after finalize is invoked, - g_type_free_instance is called to free the object instance. - Depending on the memory allocation policy decided when the type was registered (through - one of the g_type_register_* functions), the object's instance - memory will be freed or returned to the object pool for this type. - Once the object has been freed, if it was the last instance of the type, the type's class - will be destroyed as described in and - . - - - - The table below summarizes the destruction process of a GObject: - - <function><link linkend="g-object-unref">g_object_unref</link></function> - - - - - - - - Invocation time - Function invoked - Function's parameters - Remark - - - - - Last call to g_object_unref for an instance - of target type - - target type's dispose class function - GObject instance - - When dispose ends, the object should not hold any reference to any other - member object. The object is also expected to be able to answer client - method invocations (with possibly an error code but no memory violation) - until finalize is executed. dispose can be executed more than once. - dispose should chain up to its parent implementation just before returning - to the caller. - - - - - target type's finalize class function - GObject instance - - Finalize is expected to complete the destruction process initiated by - dispose. It should complete the object's destruction. finalize will be - executed only once. - finalize should chain up to its parent implementation just before returning - to the caller. - The reason why the destruction process is split is two different phases is - explained in . - - - - Last call to g_object_unref for the last - instance of target type - - interface's interface_finalize function - On interface's vtable - Never used in practice. Unlikely you will need it. - - - - interface's base_finalize function - On interface's vtable - Never used in practice. Unlikely you will need it. - - - - target type's class_finalize function - On target type's class structure - Never used in practice. Unlikely you will need it. - - - - type's base_finalize function - On the inheritance tree of classes from fundamental type to target type. - base_init is invoked once for each class structure. - Never used in practice. Unlikely you will need it. - - - -
-
- -
- - - Weak References - - - Weak references are used to monitor object finalization: - g_object_weak_ref adds a monitoring callback which does - not hold a reference to the object but which is invoked when the object runs - its dispose method. As such, each weak ref can be invoked more than once upon - object finalization (since dispose can run more than once during object - finalization). - - - - g_object_weak_unref can be used to remove a monitoring - callback from the object. - - - - Weak references are also used to implement g_object_add_weak_pointer - and g_object_remove_weak_pointer. These functions add a weak reference - to the object they are applied to which makes sure to nullify the pointer given by the user - when object is finalized. - - - - Similarly, GWeakRef can be - used to implement weak references if thread safety is required. - - - - - Reference counts and cycles - - - GObject's memory management model was designed to be easily integrated in existing code - using garbage collection. This is why the destruction process is split in two phases: - the first phase, executed in the dispose handler is supposed to release all references - to other member objects. The second phase, executed by the finalize handler is supposed - to complete the object's destruction process. Object methods should be able to run - without program error in-between the two phases. - - - - This two-step destruction process is very useful to break reference counting cycles. - While the detection of the cycles is up to the external code, once the cycles have been - detected, the external code can invoke g_object_run_dispose which - will indeed break any existing cycles since it will run the dispose handler associated - to the object and thus release all references to other objects. - - - - This explains one of the rules about the dispose handler stated earlier: - the dispose handler can be invoked multiple times. Let's say we - have a reference count cycle: object A references B which itself references object A. - Let's say we have detected the cycle and we want to destroy the two objects. One way to - do this would be to invoke g_object_run_dispose on one of the - objects. - - - - If object A releases all its references to all objects, this means it releases its - reference to object B. If object B was not owned by anyone else, this is its last - reference count which means this last unref runs B's dispose handler which, in turn, - releases B's reference on object A. If this is A's last reference count, this last - unref runs A's dispose handler which is running for the second time before - A's finalize handler is invoked ! - - - - The above example, which might seem a bit contrived, can really happen if - GObjects are being handled by language bindings — hence the rules for - object destruction should be closely followed. - - -
- - - Object properties - - - One of GObject's nice features is its generic get/set mechanism for object - properties. When an object - is instantiated, the object's class_init handler should be used to register - the object's properties with g_object_class_install_properties. - - - - The best way to understand how object properties work is by looking at a real example - of how it is used: - -/************************************************/ -/* Implementation */ -/************************************************/ - -typedef enum -{ - PROP_FILENAME = 1, - PROP_ZOOM_LEVEL, - N_PROPERTIES -} ViewerFileProperty; - -static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; - -static void -viewer_file_set_property (GObject *object, - guint property_id, - const GValue *value, - GParamSpec *pspec) -{ - ViewerFile *self = VIEWER_FILE (object); - - switch ((ViewerFileProperty) property_id) - { - case PROP_FILENAME: - g_free (self->filename); - self->filename = g_value_dup_string (value); - g_print ("filename: %s\n", self->filename); - break; - - case PROP_ZOOM_LEVEL: - self->zoom_level = g_value_get_uint (value); - g_print ("zoom level: %u\n", self->zoom_level); - break; - - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -viewer_file_get_property (GObject *object, - guint property_id, - GValue *value, - GParamSpec *pspec) -{ - ViewerFile *self = VIEWER_FILE (object); - - switch ((ViewerFileProperty) property_id) - { - case PROP_FILENAME: - g_value_set_string (value, self->filename); - break; - - case PROP_ZOOM_LEVEL: - g_value_set_uint (value, self->zoom_level); - break; - - default: - /* We don't have any other property... */ - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); - break; - } -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = viewer_file_set_property; - object_class->get_property = viewer_file_get_property; - - obj_properties[PROP_FILENAME] = - g_param_spec_string ("filename", - "Filename", - "Name of the file to load and display from.", - NULL /* default value */, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ZOOM_LEVEL] = - g_param_spec_uint ("zoom-level", - "Zoom level", - "Zoom level to view the file at.", - 0 /* minimum value */, - 10 /* maximum value */, - 2 /* default value */, - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties (object_class, - N_PROPERTIES, - obj_properties); -} - -/************************************************/ -/* Use */ -/************************************************/ - -ViewerFile *file; -GValue val = G_VALUE_INIT; - -file = g_object_new (VIEWER_TYPE_FILE, NULL); - -g_value_init (&val, G_TYPE_UINT); -g_value_set_char (&val, 11); - -g_object_set_property (G_OBJECT (file), "zoom-level", &val); - -g_value_unset (&val); - - The client code above looks simple but a lot of things happen under the hood: - - - - g_object_set_property first ensures a property - with this name was registered in file's class_init handler. If so it walks the class hierarchy, - from bottom-most most-derived type, to top-most fundamental type to find the class - which registered that property. It then tries to convert the user-provided - GValue - into a GValue whose type is that of the associated property. - - - - If the user provides a signed char GValue, as is shown - here, and if the object's property was registered as an unsigned int, - g_value_transform will try to transform the input signed char into - an unsigned int. Of course, the success of the transformation depends on the availability - of the required transform function. In practice, there will almost always be a transformation - - Its behaviour might not be what you expect but it is up to you to actually avoid - relying on these transformations. - - - which matches and conversion will be carried out if needed. - - - - After transformation, the GValue is validated by - g_param_value_validate which makes sure the user's - data stored in the GValue matches the characteristics specified by - the property's GParamSpec. - Here, the GParamSpec we - provided in class_init has a validation function which makes sure that the GValue - contains a value which respects the minimum and maximum bounds of the - GParamSpec. In the example above, the client's GValue does not - respect these constraints (it is set to 11, while the maximum is 10). As such, the - g_object_set_property function will return with an error. - - - - If the user's GValue had been set to a valid value, g_object_set_property - would have proceeded with calling the object's - set_property class method. Here, since our - implementation of ViewerFile did override this method, execution would jump to - viewer_file_set_property after having retrieved from the - GParamSpec the param_id - - - It should be noted that the param_id used here need only to uniquely identify each - GParamSpec within the ViewerFileClass such that the switch - used in the set and get methods actually works. Of course, this locally-unique - integer is purely an optimization: it would have been possible to use a set of - if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {} statements. - - - which had been stored by - g_object_class_install_property. - - - - Once the property has been set by the object's - set_property class method, execution - returns to g_object_set_property which makes sure that - the "notify" signal is emitted on the object's instance with the changed property as - parameter unless notifications were frozen by g_object_freeze_notify. - - - - g_object_thaw_notify can be used to re-enable notification of - property modifications through the - “notify” signal. It is important to remember that - even if properties are changed while property change notification is frozen, the "notify" - signal will be emitted once for each of these changed properties as soon as the property - change notification is thawed: no property change is lost for the "notify" - signal, although multiple notifications for a single property are - compressed. Signals can only be delayed by the notification freezing - mechanism. - - - - It sounds like a tedious task to set up GValues every time when one wants to modify a property. - In practice one will rarely do this. The functions g_object_set_property - and g_object_get_property - are meant to be used by language bindings. For application there is an easier way and - that is described next. - - - - Accessing multiple properties at once - - - It is interesting to note that the g_object_set and - g_object_set_valist (variadic version) functions can be used to set - multiple properties at once. The client code shown above can then be re-written as: - -ViewerFile *file; -file = /* */; -g_object_set (G_OBJECT (file), - "zoom-level", 6, - "filename", "~/some-file.txt", - NULL); - - This saves us from managing the GValues that we were needing to handle when using - g_object_set_property. - The code above will trigger one notify signal emission for each property modified. - - - - Equivalent _get versions are also available: - g_object_get - and g_object_get_valist (variadic version) can be used to get numerous - properties at once. - - - - These high level functions have one drawback — they don't provide a return value. - One should pay attention to the argument types and ranges when using them. - A known source of errors is to pass a different type from what the - property expects; for instance, passing an integer when the property - expects a floating point value and thus shifting all subsequent parameters - by some number of bytes. Also forgetting the terminating - NULL will lead to undefined behaviour. - - - - This explains how g_object_new, - g_object_newv and g_object_new_valist - work: they parse the user-provided variable number of parameters and invoke - g_object_set on the parameters only after the object has been successfully constructed. - The "notify" signal will be emitted for each property set. - - - - - - - - -
diff --git a/docs/reference/gobject/tut_gsignal.xml b/docs/reference/gobject/tut_gsignal.xml deleted file mode 100644 index d690d16..0000000 --- a/docs/reference/gobject/tut_gsignal.xml +++ /dev/null @@ -1,495 +0,0 @@ - - - - The GObject messaging system - - - Closures - - - Closures are central to the concept of asynchronous signal delivery - which is widely used throughout GTK and GNOME applications. A closure is an - abstraction, a generic representation of a callback. It is a small structure - which contains three objects: - - a function pointer (the callback itself) whose prototype looks like: - -return_type function_callback (… , gpointer user_data); - - - - the user_data pointer which is passed to the callback upon invocation of the closure - - - a function pointer which represents the destructor of the closure: whenever the - closure's refcount reaches zero, this function will be called before the closure - structure is freed. - - - - - - The GClosure structure represents the common functionality of all - closure implementations: there exists a different closure implementation for - each separate runtime which wants to use the GObject type system. - - In practice, closures sit at the boundary of language runtimes: if you are - writing Python code and one of your Python callbacks receives a signal from - a GTK widget, the C code in GTK needs to execute your Python - code. The closure invoked by the GTK object invokes the Python callback: - it behaves as a normal C object for GTK and as a normal Python object for - Python code. - - The GObject library provides a simple GCClosure type which - is a specific implementation of closures to be used with C/C++ callbacks. - - - A GClosure provides simple services: - - - Invocation (g_closure_invoke): this is what closures - were created for: they hide the details of callback invocation from the - callback invoker. - - - Notification: the closure notifies listeners of certain events such as - closure invocation, closure invalidation and closure finalization. Listeners - can be registered with g_closure_add_finalize_notifier - (finalization notification), g_closure_add_invalidate_notifier - (invalidation notification) and - g_closure_add_marshal_guards (invocation notification). - There exist symmetric deregistration functions for finalization and invalidation - events (g_closure_remove_finalize_notifier and - g_closure_remove_invalidate_notifier) but not for the invocation - process. - - Closures are reference counted and notify listeners of their destruction in a two-stage - process: the invalidation notifiers are invoked before the finalization notifiers. - - - - - - - C Closures - - - If you are using C or C++ - to connect a callback to a given event, you will either use simple GCClosures - which have a pretty minimal API or the even simpler g_signal_connect - functions (which will be presented a bit later). - - - - g_cclosure_new will create a new closure which can invoke the - user-provided callback_func with the user-provided - user_data as its last parameter. When the closure - is finalized (second stage of the destruction process), it will invoke - the destroy_data function if the user has - supplied one. - - - - g_cclosure_new_swap will create a new closure which can invoke the - user-provided callback_func with the - user-provided user_data as its first parameter - (instead of being the - last parameter as with g_cclosure_new). When the closure - is finalized (second stage of the destruction process), it will invoke - the destroy_data function if the user has - supplied one. - - - - - Non-C closures (for the fearless) - - - As was explained above, closures hide the details of callback invocation. In C, - callback invocation is just like function invocation: it is a matter of creating - the correct stack frame for the called function and executing a call - assembly instruction. - - - - C closure marshallers transform the array of GValues which represent - the parameters to the target function into a C-style function parameter list, invoke - the user-supplied C function with this new parameter list, get the return value of the - function, transform it into a GValue and return this GValue to the marshaller caller. - - - - A generic C closure marshaller is available as - g_cclosure_marshal_generic - which implements marshalling for all function types using libffi. Custom - marshallers for different types are not needed apart from performance - critical code where the libffi-based marshaller may be too slow. - - - - An example of a custom marshaller is given below, illustrating how - GValues can be converted to a C function call. The - marshaller is for a C function which takes an integer as its first - parameter and returns void. - -g_cclosure_marshal_VOID__INT (GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - typedef void (*GMarshalFunc_VOID__INT) (gpointer data1, - gint arg_1, - gpointer data2); - register GMarshalFunc_VOID__INT callback; - register GCClosure *cc = (GCClosure*) closure; - register gpointer data1, data2; - - g_return_if_fail (n_param_values == 2); - - data1 = g_value_peek_pointer (param_values + 0); - data2 = closure->data; - - callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback); - - callback (data1, - g_marshal_value_peek_int (param_values + 1), - data2); -} - - - - - There exist other kinds of marshallers, for example there is a generic - Python marshaller which is used by all Python closures (a Python closure - is used to invoke a callback written in Python). This Python marshaller - transforms the input GValue list representing the function parameters - into a Python tuple which is the equivalent structure in Python. - - - - - - - Signals - - - GObject's signals have nothing to do with standard UNIX signals: they connect - arbitrary application-specific events with any number of listeners. - For example, in GTK, every user event (keystroke or mouse move) is received - from the windowing system and generates a GTK event in the form of a signal emission - on the widget object instance. - - - - Each signal is registered in the type system together with the type on which - it can be emitted: users of the type are said to connect - to the signal on a given type instance when they register a closure to be - invoked upon the signal emission. The closure will be called synchronously on emission. - Users can also emit the signal by themselves or stop the emission of the signal from - within one of the closures connected to the signal. - - - - When a signal is emitted on a given type instance, all the closures - connected to this signal on this type instance will be invoked. All the closures - connected to such a signal represent callbacks whose signature looks like: - -return_type function_callback (gpointer instance, …, gpointer user_data); - - - - - Signal registration - - - To register a new signal on an existing type, we can use any of g_signal_newv, - g_signal_new_valist or g_signal_new functions: - -guint g_signal_newv (const gchar *signal_name, - GType itype, - GSignalFlags signal_flags, - GClosure *class_closure, - GSignalAccumulator accumulator, - gpointer accu_data, - GSignalCMarshaller c_marshaller, - GType return_type, - guint n_params, - GType *param_types); - - The number of parameters to these functions is a bit intimidating but they are relatively - simple: - - - signal_name: is a string which can be used to uniquely identify a given signal. - - - itype: is the instance type on which this signal can be emitted. - - - signal_flags: partly defines the order in which closures which were connected to the - signal are invoked. - - - class_closure: this is the default closure for the signal: if it is not NULL upon - the signal emission, it will be invoked upon this emission of the signal. The - moment where this closure is invoked compared to other closures connected to that - signal depends partly on the signal_flags. - - - accumulator: this is a function pointer which is invoked after each closure - has been invoked. If it returns FALSE, signal emission is stopped. If it returns - TRUE, signal emission proceeds normally. It is also used to compute the return - value of the signal based on the return value of all the invoked closures. - For example, an accumulator could ignore - NULL returns from closures; or it - could build a list of the values returned by the - closures. - - - accu_data: this pointer will be passed down to each invocation of the - accumulator during emission. - - - c_marshaller: this is the default C marshaller for any closure which is connected to - this signal. - - - return_type: this is the type of the return value of the signal. - - - n_params: this is the number of parameters this signal takes. - - - param_types: this is an array of GTypes which indicate the type of each parameter - of the signal. The length of this array is indicated by n_params. - - - - - - As you can see from the above definition, a signal is basically a description - of the closures which can be connected to this signal and a description of the - order in which the closures connected to this signal will be invoked. - - - - - - Signal connection - - - If you want to connect to a signal with a closure, you have three possibilities: - - - You can register a class closure at signal registration: this is a - system-wide operation. i.e.: the class closure will be invoked during each emission - of a given signal on any of the instances of the type which supports that signal. - - - You can use g_signal_override_class_closure which - overrides the class closure of a given type. It is possible to call this function - only on a derived type of the type on which the signal was registered. - This function is of use only to language bindings. - - - You can register a closure with the g_signal_connect - family of functions. This is an instance-specific operation: the closure - will be invoked only during emission of a given signal on a given instance. - - - It is also possible to connect a different kind of callback on a given signal: - emission hooks are invoked whenever a given signal is emitted whatever the instance on - which it is emitted. Emission hooks are used for example to get all mouse_clicked - emissions in an application to be able to emit the small mouse click sound. - Emission hooks are connected with g_signal_add_emission_hook - and removed with g_signal_remove_emission_hook. - - - - - - Signal emission - - - Signal emission is done through the use of the g_signal_emit family - of functions. - -void g_signal_emitv (const GValue *instance_and_params, - guint signal_id, - GQuark detail, - GValue *return_value); - - - - The instance_and_params array of GValues contains the list of input - parameters to the signal. The first element of the array is the - instance pointer on which to invoke the signal. The following elements of - the array contain the list of parameters to the signal. - - - signal_id identifies the signal to invoke. - - - detail identifies the specific detail of the signal to invoke. A detail is a kind of - magic token/argument which is passed around during signal emission and which is used - by closures connected to the signal to filter out unwanted signal emissions. In most - cases, you can safely set this value to zero. See for - more details about this parameter. - - - return_value holds the return value of the last closure invoked during emission if - no accumulator was specified. If an accumulator was specified during signal creation, - this accumulator is used to calculate the return value as a function of the return - values of all the closures invoked during emission. - If no closure is invoked during - emission, the return_value is nonetheless initialized to zero/null. - - - - - - Signal emission is done synchronously and can be decomposed in 5 steps: - - - RUN_FIRST: if the - G_SIGNAL_RUN_FIRST flag was used - during signal registration and if there exists a class closure for this signal, - the class closure is invoked. - - - EMISSION_HOOK: if any emission hook was added to - the signal, they are invoked from first to last added. Accumulate return values. - - - HANDLER_RUN_FIRST: if any closure were connected - with the g_signal_connect family of - functions, and if they are not blocked (with the g_signal_handler_block - family of functions) they are run here, from first to last connected. - - - RUN_LAST: if the G_SIGNAL_RUN_LAST - flag was set during registration and if a class closure - was set, it is invoked here. - - - HANDLER_RUN_LAST: if any closure were connected - with the g_signal_connect_after family of - functions, if they were not invoked during HANDLER_RUN_FIRST and if they - are not blocked, they are run here, from first to last connected. - - - RUN_CLEANUP: if the G_SIGNAL_RUN_CLEANUP flag - was set during registration and if a class closure was set, - it is invoked here. Signal emission is completed here. - - - - - - If, at any point during emission (except in RUN_CLEANUP or - EMISSION_HOOK state), one of the closures stops the signal emission with - g_signal_stop_emission, - emission jumps to RUN_CLEANUP state. - - - - If, at any point during emission, one of the closures or emission hook - emits the same signal on the same instance, emission is restarted from - the RUN_FIRST state. - - - - The accumulator function is invoked in all states, after invocation - of each closure (except in RUN_EMISSION_HOOK and - RUN_CLEANUP). It accumulates - the closure return value into the signal return value and returns TRUE or - FALSE. If, at any point, it does not return TRUE, emission jumps - to RUN_CLEANUP state. - - - - If no accumulator function was provided, the value returned by the last handler - run will be returned by g_signal_emit. - - - - - - - The <emphasis>detail</emphasis> argument - - All the functions related to signal emission or signal connection have a parameter - named the detail. Sometimes, this parameter is hidden by the API - but it is always there, in one form or another. - - - - Of the three main connection functions, - only one has an explicit detail parameter as a GQuark: - g_signal_connect_closure_by_id. - - A GQuark is an integer which uniquely represents a string. It is possible to transform - back and forth between the integer and string representations with the functions - g_quark_from_string and g_quark_to_string. - - - - - The two other functions, - g_signal_connect_closure and - g_signal_connect_data - hide the detail parameter in the signal name identification. - Their detailed_signal parameter is a - string which identifies the name of the signal to connect to. - The format of this string should match - signal_name::detail_name. For example, - connecting to the signal named - notify::cursor_position will actually - connect to the signal named notify with the - cursor_position detail. - Internally, the detail string is transformed to a GQuark if it is present. - - - - Of the four main signal emission functions, one hides it in its - signal name parameter: - g_signal_connect. - The other three have an explicit detail parameter as a - GQuark again: - g_signal_emit, - g_signal_emitv and - g_signal_emit_valist. - - - - If a detail is provided by the user to the emission function, it is used during emission to match - against the closures which also provide a detail. - If a closure's detail does not match the detail provided by the user, it - will not be invoked (even though it is connected to a signal which is - being emitted). - - - - This completely optional filtering mechanism is mainly used as an optimization for signals - which are often emitted for many different reasons: the clients can filter out which events they are - interested in before the closure's marshalling code runs. For example, this is used extensively - by the notify signal of GObject: whenever a property is modified on a GObject, - instead of just emitting the notify signal, GObject associates as a detail to this - signal emission the name of the property modified. This allows clients who wish to be notified of changes - to only one property to filter most events before receiving them. - - - - As a simple rule, users can and should set the detail parameter to zero: this will disable completely - this optional filtering for that signal. - - - - - - - diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml deleted file mode 100644 index c2d51b9..0000000 --- a/docs/reference/gobject/tut_gtype.xml +++ /dev/null @@ -1,1003 +0,0 @@ - - - - The GLib Dynamic Type System - - - A type, as manipulated by the GLib type system, is much more generic than what - is usually understood as an Object type. It is best explained by looking at the - structure and the functions used to register new types in the type system. - -typedef struct _GTypeInfo GTypeInfo; -struct _GTypeInfo -{ - /* interface types, classed types, instantiated types */ - guint16 class_size; - - GBaseInitFunc base_init; - GBaseFinalizeFunc base_finalize; - - /* classed types, instantiated types */ - GClassInitFunc class_init; - GClassFinalizeFunc class_finalize; - gconstpointer class_data; - - /* instantiated types */ - guint16 instance_size; - guint16 n_preallocs; - GInstanceInitFunc instance_init; - - /* value handling */ - const GTypeValueTable *value_table; -}; -GType g_type_register_static (GType parent_type, - const gchar *type_name, - const GTypeInfo *info, - GTypeFlags flags); -GType g_type_register_fundamental (GType type_id, - const gchar *type_name, - const GTypeInfo *info, - const GTypeFundamentalInfo *finfo, - GTypeFlags flags); - - - - - g_type_register_static, - g_type_register_dynamic and - g_type_register_fundamental - are the C functions, defined in - gtype.h and implemented in gtype.c - which you should use to register a new GType in the program's type system. - It is not likely you will ever need to use - g_type_register_fundamental - but in case you want to, the last chapter explains how to create - new fundamental types. - - - - Fundamental types are top-level types which do not derive from any other type - while other non-fundamental types derive from other types. - Upon initialization, the type system not only initializes its - internal data structures but it also registers a number of core - types: some of these are fundamental types. Others are types derived from these - fundamental types. - - - - Fundamental and non-fundamental types are defined by: - - - class size: the class_size field in GTypeInfo. - - - class initialization functions (C++ constructor): the base_init and - class_init fields in GTypeInfo. - - - class destruction functions (C++ destructor): the base_finalize and - class_finalize fields in GTypeInfo. - - - instance size (C++ parameter to new): the instance_size field in - GTypeInfo. - - - instantiation policy (C++ type of new operator): the n_preallocs - field in GTypeInfo. - - - copy functions (C++ copy operators): the value_table field in - GTypeInfo. - - - type characteristic flags: GTypeFlags. - - - Fundamental types are also defined by a set of GTypeFundamentalFlags - which are stored in a GTypeFundamentalInfo. - Non-fundamental types are furthermore defined by the type of their parent which is - passed as the parent_type parameter to g_type_register_static - and g_type_register_dynamic. - - - - Copy functions - - - The major common point between all GLib types (fundamental and - non-fundamental, classed and non-classed, instantiatable and non-instantiatable) is that - they can all be manipulated through a single API to copy/assign them. - - - - The GValue structure is used as an abstract container for all of these - types. Its simplistic API (defined in gobject/gvalue.h) can be - used to invoke the value_table functions registered - during type registration: for example g_value_copy copies the - content of a GValue to another GValue. This is similar - to a C++ assignment which invokes the C++ copy operator to modify the default - bit-by-bit copy semantics of C++/C structures/classes. - - - - The following code shows how you can copy around a 64 bit integer, as well as a GObject - instance pointer: - -static void test_int (void) -{ - GValue a_value = G_VALUE_INIT; - GValue b_value = G_VALUE_INIT; - guint64 a, b; - - a = 0xdeadbeef; - - g_value_init (&a_value, G_TYPE_UINT64); - g_value_set_uint64 (&a_value, a); - - g_value_init (&b_value, G_TYPE_UINT64); - g_value_copy (&a_value, &b_value); - - b = g_value_get_uint64 (&b_value); - - if (a == b) { - g_print ("Yay !! 10 lines of code to copy around a uint64.\n"); - } else { - g_print ("Are you sure this is not a Z80 ?\n"); - } -} - -static void test_object (void) -{ - GObject *obj; - GValue obj_vala = G_VALUE_INIT; - GValue obj_valb = G_VALUE_INIT; - obj = g_object_new (VIEWER_TYPE_FILE, NULL); - - g_value_init (&obj_vala, VIEWER_TYPE_FILE); - g_value_set_object (&obj_vala, obj); - - g_value_init (&obj_valb, G_TYPE_OBJECT); - - /* g_value_copy's semantics for G_TYPE_OBJECT types is to copy the reference. - * This function thus calls g_object_ref. - * It is interesting to note that the assignment works here because - * VIEWER_TYPE_FILE is a G_TYPE_OBJECT. - */ - g_value_copy (&obj_vala, &obj_valb); - - g_object_unref (G_OBJECT (obj)); - g_object_unref (G_OBJECT (obj)); -} - - The important point about the above code is that the exact semantics of the copy calls - is undefined since they depend on the implementation of the copy function. Certain - copy functions might decide to allocate a new chunk of memory and then to copy the - data from the source to the destination. Others might want to simply increment - the reference count of the instance and copy the reference to the new GValue. - - - - The value table used to specify these assignment functions is - documented in - GTypeValueTable. - - - Interestingly, it is also very unlikely - you will ever need to specify a value_table during type registration - because these value_tables are inherited from the parent types for - non-fundamental types. - - - - - Conventions - - - - There are a number of conventions users are expected to follow when creating new types - which are to be exported in a header file: - - - Type names (including object names) must be at least three - characters long and start with ‘a–z’, ‘A–Z’ or ‘_’. - - - Use the object_method pattern for function names: to invoke - the method named save on an instance of object type file, call - file_save. - - Use prefixing to avoid namespace conflicts with other projects. - If your library (or application) is named Viewer, - prefix all your function names with viewer_. - For example: viewer_object_method. - - Create a macro named PREFIX_TYPE_OBJECT which always - returns the GType for the associated object type. For an object of type - File in the Viewer namespace, - use: VIEWER_TYPE_FILE. - This macro is implemented using a function named - prefix_object_get_type; for example, viewer_file_get_type. - - - - Use G_DECLARE_FINAL_TYPE - or G_DECLARE_DERIVABLE_TYPE - to define various other conventional macros for your object: - - - PREFIX_OBJECT (obj), which - returns a pointer of type PrefixObject. This macro is used to enforce - static type safety by doing explicit casts wherever needed. It also enforces - dynamic type safety by doing runtime checks. It is possible to disable the dynamic - type checks in production builds (see building GLib). - For example, we would create - VIEWER_FILE (obj) to keep the previous example. - - PREFIX_OBJECT_CLASS (klass), which - is strictly equivalent to the previous casting macro: it does static casting with - dynamic type checking of class structures. It is expected to return a pointer - to a class structure of type PrefixObjectClass. An example is: - VIEWER_FILE_CLASS. - - PREFIX_IS_OBJECT (obj), which - returns a gboolean which indicates whether the input - object instance pointer is non-NULL and of type OBJECT. - For example, VIEWER_IS_FILE. - - PREFIX_IS_OBJECT_CLASS (klass), which returns a boolean - if the input class pointer is a pointer to a class of type OBJECT. - For example, VIEWER_IS_FILE_CLASS. - - PREFIX_OBJECT_GET_CLASS (obj), - which returns the class pointer associated to an instance of a given type. This macro - is used for static and dynamic type safety purposes (just like the previous casting - macros). - For example, VIEWER_FILE_GET_CLASS. - - - - - The implementation of these macros is pretty straightforward: a number of simple-to-use - macros are provided in gtype.h. For the example we used above, we would - write the following trivial code to declare the macros: - -#define VIEWER_TYPE_FILE viewer_file_get_type () -G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) - - - - - Unless your code has special requirements, you can use the - G_DEFINE_TYPE - macro to define a class: - -G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) - - - - - Otherwise, the viewer_file_get_type function must be - implemented manually: - -GType viewer_file_get_type (void) -{ - static GType type = 0; - if (type == 0) { - const GTypeInfo info = { - /* You fill this structure. */ - }; - type = g_type_register_static (G_TYPE_OBJECT, - "ViewerFile", - &info, 0); - } - return type; -} - - - - - - - Non-instantiatable non-classed fundamental types - - - A lot of types are not instantiatable by the type system and do not have - a class. Most of these types are fundamental trivial types such as gchar, - and are already registered by GLib. - - - - In the rare case of needing to register such a type in the type - system, fill a - GTypeInfo structure with zeros since these types are also most of the time - fundamental: - - GTypeInfo info = { - 0, /* class_size */ - NULL, /* base_init */ - NULL, /* base_destroy */ - NULL, /* class_init */ - NULL, /* class_destroy */ - NULL, /* class_data */ - 0, /* instance_size */ - 0, /* n_preallocs */ - NULL, /* instance_init */ - NULL, /* value_table */ - }; - static const GTypeValueTable value_table = { - value_init_long0, /* value_init */ - NULL, /* value_free */ - value_copy_long0, /* value_copy */ - NULL, /* value_peek_pointer */ - "i", /* collect_format */ - value_collect_int, /* collect_value */ - "p", /* lcopy_format */ - value_lcopy_char, /* lcopy_value */ - }; - info.value_table = &value_table; - type = g_type_register_fundamental (G_TYPE_CHAR, "gchar", &info, &finfo, 0); - - - - - - Having non-instantiatable types might seem a bit useless: what good is a type - if you cannot instantiate an instance of that type ? Most of these types - are used in conjunction with GValues: a GValue is initialized - with an integer or a string and it is passed around by using the registered - type's value_table. GValues (and by extension these trivial fundamental - types) are most useful when used in conjunction with object properties and signals. - - - - - - Instantiatable classed types: objects - - - This section covers the theory behind objects. See - for the recommended way to define a - GObject. - - - - Types which are registered with a class and are declared instantiatable are - what most closely resembles an object. - Although GObjects (detailed in ) - are the most well known type of instantiatable - classed types, other kinds of similar objects used as the base of an inheritance - hierarchy have been externally developed and they are all built on the fundamental - features described below. - - - - For example, the code below shows how you could register - such a fundamental object type in the type system (using none of the - GObject convenience API): - -typedef struct { - GObject parent; - - /* instance members */ - gchar *filename; -} ViewerFile; - -typedef struct { - GObjectClass parent; - - /* class members */ - /* the first is public, pure and virtual */ - void (*open) (ViewerFile *self, - GError **error); - - /* the second is public and virtual */ - void (*close) (ViewerFile *self, - GError **error); -} ViewerFileClass; - -#define VIEWER_TYPE_FILE (viewer_file_get_type ()) - -GType -viewer_file_get_type (void) -{ - static GType type = 0; - if (type == 0) { - const GTypeInfo info = { - sizeof (ViewerFileClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - (GClassInitFunc) viewer_file_class_init, - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ViewerFile), - 0, /* n_preallocs */ - (GInstanceInitFunc) NULL /* instance_init */ - }; - type = g_type_register_static (G_TYPE_OBJECT, - "ViewerFile", - &info, 0); - } - return type; -} - - Upon the first call to viewer_file_get_type, the type named - ViewerFile will be registered in the type system as inheriting - from the type G_TYPE_OBJECT. - - - - Every object must define two structures: its class structure and its - instance structure. All class structures must contain as first member - a GTypeClass structure. All instance structures must contain as first - member a GTypeInstance structure. The declaration of these C types, - coming from gtype.h is shown below: - -struct _GTypeClass -{ - GType g_type; -}; -struct _GTypeInstance -{ - GTypeClass *g_class; -}; - - These constraints allow the type system to make sure that every object instance - (identified by a pointer to the object's instance structure) contains in its - first bytes a pointer to the object's class structure. - - - This relationship is best explained by an example: let's take object B which - inherits from object A: - -/* A definitions */ -typedef struct { - GTypeInstance parent; - int field_a; - int field_b; -} A; -typedef struct { - GTypeClass parent_class; - void (*method_a) (void); - void (*method_b) (void); -} AClass; - -/* B definitions. */ -typedef struct { - A parent; - int field_c; - int field_d; -} B; -typedef struct { - AClass parent_class; - void (*method_c) (void); - void (*method_d) (void); -} BClass; - - The C standard mandates that the first field of a C structure is stored starting - in the first byte of the buffer used to hold the structure's fields in memory. - This means that the first field of an instance of an object B is A's first field - which in turn is GTypeInstance's first field which in - turn is g_class, a pointer - to B's class structure. - - - - Thanks to these simple conditions, it is possible to detect the type of every - object instance by doing: - -B *b; -b->parent.parent.g_class->g_type - - or, more quickly: - -B *b; -((GTypeInstance *) b)->g_class->g_type - - - - - Initialization and Destruction - - - instantiation of these types can be done with - g_type_create_instance, - which will look up the type information - structure associated with the type requested. Then, the instance size and instantiation - policy (if the n_preallocs field is set - to a non-zero value, the type system allocates - the object's instance structures in chunks rather than mallocing for every instance) - declared by the user are used to get a buffer to hold the object's instance - structure. - - - - If this is the first instance of the object ever created, the type system must create a class structure. - It allocates a buffer to hold the object's class structure and initializes it. The first part of the - class structure (ie: the embedded parent class structure) is initialized by copying the contents from - the class structure of the parent class. The rest of class structure is initialized to zero. If there - is no parent, the entire class structure is initialized to zero. The type system then invokes the - base_class_initialization functions - (GBaseInitFunc) from topmost - fundamental object to bottom-most most derived object. The object's class_init - (GClassInitFunc) function is invoked afterwards to complete - initialization of the class structure. - Finally, the object's interfaces are initialized (we will discuss interface initialization - in more detail later). - - - - Once the type system has a pointer to an initialized class structure, it sets the object's - instance class pointer to the object's class structure and invokes the object's - instance_init - (GInstanceInitFunc) - functions, from top-most fundamental - type to bottom-most most-derived type. - - - - Object instance destruction through g_type_free_instance is very simple: - the instance structure is returned to the instance pool if there is one and if this was the - last living instance of the object, the class is destroyed. - - - - - Class destruction (the concept of destruction is sometimes partly - referred to as finalization in GType) is the symmetric process of - the initialization: interfaces are destroyed first. - Then, the most derived - class_finalize (GClassFinalizeFunc) function is invoked. Finally, the - base_class_finalize (GBaseFinalizeFunc) functions are - invoked from bottom-most most-derived type to top-most fundamental type and - the class structure is freed. - - - - The base initialization/finalization process is - very similar to the C++ constructor/destructor paradigm. The practical details are different - though and it is important not to get confused by superficial similarities. - GTypes have no instance destruction mechanism. It is - the user's responsibility to implement correct destruction semantics on top - of the existing GType code. (This is what GObject does: see - .) - Furthermore, C++ code equivalent to the base_init - and class_init callbacks of GType is usually not needed because C++ cannot really create object - types at runtime. - - - - The instantiation/finalization process can be summarized as follows: - - GType Instantiation/Finalization - - - - - - - - Invocation time - Function invoked - Function's parameters - - - - - First call to g_type_create_instance for target type - type's base_init function - On the inheritance tree of classes from fundamental type to target type. - base_init is invoked once for each class structure. - - - - target type's class_init function - On target type's class structure - - - - interface initialization, see - - - - - Each call to g_type_create_instance for target type - target type's instance_init function - On object's instance - - - Last call to g_type_free_instance for target type - interface destruction, see - - - - - - target type's class_finalize function - On target type's class structure - - - - type's base_finalize function - On the inheritance tree of classes from fundamental type to target type. - base_finalize is invoked once for each class structure. - - - -
-
- -
- -
- - - Non-instantiatable non-classed types: interfaces - - - This section covers the theory behind interfaces. See - for the recommended way to define an - interface. - - - - GType's interfaces are very similar to Java's interfaces. They allow - to describe a common API that several classes will adhere to. - Imagine the play, pause and stop buttons on hi-fi equipment — those can - be seen as a playback interface. Once you know what they do, you can - control your CD player, MP3 player or anything that uses these symbols. - To declare an interface you have to register a non-instantiatable - non-classed type which derives from - GTypeInterface. The following piece of code declares such an interface. - -#define VIEWER_TYPE_EDITABLE viewer_editable_get_type () -G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject) - -struct _ViewerEditableInterface { - GTypeInterface parent; - - void (*save) (ViewerEditable *self, - GError **error); -}; - -void viewer_editable_save (ViewerEditable *self, - GError **error); - - The interface function, viewer_editable_save is implemented - in a pretty simple way: - -void -viewer_editable_save (ViewerEditable *self, - GError **error) -{ - ViewerEditableinterface *iface; - - g_return_if_fail (VIEWER_IS_EDITABLE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - iface = VIEWER_EDITABLE_GET_IFACE (self); - g_return_if_fail (iface->save != NULL); - iface->save (self); -} - - viewer_editable_get_type registers a type named ViewerEditable - which inherits from G_TYPE_INTERFACE. All interfaces must - be children of G_TYPE_INTERFACE in the inheritance tree. - - - - An interface is defined by only one structure which must contain as first member - a GTypeInterface structure. The interface structure is expected to - contain the function pointers of the interface methods. It is good style to - define helper functions for each of the interface methods which simply call - the interface's method directly: viewer_editable_save - is one of these. - - - - If you have no special requirements you can use the - G_IMPLEMENT_INTERFACE macro - to implement an interface: - -static void -viewer_file_save (ViewerEditable *self) -{ - g_print ("File implementation of editable interface save method.\n"); -} - -static void -viewer_file_editable_interface_init (ViewerEditableInterface *iface) -{ - iface->save = viewer_file_save; -} - -G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, VIEWER_TYPE_FILE, - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_file_editable_interface_init)) - - - - - If your code does have special requirements, you must write a custom - get_type function to register your GType which - inherits from some GObject - and which implements the interface ViewerEditable. For - example, this code registers a new ViewerFile class which - implements ViewerEditable: - -static void -viewer_file_save (ViewerEditable *editable) -{ - g_print ("File implementation of editable interface save method.\n"); -} - -static void -viewer_file_editable_interface_init (gpointer g_iface, - gpointer iface_data) -{ - ViewerEditableInterface *iface = g_iface; - - iface->save = viewer_file_save; -} - -GType -viewer_file_get_type (void) -{ - static GType type = 0; - if (type == 0) { - const GTypeInfo info = { - sizeof (ViewerFileClass), - NULL, /* base_init */ - NULL, /* base_finalize */ - NULL, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - sizeof (ViewerFile), - 0, /* n_preallocs */ - NULL /* instance_init */ - }; - const GInterfaceInfo editable_info = { - (GInterfaceInitFunc) viewer_file_editable_interface_init, /* interface_init */ - NULL, /* interface_finalize */ - NULL /* interface_data */ - }; - type = g_type_register_static (VIEWER_TYPE_FILE, - "ViewerFile", - &info, 0); - g_type_add_interface_static (type, - VIEWER_TYPE_EDITABLE, - &editable_info); - } - return type; -} - - - - - g_type_add_interface_static records in the type system that - a given type implements also FooInterface - (foo_interface_get_type returns the type of - FooInterface). - The GInterfaceInfo structure holds - information about the implementation of the interface: - -struct _GInterfaceInfo -{ - GInterfaceInitFunc interface_init; - GInterfaceFinalizeFunc interface_finalize; - gpointer interface_data; -}; - - - - - Interface Initialization - - - When an instantiatable classed type which implements an interface - (either directly or by inheriting an implementation from a superclass) - is created for the first time, its class structure is initialized - following the process described in . - After that, the interface implementations associated with - the type are initialized. - - - - First a memory buffer is allocated to hold the interface structure. The parent's - interface structure is then copied over to the new interface structure (the parent - interface is already initialized at that point). If there is no parent interface, - the interface structure is initialized with zeros. The - g_type and the - g_instance_type fields are then - initialized: g_type is set to the type of - the most-derived interface and - g_instance_type is set to the type of the - most derived type which implements this interface. - - - - The interface's base_init function is called, - and then the interface's default_init is invoked. - Finally if the type has registered an implementation of the interface, - the implementation's interface_init - function is invoked. If there are multiple implementations of an - interface the base_init and - interface_init functions will be invoked once - for each implementation initialized. - - - - It is thus recommended to use a default_init function to - initialize an interface. This function is called only once for the interface no - matter how many implementations there are. The - default_init function is declared by - G_DEFINE_INTERFACE - which can be used to define the interface: - -G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT) - -static void -viewer_editable_default_init (ViewerEditableInterface *iface) -{ - /* add properties and signals here, will only be called once */ -} - - - - - Or you can do that yourself in a GType function for your interface: - -GType -viewer_editable_get_type (void) -{ - static gsize type_id = 0; - if (g_once_init_enter (&type_id)) { - const GTypeInfo info = { - sizeof (ViewerEditableInterface), - NULL, /* base_init */ - NULL, /* base_finalize */ - viewer_editable_default_init, /* class_init */ - NULL, /* class_finalize */ - NULL, /* class_data */ - 0, /* instance_size */ - 0, /* n_preallocs */ - NULL /* instance_init */ - }; - GType type = g_type_register_static (G_TYPE_INTERFACE, - "ViewerEditable", - &info, 0); - g_once_init_leave (&type_id, type); - } - return type_id; -} - -static void -viewer_editable_default_init (ViewerEditableInterface *iface) -{ - /* add properties and signals here, will only called once */ -} - - - - - In summary, interface initialization uses the following functions: - - - - - Interface Initialization - - - - - - - - Invocation time - Function Invoked - Function's parameters - Remark - - - - - First call to g_type_create_instance - for any type implementing interface - - interface's base_init function - On interface's vtable - Rarely necessary to use this. Called once per instantiated classed type implementing the interface. - - - First call to g_type_create_instance - for each type implementing interface - - interface's default_init function - On interface's vtable - Register interface's signals, properties, etc. here. Will be called once. - - - First call to g_type_create_instance - for any type implementing interface - - implementation's interface_init function - On interface's vtable - - Initialize interface implementation. Called for each class that that - implements the interface. Initialize the interface method pointers - in the interface structure to the implementing class's implementation. - - - - -
-
- -
- - - Interface Destruction - - - When the last instance of an instantiatable type which registered - an interface implementation is destroyed, the interface's - implementations associated to the type are destroyed. - - - - To destroy an interface implementation, GType first calls the - implementation's interface_finalize function - and then the interface's most-derived - base_finalize function. - - - - Again, it is important to understand, as in - , - that both interface_finalize and base_finalize - are invoked exactly once for the destruction of each implementation of an interface. Thus, - if you were to use one of these functions, you would need to use a static integer variable - which would hold the number of instances of implementations of an interface such that - the interface's class is destroyed only once (when the integer variable reaches zero). - - - - The above process can be summarized as follows: - - Interface Finalization - - - - - - - - Invocation time - Function Invoked - Function's parameters - - - - - Last call to g_type_free_instance for type - implementing interface - - interface's interface_finalize function - On interface's vtable - - - - interface's base_finalize function - On interface's vtable - - - -
-
-
-
-
diff --git a/docs/reference/gobject/tut_howto.xml b/docs/reference/gobject/tut_howto.xml deleted file mode 100644 index 8241923..0000000 --- a/docs/reference/gobject/tut_howto.xml +++ /dev/null @@ -1,1535 +0,0 @@ - - - - Tutorial - - - This chapter tries to answer the real-life questions of users and presents - the most common use cases in order from most likely to least - likely. - - - - - How to define and implement a new GObject - - - This chapter focuses on the implementation of a subtype of GObject, for - example to create a custom class hierarchy, or to subclass a GTK widget. - - - - Throughout the chapter, a running example of a file viewer program is used, - which has a ViewerFile class to represent a single file being - viewed, and various derived classes for different types of files with - special functionality, such as audio files. The example application also - supports editing files (for example, to tweak a photo being viewed), using - a ViewerEditable interface. - - - - Boilerplate header code - - - The first step before writing the code for your GObject is to write the - type's header which contains the needed type, function and macro - definitions. Each of these elements is nothing but a convention which - is followed by almost all users of GObject, and has been refined over - multiple years of experience developing GObject-based code. If you are - writing a library, it is particularly important for you to adhere closely - to these conventions; users of your library will assume that you have. - Even if not writing a library, it will help other people who want to work - on your project. - - - - Pick a name convention for your headers and source code and stick to it: - - use a dash to separate the prefix from the typename: - viewer-file.h and viewer-file.c - (this is the convention used by Nautilus and most GNOME libraries). - use an underscore to separate the prefix from the - typename: viewer_file.h and - viewer_file.c. - Do not separate the prefix from the typename: - viewerfile.h and viewerfile.c. - (this is the convention used by GTK) - - Some people like the first two solutions better: it makes reading file - names easier for those with poor eyesight. - - - - The basic conventions for any header which exposes a GType are described - in . - - - - If you want to declare a type named ‘file’ in namespace ‘viewer’, name the - type instance ViewerFile and its class - ViewerFileClass (names are case sensitive). The - recommended method of declaring a type differs based on whether the type - is final or derivable. - - - - Final types cannot be subclassed further, and should be the default choice - for new types — changing a final type to be derivable is always a change - that will be compatible with existing uses of the code, but the converse - will often cause problems. Final types are declared using - G_DECLARE_FINAL_TYPE, - and require a structure to hold the instance data to be declared in the - source code (not the header file). - - -/* - * Copyright/Licensing information. - */ - -/* inclusion guard */ -#ifndef __VIEWER_FILE_H__ -#define __VIEWER_FILE_H__ - -#include <glib-object.h> -/* - * Potentially, include other headers on which this header depends. - */ - -G_BEGIN_DECLS - -/* - * Type declaration. - */ -#define VIEWER_TYPE_FILE viewer_file_get_type () -G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) - -/* - * Method definitions. - */ -ViewerFile *viewer_file_new (void); - -G_END_DECLS - -#endif /* __VIEWER_FILE_H__ */ - - - - - Derivable types can be subclassed further, and their class and - instance structures form part of the public API which must not be changed - if API stability is cared about. They are declared using - G_DECLARE_DERIVABLE_TYPE: - -/* - * Copyright/Licensing information. - */ - -/* inclusion guard */ -#ifndef __VIEWER_FILE_H__ -#define __VIEWER_FILE_H__ - -#include <glib-object.h> -/* - * Potentially, include other headers on which this header depends. - */ - -G_BEGIN_DECLS - -/* - * Type declaration. - */ -#define VIEWER_TYPE_FILE viewer_file_get_type () -G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) - -struct _ViewerFileClass -{ - GObjectClass parent_class; - - /* Class virtual function fields. */ - void (* open) (ViewerFile *file, - GError **error); - - /* Padding to allow adding up to 12 new virtual functions without - * breaking ABI. */ - gpointer padding[12]; -}; - -/* - * Method definitions. - */ -ViewerFile *viewer_file_new (void); - -G_END_DECLS - -#endif /* __VIEWER_FILE_H__ */ - - - - - The convention for header includes is to add the minimum number of - #include directives to the top of your headers needed - to compile that header. This - allows client code to simply #include "viewer-file.h", - without needing to know the prerequisites for - viewer-file.h. - - - - - Boilerplate code - - - In your code, the first step is to #include the - needed headers: - -/* - * Copyright information - */ - -#include "viewer-file.h" - -/* Private structure definition. */ -typedef struct { - gchar *filename; - /* stuff */ -} ViewerFilePrivate; - -/* - * forward definitions - */ - - - - - If the class is being declared as final using - G_DECLARE_FINAL_TYPE, its instance structure should - be defined in the C file: - -struct _ViewerFile -{ - GObject parent_instance; - - /* Other members, including private data. */ -}; - - - - - Call the G_DEFINE_TYPE macro (or - G_DEFINE_TYPE_WITH_PRIVATE if your class needs - private data — final types do not need private data) - using the name - of the type, the prefix of the functions and the parent GType to - reduce the amount of boilerplate needed. This macro will: - - - implement the viewer_file_get_type - function - define a parent class pointer accessible from - the whole .c file - add private instance data to the type (if using - G_DEFINE_TYPE_WITH_PRIVATE) - - - - - If the class has been declared as final using - G_DECLARE_FINAL_TYPE (see - ), private data should be placed in - the instance structure, ViewerFile, and - G_DEFINE_TYPE should be used instead of - G_DEFINE_TYPE_WITH_PRIVATE. The instance structure - for a final class is not exposed publicly, and is not embedded in the - instance structures of any derived classes (because the class is final); - so its size can vary without causing incompatibilities for code which uses - the class. Conversely, private data for derivable classes - must be included in a private structure, and - G_DEFINE_TYPE_WITH_PRIVATE must be used. - - -G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) - -or - -G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) - - - - - It is also possible to use the - G_DEFINE_TYPE_WITH_CODE macro to control the - get_type function implementation — for instance, to - add a call to the G_IMPLEMENT_INTERFACE macro to - implement an interface. - - - - - Object construction - - - People often get confused when trying to construct their GObjects because of the - sheer number of different ways to hook into the objects's construction process: it is - difficult to figure which is the correct, recommended way. - - - - shows what user-provided functions - are invoked during object instantiation and in which order they are invoked. - A user looking for the equivalent of the simple C++ constructor function should use - the instance_init method. It will be invoked after - all the parents’ instance_init - functions have been invoked. It cannot take arbitrary construction parameters - (as in C++) but if your object needs arbitrary parameters to complete initialization, - you can use construction properties. - - - - Construction properties will be set only after all - instance_init functions have run. - No object reference will be returned to the client of g_object_new - until all the construction properties have been set. - - - - It is important to note that object construction cannot ever - fail. If you require a fallible GObject construction, you can use the - GInitable and - GAsyncInitable - interfaces provided by the GIO library. - - - - You should write the following code first: - -G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ -} - -static void -viewer_file_init (ViewerFile *self) -{ - ViewerFilePrivate *priv = viewer_file_get_instance_private (self); - - /* initialize all public and private members to reasonable default values. - * They are all automatically initialized to 0 to begin with. */ -} - - - - - If you need special construction properties (with - G_PARAM_CONSTRUCT_ONLY - set), install the properties in - the class_init() function, override the set_property() - and get_property() methods of the GObject class, - and implement them as described by . - - - - Property IDs must start from 1, as 0 is reserved for internal use by - GObject. - -enum -{ - PROP_FILENAME = 1, - PROP_ZOOM_LEVEL, - N_PROPERTIES -}; - -static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = viewer_file_set_property; - object_class->get_property = viewer_file_get_property; - - obj_properties[PROP_FILENAME] = - g_param_spec_string ("filename", - "Filename", - "Name of the file to load and display from.", - NULL /* default value */, - G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); - - obj_properties[PROP_ZOOM_LEVEL] = - g_param_spec_uint ("zoom-level", - "Zoom level", - "Zoom level to view the file at.", - 0 /* minimum value */, - 10 /* maximum value */, - 2 /* default value */, - G_PARAM_READWRITE); - - g_object_class_install_properties (object_class, - N_PROPERTIES, - obj_properties); -} - - If you need this, make sure you can build and run code similar to the - code shown above. Also, make sure your construct properties can be set - without side effects during construction. - - - - Some people sometimes need to complete the initialization of an instance - of a type only after the properties passed to the constructors have been - set. This is possible through the use of the constructor() - class method as described in or, - more simply, using the constructed() class method. - Note that the constructed() - virtual function will only be invoked after the properties marked as - G_PARAM_CONSTRUCT_ONLY or - G_PARAM_CONSTRUCT have been consumed, but - before the regular properties passed to g_object_new() - have been set. - - - - - Object destruction - - - Again, it is often difficult to figure out which mechanism to use to - hook into the object's destruction process: when the last - g_object_unref - function call is made, a lot of things happen as described in - . - - - - The destruction process of your object is in two phases: dispose and - finalize. This split is necessary to handle - potential cycles due to the nature of the reference counting mechanism - used by GObject, as well as dealing with temporary revival of - instances in case of signal emission during the destruction sequence. - See for more information. - -struct _ViewerFilePrivate -{ - gchar *filename; - guint zoom_level; - - GInputStream *input_stream; -}; - -G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) - -static void -viewer_file_dispose (GObject *gobject) -{ - ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); - - /* In dispose(), you are supposed to free all types referenced from this - * object which might themselves hold a reference to self. Generally, - * the most simple solution is to unref all members on which you own a - * reference. - */ - - /* dispose() might be called multiple times, so we must guard against - * calling g_object_unref() on an invalid GObject by setting the member - * NULL; g_clear_object() does this for us. - */ - g_clear_object (&priv->input_stream); - - /* Always chain up to the parent class; there is no need to check if - * the parent class implements the dispose() virtual function: it is - * always guaranteed to do so - */ - G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject); -} - -static void -viewer_file_finalize (GObject *gobject) -{ - ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); - - g_free (priv->filename); - - /* Always chain up to the parent class; as with dispose(), finalize() - * is guaranteed to exist on the parent's class virtual function table - */ - G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject); -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->dispose = viewer_file_dispose; - object_class->finalize = viewer_file_finalize; -} - -static void -viewer_file_init (ViewerFile *self); -{ - ViewerFilePrivate *priv = viewer_file_get_instance_private (self); - - priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL); - priv->filename = /* would be set as a property */; -} - - - - - It is possible that object methods might be invoked after dispose is - run and before finalize runs. GObject does not consider this to be a - program error: you must gracefully detect this and neither crash nor - warn the user, by having a disposed instance revert to an inert state. - - - - - Object methods - - - Just as with C++, there are many different ways to define object - methods and extend them: the following list and sections draw on - C++ vocabulary. (Readers are expected to know basic C++ concepts. - Those who have not had to write C++ code recently can refer to e.g. - to refresh - their memories.) - - - non-virtual public methods, - - - virtual public methods and - - - virtual private methods - - - - - - Non-virtual public methods - - - These are the simplest, providing a simple method which - acts on the object. Provide a function - prototype in the header and an implementation of that prototype - in the source file. - -/* declaration in the header. */ -void viewer_file_open (ViewerFile *self, - GError **error); - -/* implementation in the source file */ -void -viewer_file_open (ViewerFile *self, - GError **error) -{ - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - /* do stuff here. */ -} - - - - - - Virtual public methods - - - This is the preferred way to create GObjects with overridable methods: - - - Define the common method and its virtual function in the - class structure in the public header - - - Define the common method in the header file and implement it in the - source file - - - Implement a base version of the virtual function in the source - file and initialize the virtual function pointer to this - implementation in the object’s class_init - function; or leave it as NULL for a ‘pure - virtual’ method which must be overridden by derived classes - - - Re-implement the virtual function in each derived class which needs - to override it - - - - - Note that virtual functions can only be defined if the class is - derivable, declared using - G_DECLARE_DERIVABLE_TYPE - so the class structure can be defined. - -/* declaration in viewer-file.h. */ -#define VIEWER_TYPE_FILE viewer_file_get_type () -G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) - -struct _ViewerFileClass -{ - GObjectClass parent_class; - - /* stuff */ - void (*open) (ViewerFile *self, - GError **error); - - /* Padding to allow adding up to 12 new virtual functions without - * breaking ABI. */ - gpointer padding[12]; -}; - -void viewer_file_open (ViewerFile *self, - GError **error); - -/* implementation in viewer-file.c */ -void -viewer_file_open (ViewerFile *self, - GError **error) -{ - ViewerFileClass *klass; - - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - klass = VIEWER_FILE_GET_CLASS (self); - g_return_if_fail (klass->open != NULL); - - klass->open (self, error); -} - - The code above simply redirects the open call - to the relevant virtual function. - - - - It is possible to provide a default - implementation for this class method in the object's - class_init function: initialize the - klass->open field to a pointer to the - actual implementation. - By default, class methods that are not inherited are initialized to - NULL, and thus are to be considered "pure virtual". - -static void -viewer_file_real_close (ViewerFile *self, - GError **error) -{ - /* Default implementation for the virtual method. */ -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - /* this is not necessary, except for demonstration purposes. - * - * pure virtual method: mandates implementation in children. - */ - klass->open = NULL; - - /* merely virtual method. */ - klass->close = viewer_file_real_close; -} - -void -viewer_file_open (ViewerFile *self, - GError **error) -{ - ViewerFileClass *klass; - - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - klass = VIEWER_FILE_GET_CLASS (self); - - /* if the method is purely virtual, then it is a good idea to - * check that it has been overridden before calling it, and, - * depending on the intent of the class, either ignore it silently - * or warn the user. - */ - g_return_if_fail (klass->open != NULL); - klass->open (self, error); -} - -void -viewer_file_close (ViewerFile *self, - GError **error) -{ - ViewerFileClass *klass; - - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - klass = VIEWER_FILE_GET_CLASS (self); - if (klass->close != NULL) - klass->close (self, error); -} - - - - - - Virtual private Methods - - - These are very similar to virtual - public methods. They just don't - have a public function to call directly. The header - file contains only a declaration of the virtual function: - -/* declaration in viewer-file.h. */ -struct _ViewerFileClass -{ - GObjectClass parent; - - /* Public virtual method as before. */ - void (*open) (ViewerFile *self, - GError **error); - - /* Private helper function to work out whether the file can be loaded via - * memory mapped I/O, or whether it has to be read as a stream. */ - gboolean (*can_memory_map) (ViewerFile *self); - - /* Padding to allow adding up to 12 new virtual functions without - * breaking ABI. */ - gpointer padding[12]; -}; - -void viewer_file_open (ViewerFile *self, GError **error); - - These virtual functions are often used to delegate part of the job - to child classes: - -/* this accessor function is static: it is not exported outside of this file. */ -static gboolean -viewer_file_can_memory_map (ViewerFile *self) -{ - return VIEWER_FILE_GET_CLASS (self)->can_memory_map (self); -} - -void -viewer_file_open (ViewerFile *self, - GError **error) -{ - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - /* - * Try to load the file using memory mapped I/O, if the implementation of the - * class determines that is possible using its private virtual method. - */ - if (viewer_file_can_memory_map (self)) - { - /* Load the file using memory mapped I/O. */ - } - else - { - /* Fall back to trying to load the file using streaming I/O… */ - } -} - - - - - Again, it is possible to provide a default implementation for this - private virtual function: - -static gboolean -viewer_file_real_can_memory_map (ViewerFile *self) -{ - /* As an example, always return false. Or, potentially return true if the - * file is local. */ - return FALSE; -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - /* non-pure virtual method; does not have to be implemented in children. */ - klass->can_memory_map = viewer_file_real_can_memory_map; -} - - - - - Derived classes can then override the method with code such as: - -static void -viewer_audio_file_class_init (ViewerAudioFileClass *klass) -{ - ViewerFileClass *file_class = VIEWER_FILE_CLASS (klass); - - /* implement pure virtual function. */ - file_class->can_memory_map = viewer_audio_file_can_memory_map; -} - - - - - - - Chaining up - - Chaining up is often loosely defined by the following set of - conditions: - - Parent class A defines a public virtual method named foo and - provides a default implementation. - Child class B re-implements method foo. - B’s implementation of foo calls (‘chains up to’) its parent class A’s implementation of foo. - - There are various uses of this idiom: - - You need to extend the behaviour of a class without modifying its code. You create - a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour - and chain up to ensure that the previous behaviour is not really modified, just extended. - - You need to implement the - Chain - Of Responsibility pattern: each object of the inheritance - tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that - each handler is run in turn. - - - - - To explicitly chain up to the implementation of the virtual method in the parent class, - you first need a handle to the original parent class structure. This pointer can then be used to - access the original virtual function pointer and invoke it directly. - - - The original adjective used in this sentence is not innocuous. To fully - understand its meaning, recall how class structures are initialized: for each object type, - the class structure associated with this object is created by first copying the class structure of its - parent type (a simple memcpy) and then by invoking the class_init callback on - the resulting class structure. Since the class_init callback is responsible for overwriting the class structure - with the user re-implementations of the class methods, the modified copy of the parent class - structure stored in the derived instance cannot be used. A copy of the class structure of an instance of the parent - class is needed. - - - - - - Use the parent_class pointer created and initialized - by the - G_DEFINE_TYPE - family of macros, for instance: - -static void -b_method_to_call (B *obj, gint some_param) -{ - /* do stuff before chain up */ - - /* call the method_to_call() virtual function on the - * parent of BClass, AClass. - * - * remember the explicit cast to AClass* - */ - A_CLASS (b_parent_class)->method_to_call (obj, some_param); - - /* do stuff after chain up */ -} - - - - - - - - - - How to define and implement interfaces - - - Defining interfaces - - - The theory behind how GObject interfaces work is given in - ; this section covers how to - define and implement an interface. - - - - The first step is to get the header right. This interface - defines three methods: - -/* - * Copyright/Licensing information. - */ - -#ifndef __VIEWER_EDITABLE_H__ -#define __VIEWER_EDITABLE_H__ - -#include <glib-object.h> - -G_BEGIN_DECLS - -#define VIEWER_TYPE_EDITABLE viewer_editable_get_type () -G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject) - -struct _ViewerEditableInterface -{ - GTypeInterface parent_iface; - - void (*save) (ViewerEditable *self, - GError **error); - void (*undo) (ViewerEditable *self, - guint n_steps); - void (*redo) (ViewerEditable *self, - guint n_steps); -}; - -void viewer_editable_save (ViewerEditable *self, - GError **error); -void viewer_editable_undo (ViewerEditable *self, - guint n_steps); -void viewer_editable_redo (ViewerEditable *self, - guint n_steps); - -G_END_DECLS - -#endif /* __VIEWER_EDITABLE_H__ */ - - This code is the same as the code for a normal GType - which derives from a GObject except for a few details: - - - The _GET_CLASS function is called - _GET_IFACE (and is defined by - G_DECLARE_INTERFACE). - - - The instance type, ViewerEditable, is not fully defined: it is - used merely as an abstract type which represents an instance of - whatever object which implements the interface. - - - The parent of the ViewerEditableInterface is - GTypeInterface, not GObjectClass. - - - - - - The implementation of the ViewerEditable type itself is trivial: - - G_DEFINE_INTERFACE - creates a viewer_editable_get_type function which registers the - type in the type system. The third argument is used to define a - prerequisite interface - (which we'll talk about more later). Just pass 0 for this - argument when an interface has no prerequisite. - - viewer_editable_default_init is expected - to register the interface's signals if there are any (we will see a bit - later how to use them). - The interface methods viewer_editable_save, - viewer_editable_undo and viewer_editable_redo dereference the interface - structure to access its associated interface function and call it. - - - -G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT) - -static void -viewer_editable_default_init (ViewerEditableInterface *iface) -{ - /* add properties and signals to the interface here */ -} - -void -viewer_editable_save (ViewerEditable *self, - GError **error) -{ - ViewerEditableInterface *iface; - - g_return_if_fail (VIEWER_IS_EDITABLE (self)); - g_return_if_fail (error == NULL || *error == NULL); - - iface = VIEWER_EDITABLE_GET_IFACE (self); - g_return_if_fail (iface->save != NULL); - iface->save (self, error); -} - -void -viewer_editable_undo (ViewerEditable *self, - guint n_steps) -{ - ViewerEditableInterface *iface; - - g_return_if_fail (VIEWER_IS_EDITABLE (self)); - - iface = VIEWER_EDITABLE_GET_IFACE (self); - g_return_if_fail (iface->undo != NULL); - iface->undo (self, n_steps); -} - -void -viewer_editable_redo (ViewerEditable *self, - guint n_steps) -{ - ViewerEditableInterface *iface; - - g_return_if_fail (VIEWER_IS_EDITABLE (self)); - - iface = VIEWER_EDITABLE_GET_IFACE (self); - g_return_if_fail (iface->redo != NULL); - iface->redo (self, n_steps); -} - - - - - - Implementing interfaces - - - Once the interface is defined, implementing it is rather trivial. - - - - The first step is to define a normal final GObject class exactly as in - . - - - - The second step is to implement ViewerFile by defining - it using - G_DEFINE_TYPE_WITH_CODE - and - G_IMPLEMENT_INTERFACE - instead of - G_DEFINE_TYPE: - -static void viewer_file_editable_interface_init (ViewerEditableInterface *iface); - -G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_file_editable_interface_init)) - - This definition is very much like all the similar functions seen - previously. The only interface-specific code present here is the use of - G_IMPLEMENT_INTERFACE. - - - Classes can implement multiple interfaces by using multiple calls to - G_IMPLEMENT_INTERFACE - inside the call to - G_DEFINE_TYPE_WITH_CODE - - - - viewer_file_editable_interface_init, the interface - initialization function: inside it every virtual method of the interface - must be assigned to its implementation: - -static void -viewer_file_editable_save (ViewerFile *self, - GError **error) -{ - g_print ("File implementation of editable interface save method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_undo (ViewerFile *self, - guint n_steps) -{ - g_print ("File implementation of editable interface undo method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_redo (ViewerFile *self, - guint n_steps) -{ - g_print ("File implementation of editable interface redo method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_interface_init (ViewerEditableInterface *iface) -{ - iface->save = viewer_file_editable_save; - iface->undo = viewer_file_editable_undo; - iface->redo = viewer_file_editable_redo; -} - -static void -viewer_file_init (ViewerFile *self) -{ - /* Instance variable initialisation code. */ -} - - - - If the object is not of final type, e.g. was declared using - G_DECLARE_DERIVABLE_TYPE - then - G_ADD_PRIVATE - macro should be added. The private structure should be declared exactly - as for a normal derivable object, see . - -G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, - G_ADD_PRIVATE (ViewerFile) - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_file_editable_interface_init)) - - - - - - Interface definition prerequisites - - - To specify that an interface requires the presence of other interfaces - when implemented, GObject introduces the concept of - prerequisites: it is possible to associate - a list of prerequisite types to an interface. For example, if - object A wishes to implement interface I1, and if interface I1 has a - prerequisite on interface I2, A has to implement both I1 and I2. - - - - The mechanism described above is, in practice, very similar to - Java's interface I1 extends interface I2. The example below shows - the GObject equivalent: - -/* Make the ViewerEditableLossy interface require ViewerEditable interface. */ -G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE) - - In the G_DEFINE_INTERFACE - call above, the third parameter defines the prerequisite type. This - is the GType of either an interface or a class. In this case - the ViewerEditable interface is a prerequisite of - ViewerEditableLossy. The code - below shows how an implementation can implement both interfaces and - register their implementations: - -static void -viewer_file_editable_lossy_compress (ViewerEditableLossy *editable) -{ - ViewerFile *self = VIEWER_FILE (editable); - - g_print ("File implementation of lossy editable interface compress method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface) -{ - iface->compress = viewer_file_editable_lossy_compress; -} - -static void -viewer_file_editable_save (ViewerEditable *editable, - GError **error) -{ - ViewerFile *self = VIEWER_FILE (editable); - - g_print ("File implementation of editable interface save method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_undo (ViewerEditable *editable, - guint n_steps) -{ - ViewerFile *self = VIEWER_FILE (editable); - - g_print ("File implementation of editable interface undo method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_redo (ViewerEditable *editable, - guint n_steps) -{ - ViewerFile *self = VIEWER_FILE (editable); - - g_print ("File implementation of editable interface redo method: %s.\n", - self->filename); -} - -static void -viewer_file_editable_interface_init (ViewerEditableInterface *iface) -{ - iface->save = viewer_file_editable_save; - iface->undo = viewer_file_editable_undo; - iface->redo = viewer_file_editable_redo; -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - /* Nothing here. */ -} - -static void -viewer_file_init (ViewerFile *self) -{ - /* Instance variable initialisation code. */ -} - -G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_file_editable_interface_init) - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY, - viewer_file_editable_lossy_interface_init)) - - It is very important to notice that the order in which interface - implementations are added to the main object is not random: - g_type_add_interface_static, - which is called by - G_IMPLEMENT_INTERFACE, - must be invoked first on the interfaces which have no prerequisites and then on - the others. - - - - - Interface properties - - - GObject interfaces can also have - properties. Declaration of the interface properties is similar to - declaring the properties of ordinary GObject types as explained in - , except that - g_object_interface_install_property - is used to declare the properties instead of - g_object_class_install_property. - - - - To include a property named 'autosave-frequency' of type gdouble in the - ViewerEditable interface example code above, we only need to - add one call in viewer_editable_default_init as shown - below: - -static void -viewer_editable_default_init (ViewerEditableInterface *iface) -{ - g_object_interface_install_property (iface, - g_param_spec_double ("autosave-frequency", - "Autosave frequency", - "Frequency (in per-seconds) to autosave backups of the editable content at. " - "Or zero to disable autosaves.", - 0.0, /* minimum */ - G_MAXDOUBLE, /* maximum */ - 0.0, /* default */ - G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); -} - - - - - One point worth noting is that the declared property wasn't assigned an - integer ID. The reason being that integer IDs of properties are used - only inside the get_property and - set_property virtual methods. Since interfaces - declare but do not implement properties, there is no - need to assign integer IDs to them. - - - - An implementation declares and defines its properties in the usual - way as explained in , except for one - small change: it can declare the properties of the interface it - implements using g_object_class_override_property - instead of g_object_class_install_property. - The following code snippet shows the modifications needed in the - ViewerFile declaration and implementation above: - -struct _ViewerFile -{ - GObject parent_instance; - - gdouble autosave_frequency; -}; - -enum -{ - PROP_AUTOSAVE_FREQUENCY = 1, - N_PROPERTIES -}; - -static void -viewer_file_set_property (GObject *object, - guint prop_id, - const GValue *value, - GParamSpec *pspec) -{ - ViewerFile *file = VIEWER_FILE (object); - - switch (prop_id) - { - case PROP_AUTOSAVE_FREQUENCY: - file->autosave_frequency = g_value_get_double (value); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -viewer_file_get_property (GObject *object, - guint prop_id, - GValue *value, - GParamSpec *pspec) -{ - ViewerFile *file = VIEWER_FILE (object); - - switch (prop_id) - { - case PROP_AUTOSAVE_FREQUENCY: - g_value_set_double (value, file->autosave_frequency); - break; - - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); - break; - } -} - -static void -viewer_file_class_init (ViewerFileClass *klass) -{ - GObjectClass *object_class = G_OBJECT_CLASS (klass); - - object_class->set_property = viewer_file_set_property; - object_class->get_property = viewer_file_get_property; - - g_object_class_override_property (object_class, PROP_AUTOSAVE_FREQUENCY, "autosave-frequency"); -} - - - - - - - Overriding interface methods - - - If a base class already implements an interface and a derived - class needs to implement the same interface but needs to override certain - methods, you must reimplement the interface and set only the interface - methods which need overriding. - - - - In this example, ViewerAudioFile is derived from - ViewerFile. Both implement the ViewerEditable - interface. ViewerAudioFile only implements one method of the - ViewerEditable interface and uses the base class implementation of - the other. - -static void -viewer_audio_file_editable_save (ViewerEditable *editable, - GError **error) -{ - ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); - - g_print ("Audio file implementation of editable interface save method.\n"); -} - -static void -viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) -{ - /* Override the implementation of save(). */ - iface->save = viewer_audio_file_editable_save; - - /* - * Leave iface->undo and ->redo alone, they are already set to the - * base class implementation. - */ -} - -G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_audio_file_editable_interface_init)) - -static void -viewer_audio_file_class_init (ViewerAudioFileClass *klass) -{ - /* Nothing here. */ -} - -static void -viewer_audio_file_init (ViewerAudioFile *self) -{ - /* Nothing here. */ -} - - - - - To access the base class interface implementation use - g_type_interface_peek_parent - from within an interface's default_init function. - - - - To call the base class implementation of an interface - method from a derived class where than interface method has been - overridden, stash away the pointer returned from - g_type_interface_peek_parent - in a global variable. - - - - In this example ViewerAudioFile overrides the - save interface method. In its overridden method - it calls the base class implementation of the same interface method. - -static ViewerEditableInterface *viewer_editable_parent_interface = NULL; - -static void -viewer_audio_file_editable_save (ViewerEditable *editable, - GError **error) -{ - ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); - - g_print ("Audio file implementation of editable interface save method.\n"); - - /* Now call the base implementation */ - viewer_editable_parent_interface->save (editable, error); -} - -static void -viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) -{ - viewer_editable_parent_interface = g_type_interface_peek_parent (iface); - - iface->save = viewer_audio_file_editable_save; -} - -G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, - G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, - viewer_audio_file_editable_interface_init)) - -static void -viewer_audio_file_class_init (ViewerAudioFileClass *klass) -{ - /* Nothing here. */ -} - -static void -viewer_audio_file_init (ViewerAudioFile *self) -{ - /* Nothing here. */ -} - - - - - - - - - - How to create and use signals - - - The signal system in GType is pretty complex and - flexible: it is possible for its users to connect at runtime any - number of callbacks (implemented in any language for which a binding - exists) - - A Python callback can be connected to any signal on any - C-based GObject, and vice versa, assuming that the Python object - inherits from GObject. - - to any signal and to stop the emission of any signal at any - state of the signal emission process. This flexibility makes it - possible to use GSignal for much more than just emitting signals to - multiple clients. - - - - Simple use of signals - - - The most basic use of signals is to implement event - notification. For example, given a ViewerFile object with - a write method, a signal could be emitted whenever - the file is changed using that method. - The code below shows how the user can connect a callback to the - "changed" signal. - -file = g_object_new (VIEWER_FILE_TYPE, NULL); - -g_signal_connect (file, "changed", (GCallback) changed_event, NULL); - -viewer_file_write (file, buffer, strlen (buffer)); - - - - - The ViewerFile signal is registered in the - class_init function: - -file_signals[CHANGED] = - g_signal_newv ("changed", - G_TYPE_FROM_CLASS (object_class), - G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, - NULL /* closure */, - NULL /* accumulator */, - NULL /* accumulator data */, - NULL /* C marshaller */, - G_TYPE_NONE /* return_type */, - 0 /* n_params */, - NULL /* param_types */); - - and the signal is emitted in viewer_file_write: - -void -viewer_file_write (ViewerFile *self, - const guint8 *buffer, - gsize size) -{ - g_return_if_fail (VIEWER_IS_FILE (self)); - g_return_if_fail (buffer != NULL || size == 0); - - /* First write data. */ - - /* Then, notify user of data written. */ - g_signal_emit (self, file_signals[CHANGED], 0 /* details */); -} - - As shown above, the details parameter can safely be set to zero if no - detail needs to be conveyed. For a discussion of what it can be used for, - see - - - - The C signal marshaller should always be NULL, in which - case the best marshaller for the given closure type will be chosen by - GLib. This may be an internal marshaller specific to the closure type, or - g_cclosure_marshal_generic, which implements generic - conversion of arrays of parameters to C callback invocations. GLib used to - require the user to write or generate a type-specific marshaller and pass - that, but that has been deprecated in favour of automatic selection of - marshallers. - - - - Note that g_cclosure_marshal_generic is slower than - non-generic marshallers, so should be avoided for performance critical - code. However, performance critical code should rarely be using signals - anyway, as emitting a signal blocks on emitting it to all listeners, which - has potentially unbounded cost. - - - - diff --git a/docs/reference/gobject/tut_intro.xml b/docs/reference/gobject/tut_intro.xml deleted file mode 100644 index 87e8a49..0000000 --- a/docs/reference/gobject/tut_intro.xml +++ /dev/null @@ -1,185 +0,0 @@ - - - - Background - - - GObject, and its lower-level type system, GType, are used by GTK and most GNOME libraries to - provide: - - object-oriented C-based APIs and - automatic transparent API bindings to other compiled - or interpreted languages. - - - - - A lot of programmers are used to working with compiled-only or dynamically interpreted-only - languages and do not understand the challenges associated with cross-language interoperability. - This introduction tries to provide an insight into these challenges and briefly describes - the solution chosen by GLib. - - - - The following chapters go into greater detail into how GType and GObject work and - how you can use them as a C programmer. It is useful to keep in mind that - allowing access to C objects from other interpreted languages was one of the major design - goals: this can often explain the sometimes rather convoluted APIs and features present - in this library. - - - - Data types and programming - - - One could say - that a programming language is merely a way to create data types and manipulate them. Most languages - provide a number of language-native types and a few primitives to create more complex types based - on these primitive types. - - - - In C, the language provides types such as char, long, - pointer. During compilation of C code, the compiler maps these - language types to the compiler's target architecture machine types. If you are using a C interpreter - (assuming one exists), the interpreter (the program which interprets - the source code and executes it) maps the language types to the machine types of the target machine at - runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine). - - - - Perl and Python are interpreted languages which do not really provide type definitions similar - to those used by C. Perl and Python programmers manipulate variables and the type of the variables - is decided only upon the first assignment or upon the first use which forces a type on the variable. - The interpreter also often provides a lot of automatic conversions from one type to the other. For example, - in Perl, a variable which holds an integer can be automatically converted to a string given the - required context: - -my $tmp = 10; -print "this is an integer converted to a string:" . $tmp . "\n"; - - Of course, it is also often possible to explicitly specify conversions when the default conversions provided - by the language are not intuitive. - - - - - - Exporting a C API - - - C APIs are defined by a set of functions and global variables which are usually exported from a - binary. C functions have an arbitrary number of arguments and one return value. Each function is thus - uniquely identified by the function name and the set of C types which describe the function arguments - and return value. The global variables exported by the API are similarly identified by their name and - their type. - - - - A C API is thus merely defined by a set of names to which a set of types are associated. If you know the - function calling convention and the mapping of the C types to the machine types used by the platform you - are on, you can resolve the name of each function to find where the code associated to this function - is located in memory, and then construct a valid argument list for the function. Finally, all you have to - do is trigger a call to the target C function with the argument list. - - - - For the sake of discussion, here is a sample C function and the associated 32 bit x86 - assembly code generated by GCC on a Linux computer: - -static void -function_foo (int foo) -{ -} - -int -main (int argc, - char *argv[]) -{ - function_foo (10); - - return 0; -} - -push $0xa -call 0x80482f4 <function_foo> - - The assembly code shown above is pretty straightforward: the first instruction pushes - the hexadecimal value 0xa (decimal value 10) as a 32-bit integer on the stack and calls - function_foo. As you can see, C function calls are implemented by - GCC as native function calls (this is probably the fastest implementation possible). - - - - Now, let's say we want to call the C function function_foo from - a Python program. To do this, the Python interpreter needs to: - - Find where the function is located. This probably means finding the binary generated by the C compiler - which exports this function. - Load the code of the function in executable memory. - Convert the Python parameters to C-compatible parameters before calling - the function. - Call the function with the right calling convention. - Convert the return values of the C function to Python-compatible - variables to return them to the Python code. - - - - - The process described above is pretty complex and there are a lot of ways to make it entirely automatic - and transparent to C and Python programmers: - - The first solution is to write by hand a lot of glue code, once for each function exported or imported, - which does the Python-to-C parameter conversion and the C-to-Python return value conversion. This glue code is then - linked with the interpreter which allows Python programs to call Python functions which delegate work to - C functions. - Another, nicer solution is to automatically generate the glue code, once for each function exported or - imported, with a special compiler which - reads the original function signature. - The solution used by GLib is to use the GType library which holds at runtime a description of - all the objects manipulated by the programmer. This so-called dynamic type - - - There are numerous different implementations of dynamic type systems: all C++ - compilers have one, Java and .NET have one too. A dynamic type system allows you - to get information about every instantiated object at runtime. It can be implemented - by a process-specific database: every new object created registers the characteristics - of its associated type in the type system. It can also be implemented by introspection - interfaces. The common point between all these different type systems and implementations - is that they all allow you to query for object metadata at runtime. - - - library is then used by special generic glue code to automatically convert function parameters and - function calling conventions between different runtime domains. - - The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain - boundaries is written once: the figure below states this more clearly. -
- - - - - - - - -
- - Currently, there exist at least Python and Perl generic glue code which makes it possible to use - C objects written with GType directly in Python or Perl, with a minimum amount of work: there - is no need to generate huge amounts of glue code either automatically or by hand. -
- - - Although that goal was arguably laudable, its pursuit has had a major influence on - the whole GType/GObject library. C programmers are likely to be puzzled at the complexity - of the features exposed in the following chapters if they forget that the GType/GObject library - was not only designed to offer OO-like features to C programmers but also transparent - cross-language interoperability. - - -
- -
diff --git a/docs/reference/gobject/tut_tools.xml b/docs/reference/gobject/tut_tools.xml deleted file mode 100644 index c56431e..0000000 --- a/docs/reference/gobject/tut_tools.xml +++ /dev/null @@ -1,125 +0,0 @@ - - - - Related Tools - - - - Several useful developer tools have been build around GObject - technology. The next sections briefly introduce them and link to - the respective project pages. - - - - For example, writing GObjects is often seen as a tedious task. It - requires a lot of typing and just doing a copy/paste requires a - great deal of care. A lot of projects and scripts have been - written to generate GObject skeleton form boilerplate code, or - even translating higher-level language into plain C. - - - - - Vala - - From the Vala - homepage itself: Vala is a new programming language - that aims to bring modern programming language features to GNOME - developers without imposing any additional runtime requirements - and without using a different ABI compared to applications and - libraries written in C. - - - - The syntax of Vala is similar to C#. The available compiler - translates Vala into GObject C code. It can also compile - non-GObject C, using plain C API. - - - - - GObject builder - - - In order to help a GObject class developer, one obvious idea is - to use some sort of templates for the skeletons and then run - them through a special tool to generate the real C files. GOB (or GOB2) is - such a tool. It is a preprocessor which can be used to build - GObjects with inline C code so that there is no need to edit the - generated C code. The syntax is inspired by Java and Yacc or - Lex. The implementation is intentionally kept simple: the inline C - code provided by the user is not parsed. - - - - - Graphical inspection of GObjects - - - Yet another tool that you may find helpful when working with - GObjects is G-Inspector. It - is able to display GLib/GTK objects and their properties. - - - - - Debugging reference count problems - - - The reference counting scheme used by GObject does solve quite - a few memory management problems but also introduces new sources of bugs. - In large applications, finding the exact spot where the reference count - of an Object is not properly handled can be very difficult. - - - A useful tool in debugging reference counting problems is to - set breakpoints in gdb on g_object_ref() and g_object_unref(). - Once you know the address of the object you are interested in, - you can make the breakpoints conditional: - -break g_object_ref if _object == 0xcafebabe -break g_object_unref if _object == 0xcafebabe - - - - - - Writing API docs - - The API documentation for most of the GLib, GObject, GTK and GNOME - libraries is built with a combination of complex tools. Typically, the part of - the documentation which describes the behavior of each function is extracted - from the specially-formatted source code comments by a tool named gtk-doc which - generates DocBook XML and merges this DocBook XML with a set of template XML - DocBook files. These XML DocBook files are finally processed with xsltproc - (a small program part of the libxslt library) to generate the final HTML - output. Other tools can be used to generate PDF output from the source XML. - The following code excerpt shows what these comments look like. - -/** - * gtk_widget_freeze_child_notify: - * @widget: a #GtkWidget - * - * Stops emission of "child-notify" signals on @widget. The signals are - * queued until gtk_widget_thaw_child_notify() is called on @widget. - * - * This is the analogue of g_object_freeze_notify() for child properties. - **/ -void -gtk_widget_freeze_child_notify (GtkWidget *widget) -{ -... - - - - Thorough - documentation - on how to set up and use gtk-doc in your project is provided on the - GNOME developer website. - - - diff --git a/docs/reference/gobject/tutorial.md b/docs/reference/gobject/tutorial.md new file mode 100644 index 0000000..ec5eab9 --- /dev/null +++ b/docs/reference/gobject/tutorial.md @@ -0,0 +1,1288 @@ +Title: GObject Tutorial + +# GObject Tutorial + +## How to define and implement a new GObject + +This document focuses on the implementation of a subtype of GObject, for +example to create a custom class hierarchy, or to subclass a GTK widget. + +Throughout the chapter, a running example of a file viewer program is used, +which has a `ViewerFile` class to represent a single file being viewed, and +various derived classes for different types of files with special +functionality, such as audio files. The example application also supports +editing files (for example, to tweak a photo being viewed), using a +`ViewerEditable` interface. + +### Boilerplate header code + +The first step before writing the code for your GObject is to write the +type's header which contains the needed type, function and macro +definitions. Each of these elements is nothing but a convention which is +followed by almost all users of GObject, and has been refined over multiple +years of experience developing GObject-based code. If you are writing a +library, it is particularly important for you to adhere closely to these +conventions; users of your library will assume that you have. Even if not +writing a library, it will help other people who want to work on your +project. + +Pick a name convention for your headers and source code and stick to it: + +- use a dash to separate the prefix from the typename: `viewer-file.h` and + `viewer-file.c` (this is the convention used by most GNOME libraries and + applications) +- use an underscore to separate the prefix from the typename: + `viewer_file.h` and `viewer_file.c` +- do not separate the prefix from the typename: `viewerfile.h` and + `viewerfile.c` (this is the convention used by GTK) + +Some people like the first two solutions better: it makes reading file names +easier for those with poor eyesight. + +The basic conventions for any header which exposes a GType are described in +the section of the Type system introduction called +["Conventions"](concepts.html#conventions). + +If you want to declare a type named "file" in the namespace "viewer", name +the type instance `ViewerFile` and its class `ViewerFileClass` (names are +case sensitive). The recommended method of declaring a type differs based on +whether the type is final or derivable. + +Final types cannot be subclassed further, and should be the default choice +for new types—changing a final type to be derivable is always a change that +will be compatible with existing uses of the code, but the converse will +often cause problems. Final types are declared using the +`G_DECLARE_FINAL_TYPE` macro, and require a structure to hold the instance +data to be declared in the source code (not the header file). + +```c +/* + * Copyright/Licensing information. + */ + +/* inclusion guard */ +#pragma once + +#include + +/* + * Potentially, include other headers on which this header depends. + */ + +G_BEGIN_DECLS + +/* + * Type declaration. + */ +#define VIEWER_TYPE_FILE viewer_file_get_type() +G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) + +/* + * Method definitions. + */ +ViewerFile *viewer_file_new (void); + +G_END_DECLS +``` + +Derivable types can be subclassed further, and their class and instance +structures form part of the public API which must not be changed if API +stability is cared about. They are declared using the +`G_DECLARE_DERIVABLE_TYPE` macro: + +```c +/* + * Copyright/Licensing information. + */ + +/* inclusion guard */ +#pragma once + +#include + +/* + * Potentially, include other headers on which this header depends. + */ + +G_BEGIN_DECLS + +/* + * Type declaration. + */ +#define VIEWER_TYPE_FILE viewer_file_get_type() +G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) + +struct _ViewerFileClass +{ + GObjectClass parent_class; + + /* Class virtual function fields. */ + void (* open) (ViewerFile *file, + GError **error); + + /* Padding to allow adding up to 12 new virtual functions without + * breaking ABI. */ + gpointer padding[12]; +}; + +/* + * Method definitions. + */ +ViewerFile *viewer_file_new (void); + +G_END_DECLS +``` + +The convention for header includes is to add the minimum number of +`#include` directives to the top of your headers needed to compile that +header. This allows client code to simply `#include "viewer-file.h"`, +without needing to know the prerequisites for `viewer-file.h`. + +### Boilerplate code + +In your code, the first step is to `#include` the needed headers: + +```c +/* + * Copyright/Licensing information + */ + +#include "viewer-file.h" + +/* Private structure definition. */ +typedef struct { + char *filename; + + /* other private fields */ +} ViewerFilePrivate; + +/* + * forward definitions + */ +``` + +If the class is being declared as final using `G_DECLARE_FINAL_TYPE`, its instance structure should be defined in the C file: + +```c +struct _ViewerFile +{ + GObject parent_instance; + + /* Other members, including private data. */ +}; +``` + +Call the `G_DEFINE_TYPE` macro (or `G_DEFINE_TYPE_WITH_PRIVATE` if your +class needs private data—final types do not need private data) using the +name of the type, the prefix of the functions and the parent GType to reduce +the amount of boilerplate needed. This macro will: + +- implement the `viewer_file_get_type` function +- define a parent class pointer accessible from the whole `.c` file +- add private instance data to the type (if using `G_DEFINE_TYPE_WITH_PRIVATE`) + +If the class has been declared as final using `G_DECLARE_FINAL_TYPE` private +data should be placed in the instance structure, `ViewerFile`, and +`G_DEFINE_TYPE` should be used instead of `G_DEFINE_TYPE_WITH_PRIVATE`. The +instance structure for a final class is not exposed publicly, and is not +embedded in the instance structures of any derived classes (because the +class is final); so its size can vary without causing incompatibilities for +code which uses the class. Conversely, private data for derivable classes +must be included in a private structure, and `G_DEFINE_TYPE_WITH_PRIVATE` +must be used. + +```c +G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT) +``` + +or + +```c +G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) +``` + +It is also possible to use the `G_DEFINE_TYPE_WITH_CODE` macro to control +the `get_type` function implementation — for instance, to add a call to the +`G_IMPLEMENT_INTERFACE` macro to implement an interface. + +### Object construction + +People often get confused when trying to construct their GObjects because of +the sheer number of different ways to hook into the objects's construction +process: it is difficult to figure which is the correct, recommended way. + +The [documentation on object +instantiation](concepts.html#object-instantiation) shows what user-provided +functions are invoked during object instantiation and in which order they +are invoked. A user looking for the equivalent of the simple C++ constructor +function should use the `instance_init` method. It will be invoked after all +the parents’ `instance_init` functions have been invoked. It cannot take +arbitrary construction parameters (as in C++) but if your object needs +arbitrary parameters to complete initialization, you can use construction +properties. + +Construction properties will be set only after all `instance_init` functions have run. No object reference will be returned to the client of `g_object_new()` until all the construction properties have been set. + +It is important to note that object construction cannot ever fail. If you +require a fallible GObject construction, you can use the `GInitable` and +`GAsyncInitable` interfaces provided by the GIO library. + +You should write the following code first: + +```c +G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ +} + +static void +viewer_file_init (ViewerFile *self) +{ + ViewerFilePrivate *priv = viewer_file_get_instance_private (self); + + /* initialize all public and private members to reasonable default values. + * They are all automatically initialized to 0 to begin with. */ +} +``` + +If you need special construction properties (with `G_PARAM_CONSTRUCT_ONLY` +set), install the properties in the `class_init()` function, override the +`set_property()` and `get_property()` methods of the GObject class, and +implement them as described by the section called ["Object +properties"](concepts.html#object-properties). + +Property identifiers must start from 1, as 0 is reserved for internal use by GObject. + +```c +enum +{ + PROP_FILENAME = 1, + PROP_ZOOM_LEVEL, + N_PROPERTIES +}; + +static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, }; + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = viewer_file_set_property; + object_class->get_property = viewer_file_get_property; + + obj_properties[PROP_FILENAME] = + g_param_spec_string ("filename", + "Filename", + "Name of the file to load and display from.", + NULL /* default value */, + G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE); + + obj_properties[PROP_ZOOM_LEVEL] = + g_param_spec_uint ("zoom-level", + "Zoom level", + "Zoom level to view the file at.", + 0 /* minimum value */, + 10 /* maximum value */, + 2 /* default value */, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, + N_PROPERTIES, + obj_properties); +} +``` + +If you need this, make sure you can build and run code similar to the code +shown above. Also, make sure your construct properties can be set without +side effects during construction. + +Some people sometimes need to complete the initialization of an instance of +a type only after the properties passed to the constructors have been set. +This is possible through the use of the `constructor()` class method as +described in the section called "Object instantiation" or, more simply, +using the `constructed()` class method. Note that the `constructed()` virtual +function will only be invoked after the properties marked as +`G_PARAM_CONSTRUCT_ONLY` or `G_PARAM_CONSTRUCT` have been consumed, but before +the regular properties passed to `g_object_new()` have been set. + +### Object destruction + +Again, it is often difficult to figure out which mechanism to use to hook +into the object's destruction process: when the last `g_object_unref()` function +call is made, a lot of things happen as described in [the "Object memory +management" section](concepts.html#object-memory-management) of the +documentation. + +The destruction process of your object is in two phases: dispose and +finalize. This split is necessary to handle potential cycles due to the +nature of the reference counting mechanism used by GObject, as well as +dealing with temporary revival of instances in case of signal emission +during the destruction sequence. + +```c +struct _ViewerFilePrivate +{ + gchar *filename; + guint zoom_level; + + GInputStream *input_stream; +}; + +G_DEFINE_TYPE_WITH_PRIVATE (ViewerFile, viewer_file, G_TYPE_OBJECT) + +static void +viewer_file_dispose (GObject *gobject) +{ + ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); + + /* In dispose(), you are supposed to free all types referenced from this + * object which might themselves hold a reference to self. Generally, + * the most simple solution is to unref all members on which you own a + * reference. + */ + + /* dispose() might be called multiple times, so we must guard against + * calling g_object_unref() on an invalid GObject by setting the member + * NULL; g_clear_object() does this for us. + */ + g_clear_object (&priv->input_stream); + + /* Always chain up to the parent class; there is no need to check if + * the parent class implements the dispose() virtual function: it is + * always guaranteed to do so + */ + G_OBJECT_CLASS (viewer_file_parent_class)->dispose (gobject); +} + +static void +viewer_file_finalize (GObject *gobject) +{ + ViewerFilePrivate *priv = viewer_file_get_instance_private (VIEWER_FILE (gobject)); + + g_free (priv->filename); + + /* Always chain up to the parent class; as with dispose(), finalize() + * is guaranteed to exist on the parent's class virtual function table + */ + G_OBJECT_CLASS (viewer_file_parent_class)->finalize (gobject); +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->dispose = viewer_file_dispose; + object_class->finalize = viewer_file_finalize; +} + +static void +viewer_file_init (ViewerFile *self); +{ + ViewerFilePrivate *priv = viewer_file_get_instance_private (self); + + priv->input_stream = g_object_new (VIEWER_TYPE_INPUT_STREAM, NULL); + priv->filename = /* would be set as a property */; +} +``` + +It is possible that object methods might be invoked after dispose is run and +before finalize runs. GObject does not consider this to be a program error: +you must gracefully detect this and neither crash nor warn the user, by +having a disposed instance revert to an inert state. + +### Object methods + +Just as with C++, there are many different ways to define object methods and +extend them: the following list and sections draw on C++ vocabulary. +(Readers are expected to know basic C++ concepts. Those who have not had to +write C++ code recently can refer to a [C++ +tutorial](http://www.cplusplus.com/doc/tutorial/) to refresh their +memories.) + +- non-virtual public methods, +- virtual public methods and +- virtual private methods +- non-virtual private methods + +#### Non-Virtual Methods + +These are the simplest, providing a simple method which acts on the object. +Provide a function prototype in the header and an implementation of that +prototype in the source file. + +```c +/* declaration in the header. */ +void viewer_file_open (ViewerFile *self, + GError **error); +``` + +```c +/* implementation in the source file */ +void +viewer_file_open (ViewerFile *self, + GError **error) +{ + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + /* do stuff here. */ +} +``` + +#### Virtual public methods + +This is the preferred way to create GObjects with overridable methods: + +- define the common method and its virtual function in the class structure + in the public header +- define the common method in the header file and implement it in the source + file +- implement a base version of the virtual function in the source file and + initialize the virtual function pointer to this implementation in the + object’s `class_init` function; or leave it as `NULL` for a ‘pure virtual’ + method which must be overridden by derived classes +- re-implement the virtual function in each derived class which needs to + override it + +Note that virtual functions can only be defined if the class is derivable, +declared using `G_DECLARE_DERIVABLE_TYPE` so the class structure can be +defined. + +```c +/* declaration in viewer-file.h. */ +#define VIEWER_TYPE_FILE viewer_file_get_type () +G_DECLARE_DERIVABLE_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject) + +struct _ViewerFileClass +{ + GObjectClass parent_class; + + /* stuff */ + void (*open) (ViewerFile *self, + GError **error); + + /* Padding to allow adding up to 12 new virtual functions without + * breaking ABI. */ + gpointer padding[12]; +}; + +void viewer_file_open (ViewerFile *self, + GError **error); +``` + +```c +/* implementation in viewer-file.c */ +void +viewer_file_open (ViewerFile *self, + GError **error) +{ + ViewerFileClass *klass; + + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + klass = VIEWER_FILE_GET_CLASS (self); + g_return_if_fail (klass->open != NULL); + + klass->open (self, error); +} +``` + +The code above simply redirects the open call to the relevant virtual +function. + +It is possible to provide a default implementation for this class method in +the object's `class_init` function: initialize the `klass->open` field to a +pointer to the actual implementation. By default, class methods that are not +inherited are initialized to `NULL`, and thus are to be considered "pure +virtual". + +```c +static void +viewer_file_real_close (ViewerFile *self, + GError **error) +{ + /* Default implementation for the virtual method. */ +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + /* this is not necessary, except for demonstration purposes. + * + * pure virtual method: mandates implementation in children. + */ + klass->open = NULL; + + /* merely virtual method. */ + klass->close = viewer_file_real_close; +} + +void +viewer_file_open (ViewerFile *self, + GError **error) +{ + ViewerFileClass *klass; + + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + klass = VIEWER_FILE_GET_CLASS (self); + + /* if the method is purely virtual, then it is a good idea to + * check that it has been overridden before calling it, and, + * depending on the intent of the class, either ignore it silently + * or warn the user. + */ + g_return_if_fail (klass->open != NULL); + klass->open (self, error); +} + +void +viewer_file_close (ViewerFile *self, + GError **error) +{ + ViewerFileClass *klass; + + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + klass = VIEWER_FILE_GET_CLASS (self); + if (klass->close != NULL) + klass->close (self, error); +} +``` + +#### Virtual private Methods + +These are very similar to virtual public methods. They just don't have a +public function to call directly. The header file contains only a +declaration of the virtual function: + +```c +/* declaration in viewer-file.h. */ +struct _ViewerFileClass +{ + GObjectClass parent; + + /* Public virtual method as before. */ + void (*open) (ViewerFile *self, + GError **error); + + /* Private helper function to work out whether the file can be loaded via + * memory mapped I/O, or whether it has to be read as a stream. */ + gboolean (*can_memory_map) (ViewerFile *self); + + /* Padding to allow adding up to 12 new virtual functions without + * breaking ABI. */ + gpointer padding[12]; +}; + +void viewer_file_open (ViewerFile *self, GError **error); +``` + +These virtual functions are often used to delegate part of the job to child classes: + +```c +/* this accessor function is static: it is not exported outside of this file. */ +static gboolean +viewer_file_can_memory_map (ViewerFile *self) +{ + return VIEWER_FILE_GET_CLASS (self)->can_memory_map (self); +} + +void +viewer_file_open (ViewerFile *self, + GError **error) +{ + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + /* + * Try to load the file using memory mapped I/O, if the implementation of the + * class determines that is possible using its private virtual method. + */ + if (viewer_file_can_memory_map (self)) + { + /* Load the file using memory mapped I/O. */ + } + else + { + /* Fall back to trying to load the file using streaming I/O… */ + } +} +``` + +Again, it is possible to provide a default implementation for this private virtual function: + +```c +static gboolean +viewer_file_real_can_memory_map (ViewerFile *self) +{ + /* As an example, always return false. Or, potentially return true if the + * file is local. */ + return FALSE; +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + /* non-pure virtual method; does not have to be implemented in children. */ + klass->can_memory_map = viewer_file_real_can_memory_map; +} +``` + +Derived classes can then override the method with code such as: + +```c +static void +viewer_audio_file_class_init (ViewerAudioFileClass *klass) +{ + ViewerFileClass *file_class = VIEWER_FILE_CLASS (klass); + + /* implement pure virtual function. */ + file_class->can_memory_map = viewer_audio_file_can_memory_map; +} +``` + +### Chaining up + +Chaining up is often loosely defined by the following set of conditions: + +- parent class A defines a public virtual method named `foo` and provides a + default implementation +- child class B re-implements method `foo` +- B’s implementation of `foo` calls (‘chains up to’) its parent class A’s + implementation of `foo` + +There are various uses of this idiom: + +- you need to extend the behaviour of a class without modifying its code. + You create a subclass to inherit its implementation, re-implement a public + virtual method to modify the behaviour and chain up to ensure that the + previous behaviour is not really modified, just extended +- you need to implement the + [Chain of Responsibility pattern](https://en.wikipedia.org/wiki/Chain-of-responsibility_pattern): + each object of the inheritance tree chains up to its parent (typically, at the + beginning or the end of the method) to ensure that each handler is run in turn + +To explicitly chain up to the implementation of the virtual method in the +parent class, you first need a handle to the original parent class +structure. This pointer can then be used to access the original virtual +function pointer and invoke it directly + +The "original" adjective used in the sentence above is not innocuous. To +fully understand its meaning, recall how class structures are initialized: +for each object type, the class structure associated with this object is +created by first copying the class structure of its parent type (a simple +memcpy) and then by invoking the `class_init` callback on the resulting class +structure. Since the `class_init` callback is responsible for overwriting the +class structure with the user re-implementations of the class methods, the +modified copy of the parent class structure stored in the derived instance +cannot be used. A copy of the class structure of an instance of the parent +class is needed. + +To chain up, you can use the `parent_class` pointer created and initialized +by the `G_DEFINE_TYPE` family of macros, for instance: + +```c +static void +b_method_to_call (B *obj, int some_param) +{ + /* do stuff before chain up */ + + /* call the method_to_call() virtual function on the + * parent of BClass, AClass. + * + * remember the explicit cast to AClass* + */ + A_CLASS (b_parent_class)->method_to_call (obj, some_param); + + /* do stuff after chain up */ +} +``` + +## How to define and implement interfaces + +### Defining interfaces + +The theory behind how GObject interfaces work is given in the section called +["Non-instantiatable classed types: +interfaces"](concepts.html#non-instantiatable-classed-types-interfaces); +this section covers how to define and implement an interface. + +The first step is to get the header right. This interface defines three +methods: + +```c +/* + * Copyright/Licensing information. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#define VIEWER_TYPE_EDITABLE viewer_editable_get_type() +G_DECLARE_INTERFACE (ViewerEditable, viewer_editable, VIEWER, EDITABLE, GObject) + +struct _ViewerEditableInterface +{ + GTypeInterface parent_iface; + + void (*save) (ViewerEditable *self, + GError **error); + void (*undo) (ViewerEditable *self, + guint n_steps); + void (*redo) (ViewerEditable *self, + guint n_steps); +}; + +void viewer_editable_save (ViewerEditable *self, + GError **error); +void viewer_editable_undo (ViewerEditable *self, + guint n_steps); +void viewer_editable_redo (ViewerEditable *self, + guint n_steps); + +G_END_DECLS +``` + +This code is the same as the code for a normal GType which derives from a +GObject except for a few details: + +- the `_GET_CLASS` function is called `_GET_IFACE` (and is defined by `G_DECLARE_INTERFACE`) +- the instance type, `ViewerEditable`, is not fully defined: it is used merely as an abstract type which represents an instance of whatever object which implements the interface +- the parent of the `ViewerEditableInterface` is `GTypeInterface`, not `GObjectClass` + +The implementation of the `ViewerEditable` type itself is trivial: + +- `G_DEFINE_INTERFACE` creates a `viewer_editable_get_type` function which registers the type in the type system. The third argument is used to define a prerequisite interface (which we'll talk about more later). Just pass 0 for this argument when an interface has no prerequisite +- `viewer_editable_default_init` is expected to register the interface's signals if there are any (we will see a bit later how to use them) +- the interface methods `viewer_editable_save`, `viewer_editable_undo` and `viewer_editable_redo` dereference the interface structure to access its associated interface function and call it + +```c +G_DEFINE_INTERFACE (ViewerEditable, viewer_editable, G_TYPE_OBJECT) + +static void +viewer_editable_default_init (ViewerEditableInterface *iface) +{ + /* add properties and signals to the interface here */ +} + +void +viewer_editable_save (ViewerEditable *self, + GError **error) +{ + ViewerEditableInterface *iface; + + g_return_if_fail (VIEWER_IS_EDITABLE (self)); + g_return_if_fail (error == NULL || *error == NULL); + + iface = VIEWER_EDITABLE_GET_IFACE (self); + g_return_if_fail (iface->save != NULL); + iface->save (self, error); +} + +void +viewer_editable_undo (ViewerEditable *self, + guint n_steps) +{ + ViewerEditableInterface *iface; + + g_return_if_fail (VIEWER_IS_EDITABLE (self)); + + iface = VIEWER_EDITABLE_GET_IFACE (self); + g_return_if_fail (iface->undo != NULL); + iface->undo (self, n_steps); +} + +void +viewer_editable_redo (ViewerEditable *self, + guint n_steps) +{ + ViewerEditableInterface *iface; + + g_return_if_fail (VIEWER_IS_EDITABLE (self)); + + iface = VIEWER_EDITABLE_GET_IFACE (self); + g_return_if_fail (iface->redo != NULL); + iface->redo (self, n_steps); +} +``` + +### Implementing interfaces + +Once the interface is defined, implementing it is rather trivial. + +The first step is to define a normal final GObject class exactly as usual. + +The second step is to implement `ViewerFile` by defining it using +`G_DEFINE_TYPE_WITH_CODE` and `G_IMPLEMENT_INTERFACE` instead of +`G_DEFINE_TYPE`: + +```c +static void viewer_file_editable_interface_init (ViewerEditableInterface *iface); + +G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_file_editable_interface_init)) +``` + +This definition is very much like all the similar functions seen previously. +The only interface-specific code present here is the use of +`G_IMPLEMENT_INTERFACE`. + +Classes can implement multiple interfaces by using multiple calls to +`G_IMPLEMENT_INTERFACE` inside the call to `G_DEFINE_TYPE_WITH_CODE`. + +`viewer_file_editable_interface_init` is the interface initialization +function: inside it, every virtual method of the interface must be assigned +to its implementation: + +```c +static void +viewer_file_editable_save (ViewerFile *self, + GError **error) +{ + g_print ("File implementation of editable interface save method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_undo (ViewerFile *self, + guint n_steps) +{ + g_print ("File implementation of editable interface undo method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_redo (ViewerFile *self, + guint n_steps) +{ + g_print ("File implementation of editable interface redo method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_interface_init (ViewerEditableInterface *iface) +{ + iface->save = viewer_file_editable_save; + iface->undo = viewer_file_editable_undo; + iface->redo = viewer_file_editable_redo; +} + +static void +viewer_file_init (ViewerFile *self) +{ + /* Instance variable initialisation code. */ +} +``` + +If the object is not of final type, e.g. was declared using +`G_DECLARE_DERIVABLE_TYPE` then `G_ADD_PRIVATE` macro should be added. The +private structure should be declared exactly as for a normal derivable +object. + +```c +G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, + G_ADD_PRIVATE (ViewerFile) + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_file_editable_interface_init)) +``` + +### Interface definition prerequisites + +To specify that an interface requires the presence of other interfaces when +implemented, GObject introduces the concept of prerequisites: it is possible +to associate a list of prerequisite types to an interface. For example, if +object A wishes to implement interface I1, and if interface I1 has a +prerequisite on interface I2, A has to implement both I1 and I2. + +The mechanism described above is, in practice, very similar to Java's +interface I1 extends interface I2. The example below shows the GObject +equivalent: + +``` +/* Make the ViewerEditableLossy interface require ViewerEditable interface. */ +G_DEFINE_INTERFACE (ViewerEditableLossy, viewer_editable_lossy, VIEWER_TYPE_EDITABLE) +``` + +In the `G_DEFINE_INTERFACE` call above, the third parameter defines the +prerequisite type. This is the GType of either an interface or a class. In +this case the `ViewerEditable` interface is a prerequisite of +`ViewerEditableLossy`. The code below shows how an implementation can +implement both interfaces and register their implementations: + +```c +static void +viewer_file_editable_lossy_compress (ViewerEditableLossy *editable) +{ + ViewerFile *self = VIEWER_FILE (editable); + + g_print ("File implementation of lossy editable interface compress method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_lossy_interface_init (ViewerEditableLossyInterface *iface) +{ + iface->compress = viewer_file_editable_lossy_compress; +} + +static void +viewer_file_editable_save (ViewerEditable *editable, + GError **error) +{ + ViewerFile *self = VIEWER_FILE (editable); + + g_print ("File implementation of editable interface save method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_undo (ViewerEditable *editable, + guint n_steps) +{ + ViewerFile *self = VIEWER_FILE (editable); + + g_print ("File implementation of editable interface undo method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_redo (ViewerEditable *editable, + guint n_steps) +{ + ViewerFile *self = VIEWER_FILE (editable); + + g_print ("File implementation of editable interface redo method: %s.\n", + self->filename); +} + +static void +viewer_file_editable_interface_init (ViewerEditableInterface *iface) +{ + iface->save = viewer_file_editable_save; + iface->undo = viewer_file_editable_undo; + iface->redo = viewer_file_editable_redo; +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + /* Nothing here. */ +} + +static void +viewer_file_init (ViewerFile *self) +{ + /* Instance variable initialisation code. */ +} + +G_DEFINE_TYPE_WITH_CODE (ViewerFile, viewer_file, G_TYPE_OBJECT, + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_file_editable_interface_init) + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE_LOSSY, + viewer_file_editable_lossy_interface_init)) +``` + +It is very important to notice that the order in which interface +implementations are added to the main object is not random: +`g_type_add_interface_static()`, which is called by `G_IMPLEMENT_INTERFACE`, must +be invoked first on the interfaces which have no prerequisites and then on +the others. + +### Interface properties + +GObject interfaces can also have properties. Declaration of the interface +properties is similar to declaring the properties of ordinary GObject types +as explained in the section called ["Object +properties"](concepts.html#object-properties), except that +`g_object_interface_install_property()` is used to declare the properties +instead of `g_object_class_install_property()`. + +To include a property named 'autosave-frequency' of type gdouble in the +`ViewerEditable` interface example code above, we only need to add one call in +`viewer_editable_default_init()` as shown below: + +```c +static void +viewer_editable_default_init (ViewerEditableInterface *iface) +{ + g_object_interface_install_property (iface, + g_param_spec_double ("autosave-frequency", + "Autosave frequency", + "Frequency (in per-seconds) to autosave backups of the editable content at. " + "Or zero to disable autosaves.", + 0.0, /* minimum */ + G_MAXDOUBLE, /* maximum */ + 0.0, /* default */ + G_PARAM_READWRITE)); +} +``` + +One point worth noting is that the declared property wasn't assigned an +integer ID. The reason being that integer IDs of properties are used only +inside the `get_property` and `set_property` virtual methods. Since interfaces +declare but do not implement properties, there is no need to assign integer +IDs to them. + +An implementation declares and defines its properties in the usual way as +explained in the section called “Object properties”, except for one small +change: it can declare the properties of the interface it implements using +`g_object_class_override_property()` instead of `g_object_class_install_property()`. +The following code snippet shows the modifications needed in the `ViewerFile` +declaration and implementation above: + +```c +struct _ViewerFile +{ + GObject parent_instance; + + double autosave_frequency; +}; + +enum +{ + PROP_AUTOSAVE_FREQUENCY = 1, + N_PROPERTIES +}; + +static void +viewer_file_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + ViewerFile *file = VIEWER_FILE (object); + + switch (prop_id) + { + case PROP_AUTOSAVE_FREQUENCY: + file->autosave_frequency = g_value_get_double (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +viewer_file_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ViewerFile *file = VIEWER_FILE (object); + + switch (prop_id) + { + case PROP_AUTOSAVE_FREQUENCY: + g_value_set_double (value, file->autosave_frequency); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +viewer_file_class_init (ViewerFileClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + + object_class->set_property = viewer_file_set_property; + object_class->get_property = viewer_file_get_property; + + g_object_class_override_property (object_class, PROP_AUTOSAVE_FREQUENCY, "autosave-frequency"); +} +``` + +### Overriding interface methods + +If a base class already implements an interface and a derived class needs to +implement the same interface but needs to override certain methods, you must +reimplement the interface and set only the interface methods which need +overriding. + +In this example, `ViewerAudioFile` is derived from `ViewerFile`. Both implement +the `ViewerEditable` interface. `ViewerAudioFile` only implements one method of +the `ViewerEditable` interface and uses the base class implementation of the +other. + +```c +static void +viewer_audio_file_editable_save (ViewerEditable *editable, + GError **error) +{ + ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); + + g_print ("Audio file implementation of editable interface save method.\n"); +} + +static void +viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) +{ + /* Override the implementation of save(). */ + iface->save = viewer_audio_file_editable_save; + + /* + * Leave iface->undo and ->redo alone, they are already set to the + * base class implementation. + */ +} + +G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_audio_file_editable_interface_init)) + +static void +viewer_audio_file_class_init (ViewerAudioFileClass *klass) +{ + /* Nothing here. */ +} + +static void +viewer_audio_file_init (ViewerAudioFile *self) +{ + /* Nothing here. */ +} +``` + +To access the base class interface implementation use +`g_type_interface_peek_parent()` from within an interface's `default_init` +function. + +To call the base class implementation of an interface method from a derived +class where than interface method has been overridden, stash away the +pointer returned from `g_type_interface_peek_parent()` in a global variable. + +In this example `ViewerAudioFile` overrides the save interface method. In +its overridden method it calls the base class implementation of the same +interface method. + +```c +static ViewerEditableInterface *viewer_editable_parent_interface = NULL; + +static void +viewer_audio_file_editable_save (ViewerEditable *editable, + GError **error) +{ + ViewerAudioFile *self = VIEWER_AUDIO_FILE (editable); + + g_print ("Audio file implementation of editable interface save method.\n"); + + /* Now call the base implementation */ + viewer_editable_parent_interface->save (editable, error); +} + +static void +viewer_audio_file_editable_interface_init (ViewerEditableInterface *iface) +{ + viewer_editable_parent_interface = g_type_interface_peek_parent (iface); + + iface->save = viewer_audio_file_editable_save; +} + +G_DEFINE_TYPE_WITH_CODE (ViewerAudioFile, viewer_audio_file, VIEWER_TYPE_FILE, + G_IMPLEMENT_INTERFACE (VIEWER_TYPE_EDITABLE, + viewer_audio_file_editable_interface_init)) + +static void +viewer_audio_file_class_init (ViewerAudioFileClass *klass) +{ + /* Nothing here. */ +} + +static void +viewer_audio_file_init (ViewerAudioFile *self) +{ + /* Nothing here. */ +} +``` + +## How to create and use signals + +The signal system in GType is pretty complex and flexible: it is possible +for its users to connect at runtime any number of callbacks (implemented in +any language for which a binding exists) to any signal and to stop the +emission of any signal at any state of the signal emission process. This +flexibility makes it possible to use GSignal for much more than just +emitting signals to multiple clients. + +### Simple use of signals + +The most basic use of signals is to implement event notification. For +example, given a `ViewerFile` object with a write method, a signal could be +emitted whenever the file is changed using that method. The code below shows +how the user can connect a callback to the "changed" signal. + +```c +file = g_object_new (VIEWER_FILE_TYPE, NULL); + +g_signal_connect (file, "changed", (GCallback) changed_event, NULL); + +viewer_file_write (file, buffer, strlen (buffer)); +``` + +The ViewerFile signal is registered in the `class_init` function: + +```c +file_signals[CHANGED] = + g_signal_newv ("changed", + G_TYPE_FROM_CLASS (object_class), + G_SIGNAL_RUN_LAST | G_SIGNAL_NO_RECURSE | G_SIGNAL_NO_HOOKS, + NULL /* closure */, + NULL /* accumulator */, + NULL /* accumulator data */, + NULL /* C marshaller */, + G_TYPE_NONE /* return_type */, + 0 /* n_params */, + NULL /* param_types */); +``` + +and the signal is emitted in `viewer_file_write`: + +```c +void +viewer_file_write (ViewerFile *self, + const guint8 *buffer, + gsize size) +{ + g_return_if_fail (VIEWER_IS_FILE (self)); + g_return_if_fail (buffer != NULL || size == 0); + + /* First write data. */ + + /* Then, notify user of data written. */ + g_signal_emit (self, file_signals[CHANGED], 0 /* details */); +} +``` + +As shown above, the details parameter can safely be set to zero if no detail +needs to be conveyed. For a discussion of what it can be used for, see the +section called [“The detail argument”](concepts.html#the-detail-argument). + +The C signal marshaller should always be `NULL`, in which case the best +marshaller for the given closure type will be chosen by GLib. This may be an +internal marshaller specific to the closure type, or +`g_cclosure_marshal_generic()`, which implements generic conversion of arrays of +parameters to C callback invocations. GLib used to require the user to write +or generate a type-specific marshaller and pass that, but that has been +deprecated in favour of automatic selection of marshallers. + +Note that `g_cclosure_marshal_generic()` is slower than non-generic +marshallers, so should be avoided for performance critical code. However, +performance critical code should rarely be using signals anyway, as signals +are synchronous, and the emission blocks until all listeners are invoked, +which has potentially unbounded cost. diff --git a/docs/reference/gobject/types.md b/docs/reference/gobject/types.md new file mode 100644 index 0000000..8b9bc5d --- /dev/null +++ b/docs/reference/gobject/types.md @@ -0,0 +1,64 @@ +Title: Types +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2001, 2003 Owen Taylor +SPDX-FileCopyrightText: 2002, 2003, 2004, 2005 Matthias Clasen +SPDX-FileCopyrightText: 2003, 2006 Josh Parsons +SPDX-FileCopyrightText: 2005 Stefan Kost +SPDX-FileCopyrightText: 2015 Collabora, Ltd. +SPDX-FileCopyrightText: 2021 Emmanuele Bassi +SPDX-FileCopyrightText: 2023 Endless OS Foundation, LLC + +# Types + +The GType API is the foundation of the GObject system. It provides the +facilities for registering and managing all fundamental data types, +user-defined object and interface types. + +For type creation and registration purposes, all types fall into one of +two categories: static or dynamic. Static types are never loaded or +unloaded at run-time as dynamic types may be. Static types are created +with [func@GObject.type_register_static] that gets type specific +information passed in via a `GTypeInfo` structure. + +Dynamic types are created with [func@GObject.type_register_dynamic], +which takes a `GTypePlugin` structure instead. The remaining type information +(the `GTypeInfo` structure) is retrieved during runtime through `GTypePlugin` +and the `g_type_plugin_*()` API. + +These registration functions are usually called only once from a +function whose only purpose is to return the type identifier for a +specific class. Once the type (or class or interface) is registered, +it may be instantiated, inherited, or implemented depending on exactly +what sort of type it is. + +There is also a third registration function for registering fundamental +types called [func@GObject.type_register_fundamental], which requires +both a `GTypeInfo` structure and a `GTypeFundamentalInfo` structure, but it +is rarely used since most fundamental types are predefined rather than user-defined. + +Type instance and class structs are limited to a total of 64 KiB, +including all parent types. Similarly, type instances' private data +(as created by `G_ADD_PRIVATE()`) are limited to a total of +64 KiB. If a type instance needs a large static buffer, allocate it +separately (typically by using [`struct@GLib.Array`] or [`struct@GLib.PtrArray`]) +and put a pointer to the buffer in the structure. + +As mentioned in the [GType conventions](concepts.html#conventions), type names must +be at least three characters long. There is no upper length limit. The first +character must be a letter (a–z or A–Z) or an underscore (‘\_’). Subsequent +characters can be letters, numbers or any of ‘-\_+’. + +# Runtime Debugging + +When `G_ENABLE_DEBUG` is defined during compilation, the GObject library +supports an environment variable `GOBJECT_DEBUG` that can be set to a +combination of flags to trigger debugging messages about +object bookkeeping and signal emissions during runtime. + +The currently supported flags are: + + - `objects`: Tracks all `GObject` instances in a global hash table called + `debug_objects_ht`, and prints the still-alive objects on exit. + - `instance-count`: Tracks the number of instances of every `GType` and makes + it available via the [func@GObject.type_get_instance_count] function. + - `signals`: Currently unused. diff --git a/docs/reference/gobject/urlmap.js b/docs/reference/gobject/urlmap.js new file mode 100644 index 0000000..b1f0962 --- /dev/null +++ b/docs/reference/gobject/urlmap.js @@ -0,0 +1,9 @@ +// SPDX-License-Identifier: LGPL-2.1-or-later +// SPDX-FileCopyrightText: 2023 Matthias Clasen +var baseURLs = [ + [ 'GLib', 'https://docs.gtk.org/glib/' ], + [ 'GModule', 'https://docs.gtk.org/gmodule/' ], + [ 'GObject', 'https://docs.gtk.org/gobject/' ], + [ 'Gio', 'https://docs.gtk.org/gio/' ], + [ 'Gtk', 'https://docs.gtk.org/gtk4/' ], +]; diff --git a/docs/reference/gobject/value-collection.md b/docs/reference/gobject/value-collection.md new file mode 100644 index 0000000..f040703 --- /dev/null +++ b/docs/reference/gobject/value-collection.md @@ -0,0 +1,56 @@ +Title: Value Collection +SPDX-License-Identifier: LGPL-2.1-or-later +SPDX-FileCopyrightText: 2005 Matthias Clasen + +# Value Collection + +GLib provides a set of macros for the varargs parsing support needed +in variadic GObject functions such as [ctor@GObject.Object.new] or +[method@GObject.Object.set] + +They currently support the collection of integral types, floating point +types and pointers. + +## Macros + +`G_VALUE_COLLECT_INIT(value, _value_type, var_args, flags, __error)` + +: Collects a variable argument value from a `va_list`. + + We have to implement the varargs collection as a macro, because on some + systems `va_list` variables cannot be passed by reference. + + Since: 2.24 + +`G_VALUE_COLLECT_INIT2(value, g_vci_vtab, _value_type, var_args, flags, __error)` + +: A variant of `G_VALUE_COLLECT_INIT` that provides the [struct@GObject.TypeValueTable] + to the caller. + + Since: 2.74 + +`G_VALUE_COLLECT(value, var_args, flags, __error)` + +: Collects a variable argument value from a `va_list`. + + We have to implement the varargs collection as a macro, because on some systems + `va_list` variables cannot be passed by reference. + + Note: If you are creating the `value argument` just before calling this macro, + you should use the `G_VALUE_COLLECT_INIT` variant and pass the uninitialized + `GValue`. That variant is faster than `G_VALUE_COLLECT`. + +`G_VALUE_COLLECT_SKIP(_value_type, var_args)` + +: Skip an argument of type `_value_type` from `var_args`. + +`G_VALUE_LCOPY(value, var_args, flags, __error)` + +: Stores a value’s value into one or more argument locations from a `va_list`. + + This is the inverse of G_VALUE_COLLECT(). + +`G_VALUE_COLLECT_FORMAT_MAX_LENGTH` + +: The maximal number of [type@GObject.TypeCValue]s which can be collected for a + single `GValue`. diff --git a/docs/reference/gobject/version.xml.in b/docs/reference/gobject/version.xml.in deleted file mode 100644 index af9b9c4..0000000 --- a/docs/reference/gobject/version.xml.in +++ /dev/null @@ -1 +0,0 @@ -@GLIB_VERSION@ diff --git a/docs/reference/gobject/xml/gtkdocentities.ent.in b/docs/reference/gobject/xml/gtkdocentities.ent.in deleted file mode 100644 index f12c9ff..0000000 --- a/docs/reference/gobject/xml/gtkdocentities.ent.in +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - - - diff --git a/docs/reference/gobject/xml/meson.build b/docs/reference/gobject/xml/meson.build deleted file mode 100644 index 6aeb745..0000000 --- a/docs/reference/gobject/xml/meson.build +++ /dev/null @@ -1,14 +0,0 @@ -ent_conf = configuration_data() -ent_conf.set('PACKAGE', 'glib') -ent_conf.set('PACKAGE_BUGREPORT', 'https://gitlab.gnome.org/GNOME/glib/issues/new') -ent_conf.set('PACKAGE_NAME', 'glib') -ent_conf.set('PACKAGE_STRING', 'glib') -ent_conf.set('PACKAGE_TARNAME', 'glib') -ent_conf.set('PACKAGE_URL', 'FIXME') -ent_conf.set('PACKAGE_VERSION', glib_version) -ent_conf.set('PACKAGE_API_VERSION', glib_api_version) -configure_file( - input: 'gtkdocentities.ent.in', - output: 'gtkdocentities.ent', - configuration: ent_conf -) diff --git a/docs/reference/meson.build b/docs/reference/meson.build index 67c1dda..b583278 100644 --- a/docs/reference/meson.build +++ b/docs/reference/meson.build @@ -1,58 +1,24 @@ -# The list of minor versions in the 2.x.x series which have had -# GLIB_AVAILABLE_IN_* macros. This should include the current unreleased stable -# version. -first_version = 26 -last_version = minor_version.is_odd() ? minor_version + 1 : minor_version +if get_option('documentation') and enable_gir + gidocgen_dep = dependency('gi-docgen', version: '>= 2023.1', + fallback: ['gi-docgen', 'dummy_dep'], + required: true) -ignore_decorators = [ - 'GLIB_VAR', - 'G_GNUC_INTERNAL', - 'G_GNUC_WARN_UNUSED_RESULT', - 'GLIB_AVAILABLE_IN_ALL', -] + toml_conf = configuration_data() + toml_conf.set('VERSION', meson.project_version()) -foreach i : range(first_version, last_version + 2, 2) - version = i.to_string() - ignore_decorators += [ - # Note that gtkdoc is going to use those in regex, and the longest match - # must come first. That's why '_FOR()' variant comes first. - # gtkdoc special-case '()' and replace it by a regex matching a symbol name. - 'GLIB_AVAILABLE_IN_2_' + version, - 'GLIB_DEPRECATED_IN_2_' + version + '_FOR()', - 'GLIB_DEPRECATED_IN_2_' + version, + gidocgen = find_program('gi-docgen', required: true) - 'GLIB_AVAILABLE_STATIC_INLINE_IN_2_' + version, - - 'GLIB_AVAILABLE_ENUMERATOR_IN_2_' + version, - 'GLIB_DEPRECATED_ENUMERATOR_IN_2_' + version + '_FOR()', - 'GLIB_DEPRECATED_ENUMERATOR_IN_2_' + version, - - 'GLIB_AVAILABLE_MACRO_IN_2_' + version, - 'GLIB_DEPRECATED_MACRO_IN_2_' + version + '_FOR()', - 'GLIB_DEPRECATED_MACRO_IN_2_' + version, - - 'GLIB_AVAILABLE_TYPE_IN_2_' + version, - 'GLIB_DEPRECATED_TYPE_IN_2_' + version + '_FOR()', - 'GLIB_DEPRECATED_TYPE_IN_2_' + version, + gidocgen_common_args = [ + '--quiet', + '--no-namespace-dir', + '--fatal-warnings', ] -endforeach -ignore_decorators = '|'.join(ignore_decorators) + docs_dir = glib_datadir / 'doc' / 'glib-2.0' -if get_option('gtk_doc') - # Check we have the minimum gtk-doc version required. Older versions won't - # generate correct documentation. - dependency('gtk-doc', version : '>=1.32.1', native: true, - fallback : ['gtk-doc', 'dummy_dep'], - default_options : ['tests=false']) - - # We cannot built the API reference off of a static library, - # as symbols might get dropped by the linker - if not glib_build_shared - error('The API reference can only be built against a shared library') - endif + subdir('glib') + subdir('gmodule') + subdir('gobject') + subdir('gio') + subdir('girepository') endif - -subdir('gio') -subdir('glib') -subdir('gobject') diff --git a/docs/roadmap.md b/docs/roadmap.md index 57999d9..c444a42 100644 --- a/docs/roadmap.md +++ b/docs/roadmap.md @@ -59,7 +59,7 @@ proportionally to the time since the initial release of that branch. There is no limit on the number of micro releases in a stable release series. Typically there will be around 6. Micro releases stop once there are no more -bugs found in a stable series, or once a new stable series supercedes it. +bugs found in a stable series, or once a new stable series supersedes it. The milestone for the next micro release in a stable series is created when the previous micro release is made, such that only one stable micro release is diff --git a/docs/supported-platforms.md b/docs/supported-platforms.md index ef627de..74dd01d 100644 --- a/docs/supported-platforms.md +++ b/docs/supported-platforms.md @@ -23,8 +23,6 @@ their vendor. * Windows: [minimum version is Windows 8](https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1970), minimum build chain is Visual Studio 2012 - * Static builds are only supported with MinGW-based toolchains (cf - [this comment](https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2384#note_1336662)) * Android: [minimum NDK version 15](https://gitlab.gnome.org/GNOME/glib/issues/1113) * Linux: glibc newer than 2.5 (if using glibc; other forms of libc are supported) diff --git a/docs/toolchain-requirements.md b/docs/toolchain-requirements.md index b432be5..9a1c7bf 100644 --- a/docs/toolchain-requirements.md +++ b/docs/toolchain-requirements.md @@ -156,6 +156,34 @@ and back again losslessly. Any platform or compiler which doesn’t support this cannot be used to compile GLib or code which uses GLib. This precludes use of the `-pedantic` GCC flag with GLib. +NULL defined as void pointer, or same size and representation as void pointer +--- + +_Hard requirement._ + +GLib assumes that it is safe to pass `NULL` to a variadic function without +explicitly casting it to a char * pointer, e.g.: + +``` +g_object_new (G_TYPE_FOO, + "bar", bar, + NULL); +``` + +This pattern is pervasive throughout GLib and applications that use GLib, but it +is also nonportable. If `NULL` is defined as an integer type, `0`, rather than a +pointer type, `(void *) 0`, then using an integer where a pointer is expected +results in stack corruption if the size of a pointer is different from the size +of `NULL`. Portable code would use `(char *) NULL`, `(void *) NULL` or `nullptr` +(in C23 or C++11 or later) instead. + +This requirement technically only applies to C, since GLib is written in C and +since C++ does not permit `NULL` to be defined as a void pointer. If you are +writing C++ code that uses GLib, use `nullptr` to avoid this problem. + +GLib further assumes that the representations of pointers of different types are +identical, which is not guaranteed. + `stdint.h` --- diff --git a/gio/gaction.c b/gio/gaction.c index 5599137..33e0ff7 100644 --- a/gio/gaction.c +++ b/gio/gaction.c @@ -28,47 +28,37 @@ G_DEFINE_INTERFACE (GAction, g_action, G_TYPE_OBJECT) /** - * SECTION:gaction - * @title: GAction - * @short_description: An action interface - * @include: gio/gio.h + * GAction: * - * #GAction represents a single named action. + * `GAction` represents a single named action. * * The main interface to an action is that it can be activated with - * g_action_activate(). This results in the 'activate' signal being - * emitted. An activation has a #GVariant parameter (which may be - * %NULL). The correct type for the parameter is determined by a static + * [method@Gio.Action.activate]. This results in the 'activate' signal being + * emitted. An activation has a `GVariant` parameter (which may be + * `NULL`). The correct type for the parameter is determined by a static * parameter type (which is given at construction time). * * An action may optionally have a state, in which case the state may be - * set with g_action_change_state(). This call takes a #GVariant. The + * set with [method@Gio.Action.change_state]. This call takes a #GVariant. The * correct type for the state is determined by a static state type * (which is given at construction time). * * The state may have a hint associated with it, specifying its valid * range. * - * #GAction is merely the interface to the concept of an action, as + * `GAction` is merely the interface to the concept of an action, as * described above. Various implementations of actions exist, including - * #GSimpleAction. + * [class@Gio.SimpleAction]. * * In all cases, the implementing class is responsible for storing the - * name of the action, the parameter type, the enabled state, the - * optional state type and the state and emitting the appropriate - * signals when these change. The implementor is responsible for filtering - * calls to g_action_activate() and g_action_change_state() for type - * safety and for the state being enabled. - * - * Probably the only useful thing to do with a #GAction is to put it - * inside of a #GSimpleActionGroup. - **/ - -/** - * GAction: - * - * #GAction is an opaque data structure and can only be accessed - * using the following functions. + * name of the action, the parameter type, the enabled state, the optional + * state type and the state and emitting the appropriate signals when these + * change. The implementor is responsible for filtering calls to + * [method@Gio.Action.activate] and [method@Gio.Action.change_state] + * for type safety and for the state being enabled. + * + * Probably the only useful thing to do with a `GAction` is to put it + * inside of a [class@Gio.SimpleActionGroup]. **/ /** @@ -100,9 +90,7 @@ g_action_default_init (GActionInterface *iface) * Since: 2.28 **/ g_object_interface_install_property (iface, - g_param_spec_string ("name", - P_("Action Name"), - P_("The name used to invoke the action"), + g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -117,9 +105,7 @@ g_action_default_init (GActionInterface *iface) * Since: 2.28 **/ g_object_interface_install_property (iface, - g_param_spec_boxed ("parameter-type", - P_("Parameter Type"), - P_("The type of GVariant passed to activate()"), + g_param_spec_boxed ("parameter-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -135,9 +121,7 @@ g_action_default_init (GActionInterface *iface) * Since: 2.28 **/ g_object_interface_install_property (iface, - g_param_spec_boolean ("enabled", - P_("Enabled"), - P_("If the action can be activated"), + g_param_spec_boolean ("enabled", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -151,9 +135,7 @@ g_action_default_init (GActionInterface *iface) * Since: 2.28 **/ g_object_interface_install_property (iface, - g_param_spec_boxed ("state-type", - P_("State Type"), - P_("The type of the state kept by the action"), + g_param_spec_boxed ("state-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -166,9 +148,7 @@ g_action_default_init (GActionInterface *iface) * Since: 2.28 **/ g_object_interface_install_property (iface, - g_param_spec_variant ("state", - P_("State"), - P_("The state the action is in"), + g_param_spec_variant ("state", NULL, NULL, G_VARIANT_TYPE_ANY, NULL, G_PARAM_READABLE | diff --git a/gio/gactiongroup.c b/gio/gactiongroup.c index a327195..7f7cb1c 100644 --- a/gio/gactiongroup.c +++ b/gio/gactiongroup.c @@ -26,31 +26,26 @@ #include "gmarshal-internal.h" /** - * SECTION:gactiongroup - * @title: GActionGroup - * @short_description: A group of actions - * @include: gio/gio.h - * @see_also: #GAction - * - * #GActionGroup represents a group of actions. Actions can be used to - * expose functionality in a structured way, either from one part of a - * program to another, or to the outside world. Action groups are often - * used together with a #GMenuModel that provides additional - * representation data for displaying the actions to the user, e.g. in - * a menu. - * - * The main way to interact with the actions in a GActionGroup is to - * activate them with g_action_group_activate_action(). Activating an - * action may require a #GVariant parameter. The required type of the - * parameter can be inquired with g_action_group_get_action_parameter_type(). - * Actions may be disabled, see g_action_group_get_action_enabled(). + * GActionGroup: + * + * `GActionGroup` represents a group of actions. + * + * Actions can be used to expose functionality in a structured way, either + * from one part of a program to another, or to the outside world. Action + * groups are often used together with a `GMenuModel` that provides additional + * representation data for displaying the actions to the user, e.g. in a menu. + * + * The main way to interact with the actions in a `GActionGroup` is to + * activate them with [method@Gio.ActionGroup.activate_action]. Activating an + * action may require a `GVariant` parameter. The required type of the + * parameter can be inquired with [method@Gio.ActionGroup.get_action_parameter_type]. + * Actions may be disabled, see [method@Gio.ActionGroup.get_action_enabled]. * Activating a disabled action has no effect. * - * Actions may optionally have a state in the form of a #GVariant. The - * current state of an action can be inquired with - * g_action_group_get_action_state(). Activating a stateful action may - * change its state, but it is also possible to set the state by calling - * g_action_group_change_action_state(). + * Actions may optionally have a state in the form of a #GVariant. The current + * state of an action can be inquired with [method@Gio.ActionGroup.get_action_state]. + * Activating a stateful action may change its state, but it is also possible to + * set the state by calling [method@Gio.ActionGroup.change_action_state]. * * As typical example, consider a text editing application which has an * option to change the current font to 'bold'. A good way to represent @@ -58,35 +53,28 @@ * action would toggle the state. * * Each action in the group has a unique name (which is a string). All - * method calls, except g_action_group_list_actions() take the name of + * method calls, except [method@Gio.ActionGroup.list_actions] take the name of * an action as an argument. * - * The #GActionGroup API is meant to be the 'public' API to the action - * group. The calls here are exactly the interaction that 'external + * The `GActionGroup` API is meant to be the 'public' API to the action + * group. The calls here are exactly the interaction that 'external * forces' (eg: UI, incoming D-Bus messages, etc.) are supposed to have - * with actions. 'Internal' APIs (ie: ones meant only to be accessed by - * the action group implementation) are found on subclasses. This is - * why you will find - for example - g_action_group_get_action_enabled() + * with actions. 'Internal' APIs (ie: ones meant only to be accessed by + * the action group implementation) are found on subclasses. This is + * why you will find - for example - [method@Gio.ActionGroup.get_action_enabled] * but not an equivalent set() call. * * Signals are emitted on the action group in response to state changes * on individual actions. * - * Implementations of #GActionGroup should provide implementations for - * the virtual functions g_action_group_list_actions() and - * g_action_group_query_action(). The other virtual functions should + * Implementations of `GActionGroup` should provide implementations for + * the virtual functions [method@Gio.ActionGroup.list_actions] and + * [method@Gio.ActionGroup.query_action]. The other virtual functions should * not be implemented - their "wrappers" are actually implemented with - * calls to g_action_group_query_action(). + * calls to [method@Gio.ActionGroup.query_action]. */ /** - * GActionGroup: - * - * #GActionGroup is an opaque data structure and can only be accessed - * using the following functions. - **/ - -/** * GActionGroupInterface: * @has_action: the virtual function pointer for g_action_group_has_action() * @list_actions: the virtual function pointer for g_action_group_list_actions() @@ -96,13 +84,12 @@ * @get_action_enabled: the virtual function pointer for g_action_group_get_action_enabled() * @get_action_state: the virtual function pointer for g_action_group_get_action_state() * @change_action_state: the virtual function pointer for g_action_group_change_action_state() - * @query_action: the virtual function pointer for g_action_group_query_action() * @activate_action: the virtual function pointer for g_action_group_activate_action() - * @change_action_state: the virtual function pointer for g_action_group_change_action_state() * @action_added: the class closure for the #GActionGroup::action-added signal * @action_removed: the class closure for the #GActionGroup::action-removed signal * @action_enabled_changed: the class closure for the #GActionGroup::action-enabled-changed signal * @action_state_changed: the class closure for the #GActionGroup::action-enabled-changed signal + * @query_action: the virtual function pointer for g_action_group_query_action() * * The virtual function table for #GActionGroup. * diff --git a/gio/gactiongroupexporter.c b/gio/gactiongroupexporter.c index 3bc2f04..3ec1db2 100644 --- a/gio/gactiongroupexporter.c +++ b/gio/gactiongroupexporter.c @@ -32,18 +32,14 @@ #include "gdbuserror.h" /** - * SECTION:gactiongroupexporter - * @title: GActionGroup exporter - * @include: gio/gio.h - * @short_description: Export GActionGroups on D-Bus - * @see_also: #GActionGroup, #GDBusActionGroup + * GActionGroupExporter: * - * These functions support exporting a #GActionGroup on D-Bus. + * These functions support exporting a [class@Gio.ActionGroup] on D-Bus. * The D-Bus interface that is used is a private implementation * detail. * - * To access an exported #GActionGroup remotely, use - * g_dbus_action_group_get() to obtain a #GDBusActionGroup. + * To access an exported `GActionGroup` remotely, use + * [method@Gio.DBusActionGroup.get] to obtain a [class@Gio.DBusActionGroup]. */ static GVariant * diff --git a/gio/gactionmap.c b/gio/gactionmap.c index 60c5ed5..4b58831 100644 --- a/gio/gactionmap.c +++ b/gio/gactionmap.c @@ -26,14 +26,13 @@ #include "gaction.h" /** - * SECTION:gactionmap - * @title: GActionMap - * @include: gio/gio.h - * @short_description: Interface for action containers + * GActionMap: + * + * `GActionMap` is an interface for action containers. * - * The GActionMap interface is implemented by #GActionGroup - * implementations that operate by containing a number of - * named #GAction instances, such as #GSimpleActionGroup. + * The `GActionMap` interface is implemented by [iface@Gio.ActionGroup] + * implementations that operate by containing a number of named + * [iface@Gio.Action] instances, such as [class@Gio.SimpleActionGroup]. * * One useful application of this interface is to map the * names of actions from various action groups to unique, @@ -42,14 +41,7 @@ * name. * * Since: 2.32 - **/ - -/** - * GActionMap: - * - * #GActionMap is an opaque data structure and can only be accessed - * using the following functions. - **/ + */ /** * GActionMapInterface: diff --git a/gio/gappinfo.c b/gio/gappinfo.c index 787b774..264de69 100644 --- a/gio/gappinfo.c +++ b/gio/gappinfo.c @@ -45,37 +45,37 @@ #endif /** - * SECTION:gappinfo - * @short_description: Application information and launch contexts - * @include: gio/gio.h - * @see_also: #GAppInfoMonitor - * - * #GAppInfo and #GAppLaunchContext are used for describing and launching + * GAppInfo: + * + * Information about an installed application and methods to launch + * it (with file arguments). + + * `GAppInfo` and `GAppLaunchContext` are used for describing and launching * applications installed on the system. * * As of GLib 2.20, URIs will always be converted to POSIX paths - * (using g_file_get_path()) when using g_app_info_launch() even if - * the application requested an URI and not a POSIX path. For example + * (using [method@Gio.File.get_path]) when using [method@Gio.AppInfo.launch] + * even if the application requested an URI and not a POSIX path. For example * for a desktop-file based application with Exec key `totem * %U` and a single URI, `sftp://foo/file.avi`, then * `/home/user/.gvfs/sftp on foo/file.avi` will be passed. This will - * only work if a set of suitable GIO extensions (such as gvfs 2.26 + * only work if a set of suitable GIO extensions (such as GVfs 2.26 * compiled with FUSE support), is available and operational; if this * is not the case, the URI will be passed unmodified to the application. * Some URIs, such as `mailto:`, of course cannot be mapped to a POSIX - * path (in gvfs there's no FUSE mount for it); such URIs will be + * path (in GVfs there's no FUSE mount for it); such URIs will be * passed unmodified to the application. * - * Specifically for gvfs 2.26 and later, the POSIX URI will be mapped - * back to the GIO URI in the #GFile constructors (since gvfs - * implements the #GVfs extension point). As such, if the application - * needs to examine the URI, it needs to use g_file_get_uri() or - * similar on #GFile. In other words, an application cannot assume - * that the URI passed to e.g. g_file_new_for_commandline_arg() is - * equal to the result of g_file_get_uri(). The following snippet + * Specifically for GVfs 2.26 and later, the POSIX URI will be mapped + * back to the GIO URI in the [iface@Gio.File] constructors (since GVfs + * implements the GVfs extension point). As such, if the application + * needs to examine the URI, it needs to use [method@Gio.File.get_uri] + * or similar on [iface@Gio.File]. In other words, an application cannot + * assume that the URI passed to e.g. [func@Gio.File.new_for_commandline_arg] + * is equal to the result of [method@Gio.File.get_uri]. The following snippet * illustrates this: * - * |[ + * ```c * GFile *f; * char *uri; * @@ -90,7 +90,7 @@ * // do something special with uri * } * g_object_unref (file); - * ]| + * ``` * * This code will work when both `cdda://sr0/Track 1.wav` and * `/home/user/.gvfs/cdda on sr0/Track 1.wav` is passed to the @@ -721,8 +721,8 @@ g_app_info_launch_uris_async (GAppInfo *appinfo, task = g_task_new (appinfo, cancellable, callback, user_data); g_task_set_source_tag (task, g_app_info_launch_uris_async); - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "Operation not supported for the current backend."); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + "Operation not supported for the current backend."); g_object_unref (task); return; @@ -1304,7 +1304,7 @@ g_app_info_can_delete (GAppInfo *appinfo) /** - * g_app_info_delete: + * g_app_info_delete: (virtual do_delete) * @appinfo: a #GAppInfo * * Tries to delete a #GAppInfo. @@ -1313,7 +1313,6 @@ g_app_info_can_delete (GAppInfo *appinfo) * #GAppInfos which can be deleted, and system-wide ones which cannot. * See g_app_info_can_delete(). * - * Virtual: do_delete * Returns: %TRUE if @appinfo has been deleted * * Since: 2.20 @@ -1654,53 +1653,46 @@ g_app_launch_context_launch_failed (GAppLaunchContext *context, /** - * SECTION:gappinfomonitor - * @short_description: Monitor application information for changes + * GAppInfoMonitor: * - * #GAppInfoMonitor is a very simple object used for monitoring the app + * `GAppInfoMonitor` monitors application information for changes. + * + * `GAppInfoMonitor` is a very simple object used for monitoring the app * info database for changes (newly installed or removed applications). * - * Call g_app_info_monitor_get() to get a #GAppInfoMonitor and connect - * to the #GAppInfoMonitor::changed signal. The signal will be emitted once when + * Call [func@Gio.AppInfoMonitor.get] to get a `GAppInfoMonitor` and connect + * to the [signal@Gio.AppInfoMonitor::changed] signal. The signal will be emitted once when * the app info database changes, and will not be emitted again until after the - * next call to g_app_info_get_all() or another `g_app_info_*()` function. This - * is because monitoring the app info database for changes is expensive. - * - * The following functions will re-arm the #GAppInfoMonitor::changed signal so - * it can be emitted again: - * - g_app_info_get_all() - * - g_app_info_get_all_for_type() - * - g_app_info_get_default_for_type() - * - g_app_info_get_fallback_for_type() - * - g_app_info_get_recommended_for_type() - * - g_desktop_app_info_get_implementations() - * - g_desktop_app_info_new() - * - g_desktop_app_info_new_from_filename() - * - g_desktop_app_info_new_from_keyfile() - * - g_desktop_app_info_search() + * next call to [func@Gio.AppInfo.get_all] or another `g_app_info_*()` function. + * This is because monitoring the app info database for changes is expensive. + * + * The following functions will re-arm the [signal@Gio.AppInfoMonitor::changed] + * signal so it can be emitted again: + * + * - [func@Gio.AppInfo.get_all] + * - [func@Gio.AppInfo.get_all_for_type] + * - [func@Gio.AppInfo.get_default_for_type] + * - [func@Gio.AppInfo.get_fallback_for_type] + * - [func@Gio.AppInfo.get_recommended_for_type] + * - [func@Gio.DesktopAppInfo.get_implementations] + * - [ctor@Gio.DesktopAppInfo.new] + * - [ctor@Gio.DesktopAppInfo.new_from_filename] + * - [ctor@Gio.DesktopAppInfo.new_from_keyfile] + * - [func@Gio.DesktopAppInfo.search] * * In the usual case, applications should try to make note of the change - * (doing things like invalidating caches) but not act on it. In - * particular, applications should avoid making calls to #GAppInfo APIs + * (doing things like invalidating caches) but not act on it. In + * particular, applications should avoid making calls to `GAppInfo` APIs * in response to the change signal, deferring these until the time that - * the updated data is actually required. The exception to this case is when + * the updated data is actually required. The exception to this case is when * application information is actually being displayed on the screen * (for example, during a search or when the list of all applications is shown). - * The reason for this is that changes to the list of installed - * applications often come in groups (like during system updates) and - * rescanning the list on every change is pointless and expensive. - * - * Since: 2.40 - **/ - -/** - * GAppInfoMonitor: - * - * The only thing you can do with this is to get it via - * g_app_info_monitor_get() and connect to the "changed" signal. + * The reason for this is that changes to the list of installed applications + * often come in groups (like during system updates) and rescanning the list + * on every change is pointless and expensive. * * Since: 2.40 - **/ + */ typedef struct _GAppInfoMonitorClass GAppInfoMonitorClass; diff --git a/gio/gappinfo.h b/gio/gappinfo.h index 6b13596..93974db 100644 --- a/gio/gappinfo.h +++ b/gio/gappinfo.h @@ -47,13 +47,6 @@ typedef struct _GAppLaunchContextClass GAppLaunchContextClass; typedef struct _GAppLaunchContextPrivate GAppLaunchContextPrivate; /** - * GAppInfo: - * - * Information about an installed application and methods to launch - * it (with file arguments). - */ - -/** * GAppInfoIface: * @g_iface: The parent interface. * @dup: Copies a #GAppInfo. diff --git a/gio/gapplication.c b/gio/gapplication.c index 31508eb..55e7f29 100644 --- a/gio/gapplication.c +++ b/gio/gapplication.c @@ -38,6 +38,7 @@ #include "gioenumtypes.h" #include "gioenums.h" #include "gfile.h" +#include "glib-private.h" #include "glibintl.h" #include "gmarshal-internal.h" @@ -45,25 +46,25 @@ #include /** - * SECTION:gapplication - * @title: GApplication - * @short_description: Core application class - * @include: gio/gio.h + * GApplication: + * + * `GApplication` is the core class for application support. * - * A #GApplication is the foundation of an application. It wraps some + * A `GApplication` is the foundation of an application. It wraps some * low-level platform-specific services and is intended to act as the * foundation for higher-level application classes such as - * #GtkApplication or #MxApplication. In general, you should not use + * `GtkApplication` or `MxApplication`. In general, you should not use * this class outside of a higher level framework. * - * GApplication provides convenient life cycle management by maintaining + * `GApplication` provides convenient life-cycle management by maintaining * a "use count" for the primary application instance. The use count can - * be changed using g_application_hold() and g_application_release(). If - * it drops to zero, the application exits. Higher-level classes such as - * #GtkApplication employ the use count to ensure that the application - * stays alive as long as it has any opened windows. + * be changed using [method@Gio.Application.hold] and + * [method@Gio.Application.release]. If it drops to zero, the application + * exits. Higher-level classes such as `GtkApplication` employ the use count + * to ensure that the application stays alive as long as it has any opened + * windows. * - * Another feature that GApplication (optionally) provides is process + * Another feature that `GApplication` (optionally) provides is process * uniqueness. Applications can make use of this functionality by * providing a unique application ID. If given, only one application * with this ID can be running at a time per session. The session @@ -75,53 +76,54 @@ * always the current instance. On Linux, the D-Bus session bus * is used for communication. * - * The use of #GApplication differs from some other commonly-used + * The use of `GApplication` differs from some other commonly-used * uniqueness libraries (such as libunique) in important ways. The * application is not expected to manually register itself and check * if it is the primary instance. Instead, the main() function of a - * #GApplication should do very little more than instantiating the + * `GApplication` should do very little more than instantiating the * application instance, possibly connecting signal handlers, then - * calling g_application_run(). All checks for uniqueness are done + * calling [method@Gio.Application.run]. All checks for uniqueness are done * internally. If the application is the primary instance then the * startup signal is emitted and the mainloop runs. If the application * is not the primary instance then a signal is sent to the primary - * instance and g_application_run() promptly returns. See the code + * instance and [method@Gio.Application.run] promptly returns. See the code * examples below. * - * If used, the expected form of an application identifier is the + * If used, the expected form of an application identifier is the * same as that of a * [D-Bus well-known bus name](https://dbus.freedesktop.org/doc/dbus-specification.html#message-protocol-names-bus). * Examples include: `com.example.MyApp`, `org.example.internal_apps.Calculator`, * `org._7_zip.Archiver`. - * For details on valid application identifiers, see g_application_id_is_valid(). + * For details on valid application identifiers, see [func@Gio.Application.id_is_valid]. * * On Linux, the application identifier is claimed as a well-known bus name - * on the user's session bus. This means that the uniqueness of your - * application is scoped to the current session. It also means that your + * on the user's session bus. This means that the uniqueness of your + * application is scoped to the current session. It also means that your * application may provide additional services (through registration of other - * object paths) at that bus name. The registration of these object paths - * should be done with the shared GDBus session bus. Note that due to the + * object paths) at that bus name. The registration of these object paths + * should be done with the shared GDBus session bus. Note that due to the * internal architecture of GDBus, method calls can be dispatched at any time - * (even if a main loop is not running). For this reason, you must ensure that + * (even if a main loop is not running). For this reason, you must ensure that * any object paths that you wish to register are registered before #GApplication * attempts to acquire the bus name of your application (which happens in - * g_application_register()). Unfortunately, this means that you cannot use - * g_application_get_is_remote() to decide if you want to register object paths. + * [method@Gio.Application.register]). Unfortunately, this means that you cannot + * use [property@Gio.Application:is-remote] to decide if you want to register + * object paths. * - * GApplication also implements the #GActionGroup and #GActionMap + * `GApplication` also implements the [iface@Gio.ActionGroup] and [iface@Gio.ActionMap] * interfaces and lets you easily export actions by adding them with - * g_action_map_add_action(). When invoking an action by calling - * g_action_group_activate_action() on the application, it is always + * [method@Gio.ActionMap.add_action]. When invoking an action by calling + * [method@Gio.ActionGroup.activate_action] on the application, it is always * invoked in the primary instance. The actions are also exported on - * the session bus, and GIO provides the #GDBusActionGroup wrapper to - * conveniently access them remotely. GIO provides a #GDBusMenuModel wrapper - * for remote access to exported #GMenuModels. + * the session bus, and GIO provides the [class@Gio.DBusActionGroup] wrapper to + * conveniently access them remotely. GIO provides a [class@Gio.DBusMenuModel] wrapper + * for remote access to exported [class@Gio.MenuModel]s. * * Note: Due to the fact that actions are exported on the session bus, * using `maybe` parameters is not supported, since D-Bus does not support * `maybe` types. * - * There is a number of different entry points into a GApplication: + * There is a number of different entry points into a `GApplication`: * * - via 'Activate' (i.e. just starting the application) * @@ -131,50 +133,45 @@ * * - via activating an action * - * The #GApplication::startup signal lets you handle the application + * The [signal@Gio.Application::startup] signal lets you handle the application * initialization for all of these in a single place. * * Regardless of which of these entry points is used to start the - * application, GApplication passes some ‘platform data’ from the + * application, `GApplication` passes some ‘platform data’ from the * launching instance to the primary instance, in the form of a - * #GVariant dictionary mapping strings to variants. To use platform - * data, override the @before_emit or @after_emit virtual functions - * in your #GApplication subclass. When dealing with - * #GApplicationCommandLine objects, the platform data is - * directly available via g_application_command_line_get_cwd(), - * g_application_command_line_get_environ() and - * g_application_command_line_get_platform_data(). + * [struct@GLib.Variant] dictionary mapping strings to variants. To use platform + * data, override the [vfunc@Gio.Application.before_emit] or + * [vfunc@Gio.Application.after_emit] virtual functions + * in your `GApplication` subclass. When dealing with + * [class@Gio.ApplicationCommandLine] objects, the platform data is + * directly available via [method@Gio.ApplicationCommandLine.get_cwd], + * [method@Gio.ApplicationCommandLine.get_environ] and + * [method@Gio.ApplicationCommandLine.get_platform_data]. * * As the name indicates, the platform data may vary depending on the * operating system, but it always includes the current directory (key - * "cwd"), and optionally the environment (ie the set of environment - * variables and their values) of the calling process (key "environ"). + * `cwd`), and optionally the environment (ie the set of environment + * variables and their values) of the calling process (key `environ`). * The environment is only added to the platform data if the - * %G_APPLICATION_SEND_ENVIRONMENT flag is set. #GApplication subclasses - * can add their own platform data by overriding the @add_platform_data - * virtual function. For instance, #GtkApplication adds startup notification - * data in this way. + * `G_APPLICATION_SEND_ENVIRONMENT` flag is set. `GApplication` subclasses + * can add their own platform data by overriding the + * [vfunc@Gio.Application.add_platform_data] virtual function. For instance, + * `GtkApplication` adds startup notification data in this way. * * To parse commandline arguments you may handle the - * #GApplication::command-line signal or override the local_command_line() - * vfunc, to parse them in either the primary instance or the local instance, - * respectively. + * [signal@Gio.Application::command-line] signal or override the + * [vfunc@Gio.Application.local_command_line] virtual funcion, to parse them in + * either the primary instance or the local instance, respectively. * - * For an example of opening files with a GApplication, see + * For an example of opening files with a `GApplication`, see * [gapplication-example-open.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-open.c). * - * For an example of using actions with GApplication, see + * For an example of using actions with `GApplication`, see * [gapplication-example-actions.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-actions.c). * - * For an example of using extra D-Bus hooks with GApplication, see + * For an example of using extra D-Bus hooks with `GApplication`, see * [gapplication-example-dbushooks.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-dbushooks.c). - */ - -/** - * GApplication: * - * #GApplication is an opaque data structure and can only be accessed - * using the following functions. * Since: 2.28 */ @@ -211,7 +208,7 @@ * using its D-Bus backend. You can use this to export extra objects on the * bus, that need to exist before the application tries to own the bus name. * The function is passed the #GDBusConnection to to session bus, and the - * object path that #GApplication will use to export is D-Bus API. + * object path that #GApplication will use to export its D-Bus API. * If this function returns %TRUE, registration will proceed; otherwise * registration will abort. Since: 2.34 * @dbus_unregister: invoked locally during unregistration, if the application @@ -658,8 +655,8 @@ add_packed_option (GApplication *application, /** * g_application_add_main_option_entries: * @application: a #GApplication - * @entries: (array zero-terminated=1) (element-type GOptionEntry) a - * %NULL-terminated list of #GOptionEntrys + * @entries: (array zero-terminated=1) (element-type GOptionEntry): the + * main options for the application * * Adds main option entries to be handled by @application. * @@ -1079,13 +1076,19 @@ g_application_call_command_line (GApplication *application, { GApplicationCommandLine *cmdline; GVariant *v; + gint handler_exit_status; v = g_variant_new_bytestring_array ((const gchar **) arguments, -1); cmdline = g_object_new (G_TYPE_APPLICATION_COMMAND_LINE, "arguments", v, "options", options, NULL); - g_signal_emit (application, g_application_signals[SIGNAL_COMMAND_LINE], 0, cmdline, exit_status); + g_signal_emit (application, g_application_signals[SIGNAL_COMMAND_LINE], 0, cmdline, &handler_exit_status); + + /* For consistency with remote invocations */ + g_application_command_line_set_exit_status (cmdline, handler_exit_status); + *exit_status = g_application_command_line_get_exit_status (cmdline); + g_object_unref (cmdline); } } @@ -1481,49 +1484,84 @@ g_application_class_init (GApplicationClass *class) class->dbus_unregister = g_application_real_dbus_unregister; class->name_lost = g_application_real_name_lost; + /** + * GApplication:application-id: + * + * The unique identifier for the application. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_APPLICATION_ID, - g_param_spec_string ("application-id", - P_("Application identifier"), - P_("The unique identifier for the application"), + g_param_spec_string ("application-id", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:flags: + * + * Flags specifying the behaviour of the application. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("Application flags"), - P_("Flags specifying the behaviour of the application"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_APPLICATION_FLAGS, G_APPLICATION_DEFAULT_FLAGS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:resource-base-path: + * + * The base resource path for the application. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_RESOURCE_BASE_PATH, - g_param_spec_string ("resource-base-path", - P_("Resource base path"), - P_("The base resource path for the application"), + g_param_spec_string ("resource-base-path", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:is-registered: + * + * Whether [method@Gio.Application.register] has been called. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_IS_REGISTERED, - g_param_spec_boolean ("is-registered", - P_("Is registered"), - P_("If g_application_register() has been called"), + g_param_spec_boolean ("is-registered", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:is-remote: + * + * Whether this application instance is remote. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_IS_REMOTE, - g_param_spec_boolean ("is-remote", - P_("Is remote"), - P_("If this application instance is remote"), + g_param_spec_boolean ("is-remote", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:inactivity-timeout: + * + * Time (in milliseconds) to stay alive after becoming idle. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_INACTIVITY_TIMEOUT, - g_param_spec_uint ("inactivity-timeout", - P_("Inactivity timeout"), - P_("Time (ms) to stay alive after becoming idle"), + g_param_spec_uint ("inactivity-timeout", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GApplication:action-group: + * + * The group of actions that the application exports. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_ACTION_GROUP, - g_param_spec_object ("action-group", - P_("Action group"), - P_("The group of actions that the application exports"), + g_param_spec_object ("action-group", NULL, NULL, G_TYPE_ACTION_GROUP, G_PARAM_DEPRECATED | G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); @@ -1536,9 +1574,7 @@ g_application_class_init (GApplicationClass *class) * Since: 2.44 */ g_object_class_install_property (object_class, PROP_IS_BUSY, - g_param_spec_boolean ("is-busy", - P_("Is busy"), - P_("If this application is currently marked busy"), + g_param_spec_boolean ("is-busy", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); /** @@ -2530,7 +2566,7 @@ g_application_run (GApplication *application, gchar *prgname; prgname = g_path_get_basename (argv[0]); - g_set_prgname (prgname); + GLIB_PRIVATE_CALL (g_set_prgname_once) (prgname); g_free (prgname); } @@ -2945,6 +2981,9 @@ g_application_get_is_busy (GApplication *application) * If @notification is no longer relevant, it can be withdrawn with * g_application_withdraw_notification(). * + * It is an error to call this function if @application has no + * application ID. + * * Since: 2.40 */ void @@ -2958,6 +2997,7 @@ g_application_send_notification (GApplication *application, g_return_if_fail (G_IS_NOTIFICATION (notification)); g_return_if_fail (g_application_get_is_registered (application)); g_return_if_fail (!g_application_get_is_remote (application)); + g_return_if_fail (g_application_get_application_id (application) != NULL); if (application->priv->notifications == NULL) application->priv->notifications = g_notification_backend_new_default (application); diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c index e9a6f46..5945e4e 100644 --- a/gio/gapplicationcommandline.c +++ b/gio/gapplicationcommandline.c @@ -40,36 +40,35 @@ #endif /** - * SECTION:gapplicationcommandline - * @title: GApplicationCommandLine - * @short_description: A command-line invocation of an application - * @include: gio/gio.h - * @see_also: #GApplication + * GApplicationCommandLine: + * + * `GApplicationCommandLine` represents a command-line invocation of + * an application. * - * #GApplicationCommandLine represents a command-line invocation of - * an application. It is created by #GApplication and emitted - * in the #GApplication::command-line signal and virtual function. + * It is created by [class@Gio.Application] and emitted + * in the [signal@Gio.Application::command-line] signal and virtual function. * * The class contains the list of arguments that the program was invoked - * with. It is also possible to query if the commandline invocation was + * with. It is also possible to query if the commandline invocation was * local (ie: the current process is running in direct response to the * invocation) or remote (ie: some other process forwarded the * commandline to this process). * - * The GApplicationCommandLine object can provide the @argc and @argv - * parameters for use with the #GOptionContext command-line parsing API, - * with the g_application_command_line_get_arguments() function. See + * The `GApplicationCommandLine` object can provide the @argc and @argv + * parameters for use with the [struct@Glib.OptionContext] command-line parsing API, + * with the [method@Gio.ApplicationCommandLine.get_arguments] function. See * [gapplication-example-cmdline3.c][gapplication-example-cmdline3] * for an example. * * The exit status of the originally-invoked process may be set and - * messages can be printed to stdout or stderr of that process. The - * lifecycle of the originally-invoked process is tied to the lifecycle - * of this object (ie: the process exits when the last reference is - * dropped). + * messages can be printed to stdout or stderr of that process. + * + * For remote invocation, the originally-invoked process exits when + * [method@Gio.ApplicationCommandLine.done] method is called. This method is + * also automatically called when the object is disposed. * - * The main use for #GApplicationCommandLine (and the - * #GApplication::command-line signal) is 'Emacs server' like use cases: + * The main use for `GApplicationCommandLine` (and the + * [signal@Gio.Application::command-line] signal) is 'Emacs server' like use cases: * You can set the `EDITOR` environment variable to have e.g. git use * your favourite editor to edit commit messages, and if you already * have an instance of the editor running, the editing will happen @@ -78,11 +77,12 @@ * does not return until the editing is done. * * Normally, the commandline is completely handled in the - * #GApplication::command-line handler. The launching instance exits + * [signal@Gio.Application::command-line] handler. The launching instance exits * once the signal handler in the primary instance has returned, and * the return value of the signal handler becomes the exit status * of the launching instance. - * |[ + * + * ```c * static int * command_line (GApplication *application, * GApplicationCommandLine *cmdline) @@ -104,13 +104,15 @@ * * return 0; * } - * ]| - * The complete example can be found here: + * ``` + * + * The complete example can be found here: * [gapplication-example-cmdline.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline.c) * * In more complicated cases, the handling of the commandline can be * split between the launcher and the primary instance. - * |[ + * + * ```c * static gboolean * test_local_cmdline (GApplication *application, * gchar ***arguments, @@ -156,18 +158,19 @@ * * ... * } - * ]| + * ``` + * * In this example of split commandline handling, options that start * with `--local-` are handled locally, all other options are passed - * to the #GApplication::command-line handler which runs in the primary + * to the [signal@Gio.Application::command-line] handler which runs in the primary * instance. * * The complete example can be found here: * [gapplication-example-cmdline2.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gapplication-example-cmdline2.c) * - * If handling the commandline requires a lot of work, it may - * be better to defer it. - * |[ + * If handling the commandline requires a lot of work, it may be better to defer it. + * + * ```c * static gboolean * my_cmdline_handler (gpointer data) * { @@ -197,10 +200,11 @@ * * return 0; * } - * ]| + * ``` + * * In this example the commandline is not completely handled before - * the #GApplication::command-line handler returns. Instead, we keep - * a reference to the #GApplicationCommandLine object and handle it + * the [signal@Gio.Application::command-line] handler returns. Instead, we keep + * a reference to the `GApplicationCommandLine` object and handle it * later (in this example, in an idle). Note that it is necessary to * hold the application until you are done with the commandline. * @@ -209,13 +213,6 @@ */ /** - * GApplicationCommandLine: - * - * #GApplicationCommandLine is an opaque data structure and can only be accessed - * using the following functions. - */ - -/** * GApplicationCommandLineClass: * * The #GApplicationCommandLineClass-struct @@ -242,6 +239,7 @@ struct _GApplicationCommandLinePrivate gchar **environ; gint exit_status; + gboolean done; }; G_DEFINE_TYPE_WITH_PRIVATE (GApplicationCommandLine, g_application_command_line, G_TYPE_OBJECT) @@ -305,6 +303,11 @@ g_application_command_line_real_get_stdin (GApplicationCommandLine *cmdline) } static void +g_application_command_line_real_done (GApplicationCommandLine *cmdline) +{ +} + +static void g_application_command_line_get_property (GObject *object, guint prop_id, GValue *value, @@ -364,6 +367,16 @@ g_application_command_line_set_property (GObject *object, } static void +g_application_command_line_dispose (GObject *object) +{ + GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object); + + g_application_command_line_done (cmdline); + + G_OBJECT_CLASS (g_application_command_line_parent_class)->dispose (object); +} + +static void g_application_command_line_finalize (GObject *object) { GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object); @@ -416,39 +429,63 @@ g_application_command_line_class_init (GApplicationCommandLineClass *class) object_class->get_property = g_application_command_line_get_property; object_class->set_property = g_application_command_line_set_property; object_class->finalize = g_application_command_line_finalize; + object_class->dispose = g_application_command_line_dispose; object_class->constructed = g_application_command_line_constructed; class->printerr_literal = g_application_command_line_real_printerr_literal; class->print_literal = g_application_command_line_real_print_literal; class->get_stdin = g_application_command_line_real_get_stdin; + class->done = g_application_command_line_real_done; + + /** + * GApplicationCommandLine:arguments: + * + * The commandline that caused this [signal@Gio.Application::command-line] + * signal emission. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_ARGUMENTS, - g_param_spec_variant ("arguments", - P_("Commandline arguments"), - P_("The commandline that caused this ::command-line signal emission"), + g_param_spec_variant ("arguments", NULL, NULL, G_VARIANT_TYPE_BYTESTRING_ARRAY, NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GApplicationCommandLine:options: + * + * The options sent along with the commandline. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_OPTIONS, - g_param_spec_variant ("options", - P_("Options"), - P_("The options sent along with the commandline"), + g_param_spec_variant ("options", NULL, NULL, G_VARIANT_TYPE_VARDICT, NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GApplicationCommandLine:platform-data: + * + * Platform-specific data for the commandline. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_PLATFORM_DATA, - g_param_spec_variant ("platform-data", - P_("Platform data"), - P_("Platform-specific data for the commandline"), + g_param_spec_variant ("platform-data", NULL, NULL, G_VARIANT_TYPE ("a{sv}"), NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GApplicationCommandLine:is-remote: + * + * Whether this is a remote commandline. + * + * Since: 2.28 + */ g_object_class_install_property (object_class, PROP_IS_REMOTE, - g_param_spec_boolean ("is-remote", - P_("Is remote"), - P_("TRUE if this is a remote commandline"), + g_param_spec_boolean ("is-remote", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } @@ -659,6 +696,54 @@ g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline) } /** + * g_application_command_line_print_literal: + * @cmdline: a #GApplicationCommandLine + * @message: the message + * + * Prints a message using the stdout print handler in the invoking process. + * + * Unlike g_application_command_line_print(), @message is not a `printf()`-style + * format string. Use this function if @message contains text you don't have + * control over, that could include `printf()` escape sequences. + * + * Since: 2.80 + **/ +void +g_application_command_line_print_literal (GApplicationCommandLine *cmdline, + const gchar *message) +{ + g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline)); + g_return_if_fail (message != NULL); + + G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline) + ->print_literal (cmdline, message); +} + +/** + * g_application_command_line_printerr_literal: + * @cmdline: a #GApplicationCommandLine + * @message: the message + * + * Prints a message using the stderr print handler in the invoking process. + * + * Unlike g_application_command_line_printerr(), @message is not + * a `printf()`-style format string. Use this function if @message contains text + * you don't have control over, that could include `printf()` escape sequences. + * + * Since: 2.80 + **/ +void +g_application_command_line_printerr_literal (GApplicationCommandLine *cmdline, + const gchar *message) +{ + g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline)); + g_return_if_fail (message != NULL); + + G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline) + ->printerr_literal (cmdline, message); +} + +/** * g_application_command_line_print: * @cmdline: a #GApplicationCommandLine * @format: a printf-style format string @@ -755,6 +840,9 @@ g_application_command_line_printerr (GApplicationCommandLine *cmdline, * always zero. If the application use count is zero, though, the exit * status of the local #GApplicationCommandLine is used. * + * This method is a no-op if g_application_command_line_done() has + * been called. + * * Since: 2.28 **/ void @@ -763,6 +851,9 @@ g_application_command_line_set_exit_status (GApplicationCommandLine *cmdline, { g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline)); + if (cmdline->priv->done) + return; + cmdline->priv->exit_status = exit_status; } @@ -846,3 +937,38 @@ g_application_command_line_create_file_for_arg (GApplicationCommandLine *cmdline return g_file_new_for_commandline_arg (arg); } + +/** + * g_application_command_line_done: + * @cmdline: a #GApplicationCommandLine + * + * Signals that command line processing is completed. + * + * For remote invocation, it causes the invoking process to terminate. + * + * For local invocation, it does nothing. + * + * This method should be called in the [signal@Gio.Application::command-line] + * handler, after the exit status is set and all messages are printed. + * + * After this call, g_application_command_line_set_exit_status() has no effect. + * Subsequent calls to this method are no-ops. + * + * This method is automatically called when the #GApplicationCommandLine + * object is disposed — so you can omit the call in non-garbage collected + * languages. + * + * Since: 2.80 + **/ +void +g_application_command_line_done (GApplicationCommandLine *cmdline) +{ + g_return_if_fail (G_IS_APPLICATION_COMMAND_LINE (cmdline)); + + if (cmdline->priv->done) + return; + + G_APPLICATION_COMMAND_LINE_GET_CLASS (cmdline)->done (cmdline); + + cmdline->priv->done = TRUE; +} diff --git a/gio/gapplicationcommandline.h b/gio/gapplicationcommandline.h index abb6852..51133c4 100644 --- a/gio/gapplicationcommandline.h +++ b/gio/gapplicationcommandline.h @@ -67,8 +67,9 @@ struct _GApplicationCommandLineClass void (* printerr_literal) (GApplicationCommandLine *cmdline, const gchar *message); GInputStream * (* get_stdin) (GApplicationCommandLine *cmdline); + void (* done) (GApplicationCommandLine *cmdline); - gpointer padding[11]; + gpointer padding[10]; }; GIO_AVAILABLE_IN_ALL @@ -97,6 +98,13 @@ const gchar * g_application_command_line_get_cwd (GApplic GIO_AVAILABLE_IN_ALL gboolean g_application_command_line_get_is_remote (GApplicationCommandLine *cmdline); +GIO_AVAILABLE_IN_2_80 +void g_application_command_line_print_literal (GApplicationCommandLine *cmdline, + const gchar *message); +GIO_AVAILABLE_IN_2_80 +void g_application_command_line_printerr_literal (GApplicationCommandLine *cmdline, + const gchar *message); + GIO_AVAILABLE_IN_ALL void g_application_command_line_print (GApplicationCommandLine *cmdline, const gchar *format, @@ -119,6 +127,9 @@ GIO_AVAILABLE_IN_2_36 GFile * g_application_command_line_create_file_for_arg (GApplicationCommandLine *cmdline, const gchar *arg); +GIO_AVAILABLE_IN_2_80 +void g_application_command_line_done (GApplicationCommandLine *cmdline); + G_END_DECLS #endif /* __G_APPLICATION_COMMAND_LINE_H__ */ diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index ac6644d..f9bf28c 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -970,18 +970,26 @@ g_dbus_command_line_get_stdin (GApplicationCommandLine *cmdline) static void g_dbus_command_line_finalize (GObject *object) { - GApplicationCommandLine *cmdline = G_APPLICATION_COMMAND_LINE (object); GDBusCommandLine *gdbcl = (GDBusCommandLine *) object; + + g_object_unref (gdbcl->invocation); + + G_OBJECT_CLASS (g_dbus_command_line_parent_class) + ->finalize (object); +} + +static void +g_dbus_command_line_done (GApplicationCommandLine *cmdline) +{ + GDBusCommandLine *gdbcl = (GDBusCommandLine *) cmdline; gint status; status = g_application_command_line_get_exit_status (cmdline); g_dbus_method_invocation_return_value (gdbcl->invocation, g_variant_new ("(i)", status)); - g_object_unref (gdbcl->invocation); - G_OBJECT_CLASS (g_dbus_command_line_parent_class) - ->finalize (object); + G_APPLICATION_COMMAND_LINE_CLASS (g_dbus_command_line_parent_class)->done (cmdline); } static void @@ -998,6 +1006,7 @@ g_dbus_command_line_class_init (GApplicationCommandLineClass *class) class->printerr_literal = g_dbus_command_line_printerr_literal; class->print_literal = g_dbus_command_line_print_literal; class->get_stdin = g_dbus_command_line_get_stdin; + class->done = g_dbus_command_line_done; } static GApplicationCommandLine * diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c index 433837f..346fd5b 100644 --- a/gio/gasynchelper.c +++ b/gio/gasynchelper.c @@ -26,14 +26,10 @@ /*< private > - * SECTION:gasynchelper - * @short_description: Asynchronous Helper Functions - * @include: gio/gio.h - * @see_also: #GAsyncResult + * GAsyncHelper: * * Provides helper functions for asynchronous operations. - * - **/ + */ #ifdef G_OS_WIN32 gboolean diff --git a/gio/gasyncinitable.c b/gio/gasyncinitable.c index c1a05e8..024efa2 100644 --- a/gio/gasyncinitable.c +++ b/gio/gasyncinitable.c @@ -29,27 +29,26 @@ /** - * SECTION:gasyncinitable - * @short_description: Asynchronously failable object initialization interface - * @include: gio/gio.h - * @see_also: #GInitable + * GAsyncInitable: * - * This is the asynchronous version of #GInitable; it behaves the same + * `GAsyncInitable` is an interface for asynchronously initializable objects. + * + * This is the asynchronous version of [iface@Gio.Initable]; it behaves the same * in all ways except that initialization is asynchronous. For more details - * see the descriptions on #GInitable. + * see the descriptions on `GInitable`. * - * A class may implement both the #GInitable and #GAsyncInitable interfaces. + * A class may implement both the `GInitable` and `GAsyncInitable` interfaces. * * Users of objects implementing this are not intended to use the interface * method directly; instead it will be used automatically in various ways. - * For C applications you generally just call g_async_initable_new_async() + * For C applications you generally just call [func@Gio.AsyncInitable.new_async] * directly, or indirectly via a foo_thing_new_async() wrapper. This will call - * g_async_initable_init_async() under the cover, calling back with %NULL and - * a set %GError on failure. + * [method@Gio.AsyncInitable.init_async] under the covers, calling back with `NULL` + * and a set `GError` on failure. * * A typical implementation might look something like this: * - * |[ + * ```c * enum { * NOT_INITIALIZED, * INITIALIZING, @@ -132,7 +131,9 @@ * iface->init_async = foo_init_async; * iface->init_finish = foo_init_finish; * } - * ]| + * ``` + * + * Since: 2.22 */ static void g_async_initable_real_init_async (GAsyncInitable *initable, diff --git a/gio/gasyncinitable.h b/gio/gasyncinitable.h index 1808398..eb9b026 100644 --- a/gio/gasyncinitable.h +++ b/gio/gasyncinitable.h @@ -38,13 +38,6 @@ G_BEGIN_DECLS #define G_ASYNC_INITABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_ASYNC_INITABLE, GAsyncInitableIface)) #define G_TYPE_IS_ASYNC_INITABLE(type) (g_type_is_a ((type), G_TYPE_ASYNC_INITABLE)) -/** - * GAsyncInitable: - * - * Interface for asynchronously initializable objects. - * - * Since: 2.22 - **/ typedef struct _GAsyncInitableIface GAsyncInitableIface; /** diff --git a/gio/gasyncresult.c b/gio/gasyncresult.c index 4d2f5f9..70024bc 100644 --- a/gio/gasyncresult.c +++ b/gio/gasyncresult.c @@ -27,42 +27,40 @@ /** - * SECTION:gasyncresult - * @short_description: Asynchronous Function Results - * @include: gio/gio.h - * @see_also: #GTask + * GAsyncResult: * - * Provides a base class for implementing asynchronous function results. + * `GAsyncResult` provides a base class for implementing asynchronous function results. * * Asynchronous operations are broken up into two separate operations - * which are chained together by a #GAsyncReadyCallback. To begin - * an asynchronous operation, provide a #GAsyncReadyCallback to the + * which are chained together by a `GAsyncReadyCallback`. To begin + * an asynchronous operation, provide a `GAsyncReadyCallback` to the * asynchronous function. This callback will be triggered when the * operation has completed, and must be run in a later iteration of - * the [thread-default main context][g-main-context-push-thread-default] - * from where the operation was initiated. It will be passed a - * #GAsyncResult instance filled with the details of the operation's - * success or failure, the object the asynchronous function was - * started for and any error codes returned. The asynchronous callback - * function is then expected to call the corresponding "_finish()" + * the thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) from where the operation was + * initiated. It will be passed a `GAsyncResult` instance filled with the + * details of the operation's success or failure, the object the asynchronous + * function was started for and any error codes returned. The asynchronous + * callback function is then expected to call the corresponding `_finish()` * function, passing the object the function was called for, the - * #GAsyncResult instance, and (optionally) an @error to grab any + * `GAsyncResult` instance, and (optionally) an @error to grab any * error conditions that may have occurred. * - * The "_finish()" function for an operation takes the generic result - * (of type #GAsyncResult) and returns the specific result that the - * operation in question yields (e.g. a #GFileEnumerator for a + * The `_finish()` function for an operation takes the generic result + * (of type `GAsyncResult`) and returns the specific result that the + * operation in question yields (e.g. a [class@Gio.FileEnumerator] for a * "enumerate children" operation). If the result or error status of the - * operation is not needed, there is no need to call the "_finish()" + * operation is not needed, there is no need to call the `_finish()` * function; GIO will take care of cleaning up the result and error - * information after the #GAsyncReadyCallback returns. You can pass - * %NULL for the #GAsyncReadyCallback if you don't need to take any + * information after the `GAsyncReadyCallback` returns. You can pass + * `NULL` for the `GAsyncReadyCallback` if you don't need to take any * action at all after the operation completes. Applications may also - * take a reference to the #GAsyncResult and call "_finish()" later; - * however, the "_finish()" function may be called at most once. + * take a reference to the `GAsyncResult` and call `_finish()` later; + * however, the `_finish()` function may be called at most once. * * Example of a typical asynchronous operation flow: - * |[ + * + * ```c * void _theoretical_frobnitz_async (Theoretical *t, * GCancellable *c, * GAsyncReadyCallback cb, @@ -101,20 +99,20 @@ * * ... * } - * ]| + * ``` * * The callback for an asynchronous operation is called only once, and is * always called, even in the case of a cancelled operation. On cancellation - * the result is a %G_IO_ERROR_CANCELLED error. + * the result is a `G_IO_ERROR_CANCELLED` error. * - * ## I/O Priority # {#io-priority} + * ## I/O Priority * * Many I/O-related asynchronous operations have a priority parameter, * which is used in certain cases to determine the order in which * operations are executed. They are not used to determine system-wide * I/O scheduling. Priorities are integers, with lower numbers indicating * higher priority. It is recommended to choose priorities between - * %G_PRIORITY_LOW and %G_PRIORITY_HIGH, with %G_PRIORITY_DEFAULT + * `G_PRIORITY_LOW` and `G_PRIORITY_HIGH`, with `G_PRIORITY_DEFAULT` * as a default. */ diff --git a/gio/gasyncresult.h b/gio/gasyncresult.h index 4a98c5f..17c79d4 100644 --- a/gio/gasyncresult.h +++ b/gio/gasyncresult.h @@ -36,12 +36,6 @@ G_BEGIN_DECLS #define G_IS_ASYNC_RESULT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_ASYNC_RESULT)) #define G_ASYNC_RESULT_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_ASYNC_RESULT, GAsyncResultIface)) -/** - * GAsyncResult: - * - * Holds results information for an asynchronous operation, - * usually passed directly to an asynchronous _finish() operation. - **/ typedef struct _GAsyncResultIface GAsyncResultIface; diff --git a/gio/gbufferedinputstream.c b/gio/gbufferedinputstream.c index 1729ebd..64cb293 100644 --- a/gio/gbufferedinputstream.c +++ b/gio/gbufferedinputstream.c @@ -34,25 +34,21 @@ /** - * SECTION:gbufferedinputstream - * @short_description: Buffered Input Stream - * @include: gio/gio.h - * @see_also: #GFilterInputStream, #GInputStream + * GBufferedInputStream: * * Buffered input stream implements #GFilterInputStream and provides * for buffered reads. * - * By default, #GBufferedInputStream's buffer size is set at 4 kilobytes. + * By default, `GBufferedInputStream`'s buffer size is set at 4 kilobytes. * - * To create a buffered input stream, use g_buffered_input_stream_new(), - * or g_buffered_input_stream_new_sized() to specify the buffer's size at + * To create a buffered input stream, use [ctor@Gio.BufferedInputStream.new], + * or [ctor@Gio.BufferedInputStream.new_sized] to specify the buffer's size at * construction. * * To get the size of a buffer within a buffered input stream, use - * g_buffered_input_stream_get_buffer_size(). To change the size of a - * buffered input stream's buffer, use - * g_buffered_input_stream_set_buffer_size(). Note that the buffer's size - * cannot be reduced below the size of the data within the buffer. + * [method@Gio.BufferedInputStream.get_buffer_size]. To change the size of a + * buffered input stream's buffer, use [method@Gio.BufferedInputStream.set_buffer_size]. + * Note that the buffer's size cannot be reduced below the size of the data within the buffer. */ @@ -161,11 +157,14 @@ g_buffered_input_stream_class_init (GBufferedInputStreamClass *klass) bstream_class->fill_async = g_buffered_input_stream_real_fill_async; bstream_class->fill_finish = g_buffered_input_stream_real_fill_finish; + /** + * GBufferedInputStream:buffer-size: + * + * The size of the backend buffer, in bytes. + */ g_object_class_install_property (object_class, PROP_BUFSIZE, - g_param_spec_uint ("buffer-size", - P_("Buffer Size"), - P_("The size of the backend buffer"), + g_param_spec_uint ("buffer-size", NULL, NULL, 1, G_MAXUINT, DEFAULT_BUFFER_SIZE, diff --git a/gio/gbufferedinputstream.h b/gio/gbufferedinputstream.h index c6b1dea..eced51f 100644 --- a/gio/gbufferedinputstream.h +++ b/gio/gbufferedinputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_BUFFERED_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_BUFFERED_INPUT_STREAM)) #define G_BUFFERED_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_BUFFERED_INPUT_STREAM, GBufferedInputStreamClass)) -/** - * GBufferedInputStream: - * - * Implements #GFilterInputStream with a sized input buffer. - **/ typedef struct _GBufferedInputStreamClass GBufferedInputStreamClass; typedef struct _GBufferedInputStreamPrivate GBufferedInputStreamPrivate; diff --git a/gio/gbufferedoutputstream.c b/gio/gbufferedoutputstream.c index 4999a7d..f82b10f 100644 --- a/gio/gbufferedoutputstream.c +++ b/gio/gbufferedoutputstream.c @@ -30,26 +30,22 @@ #include "glibintl.h" /** - * SECTION:gbufferedoutputstream - * @short_description: Buffered Output Stream - * @include: gio/gio.h - * @see_also: #GFilterOutputStream, #GOutputStream - * - * Buffered output stream implements #GFilterOutputStream and provides - * for buffered writes. - * - * By default, #GBufferedOutputStream's buffer size is set at 4 kilobytes. - * - * To create a buffered output stream, use g_buffered_output_stream_new(), - * or g_buffered_output_stream_new_sized() to specify the buffer's size + * GBufferedOutputStream: + * + * Buffered output stream implements [class@Gio.FilterOutputStream] and provides + * for buffered writes. + * + * By default, `GBufferedOutputStream`'s buffer size is set at 4 kilobytes. + * + * To create a buffered output stream, use [ctor@Gio.BufferedOutputStream.new], + * or [ctor@Gio.BufferedOutputStream.new_sized] to specify the buffer's size * at construction. - * - * To get the size of a buffer within a buffered input stream, use - * g_buffered_output_stream_get_buffer_size(). To change the size of a - * buffered output stream's buffer, use - * g_buffered_output_stream_set_buffer_size(). Note that the buffer's - * size cannot be reduced below the size of the data within the buffer. - **/ + * + * To get the size of a buffer within a buffered input stream, use + * [method@Gio.BufferedOutputStream.get_buffer_size]. To change the size of a + * buffered output stream's buffer, use [method@Gio.BufferedOutputStream.set_buffer_size]. + * Note that the buffer's size cannot be reduced below the size of the data within the buffer. + */ #define DEFAULT_BUFFER_SIZE 4096 @@ -149,22 +145,28 @@ g_buffered_output_stream_class_init (GBufferedOutputStreamClass *klass) ostream_class->close_async = g_buffered_output_stream_close_async; ostream_class->close_finish = g_buffered_output_stream_close_finish; + /** + * GBufferedOutputStream:buffer-size: + * + * The size of the backend buffer, in bytes. + */ g_object_class_install_property (object_class, PROP_BUFSIZE, - g_param_spec_uint ("buffer-size", - P_("Buffer Size"), - P_("The size of the backend buffer"), + g_param_spec_uint ("buffer-size", NULL, NULL, 1, G_MAXUINT, DEFAULT_BUFFER_SIZE, G_PARAM_READWRITE|G_PARAM_CONSTRUCT| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + /** + * GBufferedOutputStream:auto-grow: + * + * Whether the buffer should automatically grow. + */ g_object_class_install_property (object_class, PROP_AUTO_GROW, - g_param_spec_boolean ("auto-grow", - P_("Auto-grow"), - P_("Whether the buffer should automatically grow"), + g_param_spec_boolean ("auto-grow", NULL, NULL, FALSE, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); diff --git a/gio/gbufferedoutputstream.h b/gio/gbufferedoutputstream.h index 1259c76..339b916 100644 --- a/gio/gbufferedoutputstream.h +++ b/gio/gbufferedoutputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_BUFFERED_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_BUFFERED_OUTPUT_STREAM)) #define G_BUFFERED_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_BUFFERED_OUTPUT_STREAM, GBufferedOutputStreamClass)) -/** - * GBufferedOutputStream: - * - * An implementation of #GFilterOutputStream with a sized buffer. - **/ typedef struct _GBufferedOutputStreamClass GBufferedOutputStreamClass; typedef struct _GBufferedOutputStreamPrivate GBufferedOutputStreamPrivate; diff --git a/gio/gbytesicon.c b/gio/gbytesicon.c index b402a51..37c242a 100644 --- a/gio/gbytesicon.c +++ b/gio/gbytesicon.c @@ -33,16 +33,13 @@ /** - * SECTION:gbytesicon - * @short_description: An icon stored in memory as a GBytes - * @include: gio/gio.h - * @see_also: #GIcon, #GLoadableIcon, #GBytes + * GBytesIcon: * - * #GBytesIcon specifies an image held in memory in a common format (usually - * png) to be used as icon. + * `GBytesIcon` specifies an image held in memory in a common format (usually + * PNG) to be used as icon. * * Since: 2.38 - **/ + */ typedef GObjectClass GBytesIconClass; @@ -130,9 +127,7 @@ g_bytes_icon_class_init (GBytesIconClass *klass) * The bytes containing the icon. */ g_object_class_install_property (gobject_class, PROP_BYTES, - g_param_spec_boxed ("bytes", - P_("bytes"), - P_("The bytes containing the icon"), + g_param_spec_boxed ("bytes", NULL, NULL, G_TYPE_BYTES, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gbytesicon.h b/gio/gbytesicon.h index c917d38..1d5ccd7 100644 --- a/gio/gbytesicon.h +++ b/gio/gbytesicon.h @@ -35,11 +35,6 @@ G_BEGIN_DECLS #define G_BYTES_ICON(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), G_TYPE_BYTES_ICON, GBytesIcon)) #define G_IS_BYTES_ICON(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_BYTES_ICON)) -/** - * GBytesIcon: - * - * Gets an icon for a #GBytes. Implements #GLoadableIcon. - **/ GIO_AVAILABLE_IN_2_38 GType g_bytes_icon_get_type (void) G_GNUC_CONST; diff --git a/gio/gcancellable.c b/gio/gcancellable.c index 5ff479c..41ffab3 100644 --- a/gio/gcancellable.c +++ b/gio/gcancellable.c @@ -29,11 +29,11 @@ /** - * SECTION:gcancellable - * @short_description: Thread-safe Operation Cancellation Stack - * @include: gio/gio.h + * GCancellable: * - * GCancellable is a thread-safe operation cancellation stack used + * `GCancellable` allows operations to be cancelled. + * + * `GCancellable` is a thread-safe operation cancellation stack used * throughout GIO to allow for cancellation of synchronous and * asynchronous operations. */ diff --git a/gio/gcancellable.h b/gio/gcancellable.h index d33215d..6a76b59 100644 --- a/gio/gcancellable.h +++ b/gio/gcancellable.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_CANCELLABLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_CANCELLABLE)) #define G_CANCELLABLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_CANCELLABLE, GCancellableClass)) -/** - * GCancellable: - * - * Allows actions to be cancelled. - */ typedef struct _GCancellableClass GCancellableClass; typedef struct _GCancellablePrivate GCancellablePrivate; diff --git a/gio/gcharsetconverter.c b/gio/gcharsetconverter.c index 4993199..c9437e1 100644 --- a/gio/gcharsetconverter.c +++ b/gio/gcharsetconverter.c @@ -39,22 +39,15 @@ enum { }; /** - * SECTION:gcharsetconverter - * @short_description: Convert between charsets - * @include: gio/gio.h + * GCharsetConverter: * - * #GCharsetConverter is an implementation of #GConverter based on - * GIConv. + * `GCharsetConverter` is an implementation of [iface@Gio.Converter] based on + * [struct@GLib.IConv]. */ static void g_charset_converter_iface_init (GConverterIface *iface); static void g_charset_converter_initable_iface_init (GInitableIface *iface); -/** - * GCharsetConverter: - * - * Conversions between character sets. - */ struct _GCharsetConverter { GObject parent_instance; @@ -159,27 +152,44 @@ g_charset_converter_class_init (GCharsetConverterClass *klass) gobject_class->get_property = g_charset_converter_get_property; gobject_class->set_property = g_charset_converter_set_property; + /** + * GCharsetConverter:to-charset: + * + * The character encoding to convert to. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_TO_CHARSET, - g_param_spec_string ("to-charset", - P_("To Charset"), - P_("The character encoding to convert to"), + g_param_spec_string ("to-charset", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GCharsetConverter:from-charset: + * + * The character encoding to convert from. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_FROM_CHARSET, - g_param_spec_string ("from-charset", - P_("From Charset"), - P_("The character encoding to convert from"), + g_param_spec_string ("from-charset", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GCharsetConverter:use-fallback: + * + * Use fallback (of form `\`) for invalid bytes. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_USE_FALLBACK, - g_param_spec_boolean ("use-fallback", - P_("Fallback enabled"), - P_("Use fallback (of form \\) for invalid bytes"), + g_param_spec_boolean ("use-fallback", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | diff --git a/gio/gcontenttype.c b/gio/gcontenttype.c index 87d2df8..de9e5a7 100644 --- a/gio/gcontenttype.c +++ b/gio/gcontenttype.c @@ -38,9 +38,7 @@ /** - * SECTION:gcontenttype - * @short_description: Platform-specific content typing - * @include: gio/gio.h + * GContentType: * * A content type is a platform specific string that defines the type * of a file. On UNIX it is a diff --git a/gio/gconverter.c b/gio/gconverter.c index 57ee1b9..973224f 100644 --- a/gio/gconverter.c +++ b/gio/gconverter.c @@ -26,12 +26,11 @@ /** - * SECTION:gconverter - * @short_description: Data conversion interface - * @include: gio/gio.h - * @see_also: #GInputStream, #GOutputStream + * GConverter: * - * #GConverter is implemented by objects that convert + * `GConverter` is an interface for streaming conversions. + * + * `GConverter` is implemented by objects that convert * binary data in various ways. The conversion can be * stateful and may fail at any place. * @@ -40,7 +39,7 @@ * replace. * * Since: 2.24 - **/ + */ typedef GConverterIface GConverterInterface; diff --git a/gio/gconverter.h b/gio/gconverter.h index 16e94a1..87afbf3 100644 --- a/gio/gconverter.h +++ b/gio/gconverter.h @@ -36,13 +36,6 @@ G_BEGIN_DECLS #define G_IS_CONVERTER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_CONVERTER)) #define G_CONVERTER_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_CONVERTER, GConverterIface)) -/** - * GConverter: - * - * Seek object for streaming operations. - * - * Since: 2.24 - **/ typedef struct _GConverterIface GConverterIface; /** diff --git a/gio/gconverterinputstream.c b/gio/gconverterinputstream.c index 59277bf..c74ec29 100644 --- a/gio/gconverterinputstream.c +++ b/gio/gconverterinputstream.c @@ -33,17 +33,14 @@ /** - * SECTION:gconverterinputstream - * @short_description: Converter Input Stream - * @include: gio/gio.h - * @see_also: #GInputStream, #GConverter + * GConverterInputStream: * - * Converter input stream implements #GInputStream and allows + * Converter input stream implements [class@Gio.InputStream] and allows * conversion of data of various types during reading. * - * As of GLib 2.34, #GConverterInputStream implements - * #GPollableInputStream. - **/ + * As of GLib 2.34, `GConverterInputStream` implements + * [iface@Gio.PollableInputStream]. + */ #define INITIAL_BUFFER_SIZE 4096 @@ -116,11 +113,14 @@ g_converter_input_stream_class_init (GConverterInputStreamClass *klass) istream_class = G_INPUT_STREAM_CLASS (klass); istream_class->read_fn = g_converter_input_stream_read; + /** + * GConverterInputStream:converter: + * + * The converter object. + */ g_object_class_install_property (object_class, PROP_CONVERTER, - g_param_spec_object ("converter", - P_("Converter"), - P_("The converter object"), + g_param_spec_object ("converter", NULL, NULL, G_TYPE_CONVERTER, G_PARAM_READWRITE| G_PARAM_CONSTRUCT_ONLY| diff --git a/gio/gconverterinputstream.h b/gio/gconverterinputstream.h index 01de11e..96f4dc0 100644 --- a/gio/gconverterinputstream.h +++ b/gio/gconverterinputstream.h @@ -39,12 +39,6 @@ G_BEGIN_DECLS #define G_IS_CONVERTER_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_CONVERTER_INPUT_STREAM)) #define G_CONVERTER_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_CONVERTER_INPUT_STREAM, GConverterInputStreamClass)) -/** - * GConverterInputStream: - * - * An implementation of #GFilterInputStream that allows data - * conversion. - **/ typedef struct _GConverterInputStreamClass GConverterInputStreamClass; typedef struct _GConverterInputStreamPrivate GConverterInputStreamPrivate; diff --git a/gio/gconverteroutputstream.c b/gio/gconverteroutputstream.c index b26f645..1877b0e 100644 --- a/gio/gconverteroutputstream.c +++ b/gio/gconverteroutputstream.c @@ -33,17 +33,14 @@ /** - * SECTION:gconverteroutputstream - * @short_description: Converter Output Stream - * @include: gio/gio.h - * @see_also: #GOutputStream, #GConverter + * GConverterOutputStream: * - * Converter output stream implements #GOutputStream and allows + * Converter output stream implements [class@Gio.OutputStream] and allows * conversion of data of various types during reading. * - * As of GLib 2.34, #GConverterOutputStream implements - * #GPollableOutputStream. - **/ + * As of GLib 2.34, `GConverterOutputStream` implements + * [iface@Gio.PollableOutputStream]. + */ #define INITIAL_BUFFER_SIZE 4096 @@ -132,11 +129,14 @@ g_converter_output_stream_class_init (GConverterOutputStreamClass *klass) istream_class->write_fn = g_converter_output_stream_write; istream_class->flush = g_converter_output_stream_flush; + /** + * GConverterOutputStream:converter: + * + * The converter object. + */ g_object_class_install_property (object_class, PROP_CONVERTER, - g_param_spec_object ("converter", - P_("Converter"), - P_("The converter object"), + g_param_spec_object ("converter", NULL, NULL, G_TYPE_CONVERTER, G_PARAM_READWRITE| G_PARAM_CONSTRUCT_ONLY| diff --git a/gio/gconverteroutputstream.h b/gio/gconverteroutputstream.h index c090846..e184500 100644 --- a/gio/gconverteroutputstream.h +++ b/gio/gconverteroutputstream.h @@ -39,12 +39,6 @@ G_BEGIN_DECLS #define G_IS_CONVERTER_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_CONVERTER_OUTPUT_STREAM)) #define G_CONVERTER_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_CONVERTER_OUTPUT_STREAM, GConverterOutputStreamClass)) -/** - * GConverterOutputStream: - * - * An implementation of #GFilterOutputStream that allows data - * conversion. - **/ typedef struct _GConverterOutputStreamClass GConverterOutputStreamClass; typedef struct _GConverterOutputStreamPrivate GConverterOutputStreamPrivate; diff --git a/gio/gcredentials.c b/gio/gcredentials.c index ba5be63..11eb556 100644 --- a/gio/gcredentials.c +++ b/gio/gcredentials.c @@ -36,57 +36,47 @@ #include "glibintl.h" /** - * SECTION:gcredentials - * @short_description: An object containing credentials - * @include: gio/gio.h + * GCredentials: + * + * The `GCredentials` type is a reference-counted wrapper for native + * credentials. * - * The #GCredentials type is a reference-counted wrapper for native - * credentials. This information is typically used for identifying, + * The information in `GCredentials` is typically used for identifying, * authenticating and authorizing other processes. * - * Some operating systems supports looking up the credentials of the - * remote peer of a communication endpoint - see e.g. - * g_socket_get_credentials(). + * Some operating systems supports looking up the credentials of the remote + * peer of a communication endpoint - see e.g. [method@Gio.Socket.get_credentials]. * * Some operating systems supports securely sending and receiving - * credentials over a Unix Domain Socket, see - * #GUnixCredentialsMessage, g_unix_connection_send_credentials() and - * g_unix_connection_receive_credentials() for details. + * credentials over a Unix Domain Socket, see [class@Gio.UnixCredentialsMessage], + * [method@Gio.UnixConnection.send_credentials] and + * [method@Gio.UnixConnection.receive_credentials] for details. * * On Linux, the native credential type is a `struct ucred` - see the - * unix(7) man page for details. This corresponds to - * %G_CREDENTIALS_TYPE_LINUX_UCRED. + * [`unix(7)` man page](man:unix(7)) for details. This corresponds to + * `G_CREDENTIALS_TYPE_LINUX_UCRED`. * - * On Apple operating systems (including iOS, tvOS, and macOS), - * the native credential type is a `struct xucred`. - * This corresponds to %G_CREDENTIALS_TYPE_APPLE_XUCRED. + * On Apple operating systems (including iOS, tvOS, and macOS), the native credential + * type is a `struct xucred`. This corresponds to `G_CREDENTIALS_TYPE_APPLE_XUCRED`. * - * On FreeBSD, Debian GNU/kFreeBSD, and GNU/Hurd, the native - * credential type is a `struct cmsgcred`. This corresponds - * to %G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED. + * On FreeBSD, Debian GNU/kFreeBSD, and GNU/Hurd, the native credential type is a + * `struct cmsgcred`. This corresponds to `G_CREDENTIALS_TYPE_FREEBSD_CMSGCRED`. * * On NetBSD, the native credential type is a `struct unpcbid`. - * This corresponds to %G_CREDENTIALS_TYPE_NETBSD_UNPCBID. + * This corresponds to `G_CREDENTIALS_TYPE_NETBSD_UNPCBID`. * * On OpenBSD, the native credential type is a `struct sockpeercred`. - * This corresponds to %G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED. + * This corresponds to `G_CREDENTIALS_TYPE_OPENBSD_SOCKPEERCRED`. * - * On Solaris (including OpenSolaris and its derivatives), the native - * credential type is a `ucred_t`. This corresponds to - * %G_CREDENTIALS_TYPE_SOLARIS_UCRED. + * On Solaris (including OpenSolaris and its derivatives), the native credential type + * is a `ucred_t`. This corresponds to `G_CREDENTIALS_TYPE_SOLARIS_UCRED`. * * Since GLib 2.72, on Windows, the native credentials may contain the PID of a - * process. This corresponds to %G_CREDENTIALS_TYPE_WIN32_PID. - */ - -/** - * GCredentials: - * - * The #GCredentials structure contains only private data and - * should only be accessed using the provided API. + * process. This corresponds to `G_CREDENTIALS_TYPE_WIN32_PID`. * * Since: 2.26 */ + struct _GCredentials { /*< private >*/ diff --git a/gio/gdatagrambased.c b/gio/gdatagrambased.c index f8de372..dfa0773 100644 --- a/gio/gdatagrambased.c +++ b/gio/gdatagrambased.c @@ -32,57 +32,56 @@ #include "glibintl.h" /** - * SECTION:gdatagrambased - * @short_description: Low-level datagram communications interface - * @include: gio/gio.h - * @see_also: #GSocket, [][gio-gnetworking.h] + * GDatagramBased: * - * A #GDatagramBased is a networking interface for representing datagram-based + * Interface for socket-like objects with datagram semantics. + * + * A `GDatagramBased` is a networking interface for representing datagram-based * communications. It is a more or less direct mapping of the core parts of the * BSD socket API in a portable GObject interface. It is implemented by - * #GSocket, which wraps the UNIX socket API on UNIX and winsock2 on Windows. + * [class@Gio.Socket], which wraps the UNIX socket API on UNIX and winsock2 on Windows. * - * #GDatagramBased is entirely platform independent, and is intended to be used - * alongside higher-level networking APIs such as #GIOStream. + * `GDatagramBased` is entirely platform independent, and is intended to be used + * alongside higher-level networking APIs such as [class@Gio.IOStream]. * * It uses vectored scatter/gather I/O by default, allowing for many messages * to be sent or received in a single call. Where possible, implementations of * the interface should take advantage of vectored I/O to minimise processing - * or system calls. For example, #GSocket uses recvmmsg() and sendmmsg() where - * possible. Callers should take advantage of scatter/gather I/O (the use of + * or system calls. For example, `GSocket` uses `recvmmsg()` and `sendmmsg()` + * where possible. Callers should take advantage of scatter/gather I/O (the use of * multiple buffers per message) to avoid unnecessary copying of data to * assemble or disassemble a message. * - * Each #GDatagramBased operation has a timeout parameter which may be negative + * Each `GDatagramBased` operation has a timeout parameter which may be negative * for blocking behaviour, zero for non-blocking behaviour, or positive for * timeout behaviour. A blocking operation blocks until finished or there is an * error. A non-blocking operation will return immediately with a - * %G_IO_ERROR_WOULD_BLOCK error if it cannot make progress. A timeout operation + * `G_IO_ERROR_WOULD_BLOCK` error if it cannot make progress. A timeout operation * will block until the operation is complete or the timeout expires; if the * timeout expires it will return what progress it made, or - * %G_IO_ERROR_TIMED_OUT if no progress was made. To know when a call would - * successfully run you can call g_datagram_based_condition_check() or - * g_datagram_based_condition_wait(). You can also use - * g_datagram_based_create_source() and attach it to a #GMainContext to get - * callbacks when I/O is possible. + * `G_IO_ERROR_TIMED_OUT` if no progress was made. To know when a call would + * successfully run you can call [method@Gio.DatagramBased.condition_check] or + * [method@Gio.DatagramBased.condition_wait]. You can also use + * [method@Gio.DatagramBased.create_source] and attach it to a [struct@Glib.MainContext] + * to get callbacks when I/O is possible. * * When running a non-blocking operation applications should always be able to - * handle getting a %G_IO_ERROR_WOULD_BLOCK error even when some other function + * handle getting a `G_IO_ERROR_WOULD_BLOCK` error even when some other function * said that I/O was possible. This can easily happen in case of a race * condition in the application, but it can also happen for other reasons. For * instance, on Windows a socket is always seen as writable until a write - * returns %G_IO_ERROR_WOULD_BLOCK. + * returns `G_IO_ERROR_WOULD_BLOCK`. * - * As with #GSocket, #GDatagramBaseds can be either connection oriented (for - * example, SCTP) or connectionless (for example, UDP). #GDatagramBaseds must be + * As with `GSocket`, `GDatagramBased`s can be either connection oriented (for + * example, SCTP) or connectionless (for example, UDP). `GDatagramBased`s must be * datagram-based, not stream-based. The interface does not cover connection * establishment — use methods on the underlying type to establish a connection - * before sending and receiving data through the #GDatagramBased API. For + * before sending and receiving data through the `GDatagramBased` API. For * connectionless socket types the target/source address is specified or * received in each I/O operation. * - * Like most other APIs in GLib, #GDatagramBased is not inherently thread safe. - * To use a #GDatagramBased concurrently from multiple threads, you must + * Like most other APIs in GLib, `GDatagramBased` is not inherently thread safe. + * To use a `GDatagramBased` concurrently from multiple threads, you must * implement your own locking. * * Since: 2.48 diff --git a/gio/gdatagrambased.h b/gio/gdatagrambased.h index 585728c..aa2a1f2 100644 --- a/gio/gdatagrambased.h +++ b/gio/gdatagrambased.h @@ -41,13 +41,6 @@ G_BEGIN_DECLS #define G_TYPE_IS_DATAGRAM_BASED(type) (g_type_is_a ((type), \ G_TYPE_DATAGRAM_BASED)) -/** - * GDatagramBased: - * - * Interface for socket-like objects with datagram semantics. - * - * Since: 2.48 - */ typedef struct _GDatagramBasedInterface GDatagramBasedInterface; /** diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c index b2c080b..e2921e4 100644 --- a/gio/gdatainputstream.c +++ b/gio/gdatainputstream.c @@ -33,15 +33,11 @@ #include /** - * SECTION:gdatainputstream - * @short_description: Data Input Stream - * @include: gio/gio.h - * @see_also: #GInputStream - * - * Data input stream implements #GInputStream and includes functions for - * reading structured data directly from a binary input stream. + * GDataInputStream: * - **/ + * Data input stream implements [class@Gio.InputStream] and includes functions + * for reading structured data directly from a binary input stream. + */ struct _GDataInputStreamPrivate { GDataStreamByteOrder byte_order; @@ -86,9 +82,7 @@ g_data_input_stream_class_init (GDataInputStreamClass *klass) */ g_object_class_install_property (object_class, PROP_BYTE_ORDER, - g_param_spec_enum ("byte-order", - P_("Byte order"), - P_("The byte order"), + g_param_spec_enum ("byte-order", NULL, NULL, G_TYPE_DATA_STREAM_BYTE_ORDER, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN, G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); @@ -101,9 +95,7 @@ g_data_input_stream_class_init (GDataInputStreamClass *klass) */ g_object_class_install_property (object_class, PROP_NEWLINE_TYPE, - g_param_spec_enum ("newline-type", - P_("Newline type"), - P_("The accepted types of line ending"), + g_param_spec_enum ("newline-type", NULL, NULL, G_TYPE_DATA_STREAM_NEWLINE_TYPE, G_DATA_STREAM_NEWLINE_TYPE_LF, G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); diff --git a/gio/gdatainputstream.h b/gio/gdatainputstream.h index e130295..2e14a55 100644 --- a/gio/gdatainputstream.h +++ b/gio/gdatainputstream.h @@ -38,12 +38,6 @@ G_BEGIN_DECLS #define G_IS_DATA_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DATA_INPUT_STREAM)) #define G_DATA_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DATA_INPUT_STREAM, GDataInputStreamClass)) -/** - * GDataInputStream: - * - * An implementation of #GBufferedInputStream that allows for high-level - * data manipulation of arbitrary data (including binary operations). - **/ typedef struct _GDataInputStreamClass GDataInputStreamClass; typedef struct _GDataInputStreamPrivate GDataInputStreamPrivate; diff --git a/gio/gdataoutputstream.c b/gio/gdataoutputstream.c index f2d1f39..f183f96 100644 --- a/gio/gdataoutputstream.c +++ b/gio/gdataoutputstream.c @@ -30,16 +30,11 @@ /** - * SECTION:gdataoutputstream - * @short_description: Data Output Stream - * @include: gio/gio.h - * @see_also: #GOutputStream - * - * Data output stream implements #GOutputStream and includes functions for - * writing data directly to an output stream. + * GDataOutputStream: * - **/ - + * Data output stream implements [class@Gio.OutputStream] and includes functions + * for writing data directly to an output stream. + */ struct _GDataOutputStreamPrivate { @@ -99,9 +94,7 @@ g_data_output_stream_class_init (GDataOutputStreamClass *klass) */ g_object_class_install_property (object_class, PROP_BYTE_ORDER, - g_param_spec_enum ("byte-order", - P_("Byte order"), - P_("The byte order"), + g_param_spec_enum ("byte-order", NULL, NULL, G_TYPE_DATA_STREAM_BYTE_ORDER, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN, G_PARAM_READWRITE|G_PARAM_STATIC_NAME|G_PARAM_STATIC_BLURB)); diff --git a/gio/gdataoutputstream.h b/gio/gdataoutputstream.h index a8d434a..9fad093 100644 --- a/gio/gdataoutputstream.h +++ b/gio/gdataoutputstream.h @@ -38,12 +38,6 @@ G_BEGIN_DECLS #define G_IS_DATA_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_DATA_OUTPUT_STREAM)) #define G_DATA_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_DATA_OUTPUT_STREAM, GDataOutputStreamClass)) -/** - * GDataOutputStream: - * - * An implementation of #GBufferedOutputStream that allows for high-level - * data manipulation of arbitrary data (including binary operations). - **/ typedef struct _GDataOutputStream GDataOutputStream; typedef struct _GDataOutputStreamClass GDataOutputStreamClass; typedef struct _GDataOutputStreamPrivate GDataOutputStreamPrivate; diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py index 3933281..9bdcf18 100644 --- a/gio/gdbus-2.0/codegen/codegen.py +++ b/gio/gdbus-2.0/codegen/codegen.py @@ -5160,12 +5160,12 @@ class CodeGenerator: ) for i in self.ifaces: self.outfile.write( - ' g_hash_table_insert (lookup_hash, (gpointer) "%s", GSIZE_TO_POINTER (%sTYPE_%s_PROXY));\n' + ' g_hash_table_insert (lookup_hash, (gpointer) "%s", (gpointer) (guintptr) (%sTYPE_%s_PROXY));\n' % (i.name, i.ns_upper, i.name_upper) ) self.outfile.write(" g_once_init_leave (&once_init_value, 1);\n" " }\n") self.outfile.write( - " ret = (GType) GPOINTER_TO_SIZE (g_hash_table_lookup (lookup_hash, interface_name));\n" + " ret = (GType) (guintptr) (g_hash_table_lookup (lookup_hash, interface_name));\n" " if (ret == (GType) 0)\n" " ret = G_TYPE_DBUS_PROXY;\n" ) diff --git a/gio/gdbus-2.0/codegen/meson.build b/gio/gdbus-2.0/codegen/meson.build index 65faae9..6d19cd4 100644 --- a/gio/gdbus-2.0/codegen/meson.build +++ b/gio/gdbus-2.0/codegen/meson.build @@ -30,6 +30,7 @@ meson.override_find_program('gdbus-codegen', gdbus_codegen) codegen_dir = join_paths(glib_datadir, 'glib-2.0', 'codegen') gdbus_codegen_built_files = [] +gdbus_codegen_built_targets = [] gdbus_codegen_built_files += configure_file(input : 'config.py.in', output : 'config.py', install_dir : codegen_dir, @@ -39,8 +40,8 @@ gdbus_codegen_built_files += configure_file(input : 'config.py.in', foreach f : gdbus_codegen_files # Copy these into the builddir so that gdbus-codegen can be used uninstalled # and then install it too so that it can be used after installation - gdbus_codegen_built_files += configure_file(input : f, output : f, - install_dir : codegen_dir, - install_tag : 'bin-devel', - copy : true) + gdbus_codegen_built_targets += fs.copyfile(f, f, + install : true, + install_dir : codegen_dir, + install_tag : 'bin-devel') endforeach diff --git a/gio/gdbus-2.0/codegen/utils.py b/gio/gdbus-2.0/codegen/utils.py index 0204610..08f1ba9 100644 --- a/gio/gdbus-2.0/codegen/utils.py +++ b/gio/gdbus-2.0/codegen/utils.py @@ -19,7 +19,7 @@ # # Author: David Zeuthen -import distutils.version +import packaging.version import os import sys @@ -166,4 +166,4 @@ def version_cmp_key(key): v = str(key[0]) else: v = "0" - return (distutils.version.LooseVersion(v), key[1]) + return (packaging.version.Version(v), key[1]) diff --git a/gio/gdbusactiongroup.c b/gio/gdbusactiongroup.c index 275c5fc..0bd5311 100644 --- a/gio/gdbusactiongroup.c +++ b/gio/gdbusactiongroup.c @@ -29,22 +29,13 @@ #include "gactiongroup.h" /** - * SECTION:gdbusactiongroup - * @title: GDBusActionGroup - * @short_description: A D-Bus GActionGroup implementation - * @include: gio/gio.h - * @see_also: [GActionGroup exporter][gio-GActionGroup-exporter] - * - * #GDBusActionGroup is an implementation of the #GActionGroup - * interface that can be used as a proxy for an action group - * that is exported over D-Bus with g_dbus_connection_export_action_group(). - */ - -/** * GDBusActionGroup: * - * #GDBusActionGroup is an opaque data structure and can only be accessed - * using the following functions. + * `GDBusActionGroup` is an implementation of the [iface@Gio.ActionGroup] + * interface. + * + * `GDBusActionGroup` can be used as a proxy for an action group + * that is exported over D-Bus with [method@Gio.DBusConnection.export_action_group]. */ struct _GDBusActionGroup diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index b73ff0d..0bd0b39 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -62,10 +62,7 @@ #include "glibintl.h" /** - * SECTION:gdbusaddress - * @title: D-Bus Addresses - * @short_description: D-Bus connection endpoints - * @include: gio/gio.h + * GDBusAddress: * * Routines for working with D-Bus addresses. A D-Bus address is a string * like `unix:tmpdir=/tmp/my-app-name`. The exact format of addresses diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c index b52a06e..9e31c83 100644 --- a/gio/gdbusauth.c +++ b/gio/gdbusauth.c @@ -172,9 +172,7 @@ _g_dbus_auth_class_init (GDBusAuthClass *klass) g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_object ("stream", - P_("IO Stream"), - P_("The underlying GIOStream used for I/O"), + g_param_spec_object ("stream", NULL, NULL, G_TYPE_IO_STREAM, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gdbusauthmechanism.c b/gio/gdbusauthmechanism.c index 6e494db..be1b1dc 100644 --- a/gio/gdbusauthmechanism.c +++ b/gio/gdbusauthmechanism.c @@ -122,9 +122,7 @@ _g_dbus_auth_mechanism_class_init (GDBusAuthMechanismClass *klass) g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_object ("stream", - P_("IO Stream"), - P_("The underlying GIOStream used for I/O"), + g_param_spec_object ("stream", NULL, NULL, G_TYPE_IO_STREAM, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -144,9 +142,7 @@ _g_dbus_auth_mechanism_class_init (GDBusAuthMechanismClass *klass) */ g_object_class_install_property (gobject_class, PROP_CREDENTIALS, - g_param_spec_object ("credentials", - P_("Credentials"), - P_("The credentials of the remote peer"), + g_param_spec_object ("credentials", NULL, NULL, G_TYPE_CREDENTIALS, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gdbusauthobserver.c b/gio/gdbusauthobserver.c index c695e1a..a840532 100644 --- a/gio/gdbusauthobserver.c +++ b/gio/gdbusauthobserver.c @@ -32,26 +32,25 @@ #include "gmarshal-internal.h" /** - * SECTION:gdbusauthobserver - * @short_description: Object used for authenticating connections - * @include: gio/gio.h + * GDBusAuthObserver: + * + * `GDBusAuthObserver` provides a mechanism for participating + * in how a [class@Gio.DBusServer] (or a [class@Gio.DBusConnection]) + * authenticates remote peers. * - * The #GDBusAuthObserver type provides a mechanism for participating - * in how a #GDBusServer (or a #GDBusConnection) authenticates remote - * peers. Simply instantiate a #GDBusAuthObserver and connect to the + * Simply instantiate a `GDBusAuthObserver` and connect to the * signals you are interested in. Note that new signals may be added - * in the future + * in the future. * * ## Controlling Authentication Mechanisms * - * By default, a #GDBusServer or server-side #GDBusConnection will allow - * any authentication mechanism to be used. If you only - * want to allow D-Bus connections with the `EXTERNAL` mechanism, - * which makes use of credentials passing and is the recommended - * mechanism for modern Unix platforms such as Linux and the BSD family, - * you would use a signal handler like this: + * By default, a `GDBusServer` or server-side `GDBusConnection` will allow + * any authentication mechanism to be used. If you only want to allow D-Bus + * connections with the `EXTERNAL` mechanism, which makes use of credentials + * passing and is the recommended mechanism for modern Unix platforms such + * as Linux and the BSD family, you would use a signal handler like this: * - * |[ + * ```c * static gboolean * on_allow_mechanism (GDBusAuthObserver *observer, * const gchar *mechanism, @@ -64,19 +63,19 @@ * * return FALSE; * } - * ]| + * ``` * - * ## Controlling Authorization # {#auth-observer} + * ## Controlling Authorization * - * By default, a #GDBusServer or server-side #GDBusConnection will accept + * By default, a `GDBusServer` or server-side `GDBusConnection` will accept * connections from any successfully authenticated user (but not from * anonymous connections using the `ANONYMOUS` mechanism). If you only * want to allow D-Bus connections from processes owned by the same uid * as the server, since GLib 2.68, you should use the - * %G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER flag. It’s equivalent + * `G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER` flag. It’s equivalent * to the following signal handler: - * - * |[ + * + * ```c * static gboolean * on_authorize_authenticated_peer (GDBusAuthObserver *observer, * GIOStream *stream, @@ -97,7 +96,9 @@ * * return authorized; * } - * ]| + * ``` + * + * Since: 2.26 */ typedef struct _GDBusAuthObserverClass GDBusAuthObserverClass; @@ -126,14 +127,6 @@ struct _GDBusAuthObserverClass const gchar *mechanism); }; -/** - * GDBusAuthObserver: - * - * The #GDBusAuthObserver structure contains only private data and - * should only be accessed using the provided API. - * - * Since: 2.26 - */ struct _GDBusAuthObserver { GObject parent_instance; diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index bd0cd1b..42134a6 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -131,59 +131,62 @@ G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER) /** - * SECTION:gdbusconnection - * @short_description: D-Bus Connections - * @include: gio/gio.h + * GDBusConnection: + * + * The `GDBusConnection` type is used for D-Bus connections to remote + * peers such as a message buses. * - * The #GDBusConnection type is used for D-Bus connections to remote - * peers such as a message buses. It is a low-level API that offers a - * lot of flexibility. For instance, it lets you establish a connection - * over any transport that can by represented as a #GIOStream. + * It is a low-level API that offers a lot of flexibility. For instance, + * it lets you establish a connection over any transport that can by represented + * as a [class@Gio.IOStream]. * * This class is rarely used directly in D-Bus clients. If you are writing - * a D-Bus client, it is often easier to use the g_bus_own_name(), - * g_bus_watch_name() or g_dbus_proxy_new_for_bus() APIs. + * a D-Bus client, it is often easier to use the [func@Gio.bus_own_name], + * [func@Gio.bus_watch_name] or [func@Gio.DBusProxy.new_for_bus] APIs. * * As an exception to the usual GLib rule that a particular object must not - * be used by two threads at the same time, #GDBusConnection's methods may be - * called from any thread. This is so that g_bus_get() and g_bus_get_sync() - * can safely return the same #GDBusConnection when called from any thread. - * - * Most of the ways to obtain a #GDBusConnection automatically initialize it - * (i.e. connect to D-Bus): for instance, g_dbus_connection_new() and - * g_bus_get(), and the synchronous versions of those methods, give you an - * initialized connection. Language bindings for GIO should use - * g_initable_new() or g_async_initable_new_async(), which also initialize the - * connection. - * - * If you construct an uninitialized #GDBusConnection, such as via - * g_object_new(), you must initialize it via g_initable_init() or - * g_async_initable_init_async() before using its methods or properties. - * Calling methods or accessing properties on a #GDBusConnection that has not + * be used by two threads at the same time, `GDBusConnection`s methods may be + * called from any thread. This is so that [func@Gio.bus_get] and + * [func@Gio.bus_get_sync] can safely return the same `GDBusConnection` when + * called from any thread. + * + * Most of the ways to obtain a `GDBusConnection` automatically initialize it + * (i.e. connect to D-Bus): for instance, [func@Gio.DBusConnection.new] and + * [func@Gio.bus_get], and the synchronous versions of those methods, give you + * an initialized connection. Language bindings for GIO should use + * [func@Gio.Initable.new] or [func@Gio.AsyncInitable.new_async], which also + * initialize the connection. + * + * If you construct an uninitialized `GDBusConnection`, such as via + * [ctor@GObject.Object.new], you must initialize it via [method@Gio.Initable.init] or + * [method@Gio.AsyncInitable.init_async] before using its methods or properties. + * Calling methods or accessing properties on a `GDBusConnection` that has not * completed initialization successfully is considered to be invalid, and leads * to undefined behaviour. In particular, if initialization fails with a - * #GError, the only valid thing you can do with that #GDBusConnection is to - * free it with g_object_unref(). + * `GError`, the only valid thing you can do with that `GDBusConnection` is to + * free it with [method@GObject.Object.unref]. * - * ## An example D-Bus server # {#gdbus-server} + * ## An example D-Bus server * * Here is an example for a D-Bus server: * [gdbus-example-server.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-server.c) * - * ## An example for exporting a subtree # {#gdbus-subtree-server} + * ## An example for exporting a subtree * * Here is an example for exporting a subtree: * [gdbus-example-subtree.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-subtree.c) * - * ## An example for file descriptor passing # {#gdbus-unix-fd-client} + * ## An example for file descriptor passing * * Here is an example for passing UNIX file descriptors: * [gdbus-unix-fd-client.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-unix-fd-client.c) * - * ## An example for exporting a GObject # {#gdbus-export} + * ## An example for exporting a GObject * * Here is an example for exporting a #GObject: * [gdbus-example-export.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-export.c) + * + * Since: 2.26 */ /* ---------------------------------------------------------------------------------------------------- */ @@ -284,153 +287,6 @@ call_destroy_notify (GMainContext *context, /* ---------------------------------------------------------------------------------------------------- */ -typedef struct -{ - /* All fields are immutable after construction. */ - gatomicrefcount ref_count; - GDBusSignalCallback callback; - gpointer user_data; - GDestroyNotify user_data_free_func; - guint id; - GMainContext *context; -} SignalSubscriber; - -static SignalSubscriber * -signal_subscriber_ref (SignalSubscriber *subscriber) -{ - g_atomic_ref_count_inc (&subscriber->ref_count); - return subscriber; -} - -static void -signal_subscriber_unref (SignalSubscriber *subscriber) -{ - if (g_atomic_ref_count_dec (&subscriber->ref_count)) - { - /* Destroy the user data. It doesn’t matter which thread - * signal_subscriber_unref() is called in (or whether it’s called with a - * lock held), as call_destroy_notify() always defers to the next - * #GMainContext iteration. */ - call_destroy_notify (subscriber->context, - subscriber->user_data_free_func, - subscriber->user_data); - - g_main_context_unref (subscriber->context); - g_free (subscriber); - } -} - -typedef struct -{ - /* - * 1 reference while waiting for GetNameOwner() to finish - * 1 reference for each SignalData that points to this one as its - * shared_name_watcher - */ - grefcount ref_count; - - gchar *owner; - guint32 get_name_owner_serial; -} WatchedName; - -static WatchedName * -watched_name_new (void) -{ - WatchedName *watched_name = g_new0 (WatchedName, 1); - - g_ref_count_init (&watched_name->ref_count); - watched_name->owner = NULL; - return g_steal_pointer (&watched_name); -} - -typedef struct SignalData SignalData; - -struct SignalData -{ - gchar *rule; - gchar *sender; - gchar *interface_name; - gchar *member; - gchar *object_path; - gchar *arg0; - GDBusSignalFlags flags; - GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ - - /* - * If the sender is a well-known name, this is an unowned SignalData - * representing the NameOwnerChanged signal that tracks its owner. - * NULL if sender is NULL. - * NULL if sender is its own owner (a unique name or DBUS_SERVICE_DBUS). - * - * Invariants: if not NULL, then - * shared_name_watcher->sender == DBUS_SERVICE_DBUS - * shared_name_watcher->interface_name == DBUS_INTERFACE_DBUS - * shared_name_watcher->member == "NameOwnerChanged" - * shared_name_watcher->object_path == DBUS_PATH_DBUS - * shared_name_watcher->arg0 == sender - * shared_name_watcher->flags == NONE - * shared_name_watcher->watched_name == NULL - */ - SignalData *shared_name_watcher; - - /* - * Non-NULL if this SignalData is another SignalData's shared_name_watcher. - * One reference for each SignalData that has this one as its - * shared_name_watcher. - * Otherwise NULL. - */ - WatchedName *watched_name; -}; - -static SignalData * -signal_data_new_take (gchar *rule, - gchar *sender, - gchar *interface_name, - gchar *member, - gchar *object_path, - gchar *arg0, - GDBusSignalFlags flags) -{ - SignalData *signal_data = g_new0 (SignalData, 1); - - signal_data->rule = rule; - signal_data->sender = sender; - signal_data->interface_name = interface_name; - signal_data->member = member; - signal_data->object_path = object_path; - signal_data->arg0 = arg0; - signal_data->flags = flags; - signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); - return g_steal_pointer (&signal_data); -} - -static void -signal_data_free (SignalData *signal_data) -{ - /* The SignalData should not be freed while it still has subscribers */ - g_assert (signal_data->subscribers->len == 0); - - /* The SignalData should not be freed while it is watching for - * NameOwnerChanged on behalf of another SignalData */ - g_assert (signal_data->watched_name == NULL); - - /* The SignalData should be detached from its name watcher, if any, - * before it is freed */ - g_assert (signal_data->shared_name_watcher == NULL); - - g_free (signal_data->rule); - g_free (signal_data->sender); - g_free (signal_data->interface_name); - g_free (signal_data->member); - g_free (signal_data->object_path); - g_free (signal_data->arg0); - g_ptr_array_unref (signal_data->subscribers); - - g_free (signal_data); -} - -/* ---------------------------------------------------------------------------------------------------- */ - #ifdef G_OS_WIN32 #define CONNECTION_ENSURE_LOCK(obj) do { ; } while (FALSE) #else @@ -459,14 +315,6 @@ enum { FLAG_CLOSED = 1 << 2 }; -/** - * GDBusConnection: - * - * The #GDBusConnection structure contains only private data and - * should only be accessed using the provided API. - * - * Since: 2.26 - */ struct _GDBusConnection { /*< private >*/ @@ -557,7 +405,6 @@ struct _GDBusConnection /* Map used for managing method replies, protected by @lock */ GHashTable *map_method_serial_to_task; /* guint32 -> owned GTask* */ - GHashTable *map_method_serial_to_name_watcher; /* guint32 -> unowned SignalData* */ /* Maps used for managing signal subscription, protected by @lock */ GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */ @@ -806,7 +653,6 @@ g_dbus_connection_finalize (GObject *object) g_error_free (connection->initialization_error); g_hash_table_unref (connection->map_method_serial_to_task); - g_hash_table_unref (connection->map_method_serial_to_name_watcher); g_hash_table_unref (connection->map_rule_to_signal_data); g_hash_table_unref (connection->map_id_to_signal_data); @@ -969,9 +815,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_STREAM, - g_param_spec_object ("stream", - P_("IO Stream"), - P_("The underlying streams used for I/O"), + g_param_spec_object ("stream", NULL, NULL, G_TYPE_IO_STREAM, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -990,9 +834,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_string ("address", - P_("Address"), - P_("D-Bus address specifying potential socket endpoints"), + g_param_spec_string ("address", NULL, NULL, NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -1009,9 +851,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("Flags"), - P_("Flags"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_DBUS_CONNECTION_FLAGS, G_DBUS_CONNECTION_FLAGS_NONE, G_PARAM_READABLE | @@ -1051,9 +891,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_GUID, - g_param_spec_string ("guid", - P_("GUID"), - P_("GUID of the server peer"), + g_param_spec_string ("guid", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -1072,9 +910,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_UNIQUE_NAME, - g_param_spec_string ("unique-name", - P_("unique-name"), - P_("Unique name of bus connection"), + g_param_spec_string ("unique-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -1090,9 +926,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_CLOSED, - g_param_spec_boolean ("closed", - P_("Closed"), - P_("Whether the connection is closed"), + g_param_spec_boolean ("closed", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -1113,9 +947,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_EXIT_ON_CLOSE, - g_param_spec_boolean ("exit-on-close", - P_("Exit on close"), - P_("Whether the process is terminated when the connection is closed"), + g_param_spec_boolean ("exit-on-close", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -1133,9 +965,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_CAPABILITY_FLAGS, - g_param_spec_flags ("capabilities", - P_("Capabilities"), - P_("Capabilities"), + g_param_spec_flags ("capabilities", NULL, NULL, G_TYPE_DBUS_CAPABILITY_FLAGS, G_DBUS_CAPABILITY_FLAGS_NONE, G_PARAM_READABLE | @@ -1152,9 +982,7 @@ g_dbus_connection_class_init (GDBusConnectionClass *klass) */ g_object_class_install_property (gobject_class, PROP_AUTHENTICATION_OBSERVER, - g_param_spec_object ("authentication-observer", - P_("Authentication Observer"), - P_("Object used to assist in the authentication process"), + g_param_spec_object ("authentication-observer", NULL, NULL, G_TYPE_DBUS_AUTH_OBSERVER, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -1211,7 +1039,6 @@ g_dbus_connection_init (GDBusConnection *connection) g_mutex_init (&connection->init_lock); connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref); - connection->map_method_serial_to_name_watcher = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, NULL); connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash, g_str_equal); @@ -2001,7 +1828,7 @@ send_message_data_deliver_error (GTask *task, send_message_with_reply_cleanup (task, TRUE); CONNECTION_UNLOCK (connection); - g_task_return_new_error (task, domain, code, "%s", message); + g_task_return_new_error_literal (task, domain, code, message); g_object_unref (task); } @@ -2339,197 +2166,6 @@ g_dbus_connection_send_message_with_reply_sync (GDBusConnection *connecti /* ---------------------------------------------------------------------------------------------------- */ -/* - * Called in any thread. - * Must hold the connection lock when calling this, unless - * connection->finalizing is TRUE. - */ -static void -name_watcher_unref_watched_name (GDBusConnection *connection, - SignalData *name_watcher) -{ - WatchedName *watched_name = name_watcher->watched_name; - - g_assert (watched_name != NULL); - - if (!g_ref_count_dec (&watched_name->ref_count)) - return; - - /* Removing watched_name from the name_watcher may result in - * name_watcher being freed, so we must make sure name_watcher is no - * longer in map_method_serial_to_name_watcher. - * - * If we stop watching the name while our GetNameOwner call was still - * in-flight, then when the reply eventually arrives, we will not find - * its serial number in the map and harmlessly ignore it as a result. */ - if (watched_name->get_name_owner_serial != 0) - g_hash_table_remove (connection->map_method_serial_to_name_watcher, - GUINT_TO_POINTER (watched_name->get_name_owner_serial)); - - name_watcher->watched_name = NULL; - g_free (watched_name->owner); - g_free (watched_name); -} - -/* called in GDBusWorker thread with lock held */ -static void -name_watcher_set_name_owner_unlocked (SignalData *name_watcher, - const char *new_owner) -{ - if (new_owner != NULL && new_owner[0] == '\0') - new_owner = NULL; - - g_assert (name_watcher->watched_name != NULL); - g_set_str (&name_watcher->watched_name->owner, new_owner); -} - -/* called in GDBusWorker thread with lock held */ -static void -name_watcher_deliver_name_owner_changed_unlocked (SignalData *name_watcher, - GDBusMessage *message) -{ - GVariant *body; - - body = g_dbus_message_get_body (message); - - if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(sss)")))) - { - const char *name; - const char *new_owner; - - g_variant_get (body, "(&s&s&s)", &name, NULL, &new_owner); - - /* Our caller already checked this */ - g_assert (g_strcmp0 (name_watcher->arg0, name) == 0); - - /* FIXME: This should be validating that `new_owner` is a unique name, - * but IBus’ implementation of a message bus is not compliant with the spec. - * See https://gitlab.gnome.org/GNOME/glib/-/issues/3353 */ - if (G_LIKELY (new_owner[0] == '\0' || g_dbus_is_name (new_owner))) - name_watcher_set_name_owner_unlocked (name_watcher, new_owner); - else - g_warning ("Received NameOwnerChanged signal with invalid owner \"%s\" for \"%s\"", - new_owner, name); - } - else - { - g_warning ("Received NameOwnerChanged signal with unexpected " - "signature %s", - body == NULL ? "()" : g_variant_get_type_string (body)); - - } -} - -/* called in GDBusWorker thread with lock held */ -static void -name_watcher_deliver_get_name_owner_reply_unlocked (SignalData *name_watcher, - GDBusConnection *connection, - GDBusMessage *message) -{ - GDBusMessageType type; - GVariant *body; - WatchedName *watched_name; - - watched_name = name_watcher->watched_name; - g_assert (watched_name != NULL); - g_assert (watched_name->get_name_owner_serial != 0); - - type = g_dbus_message_get_message_type (message); - body = g_dbus_message_get_body (message); - - if (type == G_DBUS_MESSAGE_TYPE_ERROR) - { - if (g_strcmp0 (g_dbus_message_get_error_name (message), - "org.freedesktop.DBus.Error.NameHasNoOwner")) - name_watcher_set_name_owner_unlocked (name_watcher, NULL); - /* else it's something like NoReply or AccessDenied, which tells - * us nothing - leave the owner set to whatever we most recently - * learned from NameOwnerChanged, or NULL */ - } - else if (type != G_DBUS_MESSAGE_TYPE_METHOD_RETURN) - { - g_warning ("Received GetNameOwner reply with unexpected type %d", - type); - } - else if (G_LIKELY (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))) - { - const char *new_owner; - - g_variant_get (body, "(&s)", &new_owner); - - /* FIXME: This should be validating that `new_owner` is a unique name, - * but IBus’ implementation of a message bus is not compliant with the spec. - * See https://gitlab.gnome.org/GNOME/glib/-/issues/3353 */ - if (G_LIKELY (g_dbus_is_name (new_owner))) - name_watcher_set_name_owner_unlocked (name_watcher, new_owner); - else - g_warning ("Received GetNameOwner reply with invalid owner \"%s\" for \"%s\"", - new_owner, name_watcher->arg0); - } - else - { - g_warning ("Received GetNameOwner reply with unexpected signature %s", - body == NULL ? "()" : g_variant_get_type_string (body)); - } - - g_hash_table_remove (connection->map_method_serial_to_name_watcher, - GUINT_TO_POINTER (watched_name->get_name_owner_serial)); - watched_name->get_name_owner_serial = 0; -} - -/* Called in a user thread, lock is held */ -static void -name_watcher_call_get_name_owner_unlocked (GDBusConnection *connection, - SignalData *name_watcher) -{ - GDBusMessage *message; - GError *local_error = NULL; - WatchedName *watched_name; - - g_assert (g_strcmp0 (name_watcher->sender, DBUS_SERVICE_DBUS) == 0); - g_assert (g_strcmp0 (name_watcher->interface_name, DBUS_INTERFACE_DBUS) == 0); - g_assert (g_strcmp0 (name_watcher->member, "NameOwnerChanged") == 0); - g_assert (g_strcmp0 (name_watcher->object_path, DBUS_PATH_DBUS) == 0); - /* arg0 of the NameOwnerChanged message is the well-known name whose owner - * we are interested in */ - g_assert (g_dbus_is_name (name_watcher->arg0)); - g_assert (name_watcher->flags == G_DBUS_SIGNAL_FLAGS_NONE); - - watched_name = name_watcher->watched_name; - g_assert (watched_name != NULL); - g_assert (watched_name->owner == NULL); - g_assert (watched_name->get_name_owner_serial == 0); - g_assert (name_watcher->shared_name_watcher == NULL); - - message = g_dbus_message_new_method_call (DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetNameOwner"); - g_dbus_message_set_body (message, g_variant_new ("(s)", name_watcher->arg0)); - - if (g_dbus_connection_send_message_unlocked (connection, message, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - &watched_name->get_name_owner_serial, - &local_error)) - { - g_assert (watched_name->get_name_owner_serial != 0); - g_hash_table_insert (connection->map_method_serial_to_name_watcher, - GUINT_TO_POINTER (watched_name->get_name_owner_serial), - name_watcher); - } - else - { - g_critical ("Error while sending GetNameOwner() message: %s", - local_error->message); - g_clear_error (&local_error); - g_assert (watched_name->get_name_owner_serial == 0); - } - - g_object_unref (message); -} - -/* ---------------------------------------------------------------------------------------------------- */ - typedef struct { guint id; @@ -2653,7 +2289,6 @@ on_worker_message_received (GDBusWorker *worker, { guint32 reply_serial; GTask *task; - SignalData *name_watcher; reply_serial = g_dbus_message_get_reply_serial (message); CONNECTION_LOCK (connection); @@ -2669,19 +2304,6 @@ on_worker_message_received (GDBusWorker *worker, { //g_debug ("message reply/error for serial %d but no SendMessageData found for %p", reply_serial, connection); } - - name_watcher = g_hash_table_lookup (connection->map_method_serial_to_name_watcher, - GUINT_TO_POINTER (reply_serial)); - - if (name_watcher != NULL) - { - g_assert (name_watcher->watched_name != NULL); - g_assert (name_watcher->watched_name->get_name_owner_serial == reply_serial); - name_watcher_deliver_get_name_owner_reply_unlocked (name_watcher, - connection, - message); - } - CONNECTION_UNLOCK (connection); } else if (message_type == G_DBUS_MESSAGE_TYPE_SIGNAL) @@ -2764,10 +2386,10 @@ cancel_method_on_close (gpointer key, gpointer value, gpointer user_data) if (data->delivered) return FALSE; - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CLOSED, - _("The connection is closed")); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CLOSED, + _("The connection is closed")); /* Ask send_message_with_reply_cleanup not to remove the element from the * hash table - we're in the middle of a foreach; that would be unsafe. @@ -3020,7 +2642,26 @@ initable_init (GInitable *initable, g_propagate_error (error, g_error_copy (connection->initialization_error)); } - g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED); + /* Don't cache canceled errors. Otherwise other concurrent users of the same connection + * object will be canceled as well. */ + if (g_error_matches (connection->initialization_error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) + { + if (connection->worker != NULL) + { + _g_dbus_worker_stop (connection->worker); + connection->worker = NULL; + if (alive_connections != NULL) + g_warn_if_fail (g_hash_table_remove (alive_connections, connection)); + } + g_clear_error (&connection->initialization_error); + g_clear_object (&connection->stream); + g_clear_object (&connection->auth); + g_clear_object (&connection->credentials); + g_clear_pointer (&connection->guid, g_free); + connection->capabilities = 0; + } + else + g_atomic_int_or (&connection->atomic_flags, FLAG_INITIALIZED); g_mutex_unlock (&connection->init_lock); return ret; @@ -3606,6 +3247,69 @@ g_dbus_connection_remove_filter (GDBusConnection *connection, /* ---------------------------------------------------------------------------------------------------- */ +typedef struct +{ + gchar *rule; + gchar *sender; + gchar *sender_unique_name; /* if sender is unique or org.freedesktop.DBus, then that name... otherwise blank */ + gchar *interface_name; + gchar *member; + gchar *object_path; + gchar *arg0; + GDBusSignalFlags flags; + GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */ +} SignalData; + +static void +signal_data_free (SignalData *signal_data) +{ + g_free (signal_data->rule); + g_free (signal_data->sender); + g_free (signal_data->sender_unique_name); + g_free (signal_data->interface_name); + g_free (signal_data->member); + g_free (signal_data->object_path); + g_free (signal_data->arg0); + g_ptr_array_unref (signal_data->subscribers); + g_free (signal_data); +} + +typedef struct +{ + /* All fields are immutable after construction. */ + gatomicrefcount ref_count; + GDBusSignalCallback callback; + gpointer user_data; + GDestroyNotify user_data_free_func; + guint id; + GMainContext *context; +} SignalSubscriber; + +static SignalSubscriber * +signal_subscriber_ref (SignalSubscriber *subscriber) +{ + g_atomic_ref_count_inc (&subscriber->ref_count); + return subscriber; +} + +static void +signal_subscriber_unref (SignalSubscriber *subscriber) +{ + if (g_atomic_ref_count_dec (&subscriber->ref_count)) + { + /* Destroy the user data. It doesn’t matter which thread + * signal_subscriber_unref() is called in (or whether it’s called with a + * lock held), as call_destroy_notify() always defers to the next + * #GMainContext iteration. */ + call_destroy_notify (subscriber->context, + subscriber->user_data_free_func, + subscriber->user_data); + + g_main_context_unref (subscriber->context); + g_free (subscriber); + } +} + static gchar * args_to_rule (const gchar *sender, const gchar *interface_name, @@ -3717,7 +3421,7 @@ remove_match_rule (GDBusConnection *connection, static gboolean is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) { - return g_strcmp0 (signal_data->sender, "org.freedesktop.DBus") == 0 && + return g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0 && g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0 && g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0 && (g_strcmp0 (signal_data->member, "NameLost") == 0 || @@ -3726,43 +3430,6 @@ is_signal_data_for_name_lost_or_acquired (SignalData *signal_data) /* ---------------------------------------------------------------------------------------------------- */ -/* called in any thread, connection lock is held */ -static void -add_signal_data (GDBusConnection *connection, - SignalData *signal_data, - const char *sender_unique_name) -{ - GPtrArray *signal_data_array; - - g_hash_table_insert (connection->map_rule_to_signal_data, - signal_data->rule, - signal_data); - - /* Add the match rule to the bus... - * - * Avoid adding match rules for NameLost and NameAcquired messages - the bus will - * always send such messages to us. - */ - if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) - { - if (!is_signal_data_for_name_lost_or_acquired (signal_data)) - add_match_rule (connection, signal_data->rule); - } - - signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, - sender_unique_name); - if (signal_data_array == NULL) - { - signal_data_array = g_ptr_array_new (); - g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, - g_strdup (sender_unique_name), - signal_data_array); - } - g_ptr_array_add (signal_data_array, signal_data); -} - -/* ---------------------------------------------------------------------------------------------------- */ - /** * g_dbus_connection_signal_subscribe: * @connection: a #GDBusConnection @@ -3851,9 +3518,8 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, { gchar *rule; SignalData *signal_data; - SignalData *name_watcher = NULL; SignalSubscriber *subscriber; - gboolean sender_is_its_own_owner; + GPtrArray *signal_data_array; const gchar *sender_unique_name; /* Right now we abort if AddMatch() fails since it can only fail with the bus being in @@ -3889,11 +3555,6 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, rule = args_to_rule (sender, interface_name, member, object_path, arg0, flags); if (sender != NULL && (g_dbus_is_unique_name (sender) || g_strcmp0 (sender, "org.freedesktop.DBus") == 0)) - sender_is_its_own_owner = TRUE; - else - sender_is_its_own_owner = FALSE; - - if (sender_is_its_own_owner) sender_unique_name = sender; else sender_unique_name = ""; @@ -3915,62 +3576,43 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, goto out; } - signal_data = signal_data_new_take (g_steal_pointer (&rule), - g_strdup (sender), - g_strdup (interface_name), - g_strdup (member), - g_strdup (object_path), - g_strdup (arg0), - flags); + signal_data = g_new0 (SignalData, 1); + signal_data->rule = rule; + signal_data->sender = g_strdup (sender); + signal_data->sender_unique_name = g_strdup (sender_unique_name); + signal_data->interface_name = g_strdup (interface_name); + signal_data->member = g_strdup (member); + signal_data->object_path = g_strdup (object_path); + signal_data->arg0 = g_strdup (arg0); + signal_data->flags = flags; + signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref); g_ptr_array_add (signal_data->subscribers, subscriber); - /* If subscribing to a signal from a specific sender with a well-known - * name, we must first subscribe to NameOwnerChanged signals for that - * well-known name, so that we can match the current owner of the name - * against the sender of each signal. */ - if (sender != NULL && !sender_is_its_own_owner) - { - gchar *name_owner_rule = NULL; - - /* We already checked that sender != NULL implies MESSAGE_BUS_CONNECTION */ - g_assert (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION); - - name_owner_rule = args_to_rule (DBUS_SERVICE_DBUS, - DBUS_INTERFACE_DBUS, - "NameOwnerChanged", - DBUS_PATH_DBUS, - sender, - G_DBUS_SIGNAL_FLAGS_NONE); - name_watcher = g_hash_table_lookup (connection->map_rule_to_signal_data, name_owner_rule); - - if (name_watcher == NULL) - { - name_watcher = signal_data_new_take (g_steal_pointer (&name_owner_rule), - g_strdup (DBUS_SERVICE_DBUS), - g_strdup (DBUS_INTERFACE_DBUS), - g_strdup ("NameOwnerChanged"), - g_strdup (DBUS_PATH_DBUS), - g_strdup (sender), - G_DBUS_SIGNAL_FLAGS_NONE); - add_signal_data (connection, name_watcher, DBUS_SERVICE_DBUS); - } - - if (name_watcher->watched_name == NULL) - { - name_watcher->watched_name = watched_name_new (); - name_watcher_call_get_name_owner_unlocked (connection, name_watcher); - } - else - { - g_ref_count_inc (&name_watcher->watched_name->ref_count); - } - - signal_data->shared_name_watcher = name_watcher; + g_hash_table_insert (connection->map_rule_to_signal_data, + signal_data->rule, + signal_data); - g_clear_pointer (&name_owner_rule, g_free); + /* Add the match rule to the bus... + * + * Avoid adding match rules for NameLost and NameAcquired messages - the bus will + * always send such messages to us. + */ + if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) + { + if (!is_signal_data_for_name_lost_or_acquired (signal_data)) + add_match_rule (connection, signal_data->rule); } - add_signal_data (connection, signal_data, sender_unique_name); + signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, + signal_data->sender_unique_name); + if (signal_data_array == NULL) + { + signal_data_array = g_ptr_array_new (); + g_hash_table_insert (connection->map_sender_unique_name_to_signal_data_array, + g_strdup (signal_data->sender_unique_name), + signal_data_array); + } + g_ptr_array_add (signal_data_array, signal_data); out: g_hash_table_insert (connection->map_id_to_signal_data, @@ -3984,75 +3626,6 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection, /* ---------------------------------------------------------------------------------------------------- */ -/* - * Called in any thread. - * Must hold the connection lock when calling this, unless - * connection->finalizing is TRUE. - * May free signal_data, so do not dereference it after this. - */ -static void -remove_signal_data_if_unused (GDBusConnection *connection, - SignalData *signal_data) -{ - const gchar *sender_unique_name; - GPtrArray *signal_data_array; - - /* Cannot remove while there are still subscribers */ - if (signal_data->subscribers->len != 0) - return; - - /* Cannot remove while another SignalData is still using this one - * as its shared_name_watcher, which holds watched_name->ref_count > 0 */ - if (signal_data->watched_name != NULL) - return; - - /* Point of no return: we have committed to removing it */ - - if (signal_data->sender != NULL && signal_data->shared_name_watcher == NULL) - sender_unique_name = signal_data->sender; - else - sender_unique_name = ""; - - g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); - - signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, - sender_unique_name); - g_warn_if_fail (signal_data_array != NULL); - g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); - - if (signal_data_array->len == 0) - { - g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, - sender_unique_name)); - } - - /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ - if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && - !is_signal_data_for_name_lost_or_acquired (signal_data) && - !g_dbus_connection_is_closed (connection) && - !connection->finalizing) - { - /* The check for g_dbus_connection_is_closed() means that - * sending the RemoveMatch message can't fail with - * G_IO_ERROR_CLOSED, because we're holding the lock, - * so on_worker_closed() can't happen between the check we just - * did, and releasing the lock later. - */ - remove_match_rule (connection, signal_data->rule); - } - - if (signal_data->shared_name_watcher != NULL) - { - SignalData *name_watcher = g_steal_pointer (&signal_data->shared_name_watcher); - - name_watcher_unref_watched_name (connection, name_watcher); - /* May free signal_data */ - remove_signal_data_if_unused (connection, name_watcher); - } - - signal_data_free (signal_data); -} - /* called in any thread */ /* must hold lock when calling this (except if connection->finalizing is TRUE) * returns the number of removed subscribers */ @@ -4061,6 +3634,7 @@ unsubscribe_id_internal (GDBusConnection *connection, guint subscription_id) { SignalData *signal_data; + GPtrArray *signal_data_array; guint n; guint n_removed = 0; @@ -4087,8 +3661,40 @@ unsubscribe_id_internal (GDBusConnection *connection, GUINT_TO_POINTER (subscription_id))); n_removed++; g_ptr_array_remove_index_fast (signal_data->subscribers, n); - /* May free signal_data */ - remove_signal_data_if_unused (connection, signal_data); + + if (signal_data->subscribers->len == 0) + { + g_warn_if_fail (g_hash_table_remove (connection->map_rule_to_signal_data, signal_data->rule)); + + signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, + signal_data->sender_unique_name); + g_warn_if_fail (signal_data_array != NULL); + g_warn_if_fail (g_ptr_array_remove (signal_data_array, signal_data)); + + if (signal_data_array->len == 0) + { + g_warn_if_fail (g_hash_table_remove (connection->map_sender_unique_name_to_signal_data_array, + signal_data->sender_unique_name)); + } + + /* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */ + if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) && + !is_signal_data_for_name_lost_or_acquired (signal_data) && + !g_dbus_connection_is_closed (connection) && + !connection->finalizing) + { + /* The check for g_dbus_connection_is_closed() means that + * sending the RemoveMatch message can't fail with + * G_IO_ERROR_CLOSED, because we're holding the lock, + * so on_worker_closed() can't happen between the check we just + * did, and releasing the lock later. + */ + remove_match_rule (connection, signal_data->rule); + } + + signal_data_free (signal_data); + } + goto out; } @@ -4262,16 +3868,22 @@ schedule_callbacks (GDBusConnection *connection, const gchar *member; const gchar *path; const gchar *arg0; + const gchar *arg0_path; interface = NULL; member = NULL; path = NULL; arg0 = NULL; + arg0_path = NULL; interface = g_dbus_message_get_interface (message); member = g_dbus_message_get_member (message); path = g_dbus_message_get_path (message); arg0 = g_dbus_message_get_arg0 (message); + arg0_path = g_dbus_message_get_arg0_path (message); + + /* These two are mutually exclusive through the type system. */ + g_assert (arg0 == NULL || arg0_path == NULL); #if 0 g_print ("In schedule_callbacks:\n" @@ -4303,76 +3915,23 @@ schedule_callbacks (GDBusConnection *connection, if (signal_data->object_path != NULL && g_strcmp0 (signal_data->object_path, path) != 0) continue; - if (signal_data->shared_name_watcher != NULL) - { - /* We want signals from a specified well-known name, which means - * the signal's sender needs to be the unique name that currently - * owns that well-known name, and we will have found this - * SignalData in - * connection->map_sender_unique_name_to_signal_data_array[""]. */ - const WatchedName *watched_name; - const char *current_owner; - - g_assert (signal_data->sender != NULL); - /* Invariant: We never need to watch for the owner of a unique - * name, or for the owner of DBUS_SERVICE_DBUS, either of which - * is always its own owner */ - g_assert (!g_dbus_is_unique_name (signal_data->sender)); - g_assert (g_strcmp0 (signal_data->sender, DBUS_SERVICE_DBUS) != 0); - - watched_name = signal_data->shared_name_watcher->watched_name; - g_assert (watched_name != NULL); - current_owner = watched_name->owner; - - /* Skip the signal if the actual sender is not known to own - * the required name */ - if (current_owner == NULL || g_strcmp0 (current_owner, sender) != 0) - continue; - } - else if (signal_data->sender != NULL) - { - /* We want signals from a unique name or o.fd.DBus... */ - g_assert (g_dbus_is_unique_name (signal_data->sender) - || g_str_equal (signal_data->sender, DBUS_SERVICE_DBUS)); - - /* ... which means we must have found this SignalData in - * connection->map_sender_unique_name_to_signal_data_array[signal_data->sender], - * therefore we would only have found it if the signal's - * actual sender matches the required signal_data->sender */ - g_assert (g_strcmp0 (signal_data->sender, sender) == 0); - } - /* else the sender is unspecified and we will accept anything */ - if (signal_data->arg0 != NULL) { - if (arg0 == NULL) - continue; - if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE) { - if (!namespace_rule_matches (signal_data->arg0, arg0)) + if (arg0 == NULL || !namespace_rule_matches (signal_data->arg0, arg0)) continue; } else if (signal_data->flags & G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH) { - if (!path_rule_matches (signal_data->arg0, arg0)) + if ((arg0 == NULL || !path_rule_matches (signal_data->arg0, arg0)) && + (arg0_path == NULL || !path_rule_matches (signal_data->arg0, arg0_path))) continue; } else if (!g_str_equal (signal_data->arg0, arg0)) continue; } - if (signal_data->watched_name != NULL) - { - /* Invariant: SignalData should only have a watched_name if it - * represents the NameOwnerChanged signal */ - g_assert (g_strcmp0 (sender, DBUS_SERVICE_DBUS) == 0); - g_assert (g_strcmp0 (interface, DBUS_INTERFACE_DBUS) == 0); - g_assert (g_strcmp0 (path, DBUS_PATH_DBUS) == 0); - g_assert (g_strcmp0 (member, "NameOwnerChanged") == 0); - name_watcher_deliver_name_owner_changed_unlocked (signal_data, message); - } - for (m = 0; m < signal_data->subscribers->len; m++) { SignalSubscriber *subscriber = signal_data->subscribers->pdata[m]; @@ -4444,7 +4003,7 @@ distribute_signals (GDBusConnection *connection, schedule_callbacks (connection, signal_data_array, message, sender); } - /* collect subscribers not matching on sender, or matching a well-known name */ + /* collect subscribers not matching on sender */ signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array, ""); if (signal_data_array != NULL) schedule_callbacks (connection, signal_data_array, message, sender); diff --git a/gio/gdbusdaemon.c b/gio/gdbusdaemon.c index 70009f9..3474b70 100644 --- a/gio/gdbusdaemon.c +++ b/gio/gdbusdaemon.c @@ -1692,9 +1692,7 @@ g_dbus_daemon_class_init (GDBusDaemonClass *klass) g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_string ("address", - "Bus Address", - "The address the bus should use", + g_param_spec_string ("address", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gdbuserror.c b/gio/gdbuserror.c index 1cee9e5..432b24c 100644 --- a/gio/gdbuserror.c +++ b/gio/gdbuserror.c @@ -33,82 +33,6 @@ #include "glibintl.h" -/** - * SECTION:gdbuserror - * @title: GDBusError - * @short_description: Mapping D-Bus errors to and from GError - * @include: gio/gio.h - * - * All facilities that return errors from remote methods (such as - * g_dbus_connection_call_sync()) use #GError to represent both D-Bus - * errors (e.g. errors returned from the other peer) and locally - * in-process generated errors. - * - * To check if a returned #GError is an error from a remote peer, use - * g_dbus_error_is_remote_error(). To get the actual D-Bus error name, - * use g_dbus_error_get_remote_error(). Before presenting an error, - * always use g_dbus_error_strip_remote_error(). - * - * In addition, facilities used to return errors to a remote peer also - * use #GError. See g_dbus_method_invocation_return_error() for - * discussion about how the D-Bus error name is set. - * - * Applications can associate a #GError error domain with a set of D-Bus errors in order to - * automatically map from D-Bus errors to #GError and back. This - * is typically done in the function returning the #GQuark for the - * error domain: - * |[ - * // foo-bar-error.h: - * - * #define FOO_BAR_ERROR (foo_bar_error_quark ()) - * GQuark foo_bar_error_quark (void); - * - * typedef enum - * { - * FOO_BAR_ERROR_FAILED, - * FOO_BAR_ERROR_ANOTHER_ERROR, - * FOO_BAR_ERROR_SOME_THIRD_ERROR, - * FOO_BAR_N_ERRORS / *< skip >* / - * } FooBarError; - * - * // foo-bar-error.c: - * - * static const GDBusErrorEntry foo_bar_error_entries[] = - * { - * {FOO_BAR_ERROR_FAILED, "org.project.Foo.Bar.Error.Failed"}, - * {FOO_BAR_ERROR_ANOTHER_ERROR, "org.project.Foo.Bar.Error.AnotherError"}, - * {FOO_BAR_ERROR_SOME_THIRD_ERROR, "org.project.Foo.Bar.Error.SomeThirdError"}, - * }; - * - * // Ensure that every error code has an associated D-Bus error name - * G_STATIC_ASSERT (G_N_ELEMENTS (foo_bar_error_entries) == FOO_BAR_N_ERRORS); - * - * GQuark - * foo_bar_error_quark (void) - * { - * static gsize quark = 0; - * g_dbus_error_register_error_domain ("foo-bar-error-quark", - * &quark, - * foo_bar_error_entries, - * G_N_ELEMENTS (foo_bar_error_entries)); - * return (GQuark) quark; - * } - * ]| - * With this setup, a D-Bus peer can transparently pass e.g. %FOO_BAR_ERROR_ANOTHER_ERROR and - * other peers will see the D-Bus error name org.project.Foo.Bar.Error.AnotherError. - * - * If the other peer is using GDBus, and has registered the association with - * g_dbus_error_register_error_domain() in advance (e.g. by invoking the %FOO_BAR_ERROR quark - * generation itself in the previous example) the peer will see also %FOO_BAR_ERROR_ANOTHER_ERROR instead - * of %G_IO_ERROR_DBUS_ERROR. Note that GDBus clients can still recover - * org.project.Foo.Bar.Error.AnotherError using g_dbus_error_get_remote_error(). - * - * Note that the %G_DBUS_ERROR error domain is intended only - * for returning errors from a remote message bus process. Errors - * generated locally in-process by e.g. #GDBusConnection should use the - * %G_IO_ERROR domain. - */ - static const GDBusErrorEntry g_dbus_error_entries[] = { {G_DBUS_ERROR_FAILED, "org.freedesktop.DBus.Error.Failed"}, diff --git a/gio/gdbusinterface.c b/gio/gdbusinterface.c index b479676..317834b 100644 --- a/gio/gdbusinterface.c +++ b/gio/gdbusinterface.c @@ -28,13 +28,15 @@ #include "glibintl.h" /** - * SECTION:gdbusinterface - * @short_description: Base type for D-Bus interfaces - * @include: gio/gio.h + * GDBusInterface: * - * The #GDBusInterface type is the base type for D-Bus interfaces both - * on the service side (see #GDBusInterfaceSkeleton) and client side - * (see #GDBusProxy). + * Base type for D-Bus interfaces. + * + * The `GDBusInterface` type is the base type for D-Bus interfaces both + * on the service side (see [class@Gio.DBusInterfaceSkeleton]) and client side + * (see [class@Gio.DBusProxy]). + * + * Since: 2.30 */ typedef GDBusInterfaceIface GDBusInterfaceInterface; diff --git a/gio/gdbusinterface.h b/gio/gdbusinterface.h index 838a54e..4488975 100644 --- a/gio/gdbusinterface.h +++ b/gio/gdbusinterface.h @@ -32,14 +32,6 @@ G_BEGIN_DECLS #define G_IS_DBUS_INTERFACE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_INTERFACE)) #define G_DBUS_INTERFACE_GET_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE((o), G_TYPE_DBUS_INTERFACE, GDBusInterfaceIface)) -/** - * GDBusInterface: - * - * Base type for D-Bus interfaces. - * - * Since: 2.30 - */ - typedef struct _GDBusInterfaceIface GDBusInterfaceIface; /** diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c index 1a6aa64..5f9be9c 100644 --- a/gio/gdbusinterfaceskeleton.c +++ b/gio/gdbusinterfaceskeleton.c @@ -36,11 +36,11 @@ #include "glibintl.h" /** - * SECTION:gdbusinterfaceskeleton - * @short_description: Service-side D-Bus interface - * @include: gio/gio.h + * GDBusInterfaceSkeleton: * * Abstract base class for D-Bus interfaces on the service side. + * + * Since: 2.30 */ struct _GDBusInterfaceSkeletonPrivate @@ -192,9 +192,7 @@ g_dbus_interface_skeleton_class_init (GDBusInterfaceSkeletonClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_FLAGS, - g_param_spec_flags ("g-flags", - "g-flags", - "Flags for the interface skeleton", + g_param_spec_flags ("g-flags", NULL, NULL, G_TYPE_DBUS_INTERFACE_SKELETON_FLAGS, G_DBUS_INTERFACE_SKELETON_FLAGS_NONE, G_PARAM_READABLE | diff --git a/gio/gdbusinterfaceskeleton.h b/gio/gdbusinterfaceskeleton.h index 244ee0e..5de5ff9 100644 --- a/gio/gdbusinterfaceskeleton.h +++ b/gio/gdbusinterfaceskeleton.h @@ -37,14 +37,6 @@ G_BEGIN_DECLS typedef struct _GDBusInterfaceSkeletonClass GDBusInterfaceSkeletonClass; typedef struct _GDBusInterfaceSkeletonPrivate GDBusInterfaceSkeletonPrivate; -/** - * GDBusInterfaceSkeleton: - * - * The #GDBusInterfaceSkeleton structure contains private data and should - * only be accessed using the provided API. - * - * Since: 2.30 - */ struct _GDBusInterfaceSkeleton { /*< private >*/ diff --git a/gio/gdbusintrospection.c b/gio/gdbusintrospection.c index c7be334..7ee3e32 100644 --- a/gio/gdbusintrospection.c +++ b/gio/gdbusintrospection.c @@ -29,20 +29,6 @@ #include "glibintl.h" -/** - * SECTION:gdbusintrospection - * @title: D-Bus Introspection Data - * @short_description: Node and interface description data structures - * @include: gio/gio.h - * - * Various data structures and convenience routines to parse and - * generate D-Bus introspection XML. Introspection information is - * used when registering objects with g_dbus_connection_register_object(). - * - * The format of D-Bus introspection XML is specified in the - * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format) - */ - /* ---------------------------------------------------------------------------------------------------- */ #define _MY_DEFINE_BOXED_TYPE(TypeName, type_name) \ diff --git a/gio/gdbusmenumodel.c b/gio/gdbusmenumodel.c index 0a34ed2..dd77f5e 100644 --- a/gio/gdbusmenumodel.c +++ b/gio/gdbusmenumodel.c @@ -29,22 +29,11 @@ /* Prelude {{{1 */ /** - * SECTION:gdbusmenumodel - * @title: GDBusMenuModel - * @short_description: A D-Bus GMenuModel implementation - * @include: gio/gio.h - * @see_also: [GMenuModel Exporter][gio-GMenuModel-exporter] - * - * #GDBusMenuModel is an implementation of #GMenuModel that can be used - * as a proxy for a menu model that is exported over D-Bus with - * g_dbus_connection_export_menu_model(). - */ - -/** * GDBusMenuModel: * - * #GDBusMenuModel is an opaque data structure and can only be accessed - * using the following functions. + * `GDBusMenuModel` is an implementation of [class@Gio.MenuModel] that can be + * used as a proxy for a menu model that is exported over D-Bus with + * [method@Gio.DBusConnection.export_menu_model]. */ /* diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 6c4a5bf..4e5e3d2 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -462,16 +462,6 @@ g_memory_buffer_put_string (GMemoryBuffer *mbuf, return g_memory_buffer_write (mbuf, str, strlen (str)); } - -/** - * SECTION:gdbusmessage - * @short_description: D-Bus Message - * @include: gio/gio.h - * - * A type for representing D-Bus messages that can be sent or received - * on a #GDBusConnection. - */ - typedef struct _GDBusMessageClass GDBusMessageClass; /** @@ -490,8 +480,8 @@ struct _GDBusMessageClass /** * GDBusMessage: * - * The #GDBusMessage structure contains only private data and should - * only be accessed using the provided API. + * A type for representing D-Bus messages that can be sent or received + * on a [class@Gio.DBusConnection]. * * Since: 2.26 */ @@ -579,9 +569,7 @@ g_dbus_message_class_init (GDBusMessageClass *klass) */ g_object_class_install_property (gobject_class, PROP_LOCKED, - g_param_spec_boolean ("locked", - P_("Locked"), - P_("Whether the message is locked"), + g_param_spec_boolean ("locked", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -3410,6 +3398,9 @@ g_dbus_message_set_signature (GDBusMessage *message, * * Convenience to get the first item in the body of @message. * + * See [method@Gio.DBusMessage.get_arg0_path] for returning object-path-typed + * arg0 values. + * * Returns: (nullable): The string item or %NULL if the first item in the body of * @message is not a string. * @@ -3427,6 +3418,31 @@ g_dbus_message_get_arg0 (GDBusMessage *message) return NULL; } +/** + * g_dbus_message_get_arg0_path: + * @message: A `GDBusMessage`. + * + * Convenience to get the first item in the body of @message. + * + * See [method@Gio.DBusMessage.get_arg0] for returning string-typed arg0 values. + * + * Returns: (nullable): The object path item or `NULL` if the first item in the + * body of @message is not an object path. + * + * Since: 2.80 + */ +const gchar * +g_dbus_message_get_arg0_path (GDBusMessage *message) +{ + g_return_val_if_fail (G_IS_DBUS_MESSAGE (message), NULL); + + if (message->arg0_cache != NULL && + g_variant_is_of_type (message->arg0_cache, G_VARIANT_TYPE_OBJECT_PATH)) + return g_variant_get_string (message->arg0_cache, NULL); + + return NULL; +} + /* ---------------------------------------------------------------------------------------------------- */ /** @@ -3602,7 +3618,7 @@ _sort_keys_func (gconstpointer a, * The contents of the description has no ABI guarantees, the contents * and formatting is subject to change at any time. Typical output * looks something like this: - * |[ + * ``` * Type: method-call * Flags: none * Version: 0 @@ -3615,9 +3631,9 @@ _sort_keys_func (gconstpointer a, * Body: () * UNIX File Descriptors: * (none) - * ]| + * ``` * or - * |[ + * ``` * Type: method-return * Flags: no-reply-expected * Version: 0 @@ -3630,9 +3646,9 @@ _sort_keys_func (gconstpointer a, * Body: () * UNIX File Descriptors: * fd 12: dev=0:10,mode=020620,ino=5,uid=500,gid=5,rdev=136:2,size=0,atime=1273085037,mtime=1273085851,ctime=1272982635 - * ]| + * ``` * - * Returns: (not nullable): A string that should be freed with g_free(). + * Returns: (not nullable): A string that should be freed with [func@GLib.free]. * * Since: 2.26 */ diff --git a/gio/gdbusmessage.h b/gio/gdbusmessage.h index 6e4bb9e..643aca0 100644 --- a/gio/gdbusmessage.h +++ b/gio/gdbusmessage.h @@ -176,7 +176,8 @@ void g_dbus_message_set_num_unix_fds (GDBusMessage GIO_AVAILABLE_IN_ALL const gchar *g_dbus_message_get_arg0 (GDBusMessage *message); - +GIO_AVAILABLE_IN_2_80 +const gchar *g_dbus_message_get_arg0_path (GDBusMessage *message); GIO_AVAILABLE_IN_ALL GDBusMessage *g_dbus_message_new_from_blob (guchar *blob, diff --git a/gio/gdbusmethodinvocation.c b/gio/gdbusmethodinvocation.c index e5a9166..00a6de2 100644 --- a/gio/gdbusmethodinvocation.c +++ b/gio/gdbusmethodinvocation.c @@ -40,17 +40,18 @@ #include "glibintl.h" /** - * SECTION:gdbusmethodinvocation - * @short_description: Object for handling remote calls - * @include: gio/gio.h + * GDBusMethodInvocation: * - * Instances of the #GDBusMethodInvocation class are used when + * Instances of the `GDBusMethodInvocation` class are used when * handling D-Bus method calls. It provides a way to asynchronously * return results and errors. * - * The normal way to obtain a #GDBusMethodInvocation object is to receive - * it as an argument to the handle_method_call() function in a - * #GDBusInterfaceVTable that was passed to g_dbus_connection_register_object(). + * The normal way to obtain a `GDBusMethodInvocation` object is to receive + * it as an argument to the `handle_method_call()` function in a + * [type@Gio.DBusInterfaceVTable] that was passed to + * [method@Gio.DBusConnection.register_object]. + * + * Since: 2.26 */ typedef struct _GDBusMethodInvocationClass GDBusMethodInvocationClass; @@ -68,14 +69,6 @@ struct _GDBusMethodInvocationClass GObjectClass parent_class; }; -/** - * GDBusMethodInvocation: - * - * The #GDBusMethodInvocation structure contains only private data and - * should only be accessed using the provided API. - * - * Since: 2.26 - */ struct _GDBusMethodInvocation { /*< private >*/ diff --git a/gio/gdbusnameowning.c b/gio/gdbusnameowning.c index 289ea03..40feba2 100644 --- a/gio/gdbusnameowning.c +++ b/gio/gdbusnameowning.c @@ -32,18 +32,6 @@ #include "glibintl.h" -/** - * SECTION:gdbusnameowning - * @title: Owning Bus Names - * @short_description: Simple API for owning bus names - * @include: gio/gio.h - * - * Convenience API for owning bus names. - * - * A simple example for owning a name can be found in - * [gdbus-example-own-name.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-own-name.c) - */ - G_LOCK_DEFINE_STATIC (lock); /* ---------------------------------------------------------------------------------------------------- */ @@ -521,8 +509,10 @@ connection_get_cb (GObject *source_object, * @connection: a #GDBusConnection * @name: the well-known name to own * @flags: a set of flags from the #GBusNameOwnerFlags enumeration - * @name_acquired_handler: (nullable): handler to invoke when @name is acquired or %NULL - * @name_lost_handler: (nullable): handler to invoke when @name is lost or %NULL + * @name_acquired_handler: (nullable) (scope notified): handler to invoke when + * @name is acquired or %NULL + * @name_lost_handler: (nullable) (scope notified): handler to invoke when @name + * is lost or %NULL * @user_data: user data to pass to handlers * @user_data_free_func: (nullable): function for freeing @user_data or %NULL * @@ -583,9 +573,12 @@ g_bus_own_name_on_connection (GDBusConnection *connection, * @bus_type: the type of bus to own a name on * @name: the well-known name to own * @flags: a set of flags from the #GBusNameOwnerFlags enumeration - * @bus_acquired_handler: (nullable): handler to invoke when connected to the bus of type @bus_type or %NULL - * @name_acquired_handler: (nullable): handler to invoke when @name is acquired or %NULL - * @name_lost_handler: (nullable): handler to invoke when @name is lost or %NULL + * @bus_acquired_handler: (nullable) (scope notified): handler to invoke when + * connected to the bus of type @bus_type or %NULL + * @name_acquired_handler: (nullable) (scope notified): handler to invoke when + * @name is acquired or %NULL + * @name_lost_handler: (nullable) (scope notified): handler to invoke when @name + * is lost or %NULL * @user_data: user data to pass to handlers * @user_data_free_func: (nullable): function for freeing @user_data or %NULL * diff --git a/gio/gdbusnamewatching.c b/gio/gdbusnamewatching.c index c834fe1..c86051c 100644 --- a/gio/gdbusnamewatching.c +++ b/gio/gdbusnamewatching.c @@ -33,18 +33,6 @@ #include "glibintl.h" -/** - * SECTION:gdbusnamewatching - * @title: Watching Bus Names - * @short_description: Simple API for watching bus names - * @include: gio/gio.h - * - * Convenience API for watching bus names. - * - * A simple example for watching a name can be found in - * [gdbus-example-watch-name.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-name.c) - */ - G_LOCK_DEFINE_STATIC (lock); /* ---------------------------------------------------------------------------------------------------- */ @@ -576,8 +564,10 @@ connection_get_cb (GObject *source_object, * @bus_type: The type of bus to watch a name on. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. - * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL. - * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL. + * @name_appeared_handler: (nullable) (scope notified): Handler to invoke when + * @name is known to exist or %NULL. + * @name_vanished_handler: (nullable) (scope notified): Handler to invoke when + * @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL. * @@ -665,8 +655,10 @@ g_bus_watch_name (GBusType bus_type, * @connection: A #GDBusConnection. * @name: The name (well-known or unique) to watch. * @flags: Flags from the #GBusNameWatcherFlags enumeration. - * @name_appeared_handler: (nullable): Handler to invoke when @name is known to exist or %NULL. - * @name_vanished_handler: (nullable): Handler to invoke when @name is known to not exist or %NULL. + * @name_appeared_handler: (nullable) (scope notified): Handler to invoke when + * @name is known to exist or %NULL. + * @name_vanished_handler: (nullable) (scope notified): Handler to invoke when + * @name is known to not exist or %NULL. * @user_data: User data to pass to handlers. * @user_data_free_func: (nullable): Function for freeing @user_data or %NULL. * diff --git a/gio/gdbusobject.c b/gio/gdbusobject.c index 5cd425e..ab670d2 100644 --- a/gio/gdbusobject.c +++ b/gio/gdbusobject.c @@ -29,21 +29,12 @@ #include "glibintl.h" /** - * SECTION:gdbusobject - * @short_description: Base type for D-Bus objects - * @include: gio/gio.h - * - * The #GDBusObject type is the base type for D-Bus objects on both - * the service side (see #GDBusObjectSkeleton) and the client side - * (see #GDBusObjectProxy). It is essentially just a container of - * interfaces. - */ - -/** * GDBusObject: * - * #GDBusObject is an opaque data structure and can only be accessed - * using the following functions. + * The `GDBusObject` type is the base type for D-Bus objects on both + * the service side (see [class@Gio.DBusObjectSkeleton]) and the client side + * (see [class@Gio.DBusObjectProxy]). It is essentially just a container of + * interfaces. */ typedef GDBusObjectIface GDBusObjectInterface; diff --git a/gio/gdbusobjectmanager.c b/gio/gdbusobjectmanager.c index cd56c2a..2578c9b 100644 --- a/gio/gdbusobjectmanager.c +++ b/gio/gdbusobjectmanager.c @@ -31,24 +31,15 @@ #include "gmarshal-internal.h" /** - * SECTION:gdbusobjectmanager - * @short_description: Base type for D-Bus object managers - * @include: gio/gio.h + * GDBusObjectManager: * - * The #GDBusObjectManager type is the base type for service- and + * The `GDBusObjectManager` type is the base type for service- and * client-side implementations of the standardized - * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) + * [`org.freedesktop.DBus.ObjectManager`](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) * interface. * - * See #GDBusObjectManagerClient for the client-side implementation - * and #GDBusObjectManagerServer for the service-side implementation. - */ - -/** - * GDBusObjectManager: - * - * #GDBusObjectManager is an opaque data structure and can only be accessed - * using the following functions. + * See [class@Gio.DBusObjectManagerClient] for the client-side implementation + * and [class@Gio.DBusObjectManagerServer] for the service-side implementation. */ typedef GDBusObjectManagerIface GDBusObjectManagerInterface; diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c index b6b3b21..cb35d06 100644 --- a/gio/gdbusobjectmanagerclient.c +++ b/gio/gdbusobjectmanagerclient.c @@ -43,85 +43,88 @@ #include "gmarshal-internal.h" /** - * SECTION:gdbusobjectmanagerclient - * @short_description: Client-side object manager - * @include: gio/gio.h + * GDBusObjectManagerClient: * - * #GDBusObjectManagerClient is used to create, monitor and delete object - * proxies for remote objects exported by a #GDBusObjectManagerServer (or any - * code implementing the + * `GDBusObjectManagerClient` is used to create, monitor and delete object + * proxies for remote objects exported by a [class@Gio.DBusObjectManagerServer] + * (or any code implementing the * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) * interface). * * Once an instance of this type has been created, you can connect to - * the #GDBusObjectManager::object-added and - * #GDBusObjectManager::object-removed signals and inspect the - * #GDBusObjectProxy objects returned by - * g_dbus_object_manager_get_objects(). + * the [signal@Gio.DBusObjectManager::object-added] and + * [signal@Gio.DBusObjectManager::object-removed signals] and inspect the + * [class@Gio.DBusObjectProxy] objects returned by + * [method@Gio.DBusObjectManager.get_objects]. * - * If the name for a #GDBusObjectManagerClient is not owned by anyone at + * If the name for a `GDBusObjectManagerClient` is not owned by anyone at * object construction time, the default behavior is to request the * message bus to launch an owner for the name. This behavior can be - * disabled using the %G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START - * flag. It's also worth noting that this only works if the name of + * disabled using the `G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_DO_NOT_AUTO_START` + * flag. It’s also worth noting that this only works if the name of * interest is activatable in the first place. E.g. in some cases it * is not possible to launch an owner for the requested name. In this - * case, #GDBusObjectManagerClient object construction still succeeds but + * case, `GDBusObjectManagerClient` object construction still succeeds but * there will be no object proxies - * (e.g. g_dbus_object_manager_get_objects() returns the empty list) and - * the #GDBusObjectManagerClient:name-owner property is %NULL. + * (e.g. [method@Gio.DBusObjectManager.get_objects] returns the empty list) and + * the [property@Gio.DBusObjectManagerClient:name-owner] property is `NULL`. * * The owner of the requested name can come and go (for example - * consider a system service being restarted) – #GDBusObjectManagerClient - * handles this case too; simply connect to the #GObject::notify - * signal to watch for changes on the #GDBusObjectManagerClient:name-owner - * property. When the name owner vanishes, the behavior is that - * #GDBusObjectManagerClient:name-owner is set to %NULL (this includes - * emission of the #GObject::notify signal) and then - * #GDBusObjectManager::object-removed signals are synthesized + * consider a system service being restarted) – `GDBusObjectManagerClient` + * handles this case too; simply connect to the [signal@GObject.Object::notify] + * signal to watch for changes on the + * [property@Gio.DBusObjectManagerClient:name-owner] property. When the name + * owner vanishes, the behavior is that + * [property@Gio.DBusObjectManagerClient:name-owner] is set to `NULL` (this + * includes emission of the [signal@GObject.Object::notify] signal) and then + * [signal@Gio.DBusObjectManager::object-removed] signals are synthesized * for all currently existing object proxies. Since - * #GDBusObjectManagerClient:name-owner is %NULL when this happens, you can - * use this information to disambiguate a synthesized signal from a - * genuine signal caused by object removal on the remote - * #GDBusObjectManager. Similarly, when a new name owner appears, - * #GDBusObjectManager::object-added signals are synthesized - * while #GDBusObjectManagerClient:name-owner is still %NULL. Only when all - * object proxies have been added, the #GDBusObjectManagerClient:name-owner - * is set to the new name owner (this includes emission of the - * #GObject::notify signal). Furthermore, you are guaranteed that - * #GDBusObjectManagerClient:name-owner will alternate between a name owner - * (e.g. `:1.42`) and %NULL even in the case where + * [property@Gio.DBusObjectManagerClient:name-owner] is `NULL` when this + * happens, you can use this information to disambiguate a synthesized signal + * from a genuine signal caused by object removal on the remote + * [iface@Gio.DBusObjectManager]. Similarly, when a new name owner appears, + * [signal@Gio.DBusObjectManager::object-added] signals are synthesized + * while [property@Gio.DBusObjectManagerClient:name-owner] is still `NULL`. Only + * when all object proxies have been added, the + * [property@Gio.DBusObjectManagerClient:name-owner] is set to the new name + * owner (this includes emission of the [signal@GObject.Object::notify] signal). + * Furthermore, you are guaranteed that + * [property@Gio.DBusObjectManagerClient:name-owner] will alternate between a + * name owner (e.g. `:1.42`) and `NULL` even in the case where * the name of interest is atomically replaced * - * Ultimately, #GDBusObjectManagerClient is used to obtain #GDBusProxy - * instances. All signals (including the - * org.freedesktop.DBus.Properties::PropertiesChanged signal) - * delivered to #GDBusProxy instances are guaranteed to originate + * Ultimately, `GDBusObjectManagerClient` is used to obtain + * [class@Gio.DBusProxy] instances. All signals (including the + * `org.freedesktop.DBus.Properties::PropertiesChanged` signal) + * delivered to [class@Gio.DBusProxy] instances are guaranteed to originate * from the name owner. This guarantee along with the behavior * described above, means that certain race conditions including the - * "half the proxy is from the old owner and the other half is from - * the new owner" problem cannot happen. + * “half the proxy is from the old owner and the other half is from + * the new owner” problem cannot happen. * * To avoid having the application connect to signals on the returned - * #GDBusObjectProxy and #GDBusProxy objects, the - * #GDBusObject::interface-added, - * #GDBusObject::interface-removed, - * #GDBusProxy::g-properties-changed and - * #GDBusProxy::g-signal signals - * are also emitted on the #GDBusObjectManagerClient instance managing these + * [class@Gio.DBusObjectProxy] and [class@Gio.DBusProxy] objects, the + * [signal@Gio.DBusObject::interface-added], + * [signal@Gio.DBusObject::interface-removed], + * [signal@Gio.DBusProxy::g-properties-changed] and + * [signal@Gio.DBusProxy::g-signal] signals + * are also emitted on the `GDBusObjectManagerClient` instance managing these * objects. The signals emitted are - * #GDBusObjectManager::interface-added, - * #GDBusObjectManager::interface-removed, - * #GDBusObjectManagerClient::interface-proxy-properties-changed and - * #GDBusObjectManagerClient::interface-proxy-signal. + * [signal@Gio.DBusObjectManager::interface-added], + * [signal@Gio.DBusObjectManager::interface-removed], + * [signal@Gio.DBusObjectManagerClient::interface-proxy-properties-changed] and + * [signal@Gio.DBusObjectManagerClient::interface-proxy-signal]. * * Note that all callbacks and signals are emitted in the - * [thread-default main context][g-main-context-push-thread-default] - * that the #GDBusObjectManagerClient object was constructed - * in. Additionally, the #GDBusObjectProxy and #GDBusProxy objects - * originating from the #GDBusObjectManagerClient object will be created in + * thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) that the + * `GDBusObjectManagerClient` object was constructed in. Additionally, the + * [class@Gio.DBusObjectProxy] and [class@Gio.DBusProxy] objects + * originating from the `GDBusObjectManagerClient` object will be created in * the same context and, consequently, will deliver signals in the * same main loop. + * + * Since: 2.30 */ struct _GDBusObjectManagerClientPrivate @@ -360,9 +363,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_CONNECTION, - g_param_spec_object ("connection", - "Connection", - "The connection to use", + g_param_spec_object ("connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -381,9 +382,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_BUS_TYPE, - g_param_spec_enum ("bus-type", - "Bus Type", - "The bus to connect to, if any", + g_param_spec_enum ("bus-type", NULL, NULL, G_TYPE_BUS_TYPE, G_BUS_TYPE_NONE, G_PARAM_WRITABLE | @@ -401,9 +400,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", - "Flags", - "Flags for the proxy manager", + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_DBUS_OBJECT_MANAGER_CLIENT_FLAGS, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, G_PARAM_READABLE | @@ -422,9 +419,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_OBJECT_PATH, - g_param_spec_string ("object-path", - "Object Path", - "The object path of the control object", + g_param_spec_string ("object-path", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -440,9 +435,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_NAME, - g_param_spec_string ("name", - "Name", - "Name that the manager is for", + g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -460,9 +453,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_NAME_OWNER, - g_param_spec_string ("name-owner", - "Name Owner", - "The owner of the name we are watching", + g_param_spec_string ("name-owner", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -477,9 +468,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_GET_PROXY_TYPE_FUNC, - g_param_spec_pointer ("get-proxy-type-func", - "GDBusProxyTypeFunc Function Pointer", - "The GDBusProxyTypeFunc pointer to use", + g_param_spec_pointer ("get-proxy-type-func", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -494,9 +483,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_GET_PROXY_TYPE_USER_DATA, - g_param_spec_pointer ("get-proxy-type-user-data", - "GDBusProxyTypeFunc User Data", - "The GDBusProxyTypeFunc user_data", + g_param_spec_pointer ("get-proxy-type-user-data", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -511,9 +498,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) */ g_object_class_install_property (gobject_class, PROP_GET_PROXY_TYPE_DESTROY_NOTIFY, - g_param_spec_pointer ("get-proxy-type-destroy-notify", - "GDBusProxyTypeFunc user data free function", - "The GDBusProxyTypeFunc user data free function", + g_param_spec_pointer ("get-proxy-type-destroy-notify", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gdbusobjectmanagerclient.h b/gio/gdbusobjectmanagerclient.h index 2ebeedc..f02c693 100644 --- a/gio/gdbusobjectmanagerclient.h +++ b/gio/gdbusobjectmanagerclient.h @@ -37,14 +37,6 @@ G_BEGIN_DECLS typedef struct _GDBusObjectManagerClientClass GDBusObjectManagerClientClass; typedef struct _GDBusObjectManagerClientPrivate GDBusObjectManagerClientPrivate; -/** - * GDBusObjectManagerClient: - * - * The #GDBusObjectManagerClient structure contains private data and should - * only be accessed using the provided API. - * - * Since: 2.30 - */ struct _GDBusObjectManagerClient { /*< private >*/ diff --git a/gio/gdbusobjectmanagerserver.c b/gio/gdbusobjectmanagerserver.c index 68539ea..bbc390f 100644 --- a/gio/gdbusobjectmanagerserver.c +++ b/gio/gdbusobjectmanagerserver.c @@ -37,13 +37,11 @@ #include "glibintl.h" /** - * SECTION:gdbusobjectmanagerserver - * @short_description: Service-side object manager - * @include: gio/gio.h + * GDBusObjectManagerServer: * - * #GDBusObjectManagerServer is used to export #GDBusObject instances using - * the standardized - * [org.freedesktop.DBus.ObjectManager](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) + * `GDBusObjectManagerServer` is used to export [iface@Gio.DBusObject] instances + * using the standardized + * [`org.freedesktop.DBus.ObjectManager`](http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager) * interface. For example, remote D-Bus clients can get all objects * and properties in a single call. Additionally, any change in the * object hierarchy is broadcast using signals. This means that D-Bus @@ -59,10 +57,11 @@ * It is supported, but not recommended, to export an object manager at the root * path, `/`. * - * See #GDBusObjectManagerClient for the client-side code that is - * intended to be used with #GDBusObjectManagerServer or any D-Bus - * object implementing the org.freedesktop.DBus.ObjectManager - * interface. + * See [class@Gio.DBusObjectManagerClient] for the client-side code that is + * intended to be used with `GDBusObjectManagerServer` or any D-Bus + * object implementing the `org.freedesktop.DBus.ObjectManager` interface. + * + * Since: 2.30 */ typedef struct @@ -210,9 +209,7 @@ g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_CONNECTION, - g_param_spec_object ("connection", - "Connection", - "The connection to export objects on", + g_param_spec_object ("connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -227,9 +224,7 @@ g_dbus_object_manager_server_class_init (GDBusObjectManagerServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_OBJECT_PATH, - g_param_spec_string ("object-path", - "Object Path", - "The object path to register the manager object at", + g_param_spec_string ("object-path", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gdbusobjectmanagerserver.h b/gio/gdbusobjectmanagerserver.h index 92543dd..a4b7418 100644 --- a/gio/gdbusobjectmanagerserver.h +++ b/gio/gdbusobjectmanagerserver.h @@ -37,14 +37,6 @@ G_BEGIN_DECLS typedef struct _GDBusObjectManagerServerClass GDBusObjectManagerServerClass; typedef struct _GDBusObjectManagerServerPrivate GDBusObjectManagerServerPrivate; -/** - * GDBusObjectManagerServer: - * - * The #GDBusObjectManagerServer structure contains private data and should - * only be accessed using the provided API. - * - * Since: 2.30 - */ struct _GDBusObjectManagerServer { /*< private >*/ diff --git a/gio/gdbusobjectproxy.c b/gio/gdbusobjectproxy.c index ac5e448..dcdfe5b 100644 --- a/gio/gdbusobjectproxy.c +++ b/gio/gdbusobjectproxy.c @@ -32,13 +32,11 @@ #include "glibintl.h" /** - * SECTION:gdbusobjectproxy - * @short_description: Client-side D-Bus object - * @include: gio/gio.h + * GDBusObjectProxy: * - * A #GDBusObjectProxy is an object used to represent a remote object - * with one or more D-Bus interfaces. Normally, you don't instantiate - * a #GDBusObjectProxy yourself - typically #GDBusObjectManagerClient + * A `GDBusObjectProxy` is an object used to represent a remote object + * with one or more D-Bus interfaces. Normally, you don’t instantiate + * a `GDBusObjectProxy` yourself — typically [class@Gio.DBusObjectManagerClient] * is used to obtain it. * * Since: 2.30 @@ -154,9 +152,7 @@ g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_OBJECT_PATH, - g_param_spec_string ("g-object-path", - "Object Path", - "The object path of the proxy", + g_param_spec_string ("g-object-path", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -171,9 +167,7 @@ g_dbus_object_proxy_class_init (GDBusObjectProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_CONNECTION, - g_param_spec_object ("g-connection", - "Connection", - "The connection of the proxy", + g_param_spec_object ("g-connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gdbusobjectproxy.h b/gio/gdbusobjectproxy.h index ea5af0f..8397dba 100644 --- a/gio/gdbusobjectproxy.h +++ b/gio/gdbusobjectproxy.h @@ -37,14 +37,6 @@ G_BEGIN_DECLS typedef struct _GDBusObjectProxyClass GDBusObjectProxyClass; typedef struct _GDBusObjectProxyPrivate GDBusObjectProxyPrivate; -/** - * GDBusObjectProxy: - * - * The #GDBusObjectProxy structure contains private data and should - * only be accessed using the provided API. - * - * Since: 2.30 - */ struct _GDBusObjectProxy { /*< private >*/ diff --git a/gio/gdbusobjectskeleton.c b/gio/gdbusobjectskeleton.c index 0b857ba..f137675 100644 --- a/gio/gdbusobjectskeleton.c +++ b/gio/gdbusobjectskeleton.c @@ -34,15 +34,15 @@ #include "glibintl.h" /** - * SECTION:gdbusobjectskeleton - * @short_description: Service-side D-Bus object - * @include: gio/gio.h + * GDBusObjectSkeleton: * - * A #GDBusObjectSkeleton instance is essentially a group of D-Bus + * A `GDBusObjectSkeleton` instance is essentially a group of D-Bus * interfaces. The set of exported interfaces on the object may be * dynamic and change at runtime. * - * This type is intended to be used with #GDBusObjectManager. + * This type is intended to be used with [iface@Gio.DBusObjectManager]. + * + * Since: 2.30 */ struct _GDBusObjectSkeletonPrivate @@ -157,9 +157,7 @@ g_dbus_object_skeleton_class_init (GDBusObjectSkeletonClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_OBJECT_PATH, - g_param_spec_string ("g-object-path", - "Object Path", - "The object path where the object is exported", + g_param_spec_string ("g-object-path", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gdbusobjectskeleton.h b/gio/gdbusobjectskeleton.h index b15a288..f902d54 100644 --- a/gio/gdbusobjectskeleton.h +++ b/gio/gdbusobjectskeleton.h @@ -37,14 +37,6 @@ G_BEGIN_DECLS typedef struct _GDBusObjectSkeletonClass GDBusObjectSkeletonClass; typedef struct _GDBusObjectSkeletonPrivate GDBusObjectSkeletonPrivate; -/** - * GDBusObjectSkeleton: - * - * The #GDBusObjectSkeleton structure contains private data and should only be - * accessed using the provided API. - * - * Since: 2.30 - */ struct _GDBusObjectSkeleton { /*< private >*/ diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 2c9238c..28083e4 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -294,10 +294,9 @@ gdbus_shared_thread_func (gpointer user_data) static SharedThreadData * _g_dbus_shared_thread_ref (void) { - static gsize shared_thread_data = 0; - SharedThreadData *ret; + static SharedThreadData *shared_thread_data = 0; - if (g_once_init_enter (&shared_thread_data)) + if (g_once_init_enter_pointer (&shared_thread_data)) { SharedThreadData *data; @@ -310,12 +309,11 @@ _g_dbus_shared_thread_ref (void) gdbus_shared_thread_func, data); /* We can cast between gsize and gpointer safely */ - g_once_init_leave (&shared_thread_data, (gsize) data); + g_once_init_leave_pointer (&shared_thread_data, data); } - ret = (SharedThreadData*) shared_thread_data; - g_atomic_int_inc (&ret->refcount); - return ret; + g_atomic_int_inc (&shared_thread_data->refcount); + return shared_thread_data; } static void @@ -1032,10 +1030,12 @@ write_message_continue_writing (MessageToWriteData *data) if (!(data->worker->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING)) { GTask *task = g_steal_pointer (&data->task); - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_FAILED, - "Tried sending a file descriptor but remote peer does not support this capability"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_FAILED, + "Tried sending a file descriptor " + "but remote peer does not support " + "this capability"); g_clear_object (&task); goto out; } @@ -2028,10 +2028,10 @@ _g_dbus_compute_complete_signature (GDBusArgInfo **args) #ifdef G_OS_WIN32 -#define DBUS_DAEMON_ADDRESS_INFO "DBusDaemonAddressInfo" -#define DBUS_DAEMON_MUTEX "DBusDaemonMutex" -#define UNIQUE_DBUS_INIT_MUTEX "UniqueDBusInitMutex" -#define DBUS_AUTOLAUNCH_MUTEX "DBusAutolaunchMutex" +#define DBUS_DAEMON_ADDRESS_INFO L"DBusDaemonAddressInfo" +#define DBUS_DAEMON_MUTEX L"DBusDaemonMutex" +#define UNIQUE_DBUS_INIT_MUTEX L"UniqueDBusInitMutex" +#define DBUS_AUTOLAUNCH_MUTEX L"DBusAutolaunchMutex" static void release_mutex (HANDLE mutex) @@ -2041,12 +2041,12 @@ release_mutex (HANDLE mutex) } static HANDLE -acquire_mutex (const char *mutexname) +acquire_mutex (const wchar_t *mutexname) { HANDLE mutex; DWORD res; - mutex = CreateMutexA (NULL, FALSE, mutexname); + mutex = CreateMutex (NULL, FALSE, mutexname); if (!mutex) return 0; @@ -2065,12 +2065,12 @@ acquire_mutex (const char *mutexname) } static gboolean -is_mutex_owned (const char *mutexname) +is_mutex_owned (const wchar_t *mutexname) { HANDLE mutex; gboolean res = FALSE; - mutex = CreateMutexA (NULL, FALSE, mutexname); + mutex = CreateMutex (NULL, FALSE, mutexname); if (WaitForSingleObject (mutex, 10) == WAIT_TIMEOUT) res = TRUE; else @@ -2081,7 +2081,7 @@ is_mutex_owned (const char *mutexname) } static char * -read_shm (const char *shm_name) +read_shm (const wchar_t *shm_name) { HANDLE shared_mem; char *shared_data; @@ -2092,7 +2092,7 @@ read_shm (const char *shm_name) for (i = 0; i < 20; i++) { - shared_mem = OpenFileMappingA (FILE_MAP_READ, FALSE, shm_name); + shared_mem = OpenFileMapping (FILE_MAP_READ, FALSE, shm_name); if (shared_mem != 0) break; Sleep (100); @@ -2122,13 +2122,13 @@ read_shm (const char *shm_name) } static HANDLE -set_shm (const char *shm_name, const char *value) +set_shm (const wchar_t *shm_name, const char *value) { HANDLE shared_mem; char *shared_data; - shared_mem = CreateFileMappingA (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, - 0, strlen (value) + 1, shm_name); + shared_mem = CreateFileMapping (INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, + 0, strlen (value) + 1, shm_name); if (shared_mem == 0) return 0; @@ -2154,7 +2154,7 @@ publish_session_bus (const char *address) init_mutex = acquire_mutex (UNIQUE_DBUS_INIT_MUTEX); - published_daemon_mutex = CreateMutexA (NULL, FALSE, DBUS_DAEMON_MUTEX); + published_daemon_mutex = CreateMutex (NULL, FALSE, DBUS_DAEMON_MUTEX); if (WaitForSingleObject (published_daemon_mutex, 10 ) != WAIT_OBJECT_0) { release_mutex (init_mutex); @@ -2397,11 +2397,11 @@ gchar * _g_dbus_get_machine_id (GError **error) { #ifdef G_OS_WIN32 - HW_PROFILE_INFOA info; - char *src, *dest, *res; + HW_PROFILE_INFO info; + char *guid, *src, *dest, *res; int i; - if (!GetCurrentHwProfileA (&info)) + if (!GetCurrentHwProfile (&info)) { char *message = g_win32_error_message (GetLastError ()); g_set_error (error, @@ -2412,8 +2412,11 @@ _g_dbus_get_machine_id (GError **error) return NULL; } - /* Form: {12340001-4980-1920-6788-123456789012} */ - src = &info.szHwProfileGuid[0]; + if (!(guid = g_utf16_to_utf8 (info.szHwProfileGuid, -1, NULL, NULL, NULL))) + return NULL; + + /* Guid is of the form: {12340001-4980-1920-6788-123456789012} */ + src = guid; res = g_malloc (32+1); dest = res; @@ -2435,6 +2438,8 @@ _g_dbus_get_machine_id (GError **error) *dest++ = *src++; *dest = 0; + g_free (guid); + return res; #else gchar *ret = NULL; diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h index 57147e1..e7a5bfa 100644 --- a/gio/gdbusprivate.h +++ b/gio/gdbusprivate.h @@ -27,11 +27,6 @@ G_BEGIN_DECLS -/* Bus name, interface and object path of the message bus itself */ -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS -#define DBUS_PATH_DBUS "/org/freedesktop/DBus" - /* ---------------------------------------------------------------------------------------------------- */ typedef struct GDBusWorker GDBusWorker; diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c index afc6fe9..5d9a637 100644 --- a/gio/gdbusproxy.c +++ b/gio/gdbusproxy.c @@ -47,54 +47,56 @@ #include "gmarshal-internal.h" /** - * SECTION:gdbusproxy - * @short_description: Client-side D-Bus interface proxy - * @include: gio/gio.h + * GDBusProxy: * - * #GDBusProxy is a base class used for proxies to access a D-Bus - * interface on a remote object. A #GDBusProxy can be constructed for + * `GDBusProxy` is a base class used for proxies to access a D-Bus + * interface on a remote object. A `GDBusProxy` can be constructed for * both well-known and unique names. * - * By default, #GDBusProxy will cache all properties (and listen to + * By default, `GDBusProxy` will cache all properties (and listen to * changes) of the remote object, and proxy all signals that get * emitted. This behaviour can be changed by passing suitable - * #GDBusProxyFlags when the proxy is created. If the proxy is for a + * [flags@Gio.DBusProxyFlags] when the proxy is created. If the proxy is for a * well-known name, the property cache is flushed when the name owner * vanishes and reloaded when a name owner appears. * - * The unique name owner of the proxy's name is tracked and can be read from - * #GDBusProxy:g-name-owner. Connect to the #GObject::notify signal to - * get notified of changes. Additionally, only signals and property - * changes emitted from the current name owner are considered and - * calls are always sent to the current name owner. This avoids a - * number of race conditions when the name is lost by one owner and - * claimed by another. However, if no name owner currently exists, + * The unique name owner of the proxy’s name is tracked and can be read from + * [property@Gio.DBusProxy:g-name-owner]. Connect to the + * [signal@GObject.Object::notify] signal to get notified of changes. + * Additionally, only signals and property changes emitted from the current name + * owner are considered and calls are always sent to the current name owner. + * This avoids a number of race conditions when the name is lost by one owner + * and claimed by another. However, if no name owner currently exists, * then calls will be sent to the well-known name which may result in * the message bus launching an owner (unless - * %G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START is set). + * `G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START` is set). * * If the proxy is for a stateless D-Bus service, where the name owner may - * be started and stopped between calls, the #GDBusProxy:g-name-owner tracking - * of #GDBusProxy will cause the proxy to drop signal and property changes from - * the service after it has restarted for the first time. When interacting - * with a stateless D-Bus service, do not use #GDBusProxy — use direct D-Bus - * method calls and signal connections. - * - * The generic #GDBusProxy::g-properties-changed and - * #GDBusProxy::g-signal signals are not very convenient to work with. - * Therefore, the recommended way of working with proxies is to subclass - * #GDBusProxy, and have more natural properties and signals in your derived - * class. This [example][gdbus-example-gdbus-codegen] shows how this can - * easily be done using the [gdbus-codegen][gdbus-codegen] tool. - * - * A #GDBusProxy instance can be used from multiple threads but note - * that all signals (e.g. #GDBusProxy::g-signal, #GDBusProxy::g-properties-changed - * and #GObject::notify) are emitted in the - * [thread-default main context][g-main-context-push-thread-default] - * of the thread where the instance was constructed. + * be started and stopped between calls, the + * [property@Gio.DBusProxy:g-name-owner] tracking of `GDBusProxy` will cause the + * proxy to drop signal and property changes from the service after it has + * restarted for the first time. When interacting with a stateless D-Bus + * service, do not use `GDBusProxy` — use direct D-Bus method calls and signal + * connections. + * + * The generic [signal@Gio.DBusProxy::g-properties-changed] and + * [signal@Gio.DBusProxy::g-signal] signals are not very convenient to work + * with. Therefore, the recommended way of working with proxies is to subclass + * `GDBusProxy`, and have more natural properties and signals in your derived + * class. This [example](migrating-gdbus.html#using-gdbus-codegen) shows how + * this can easily be done using the [`gdbus-codegen`](gdbus-codegen.html) tool. + * + * A `GDBusProxy` instance can be used from multiple threads but note + * that all signals (e.g. [signal@Gio.DBusProxy::g-signal], + * [signal@Gio.DBusProxy::g-properties-changed] and + * [signal@GObject.Object::notify]) are emitted in the thread-default main + * context (see [method@GLib.MainContext.push_thread_default]) of the thread + * where the instance was constructed. * * An example using a proxy for a well-known name can be found in - * [gdbus-example-watch-proxy.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-proxy.c) + * [`gdbus-example-watch-proxy.c`](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-watch-proxy.c). + * + * Since: 2.26 */ /* lock protecting the mutable properties: name_owner, timeout_msec, @@ -367,9 +369,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_INTERFACE_INFO, - g_param_spec_boxed ("g-interface-info", - P_("Interface Information"), - P_("Interface Information"), + g_param_spec_boxed ("g-interface-info", NULL, NULL, G_TYPE_DBUS_INTERFACE_INFO, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -386,9 +386,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_CONNECTION, - g_param_spec_object ("g-connection", - P_("g-connection"), - P_("The connection the proxy is for"), + g_param_spec_object ("g-connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -409,9 +407,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_BUS_TYPE, - g_param_spec_enum ("g-bus-type", - P_("Bus Type"), - P_("The bus to connect to, if any"), + g_param_spec_enum ("g-bus-type", NULL, NULL, G_TYPE_BUS_TYPE, G_BUS_TYPE_NONE, G_PARAM_WRITABLE | @@ -429,9 +425,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_FLAGS, - g_param_spec_flags ("g-flags", - P_("g-flags"), - P_("Flags for the proxy"), + g_param_spec_flags ("g-flags", NULL, NULL, G_TYPE_DBUS_PROXY_FLAGS, G_DBUS_PROXY_FLAGS_NONE, G_PARAM_READABLE | @@ -450,9 +444,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_NAME, - g_param_spec_string ("g-name", - P_("g-name"), - P_("The well-known or unique name that the proxy is for"), + g_param_spec_string ("g-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -472,9 +464,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_NAME_OWNER, - g_param_spec_string ("g-name-owner", - P_("g-name-owner"), - P_("The unique name for the owner"), + g_param_spec_string ("g-name-owner", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -490,9 +480,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_OBJECT_PATH, - g_param_spec_string ("g-object-path", - P_("g-object-path"), - P_("The object path the proxy is for"), + g_param_spec_string ("g-object-path", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -510,9 +498,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_INTERFACE_NAME, - g_param_spec_string ("g-interface-name", - P_("g-interface-name"), - P_("The D-Bus interface name the proxy is for"), + g_param_spec_string ("g-interface-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -537,9 +523,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) */ g_object_class_install_property (gobject_class, PROP_G_DEFAULT_TIMEOUT, - g_param_spec_int ("g-default-timeout", - P_("Default Timeout"), - P_("Timeout for remote method invocation"), + g_param_spec_int ("g-default-timeout", NULL, NULL, -1, G_MAXINT, -1, diff --git a/gio/gdbusproxy.h b/gio/gdbusproxy.h index 7483156..d74cf75 100644 --- a/gio/gdbusproxy.h +++ b/gio/gdbusproxy.h @@ -42,14 +42,6 @@ G_BEGIN_DECLS typedef struct _GDBusProxyClass GDBusProxyClass; typedef struct _GDBusProxyPrivate GDBusProxyPrivate; -/** - * GDBusProxy: - * - * The #GDBusProxy structure contains only private data and - * should only be accessed using the provided API. - * - * Since: 2.26 - */ struct _GDBusProxy { /*< private >*/ diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index db0c9ab..4e23e52 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -63,35 +63,28 @@ G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER) /** - * SECTION:gdbusserver - * @short_description: Helper for accepting connections - * @include: gio/gio.h + * GDBusServer: * - * #GDBusServer is a helper for listening to and accepting D-Bus + * `GDBusServer` is a helper for listening to and accepting D-Bus * connections. This can be used to create a new D-Bus server, allowing two * peers to use the D-Bus protocol for their own specialized communication. * A server instance provided in this way will not perform message routing or - * implement the org.freedesktop.DBus interface. + * implement the + * [`org.freedesktop.DBus` interface](https://dbus.freedesktop.org/doc/dbus-specification.html#message-bus-messages). * * To just export an object on a well-known name on a message bus, such as the - * session or system bus, you should instead use g_bus_own_name(). + * session or system bus, you should instead use [func@Gio.bus_own_name]. * * An example of peer-to-peer communication with GDBus can be found * in [gdbus-example-peer.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/tests/gdbus-example-peer.c). * - * Note that a minimal #GDBusServer will accept connections from any - * peer. In many use-cases it will be necessary to add a #GDBusAuthObserver - * that only accepts connections that have successfully authenticated - * as the same user that is running the #GDBusServer. Since GLib 2.68 this can - * be achieved more simply by passing the - * %G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER flag to the server. - */ - -/** - * GDBusServer: - * - * The #GDBusServer structure contains only private data and - * should only be accessed using the provided API. + * Note that a minimal `GDBusServer` will accept connections from any + * peer. In many use-cases it will be necessary to add a + * [class@Gio.DBusAuthObserver] that only accepts connections that have + * successfully authenticated as the same user that is running the + * `GDBusServer`. Since GLib 2.68 this can be achieved more simply by passing + * the `G_DBUS_SERVER_FLAGS_AUTHENTICATION_REQUIRE_SAME_USER` flag to the + * server. * * Since: 2.26 */ @@ -305,9 +298,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("Flags"), - P_("Flags for the server"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_DBUS_SERVER_FLAGS, G_DBUS_SERVER_FLAGS_NONE, G_PARAM_READABLE | @@ -328,9 +319,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_GUID, - g_param_spec_string ("guid", - P_("GUID"), - P_("The guid of the server"), + g_param_spec_string ("guid", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -348,9 +337,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_string ("address", - P_("Address"), - P_("The address to listen on"), + g_param_spec_string ("address", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | @@ -368,9 +355,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_CLIENT_ADDRESS, - g_param_spec_string ("client-address", - P_("Client Address"), - P_("The address clients can use"), + g_param_spec_string ("client-address", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -386,9 +371,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_ACTIVE, - g_param_spec_boolean ("active", - P_("Active"), - P_("Whether the server is currently active"), + g_param_spec_boolean ("active", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_NAME | @@ -404,9 +387,7 @@ g_dbus_server_class_init (GDBusServerClass *klass) */ g_object_class_install_property (gobject_class, PROP_AUTHENTICATION_OBSERVER, - g_param_spec_object ("authentication-observer", - P_("Authentication Observer"), - P_("Object used to assist in the authentication process"), + g_param_spec_object ("authentication-observer", NULL, NULL, G_TYPE_DBUS_AUTH_OBSERVER, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gdbusutils.c b/gio/gdbusutils.c index 4b4b7e1..a76e9ac 100644 --- a/gio/gdbusutils.c +++ b/gio/gdbusutils.c @@ -29,15 +29,6 @@ #include "glibintl.h" -/** - * SECTION:gdbusutils - * @title: D-Bus Utilities - * @short_description: Various utilities related to D-Bus - * @include: gio/gio.h - * - * Various utility routines related to D-Bus. - */ - static gboolean is_valid_bus_name_character (gint c, gboolean allow_hyphen) diff --git a/gio/gdebugcontroller.c b/gio/gdebugcontroller.c index 159a699..ab72f09 100644 --- a/gio/gdebugcontroller.c +++ b/gio/gdebugcontroller.c @@ -29,25 +29,23 @@ #include "giomodule-priv.h" /** - * SECTION:gdebugcontroller - * @title: GDebugController - * @short_description: Debugging controller - * @include: gio/gio.h + * GDebugController: * - * #GDebugController is an interface to expose control of debugging features and + * `GDebugController` is an interface to expose control of debugging features and * debug output. * - * It is implemented on Linux using #GDebugControllerDBus, which exposes a D-Bus - * interface to allow authenticated peers to control debug features in this - * process. + * It is implemented on Linux using [class@Gio.DebugControllerDBus], which + * exposes a D-Bus interface to allow authenticated peers to control debug + * features in this process. * * Whether debug output is enabled is exposed as - * #GDebugController:debug-enabled. This controls g_log_set_debug_enabled() by - * default. Application code may connect to the #GObject::notify signal for it + * [property@Gio.DebugController:debug-enabled]. This controls + * [func@GLib.log_set_debug_enabled] by default. Application code may + * connect to the [signal@GObject.Object::notify] signal for it * to control other parts of its debug infrastructure as necessary. * * If your application or service is using the default GLib log writer function, - * creating one of the built-in implementations of #GDebugController should be + * creating one of the built-in implementations of `GDebugController` should be * all that’s needed to dynamically enable or disable debug output. * * Since: 2.72 @@ -68,9 +66,7 @@ g_debug_controller_default_init (GDebugControllerInterface *iface) * Since: 2.72 */ g_object_interface_install_property (iface, - g_param_spec_boolean ("debug-enabled", - "Debug Enabled", - "Whether to expose debug output", + g_param_spec_boolean ("debug-enabled", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | diff --git a/gio/gdebugcontroller.h b/gio/gdebugcontroller.h index e59cd34..b89ce06 100644 --- a/gio/gdebugcontroller.h +++ b/gio/gdebugcontroller.h @@ -41,14 +41,6 @@ G_BEGIN_DECLS */ #define G_DEBUG_CONTROLLER_EXTENSION_POINT_NAME "gio-debug-controller" -/** - * GDebugController: - * - * #GDebugController is an interface to expose control of debugging features and - * debug output. - * - * Since: 2.72 - */ #define G_TYPE_DEBUG_CONTROLLER (g_debug_controller_get_type ()) GIO_AVAILABLE_IN_2_72 G_DECLARE_INTERFACE(GDebugController, g_debug_controller, g, debug_controller, GObject) diff --git a/gio/gdebugcontrollerdbus.c b/gio/gdebugcontrollerdbus.c index ce0f703..03dd1be 100644 --- a/gio/gdebugcontrollerdbus.c +++ b/gio/gdebugcontrollerdbus.c @@ -31,35 +31,34 @@ #include "gio/gmarshal-internal.h" /** - * SECTION:gdebugcontrollerdbus - * @title: GDebugControllerDBus - * @short_description: Debugging controller D-Bus implementation - * @include: gio/gio.h + * GDebugControllerDBus: * - * #GDebugControllerDBus is an implementation of #GDebugController which exposes - * debug settings as a D-Bus object. + * `GDebugControllerDBus` is an implementation of [iface@Gio.DebugController] + * which exposes debug settings as a D-Bus object. * - * It is a #GInitable object, and will register an object at + * It is a [iface@Gio.Initable] object, and will register an object at * `/org/gtk/Debugging` on the bus given as - * #GDebugControllerDBus:connection once it’s initialized. The object will be - * unregistered when the last reference to the #GDebugControllerDBus is dropped. + * [property@Gio.DebugControllerDBus:connection] once it’s initialized. The + * object will be unregistered when the last reference to the + * `GDebugControllerDBus` is dropped. * * This D-Bus object can be used by remote processes to enable or disable debug * output in this process. Remote processes calling * `org.gtk.Debugging.SetDebugEnabled()` will affect the value of - * #GDebugController:debug-enabled and, by default, g_log_get_debug_enabled(). - * default. + * [property@Gio.DebugController:debug-enabled] and, by default, + * [func@GLib.log_get_debug_enabled]. * * By default, no processes are allowed to call `SetDebugEnabled()` unless a - * #GDebugControllerDBus::authorize signal handler is installed. This is because - * the process may be privileged, or might expose sensitive information in its - * debug output. You may want to restrict the ability to enable debug output to - * privileged users or processes. + * [signal@Gio.DebugControllerDBus::authorize] signal handler is installed. This + * is because the process may be privileged, or might expose sensitive + * information in its debug output. You may want to restrict the ability to + * enable debug output to privileged users or processes. * * One option is to install a D-Bus security policy which restricts access to * `SetDebugEnabled()`, installing something like the following in * `$datadir/dbus-1/system.d/`: - * |[ + * + * ```xml * * @@ -71,7 +70,7 @@ * * * - * ]| + * ``` * * This will prevent the `SetDebugEnabled()` method from being called by all * except root. It will not prevent the `DebugEnabled` property from being read, @@ -79,9 +78,10 @@ * * Another option is to use polkit to allow or deny requests on a case-by-case * basis, allowing for the possibility of dynamic authorisation. To do this, - * connect to the #GDebugControllerDBus::authorize signal and query polkit in - * it: - * |[ + * connect to the [signal@Gio.DebugControllerDBus::authorize] signal and query + * polkit in it: + * + * ```c * g_autoptr(GError) child_error = NULL; * g_autoptr(GDBusConnection) connection = g_bus_get_sync (G_BUS_TYPE_SYSTEM, NULL, NULL); * gulong debug_controller_authorize_id = 0; @@ -142,7 +142,7 @@ * * return polkit_authorization_result_get_is_authorized (auth_result); * } - * ]| + * ``` * * Since: 2.72 */ @@ -561,8 +561,7 @@ g_debug_controller_dbus_class_init (GDebugControllerDBusClass *klass) * Since: 2.72 */ props[PROP_CONNECTION] = - g_param_spec_object ("connection", "D-Bus Connection", - "The D-Bus connection to expose the debugging interface on.", + g_param_spec_object ("connection", NULL, NULL, G_TYPE_DBUS_CONNECTION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gdebugcontrollerdbus.h b/gio/gdebugcontrollerdbus.h index c6e6c70..17e3658 100644 --- a/gio/gdebugcontrollerdbus.h +++ b/gio/gdebugcontrollerdbus.h @@ -28,13 +28,6 @@ G_BEGIN_DECLS -/** - * GDebugControllerDBus: - * - * #GDebugControllerDBus is an implementation of #GDebugController over D-Bus. - * - * Since: 2.72 - */ #define G_TYPE_DEBUG_CONTROLLER_DBUS (g_debug_controller_dbus_get_type ()) GIO_AVAILABLE_IN_2_72 G_DECLARE_DERIVABLE_TYPE (GDebugControllerDBus, g_debug_controller_dbus, G, DEBUG_CONTROLLER_DBUS, GObject) diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 1f16132..bde0793 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -63,12 +63,9 @@ #endif /** - * SECTION:gdesktopappinfo - * @title: GDesktopAppInfo - * @short_description: Application information from desktop files - * @include: gio/gdesktopappinfo.h + * GDesktopAppInfo: * - * #GDesktopAppInfo is an implementation of #GAppInfo based on + * `GDesktopAppInfo` is an implementation of [iface@Gio.AppInfo] based on * desktop files. * * Note that `` belongs to the UNIX-specific @@ -95,11 +92,6 @@ static gboolean g_desktop_app_info_ensure_saved (GDesktopAppInfo *info, GError **error); static gboolean g_desktop_app_info_load_file (GDesktopAppInfo *self); -/** - * GDesktopAppInfo: - * - * Information about an installed application from a desktop file. - */ struct _GDesktopAppInfo { GObject parent_instance; @@ -365,7 +357,7 @@ get_lowercase_current_desktops (void) { static gchar **result; - if (g_once_init_enter (&result)) + if (g_once_init_enter_pointer (&result)) { char **tmp = get_valid_current_desktops (NULL); gsize i, j; @@ -377,7 +369,7 @@ get_lowercase_current_desktops (void) tmp[i][j] = g_ascii_tolower (tmp[i][j]); } - g_once_init_leave (&result, tmp); + g_once_init_leave_pointer (&result, tmp); } return (const gchar **) result; @@ -388,11 +380,11 @@ get_current_desktops (const gchar *value) { static gchar **result; - if (g_once_init_enter (&result)) + if (g_once_init_enter_pointer (&result)) { char **tmp = get_valid_current_desktops (value); - g_once_init_leave (&result, tmp); + g_once_init_leave_pointer (&result, tmp); } return (const gchar **) result; @@ -432,7 +424,6 @@ add_to_table_if_appropriate (GHashTable *apps, enum { - DESKTOP_KEY_Comment, DESKTOP_KEY_Exec, DESKTOP_KEY_GenericName, DESKTOP_KEY_Keywords, @@ -452,13 +443,14 @@ const gchar desktop_key_match_category[N_DESKTOP_KEYS] = { [DESKTOP_KEY_Exec] = 2, [DESKTOP_KEY_Keywords] = 3, [DESKTOP_KEY_GenericName] = 4, - [DESKTOP_KEY_X_GNOME_FullName] = 5, - [DESKTOP_KEY_Comment] = 6 + [DESKTOP_KEY_X_GNOME_FullName] = 5 }; typedef enum { /* Lower numbers have higher priority. - * Prefix match should put before substring match. + * Prefix match should put before substring match, independently of + * category relevance, i.e. a prefix match in 'Keyword' category will + * come before a substring match in a more relevant category like 'Name'. */ MATCH_TYPE_PREFIX = 1, MATCH_TYPE_SUBSTRING = 2 @@ -485,8 +477,6 @@ desktop_key_get_name (guint key_id) { switch (key_id) { - case DESKTOP_KEY_Comment: - return "Comment"; case DESKTOP_KEY_Exec: return "Exec"; case DESKTOP_KEY_GenericName: @@ -576,7 +566,10 @@ compare_results (gconstpointer a, } else { - if (ra->category == rb->category) + /* We prioritize prefix matches over category relevance e.g. a prefix match in 'Keyword' + * category is better than a substring match in a more relevance category like 'Name'. + */ + if (ra->match_type != rb->match_type) return ra->match_type - rb->match_type; return ra->category - rb->category; @@ -590,10 +583,10 @@ compare_categories (gconstpointer a, const struct search_result *ra = a; const struct search_result *rb = b; - /* Also compare match types so we can put prefix match in a group while - * substring match in another group. + /* We prioritize prefix matches over category relevance e.g. a prefix match in 'Keyword' + * category is better than a substring match in a more relevance category like 'Name'. */ - if (ra->category == rb->category) + if (ra->match_type != rb->match_type) return ra->match_type - rb->match_type; return ra->category - rb->category; @@ -1788,7 +1781,7 @@ g_desktop_app_info_class_init (GDesktopAppInfoClass *klass) */ g_object_class_install_property (gobject_class, PROP_FILENAME, - g_param_spec_string ("filename", "Filename", "", NULL, + g_param_spec_string ("filename", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } @@ -3011,7 +3004,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info, g_free (program); } - if (g_once_init_enter (&gio_launch_desktop_path)) + if (g_once_init_enter_pointer (&gio_launch_desktop_path)) { const gchar *tmp = NULL; gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) (); @@ -3027,7 +3020,7 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info, /* Fall back on usual searching in $PATH */ if (tmp == NULL) tmp = "gio-launch-desktop"; - g_once_init_leave (&gio_launch_desktop_path, tmp); + g_once_init_leave_pointer (&gio_launch_desktop_path, tmp); } wrapped_argv = g_new (char *, argc + 2); diff --git a/gio/gdrive.c b/gio/gdrive.c index 4e33d23..fbb86e5 100644 --- a/gio/gdrive.c +++ b/gio/gdrive.c @@ -31,36 +31,34 @@ /** - * SECTION:gdrive - * @short_description: Drive management - * @include: gio/gio.h + * GDrive: * - * #GDrive - this represent a piece of hardware connected to the machine. - * It's generally only created for removable hardware or hardware with + * `GDrive` represents a piece of hardware connected to the machine. + * It’s generally only created for removable hardware or hardware with * removable media. * - * #GDrive is a container class for #GVolume objects that stem from - * the same piece of media. As such, #GDrive abstracts a drive with + * `GDrive` is a container class for [iface@Gio.Volume] objects that stem from + * the same piece of media. As such, `GDrive` abstracts a drive with * (or without) removable media and provides operations for querying * whether media is available, determining whether media change is * automatically detected and ejecting the media. * - * If the #GDrive reports that media isn't automatically detected, one + * If the `GDrive` reports that media isn’t automatically detected, one * can poll for media; typically one should not do this periodically * as a poll for media operation is potentially expensive and may * spin up the drive creating noise. * - * #GDrive supports starting and stopping drives with authentication + * `GDrive` supports starting and stopping drives with authentication * support for the former. This can be used to support a diverse set * of use cases including connecting/disconnecting iSCSI devices, * powering down external disk enclosures and starting/stopping * multi-disk devices such as RAID devices. Note that the actual - * semantics and side-effects of starting/stopping a #GDrive may vary + * semantics and side-effects of starting/stopping a `GDrive` may vary * according to implementation. To choose the correct verbs in e.g. a - * file manager, use g_drive_get_start_stop_type(). + * file manager, use [method@Gio.Drive.get_start_stop_type]. * - * For porting from GnomeVFS note that there is no equivalent of - * #GDrive in that API. + * For [porting from GnomeVFS](migrating-gnome-vfs.html) note that there is no + * equivalent of `GDrive` in that API. **/ typedef GDriveIface GDriveInterface; diff --git a/gio/gdtlsclientconnection.c b/gio/gdtlsclientconnection.c index 507823c..d19105a 100644 --- a/gio/gdtlsclientconnection.c +++ b/gio/gdtlsclientconnection.c @@ -32,25 +32,13 @@ #include "glibintl.h" /** - * SECTION:gdtlsclientconnection - * @short_description: DTLS client-side connection - * @include: gio/gio.h - * - * #GDtlsClientConnection is the client-side subclass of - * #GDtlsConnection, representing a client-side DTLS connection. - * - * Since: 2.48 - */ - -/** * GDtlsClientConnection: * - * Abstract base class for the backend-specific client connection - * type. + * `GDtlsClientConnection` is the client-side subclass of + * [iface@Gio.DtlsConnection], representing a client-side DTLS connection. * * Since: 2.48 */ - G_DEFINE_INTERFACE (GDtlsClientConnection, g_dtls_client_connection, G_TYPE_DTLS_CONNECTION) @@ -82,9 +70,7 @@ g_dtls_client_connection_default_init (GDtlsClientConnectionInterface *iface) * Deprecated: 2.74: Do not attempt to ignore validation errors. */ g_object_interface_install_property (iface, - g_param_spec_flags ("validation-flags", - P_("Validation flags"), - P_("What certificate validation to perform"), + g_param_spec_flags ("validation-flags", NULL, NULL, G_TYPE_TLS_CERTIFICATE_FLAGS, G_TLS_CERTIFICATE_VALIDATE_ALL, G_PARAM_READWRITE | @@ -112,9 +98,7 @@ g_dtls_client_connection_default_init (GDtlsClientConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("server-identity", - P_("Server identity"), - P_("GSocketConnectable identifying the server"), + g_param_spec_object ("server-identity", NULL, NULL, G_TYPE_SOCKET_CONNECTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -134,9 +118,7 @@ g_dtls_client_connection_default_init (GDtlsClientConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_pointer ("accepted-cas", - P_("Accepted CAs"), - P_("Distinguished names of the CAs the server accepts certificates from"), + g_param_spec_pointer ("accepted-cas", NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gdtlsconnection.c b/gio/gdtlsconnection.c index ef96106..bca4d66 100644 --- a/gio/gdtlsconnection.c +++ b/gio/gdtlsconnection.c @@ -36,42 +36,32 @@ #include "gmarshal-internal.h" /** - * SECTION:gdtlsconnection - * @short_description: DTLS connection type - * @include: gio/gio.h + * GDtlsConnection: * - * #GDtlsConnection is the base DTLS connection class type, which wraps - * a #GDatagramBased and provides DTLS encryption on top of it. Its - * subclasses, #GDtlsClientConnection and #GDtlsServerConnection, - * implement client-side and server-side DTLS, respectively. + * `GDtlsConnection` is the base DTLS connection class type, which wraps + * a [iface@Gio.DatagramBased] and provides DTLS encryption on top of it. Its + * subclasses, [iface@Gio.DtlsClientConnection] and + * [iface@Gio.DtlsServerConnection], implement client-side and server-side DTLS, + * respectively. * - * For TLS support, see #GTlsConnection. + * For TLS support, see [class@Gio.TlsConnection]. * - * As DTLS is datagram based, #GDtlsConnection implements #GDatagramBased, - * presenting a datagram-socket-like API for the encrypted connection. This - * operates over a base datagram connection, which is also a #GDatagramBased - * (#GDtlsConnection:base-socket). + * As DTLS is datagram based, `GDtlsConnection` implements + * [iface@Gio.DatagramBased], presenting a datagram-socket-like API for the + * encrypted connection. This operates over a base datagram connection, which is + * also a `GDatagramBased` ([property@Gio.DtlsConnection:base-socket]). * - * To close a DTLS connection, use g_dtls_connection_close(). + * To close a DTLS connection, use [method@Gio.DtlsConnection.close]. * - * Neither #GDtlsServerConnection or #GDtlsClientConnection set the peer address - * on their base #GDatagramBased if it is a #GSocket — it is up to the caller to - * do that if they wish. If they do not, and g_socket_close() is called on the - * base socket, the #GDtlsConnection will not raise a %G_IO_ERROR_NOT_CONNECTED - * error on further I/O. + * Neither [iface@Gio.DtlsServerConnection] or [iface@Gio.DtlsClientConnection] + * set the peer address on their base [iface@Gio.DatagramBased] if it is a + * [class@Gio.Socket] — it is up to the caller to do that if they wish. If they + * do not, and [method@Gio.Socket.close] is called on the base socket, the + * `GDtlsConnection` will not raise a `G_IO_ERROR_NOT_CONNECTED` error on + * further I/O. * * Since: 2.48 */ - -/** - * GDtlsConnection: - * - * Abstract base class for the backend-specific #GDtlsClientConnection - * and #GDtlsServerConnection types. - * - * Since: 2.48 - */ - G_DEFINE_INTERFACE (GDtlsConnection, g_dtls_connection, G_TYPE_DATAGRAM_BASED) enum { @@ -106,9 +96,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("base-socket", - P_("Base Socket"), - P_("The GDatagramBased that the connection wraps"), + g_param_spec_object ("base-socket", NULL, NULL, G_TYPE_DATAGRAM_BASED, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -136,9 +124,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("database", - P_("Database"), - P_("Certificate database to use for looking up or verifying certificates"), + g_param_spec_object ("database", NULL, NULL, G_TYPE_TLS_DATABASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -152,9 +138,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("interaction", - P_("Interaction"), - P_("Optional object for user interaction"), + g_param_spec_object ("interaction", NULL, NULL, G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -167,9 +151,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_boolean ("require-close-notify", - P_("Require close notify"), - P_("Whether to require proper TLS close notification"), + g_param_spec_boolean ("require-close-notify", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -185,9 +167,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Deprecated: 2.60: The rehandshake mode is ignored. */ g_object_interface_install_property (iface, - g_param_spec_enum ("rehandshake-mode", - P_("Rehandshake mode"), - P_("When to allow rehandshaking"), + g_param_spec_enum ("rehandshake-mode", NULL, NULL, G_TYPE_TLS_REHANDSHAKE_MODE, G_TLS_REHANDSHAKE_NEVER, G_PARAM_READWRITE | @@ -203,9 +183,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("certificate", - P_("Certificate"), - P_("The connection’s certificate"), + g_param_spec_object ("certificate", NULL, NULL, G_TYPE_TLS_CERTIFICATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -222,9 +200,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_object ("peer-certificate", - P_("Peer Certificate"), - P_("The connection’s peer’s certificate"), + g_param_spec_object ("peer-certificate", NULL, NULL, G_TYPE_TLS_CERTIFICATE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -249,9 +225,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_flags ("peer-certificate-errors", - P_("Peer Certificate Errors"), - P_("Errors found with the peer’s certificate"), + g_param_spec_flags ("peer-certificate-errors", NULL, NULL, G_TYPE_TLS_CERTIFICATE_FLAGS, 0, G_PARAM_READABLE | @@ -266,9 +240,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.60 */ g_object_interface_install_property (iface, - g_param_spec_boxed ("advertised-protocols", - P_("Advertised Protocols"), - P_("Application-layer protocols available on this connection"), + g_param_spec_boxed ("advertised-protocols", NULL, NULL, G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -281,9 +253,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.60 */ g_object_interface_install_property (iface, - g_param_spec_string ("negotiated-protocol", - P_("Negotiated Protocol"), - P_("Application-layer protocol negotiated for this connection"), + g_param_spec_string ("negotiated-protocol", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -296,9 +266,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.70 */ g_object_interface_install_property (iface, - g_param_spec_enum ("protocol-version", - P_("Protocol Version"), - P_("DTLS protocol version negotiated for this connection"), + g_param_spec_enum ("protocol-version", NULL, NULL, G_TYPE_TLS_PROTOCOL_VERSION, G_TLS_PROTOCOL_VERSION_UNKNOWN, G_PARAM_READABLE | @@ -312,9 +280,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface) * Since: 2.70 */ g_object_interface_install_property (iface, - g_param_spec_string ("ciphersuite-name", - P_("Ciphersuite Name"), - P_("Name of ciphersuite negotiated for this connection"), + g_param_spec_string ("ciphersuite-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gdtlsserverconnection.c b/gio/gdtlsserverconnection.c index a524121..e123439 100644 --- a/gio/gdtlsserverconnection.c +++ b/gio/gdtlsserverconnection.c @@ -31,16 +31,13 @@ #include "glibintl.h" /** - * SECTION:gdtlsserverconnection - * @short_description: DTLS server-side connection - * @include: gio/gio.h + * GDtlsServerConnection: * - * #GDtlsServerConnection is the server-side subclass of #GDtlsConnection, - * representing a server-side DTLS connection. + * `GDtlsServerConnection` is the server-side subclass of + * [iface@Gio.DtlsConnection], representing a server-side DTLS connection. * * Since: 2.48 */ - G_DEFINE_INTERFACE (GDtlsServerConnection, g_dtls_server_connection, G_TYPE_DTLS_CONNECTION) @@ -57,9 +54,7 @@ g_dtls_server_connection_default_init (GDtlsServerConnectionInterface *iface) * Since: 2.48 */ g_object_interface_install_property (iface, - g_param_spec_enum ("authentication-mode", - P_("Authentication Mode"), - P_("The client authentication mode"), + g_param_spec_enum ("authentication-mode", NULL, NULL, G_TYPE_TLS_AUTHENTICATION_MODE, G_TLS_AUTHENTICATION_NONE, G_PARAM_READWRITE | diff --git a/gio/gdtlsserverconnection.h b/gio/gdtlsserverconnection.h index d463660..3832818 100644 --- a/gio/gdtlsserverconnection.h +++ b/gio/gdtlsserverconnection.h @@ -35,14 +35,6 @@ G_BEGIN_DECLS #define G_IS_DTLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_DTLS_SERVER_CONNECTION)) #define G_DTLS_SERVER_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_DTLS_SERVER_CONNECTION, GDtlsServerConnectionInterface)) -/** - * GDtlsServerConnection: - * - * DTLS server-side connection. This is the server-side implementation - * of a #GDtlsConnection. - * - * Since: 2.48 - */ typedef struct _GDtlsServerConnectionInterface GDtlsServerConnectionInterface; /** diff --git a/gio/gdummytlsbackend.c b/gio/gdummytlsbackend.c index 1ec00c9..4c69f1d 100644 --- a/gio/gdummytlsbackend.c +++ b/gio/gdummytlsbackend.c @@ -93,12 +93,12 @@ g_dummy_tls_backend_get_default_database (GTlsBackend *backend) { GDummyTlsBackend *dummy = G_DUMMY_TLS_BACKEND (backend); - if (g_once_init_enter (&dummy->database)) + if (g_once_init_enter_pointer (&dummy->database)) { GTlsDatabase *tlsdb; tlsdb = g_object_new (_g_dummy_tls_database_get_type (), NULL); - g_once_init_leave (&dummy->database, tlsdb); + g_once_init_leave_pointer (&dummy->database, tlsdb); } return g_object_ref (dummy->database); diff --git a/gio/gemblem.c b/gio/gemblem.c index af1ba00..dc03267 100644 --- a/gio/gemblem.c +++ b/gio/gemblem.c @@ -31,14 +31,11 @@ /** - * SECTION:gemblem - * @short_description: An object for emblems - * @include: gio/gio.h - * @see_also: #GIcon, #GEmblemedIcon, #GLoadableIcon, #GThemedIcon + * GEmblem: * - * #GEmblem is an implementation of #GIcon that supports + * `GEmblem` is an implementation of [iface@Gio.Icon] that supports * having an emblem, which is an icon with additional properties. - * It can than be added to a #GEmblemedIcon. + * It can than be added to a [class@Gio.EmblemedIcon]. * * Currently, only metainformation about the emblem's origin is * supported. More may be added in the future. @@ -137,20 +134,30 @@ g_emblem_class_init (GEmblemClass *klass) gobject_class->set_property = g_emblem_set_property; gobject_class->get_property = g_emblem_get_property; + /** + * GEmblem:origin: + * + * The origin the emblem is derived from. + * + * Since: 2.18 + */ g_object_class_install_property (gobject_class, PROP_ORIGIN, - g_param_spec_enum ("origin", - P_("GEmblem’s origin"), - P_("Tells which origin the emblem is derived from"), + g_param_spec_enum ("origin", NULL, NULL, G_TYPE_EMBLEM_ORIGIN, G_EMBLEM_ORIGIN_UNKNOWN, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GEmblem:icon: + * + * The actual icon of the emblem. + * + * Since: 2.18 + */ g_object_class_install_property (gobject_class, PROP_ICON, - g_param_spec_object ("icon", - P_("The icon of the emblem"), - P_("The actual icon of the emblem"), + g_param_spec_object ("icon", NULL, NULL, G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gemblem.h b/gio/gemblem.h index eb00c3b..3fa6b61 100644 --- a/gio/gemblem.h +++ b/gio/gemblem.h @@ -37,11 +37,6 @@ G_BEGIN_DECLS #define G_IS_EMBLEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EMBLEM)) #define G_EMBLEM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EMBLEM, GEmblemClass)) -/** - * GEmblem: - * - * An object for Emblems - */ typedef struct _GEmblem GEmblem; typedef struct _GEmblemClass GEmblemClass; diff --git a/gio/gemblemedicon.c b/gio/gemblemedicon.c index 8b72f12..9415c0b 100644 --- a/gio/gemblemedicon.c +++ b/gio/gemblemedicon.c @@ -33,17 +33,14 @@ /** - * SECTION:gemblemedicon - * @short_description: Icon with emblems - * @include: gio/gio.h - * @see_also: #GIcon, #GLoadableIcon, #GThemedIcon, #GEmblem + * GEmblemedIcon: * - * #GEmblemedIcon is an implementation of #GIcon that supports + * `GEmblemedIcon` is an implementation of [iface@Gio.Icon] that supports * adding an emblem to an icon. Adding multiple emblems to an - * icon is ensured via g_emblemed_icon_add_emblem(). + * icon is ensured via [method@Gio.EmblemedIcon.add_emblem]. * - * Note that #GEmblemedIcon allows no control over the position - * of the emblems. See also #GEmblem for more information. + * Note that `GEmblemedIcon` allows no control over the position + * of the emblems. See also [class@Gio.Emblem] for more information. **/ enum { @@ -126,10 +123,15 @@ g_emblemed_icon_class_init (GEmblemedIconClass *klass) gobject_class->set_property = g_emblemed_icon_set_property; gobject_class->get_property = g_emblemed_icon_get_property; + /** + * GEmblemedIcon:gicon: + * + * The [iface@Gio.Icon] to attach emblems to. + * + * Since: 2.18 + */ properties[PROP_GICON] = - g_param_spec_object ("gicon", - P_("The base GIcon"), - P_("The GIcon to attach emblems to"), + g_param_spec_object ("gicon", NULL, NULL, G_TYPE_ICON, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS); diff --git a/gio/gemblemedicon.h b/gio/gemblemedicon.h index 1702b7b..7145efd 100644 --- a/gio/gemblemedicon.h +++ b/gio/gemblemedicon.h @@ -40,11 +40,6 @@ G_BEGIN_DECLS #define G_IS_EMBLEMED_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_EMBLEMED_ICON)) #define G_EMBLEMED_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_EMBLEMED_ICON, GEmblemedIconClass)) -/** - * GEmblemedIcon: - * - * An implementation of #GIcon for icons with emblems. - **/ typedef struct _GEmblemedIcon GEmblemedIcon; typedef struct _GEmblemedIconClass GEmblemedIconClass; typedef struct _GEmblemedIconPrivate GEmblemedIconPrivate; diff --git a/gio/gfile.c b/gio/gfile.c index c7658ca..2ceeb3b 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -86,94 +86,99 @@ typedef off_t loff_t; /** - * SECTION:gfile - * @short_description: File and Directory Handling - * @include: gio/gio.h - * @see_also: #GFileInfo, #GFileEnumerator + * GFile: * - * #GFile is a high level abstraction for manipulating files on a - * virtual file system. #GFiles are lightweight, immutable objects + * `GFile` is a high level abstraction for manipulating files on a + * virtual file system. `GFile`s are lightweight, immutable objects * that do no I/O upon creation. It is necessary to understand that - * #GFile objects do not represent files, merely an identifier for a + * `GFile` objects do not represent files, merely an identifier for a * file. All file content I/O is implemented as streaming operations - * (see #GInputStream and #GOutputStream). - * - * To construct a #GFile, you can use: - * - g_file_new_for_path() if you have a path. - * - g_file_new_for_uri() if you have a URI. - * - g_file_new_for_commandline_arg() for a command line argument. - * - g_file_new_tmp() to create a temporary file from a template. - * - g_file_new_tmp_async() to asynchronously create a temporary file. - * - g_file_new_tmp_dir_async() to asynchronously create a temporary directory. - * - g_file_parse_name() from a UTF-8 string gotten from g_file_get_parse_name(). - * - g_file_new_build_filename() or g_file_new_build_filenamev() to create a file from path elements. - * - * One way to think of a #GFile is as an abstraction of a pathname. For + * (see [class@Gio.InputStream] and [class@Gio.OutputStream]). + * + * To construct a `GFile`, you can use: + * + * - [func@Gio.File.new_for_path] if you have a path. + * - [func@Gio.File.new_for_uri] if you have a URI. + * - [func@Gio.File.new_for_commandline_arg] or + * [func@Gio.File.new_for_commandline_arg_and_cwd] for a command line + * argument. + * - [func@Gio.File.new_tmp] to create a temporary file from a template. + * - [func@Gio.File.new_tmp_async] to asynchronously create a temporary file. + * - [func@Gio.File.new_tmp_dir_async] to asynchronously create a temporary + * directory. + * - [func@Gio.File.parse_name] from a UTF-8 string gotten from + * [method@Gio.File.get_parse_name]. + * - [func@Gio.File.new_build_filename] or [func@Gio.File.new_build_filenamev] + * to create a file from path elements. + * + * One way to think of a `GFile` is as an abstraction of a pathname. For * normal files the system pathname is what is stored internally, but as - * #GFiles are extensible it could also be something else that corresponds + * `GFile`s are extensible it could also be something else that corresponds * to a pathname in a userspace implementation of a filesystem. * - * #GFiles make up hierarchies of directories and files that correspond to + * `GFile`s make up hierarchies of directories and files that correspond to * the files on a filesystem. You can move through the file system with - * #GFile using g_file_get_parent() to get an identifier for the parent - * directory, g_file_get_child() to get a child within a directory, - * g_file_resolve_relative_path() to resolve a relative path between two - * #GFiles. There can be multiple hierarchies, so you may not end up at - * the same root if you repeatedly call g_file_get_parent() on two different - * files. - * - * All #GFiles have a basename (get with g_file_get_basename()). These names - * are byte strings that are used to identify the file on the filesystem + * `GFile` using [method@Gio.File.get_parent] to get an identifier for the + * parent directory, [method@Gio.File.get_child] to get a child within a + * directory, and [method@Gio.File.resolve_relative_path] to resolve a relative + * path between two `GFile`s. There can be multiple hierarchies, so you may not + * end up at the same root if you repeatedly call [method@Gio.File.get_parent] + * on two different files. + * + * All `GFile`s have a basename (get with [method@Gio.File.get_basename]). These + * names are byte strings that are used to identify the file on the filesystem * (relative to its parent directory) and there is no guarantees that they * have any particular charset encoding or even make any sense at all. If * you want to use filenames in a user interface you should use the display * name that you can get by requesting the - * %G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME attribute with g_file_query_info(). - * This is guaranteed to be in UTF-8 and can be used in a user interface. - * But always store the real basename or the #GFile to use to actually - * access the file, because there is no way to go from a display name to - * the actual name. + * `G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME` attribute with + * [method@Gio.File.query_info]. This is guaranteed to be in UTF-8 and can be + * used in a user interface. But always store the real basename or the `GFile` + * to use to actually access the file, because there is no way to go from a + * display name to the actual name. * - * Using #GFile as an identifier has the same weaknesses as using a path + * Using `GFile` as an identifier has the same weaknesses as using a path * in that there may be multiple aliases for the same file. For instance, - * hard or soft links may cause two different #GFiles to refer to the same + * hard or soft links may cause two different `GFile`s to refer to the same * file. Other possible causes for aliases are: case insensitive filesystems, * short and long names on FAT/NTFS, or bind mounts in Linux. If you want to - * check if two #GFiles point to the same file you can query for the - * %G_FILE_ATTRIBUTE_ID_FILE attribute. Note that #GFile does some trivial + * check if two `GFile`s point to the same file you can query for the + * `G_FILE_ATTRIBUTE_ID_FILE` attribute. Note that `GFile` does some trivial * canonicalization of pathnames passed in, so that trivial differences in * the path string used at creation (duplicated slashes, slash at end of - * path, "." or ".." path segments, etc) does not create different #GFiles. + * path, `.` or `..` path segments, etc) does not create different `GFile`s. * - * Many #GFile operations have both synchronous and asynchronous versions + * Many `GFile` operations have both synchronous and asynchronous versions * to suit your application. Asynchronous versions of synchronous functions - * simply have _async() appended to their function names. The asynchronous - * I/O functions call a #GAsyncReadyCallback which is then used to finalize - * the operation, producing a GAsyncResult which is then passed to the - * function's matching _finish() operation. + * simply have `_async()` appended to their function names. The asynchronous + * I/O functions call a [callback@Gio.AsyncReadyCallback] which is then used to + * finalize the operation, producing a [iface@Gio.AsyncResult] which is then + * passed to the function’s matching `_finish()` operation. * * It is highly recommended to use asynchronous calls when running within a * shared main loop, such as in the main thread of an application. This avoids * I/O operations blocking other sources on the main loop from being dispatched. * Synchronous I/O operations should be performed from worker threads. See the - * [introduction to asynchronous programming section][async-programming] for - * more. + * [introduction to asynchronous programming section](overview.html#asynchronous-programming) + * for more. * - * Some #GFile operations almost always take a noticeable amount of time, and + * Some `GFile` operations almost always take a noticeable amount of time, and * so do not have synchronous analogs. Notable cases include: - * - g_file_mount_mountable() to mount a mountable file. - * - g_file_unmount_mountable_with_operation() to unmount a mountable file. - * - g_file_eject_mountable_with_operation() to eject a mountable file. * - * ## Entity Tags # {#gfile-etag} + * - [method@Gio.File.mount_mountable] to mount a mountable file. + * - [method@Gio.File.unmount_mountable_with_operation] to unmount a mountable + * file. + * - [method@Gio.File.eject_mountable_with_operation] to eject a mountable file. * - * One notable feature of #GFiles are entity tags, or "etags" for + * ## Entity Tags + * + * One notable feature of `GFile`s are entity tags, or ‘etags’ for * short. Entity tags are somewhat like a more abstract version of the * traditional mtime, and can be used to quickly determine if the file * has been modified from the version on the file system. See the * HTTP 1.1 * [specification](http://www.w3.org/Protocols/rfc2616/rfc2616-sec14.html) - * for HTTP Etag headers, which are a very similar concept. + * for HTTP `ETag` headers, which are a very similar concept. */ static void g_file_real_query_info_async (GFile *file, @@ -747,14 +752,13 @@ g_file_dup (GFile *file) } /** - * g_file_hash: + * g_file_hash: (virtual hash) * @file: (type GFile): #gconstpointer to a #GFile * * Creates a hash value for a #GFile. * * This call does no blocking I/O. * - * Virtual: hash * Returns: 0 if @file is not a valid #GFile, otherwise an * integer that can be used as hash value for the #GFile. * This function is intended for easily hashing a #GFile to @@ -939,7 +943,7 @@ g_file_get_child_for_display_name (GFile *file, } /** - * g_file_has_prefix: + * g_file_has_prefix: (virtual prefix_matches) * @file: input #GFile * @prefix: input #GFile * @@ -958,7 +962,6 @@ g_file_get_child_for_display_name (GFile *file, * filesystem point of view), because the prefix of @file is an alias * of @prefix. * - * Virtual: prefix_matches * Returns: %TRUE if the @file's parent, grandparent, etc is @prefix, * %FALSE otherwise. */ @@ -1674,7 +1677,7 @@ g_file_find_enclosing_mount_finish (GFile *file, /** - * g_file_read: + * g_file_read: (virtual read_fn) * @file: #GFile to read * @cancellable: (nullable): a #GCancellable * @error: a #GError, or %NULL @@ -1691,7 +1694,6 @@ g_file_find_enclosing_mount_finish (GFile *file, * error will be returned. Other errors are possible too, and depend * on what kind of filesystem the file is on. * - * Virtual: read_fn * Returns: (transfer full): #GFileInputStream or %NULL on error. * Free the returned object with g_object_unref(). */ @@ -1836,7 +1838,7 @@ g_file_create (GFile *file, /** * g_file_replace: * @file: input #GFile - * @etag: (nullable): an optional [entity tag][gfile-etag] + * @etag: (nullable): an optional [entity tag](#entity-tags) * for the current #GFile, or #NULL to ignore * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags @@ -2041,7 +2043,7 @@ g_file_create_readwrite (GFile *file, /** * g_file_replace_readwrite: * @file: a #GFile - * @etag: (nullable): an optional [entity tag][gfile-etag] + * @etag: (nullable): an optional [entity tag](#entity-tags) * for the current #GFile, or #NULL to ignore * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags @@ -2305,7 +2307,7 @@ g_file_create_finish (GFile *file, /** * g_file_replace_async: * @file: input #GFile - * @etag: (nullable): an [entity tag][gfile-etag] for the current #GFile, + * @etag: (nullable): an [entity tag](#entity-tags) for the current #GFile, * or %NULL to ignore * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags @@ -2529,7 +2531,7 @@ g_file_create_readwrite_finish (GFile *file, /** * g_file_replace_readwrite_async: * @file: input #GFile - * @etag: (nullable): an [entity tag][gfile-etag] for the current #GFile, + * @etag: (nullable): an [entity tag](#entity-tags) for the current #GFile, * or %NULL to ignore * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags @@ -2743,10 +2745,12 @@ open_source_for_copy (GFile *source, static gboolean should_copy (GFileAttributeInfo *info, gboolean copy_all_attributes, - gboolean skip_perms) + gboolean skip_perms, + gboolean skip_modified_time) { - if (skip_perms && strcmp(info->name, "unix::mode") == 0) - return FALSE; + if ((skip_perms && strcmp(info->name, "unix::mode") == 0) || + (skip_modified_time && strncmp(info->name, "time::modified", 14) == 0)) + return FALSE; if (copy_all_attributes) return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED; @@ -2789,6 +2793,7 @@ g_file_build_attribute_list_for_copy (GFile *file, int i; gboolean copy_all_attributes; gboolean skip_perms; + gboolean skip_modified_time; g_return_val_if_fail (G_IS_FILE (file), NULL); g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); @@ -2796,6 +2801,7 @@ g_file_build_attribute_list_for_copy (GFile *file, copy_all_attributes = flags & G_FILE_COPY_ALL_METADATA; skip_perms = (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) != 0; + skip_modified_time = (flags & G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME) != 0; /* Ignore errors here, if the target supports no attributes there is * nothing to copy. We still honor the cancellable though. @@ -2823,7 +2829,7 @@ g_file_build_attribute_list_for_copy (GFile *file, { for (i = 0; i < attributes->n_infos; i++) { - if (should_copy (&attributes->infos[i], copy_all_attributes, skip_perms)) + if (should_copy (&attributes->infos[i], copy_all_attributes, skip_perms, skip_modified_time)) { if (first) first = FALSE; @@ -2839,7 +2845,7 @@ g_file_build_attribute_list_for_copy (GFile *file, { for (i = 0; i < namespaces->n_infos; i++) { - if (should_copy (&namespaces->infos[i], copy_all_attributes, FALSE)) + if (should_copy (&namespaces->infos[i], copy_all_attributes, FALSE, FALSE)) { if (first) first = FALSE; @@ -4093,7 +4099,7 @@ g_file_make_directory (GFile *file, } /** - * g_file_make_directory_async: + * g_file_make_directory_async: (virtual make_directory_async) * @file: input #GFile * @io_priority: the [I/O priority][io-priority] of the request * @cancellable: (nullable): optional #GCancellable object, @@ -4104,7 +4110,6 @@ g_file_make_directory (GFile *file, * * Asynchronously creates a directory. * - * Virtual: make_directory_async * Since: 2.38 */ void @@ -4127,7 +4132,7 @@ g_file_make_directory_async (GFile *file, } /** - * g_file_make_directory_finish: + * g_file_make_directory_finish: (virtual make_directory_finish) * @file: input #GFile * @result: a #GAsyncResult * @error: a #GError, or %NULL @@ -4135,7 +4140,6 @@ g_file_make_directory_async (GFile *file, * Finishes an asynchronous directory creation, started with * g_file_make_directory_async(). * - * Virtual: make_directory_finish * Returns: %TRUE on successful directory creation, %FALSE otherwise. * Since: 2.38 */ @@ -4367,7 +4371,7 @@ g_file_real_make_symbolic_link_async (GFile *file, } /** - * g_file_make_symbolic_link_async: + * g_file_make_symbolic_link_async: (virtual make_symbolic_link_async) * @file: a #GFile with the name of the symlink to create * @symlink_value: (type filename): a string with the path for the target * of the new symlink @@ -4381,7 +4385,6 @@ g_file_real_make_symbolic_link_async (GFile *file, * Asynchronously creates a symbolic link named @file which contains the * string @symlink_value. * - * Virtual: make_symbolic_link_async * Since: 2.74 */ void @@ -4418,7 +4421,7 @@ g_file_real_make_symbolic_link_finish (GFile *file, } /** - * g_file_make_symbolic_link_finish: + * g_file_make_symbolic_link_finish: (virtual make_symbolic_link_finish) * @file: input #GFile * @result: a #GAsyncResult * @error: a #GError, or %NULL @@ -4426,7 +4429,6 @@ g_file_real_make_symbolic_link_finish (GFile *file, * Finishes an asynchronous symbolic link creation, started with * g_file_make_symbolic_link_async(). * - * Virtual: make_symbolic_link_finish * Returns: %TRUE on successful directory creation, %FALSE otherwise. * Since: 2.74 */ @@ -4448,7 +4450,7 @@ g_file_make_symbolic_link_finish (GFile *file, } /** - * g_file_delete: + * g_file_delete: (virtual delete_file) * @file: input #GFile * @cancellable: (nullable): optional #GCancellable object, * %NULL to ignore @@ -4476,7 +4478,6 @@ g_file_make_symbolic_link_finish (GFile *file, * triggering the cancellable object from another thread. If the operation * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. * - * Virtual: delete_file * Returns: %TRUE if the file was deleted. %FALSE otherwise. */ gboolean @@ -4505,7 +4506,7 @@ g_file_delete (GFile *file, } /** - * g_file_delete_async: + * g_file_delete_async: (virtual delete_file_async) * @file: input #GFile * @io_priority: the [I/O priority][io-priority] of the request * @cancellable: (nullable): optional #GCancellable object, @@ -4518,7 +4519,6 @@ g_file_delete (GFile *file, * only be deleted if it is empty. This has the same semantics as * g_unlink(). * - * Virtual: delete_file_async * Since: 2.34 */ void @@ -4541,14 +4541,13 @@ g_file_delete_async (GFile *file, } /** - * g_file_delete_finish: + * g_file_delete_finish: (virtual delete_file_finish) * @file: input #GFile * @result: a #GAsyncResult * @error: a #GError, or %NULL * * Finishes deleting a file started with g_file_delete_async(). * - * Virtual: delete_file_finish * Returns: %TRUE if the file was deleted. %FALSE otherwise. * Since: 2.34 **/ @@ -4570,7 +4569,7 @@ g_file_delete_finish (GFile *file, } /** - * g_file_trash: + * g_file_trash: (virtual trash) * @file: #GFile to send to trash * @cancellable: (nullable): optional #GCancellable object, * %NULL to ignore @@ -4587,7 +4586,6 @@ g_file_delete_finish (GFile *file, * triggering the cancellable object from another thread. If the operation * was cancelled, the error %G_IO_ERROR_CANCELLED will be returned. * - * Virtual: trash * Returns: %TRUE on successful trash, %FALSE otherwise. */ gboolean @@ -4616,7 +4614,7 @@ g_file_trash (GFile *file, } /** - * g_file_trash_async: + * g_file_trash_async: (virtual trash_async) * @file: input #GFile * @io_priority: the [I/O priority][io-priority] of the request * @cancellable: (nullable): optional #GCancellable object, @@ -4627,7 +4625,6 @@ g_file_trash (GFile *file, * * Asynchronously sends @file to the Trash location, if possible. * - * Virtual: trash_async * Since: 2.38 */ void @@ -4650,7 +4647,7 @@ g_file_trash_async (GFile *file, } /** - * g_file_trash_finish: + * g_file_trash_finish: (virtual trash_finish) * @file: input #GFile * @result: a #GAsyncResult * @error: a #GError, or %NULL @@ -4658,7 +4655,6 @@ g_file_trash_async (GFile *file, * Finishes an asynchronous file trashing operation, started with * g_file_trash_async(). * - * Virtual: trash_finish * Returns: %TRUE on successful trash, %FALSE otherwise. * Since: 2.38 */ @@ -5794,7 +5790,7 @@ g_file_eject_mountable_with_operation_finish (GFile *file, } /** - * g_file_monitor_directory: + * g_file_monitor_directory: (virtual monitor_dir) * @file: input #GFile * @flags: a set of #GFileMonitorFlags * @cancellable: (nullable): optional #GCancellable object, @@ -5814,10 +5810,8 @@ g_file_eject_mountable_with_operation_finish (GFile *file, * directory for changes made via hard links; if you want to do this then * you must register individual watches with g_file_monitor(). * - * Virtual: monitor_dir * Returns: (transfer full): a #GFileMonitor for the given @file, - * or %NULL on error. - * Free the returned object with g_object_unref(). + * or %NULL on error. Free the returned object with g_object_unref(). */ GFileMonitor * g_file_monitor_directory (GFile *file, @@ -7727,9 +7721,9 @@ query_default_handler_query_app_info_for_type_cb (GObject *object, } else if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND)) { - g_task_return_new_error (task, - G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, - "%s", error->message); + g_task_return_new_error_literal (task, + G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, + error->message); } else { @@ -7780,10 +7774,10 @@ query_default_handler_query_info_cb (GObject *object, } else { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_NOT_SUPPORTED, - _("No application is registered as handling this file")); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("No application is registered as handling this file")); } g_object_unref (info); @@ -8320,11 +8314,11 @@ g_file_load_contents_finish (GFile *file, * @file: input #GFile * @contents: (element-type guint8) (array length=length): a string containing the new contents for @file * @length: the length of @contents in bytes - * @etag: (nullable): the old [entity-tag][gfile-etag] for the document, + * @etag: (nullable): the old [entity-tag](#entity-tags) for the document, * or %NULL * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags - * @new_etag: (out) (optional) (nullable): a location to a new [entity tag][gfile-etag] + * @new_etag: (out) (optional) (nullable): a location to a new [entity tag](#entity-tags) * for the document. This should be freed with g_free() when no longer * needed, or %NULL * @cancellable: optional #GCancellable object, %NULL to ignore @@ -8527,7 +8521,7 @@ replace_contents_open_callback (GObject *obj, * @file: input #GFile * @contents: (element-type guint8) (array length=length): string of contents to replace the file with * @length: the length of @contents in bytes - * @etag: (nullable): a new [entity tag][gfile-etag] for the @file, or %NULL + * @etag: (nullable): a new [entity tag](#entity-tags) for the @file, or %NULL * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags * @cancellable: optional #GCancellable object, %NULL to ignore @@ -8577,7 +8571,7 @@ g_file_replace_contents_async (GFile *file, * g_file_replace_contents_bytes_async: * @file: input #GFile * @contents: a #GBytes - * @etag: (nullable): a new [entity tag][gfile-etag] for the @file, or %NULL + * @etag: (nullable): a new [entity tag](#entity-tags) for the @file, or %NULL * @make_backup: %TRUE if a backup should be created * @flags: a set of #GFileCreateFlags * @cancellable: optional #GCancellable object, %NULL to ignore @@ -8632,7 +8626,7 @@ g_file_replace_contents_bytes_async (GFile *file, * g_file_replace_contents_finish: * @file: input #GFile * @res: a #GAsyncResult - * @new_etag: (out) (optional) (nullable): a location of a new [entity tag][gfile-etag] + * @new_etag: (out) (optional) (nullable): a location of a new [entity tag](#entity-tags) * for the document. This should be freed with g_free() when it is no * longer needed, or %NULL * @error: a #GError, or %NULL @@ -8831,7 +8825,7 @@ g_file_real_measure_disk_usage_finish (GFile *file, * @file: a #GFile * @flags: #GFileMeasureFlags * @cancellable: (nullable): optional #GCancellable - * @progress_callback: (nullable): a #GFileMeasureProgressCallback + * @progress_callback: (nullable) (scope call): a #GFileMeasureProgressCallback * @progress_data: user_data for @progress_callback * @disk_usage: (out) (optional): the number of bytes of disk space used * @num_dirs: (out) (optional): the number of directories encountered diff --git a/gio/gfile.h b/gio/gfile.h index 7c43fe0..b45689e 100644 --- a/gio/gfile.h +++ b/gio/gfile.h @@ -36,16 +36,6 @@ G_BEGIN_DECLS #define G_IS_FILE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_FILE)) #define G_FILE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_FILE, GFileIface)) -#if 0 -/** - * GFile: - * - * A handle to an object implementing the #GFileIface interface. - * Generally stores a location within the file system. Handles do not - * necessarily represent files or directories that currently exist. - **/ -typedef struct _GFile GFile; /* Dummy typedef */ -#endif typedef struct _GFileIface GFileIface; diff --git a/gio/gfileattribute-priv.h b/gio/gfileattribute-priv.h index de5e038..59a0ed5 100644 --- a/gio/gfileattribute-priv.h +++ b/gio/gfileattribute-priv.h @@ -29,8 +29,8 @@ #define G_FILE_ATTRIBUTE_VALUE_INIT {0} typedef struct { - GFileAttributeType type : 8; - GFileAttributeStatus status : 8; + guint type : 8; /* GFileAttributeType */ + guint status : 8; /* GFileAttributeStatus */ union { gboolean boolean; gint32 int32; diff --git a/gio/gfileattribute.c b/gio/gfileattribute.c index 124eb4d..c6fde60 100644 --- a/gio/gfileattribute.c +++ b/gio/gfileattribute.c @@ -31,113 +31,6 @@ /** - * SECTION:gfileattribute - * @short_description: Key-Value Paired File Attributes - * @include: gio/gio.h - * @see_also: #GFile, #GFileInfo - * - * File attributes in GIO consist of a list of key-value pairs. - * - * Keys are strings that contain a key namespace and a key name, separated - * by a colon, e.g. "namespace::keyname". Namespaces are included to sort - * key-value pairs by namespaces for relevance. Keys can be retrieved - * using wildcards, e.g. "standard::*" will return all of the keys in the - * "standard" namespace. - * - * The list of possible attributes for a filesystem (pointed to by a #GFile) is - * available as a #GFileAttributeInfoList. This list is queryable by key names - * as indicated earlier. - * - * Information is stored within the list in #GFileAttributeInfo structures. - * The info structure can store different types, listed in the enum - * #GFileAttributeType. Upon creation of a #GFileAttributeInfo, the type will - * be set to %G_FILE_ATTRIBUTE_TYPE_INVALID. - * - * Classes that implement #GFileIface will create a #GFileAttributeInfoList and - * install default keys and values for their given file system, architecture, - * and other possible implementation details (e.g., on a UNIX system, a file - * attribute key will be registered for the user id for a given file). - * - * ## Default Namespaces - * - * - `"standard"`: The "Standard" namespace. General file information that - * any application may need should be put in this namespace. Examples - * include the file's name, type, and size. - * - `"etag`: The [Entity Tag][gfile-etag] namespace. Currently, the only key - * in this namespace is "value", which contains the value of the current - * entity tag. - * - `"id"`: The "Identification" namespace. This namespace is used by file - * managers and applications that list directories to check for loops and - * to uniquely identify files. - * - `"access"`: The "Access" namespace. Used to check if a user has the - * proper privileges to access files and perform file operations. Keys in - * this namespace are made to be generic and easily understood, e.g. the - * "can_read" key is %TRUE if the current user has permission to read the - * file. UNIX permissions and NTFS ACLs in Windows should be mapped to - * these values. - * - `"mountable"`: The "Mountable" namespace. Includes simple boolean keys - * for checking if a file or path supports mount operations, e.g. mount, - * unmount, eject. These are used for files of type %G_FILE_TYPE_MOUNTABLE. - * - `"time"`: The "Time" namespace. Includes file access, changed, created - * times. - * - `"unix"`: The "Unix" namespace. Includes UNIX-specific information and - * may not be available for all files. Examples include the UNIX "UID", - * "GID", etc. - * - `"dos"`: The "DOS" namespace. Includes DOS-specific information and may - * not be available for all files. Examples include "is_system" for checking - * if a file is marked as a system file, and "is_archive" for checking if a - * file is marked as an archive file. - * - `"owner"`: The "Owner" namespace. Includes information about who owns a - * file. May not be available for all file systems. Examples include "user" - * for getting the user name of the file owner. This information is often - * mapped from some backend specific data such as a UNIX UID. - * - `"thumbnail"`: The "Thumbnail" namespace. Includes information about file - * thumbnails and their location within the file system. Examples of keys in - * this namespace include "path" to get the location of a thumbnail, "failed" - * to check if thumbnailing of the file failed, and "is-valid" to check if - * the thumbnail is outdated. - * - `"filesystem"`: The "Filesystem" namespace. Gets information about the - * file system where a file is located, such as its type, how much space is - * left available, and the overall size of the file system. - * - `"gvfs"`: The "GVFS" namespace. Keys in this namespace contain information - * about the current GVFS backend in use. - * - `"xattr"`: The "xattr" namespace. Gets information about extended - * user attributes. See attr(5). The "user." prefix of the extended user - * attribute name is stripped away when constructing keys in this namespace, - * e.g. "xattr::mime_type" for the extended attribute with the name - * "user.mime_type". Note that this information is only available if - * GLib has been built with extended attribute support. - * - `"xattr-sys"`: The "xattr-sys" namespace. Gets information about - * extended attributes which are not user-specific. See attr(5). Note - * that this information is only available if GLib has been built with - * extended attribute support. - * - `"selinux"`: The "SELinux" namespace. Includes information about the - * SELinux context of files. Note that this information is only available - * if GLib has been built with SELinux support. - * - * Please note that these are not all of the possible namespaces. - * More namespaces can be added from GIO modules or by individual applications. - * For more information about writing GIO modules, see #GIOModule. - * - * - * - * ## Default Keys - * - * For a list of the built-in keys and their types, see the - * [GFileInfo][GFileInfo] documentation. - * - * Note that there are no predefined keys in the "xattr" and "xattr-sys" - * namespaces. Keys for the "xattr" namespace are constructed by stripping - * away the "user." prefix from the extended user attribute, and prepending - * "xattr::". Keys for the "xattr-sys" namespace are constructed by - * concatenating "xattr-sys::" with the extended attribute name. All extended - * attribute values are returned as hex-encoded strings in which bytes outside - * the ASCII range are encoded as escape sequences of the form \x`nn` - * where `nn` is a 2-digit hexadecimal number. - */ - -/** * _g_file_attribute_value_free: * @attr: a #GFileAttributeValue. * diff --git a/gio/gfiledescriptorbased.c b/gio/gfiledescriptorbased.c index 53f55fe..5ebdf6e 100644 --- a/gio/gfiledescriptorbased.c +++ b/gio/gfiledescriptorbased.c @@ -26,20 +26,18 @@ /** - * SECTION:gfiledescriptorbased - * @short_description: Interface for file descriptor based IO - * @include: gio/gfiledescriptorbased.h - * @see_also: #GInputStream, #GOutputStream + * GFileDescriptorBased: * - * #GFileDescriptorBased is implemented by streams (implementations of - * #GInputStream or #GOutputStream) that are based on file descriptors. + * `GFileDescriptorBased` is an interface for file descriptor based IO. + * + * It is implemented by streams (implementations of [class@Gio.InputStream] or + * [class@Gio.OutputStream]) that are based on file descriptors. * * Note that `` belongs to the UNIX-specific * GIO interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config * file when using it. * * Since: 2.24 - * **/ typedef GFileDescriptorBasedIface GFileDescriptorBasedInterface; diff --git a/gio/gfiledescriptorbased.h b/gio/gfiledescriptorbased.h index 46fdbf5..a512feb 100644 --- a/gio/gfiledescriptorbased.h +++ b/gio/gfiledescriptorbased.h @@ -33,11 +33,6 @@ G_BEGIN_DECLS #define G_FILE_DESCRIPTOR_BASED_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_FILE_DESCRIPTOR_BASED, GFileDescriptorBasedIface)) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFileDescriptorBased, g_object_unref) -/** - * GFileDescriptorBased: - * - * An interface for file descriptor based io objects. - **/ typedef struct _GFileDescriptorBasedIface GFileDescriptorBasedIface; /** diff --git a/gio/gfileenumerator.c b/gio/gfileenumerator.c index ee0f563..7225379 100644 --- a/gio/gfileenumerator.c +++ b/gio/gfileenumerator.c @@ -39,23 +39,21 @@ struct _GFileEnumeratorPrivate { }; /** - * SECTION:gfileenumerator - * @short_description: Enumerated Files Routines - * @include: gio/gio.h + * GFileEnumerator: * - * #GFileEnumerator allows you to operate on a set of #GFiles, - * returning a #GFileInfo structure for each file enumerated (e.g. - * g_file_enumerate_children() will return a #GFileEnumerator for each + * `GFileEnumerator` allows you to operate on a set of [iface@Gio.File] objects, + * returning a [class@Gio.FileInfo] structure for each file enumerated (e.g. + * [method@Gio.File.enumerate_children] will return a `GFileEnumerator` for each * of the children within a directory). * - * To get the next file's information from a #GFileEnumerator, use - * g_file_enumerator_next_file() or its asynchronous version, - * g_file_enumerator_next_files_async(). Note that the asynchronous - * version will return a list of #GFileInfos, whereas the + * To get the next file's information from a `GFileEnumerator`, use + * [method@Gio.FileEnumerator.next_file] or its asynchronous version, + * [method@Gio.FileEnumerator.next_files_async]. Note that the asynchronous + * version will return a list of [class@Gio.FileInfo] objects, whereas the * synchronous will only return the next file in the enumerator. * * The ordering of returned files is unspecified for non-Unix - * platforms; for more information, see g_dir_read_name(). On Unix, + * platforms; for more information, see [method@GLib.Dir.read_name]. On Unix, * when operating on local files, returned files will be sorted by * inode number. Effectively you can assume that the ordering of * returned files will be stable between successive calls (and @@ -65,10 +63,10 @@ struct _GFileEnumeratorPrivate { * modification time, you will have to implement that in your * application code. * - * To close a #GFileEnumerator, use g_file_enumerator_close(), or - * its asynchronous version, g_file_enumerator_close_async(). Once - * a #GFileEnumerator is closed, no further actions may be performed - * on it, and it should be freed with g_object_unref(). + * To close a `GFileEnumerator`, use [method@Gio.FileEnumerator.close], or + * its asynchronous version, [method@Gio.FileEnumerator.close_async]. Once + * a `GFileEnumerator` is closed, no further actions may be performed + * on it, and it should be freed with [method@GObject.Object.unref]. * **/ @@ -159,10 +157,14 @@ g_file_enumerator_class_init (GFileEnumeratorClass *klass) klass->close_async = g_file_enumerator_real_close_async; klass->close_finish = g_file_enumerator_real_close_finish; + /** + * GFileEnumerator:container: + * + * The container that is being enumerated. + */ g_object_class_install_property (gobject_class, PROP_CONTAINER, - g_param_spec_object ("container", P_("Container"), - P_("The container that is being enumerated"), + g_param_spec_object ("container", NULL, NULL, G_TYPE_FILE, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gfileenumerator.h b/gio/gfileenumerator.h index eddb580..274d8ed 100644 --- a/gio/gfileenumerator.h +++ b/gio/gfileenumerator.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_ENUMERATOR)) #define G_FILE_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_ENUMERATOR, GFileEnumeratorClass)) -/** - * GFileEnumerator: - * - * A per matched file iterator. - **/ typedef struct _GFileEnumeratorClass GFileEnumeratorClass; typedef struct _GFileEnumeratorPrivate GFileEnumeratorPrivate; diff --git a/gio/gfileicon.c b/gio/gfileicon.c index bd727cd..d796ed4 100644 --- a/gio/gfileicon.c +++ b/gio/gfileicon.c @@ -33,15 +33,13 @@ /** - * SECTION:gfileicon - * @short_description: Icons pointing to an image file - * @include: gio/gio.h - * @see_also: #GIcon, #GLoadableIcon + * GFileIcon: * - * #GFileIcon specifies an icon by pointing to an image file + * `GFileIcon` specifies an icon by pointing to an image file * to be used as icon. * - **/ + * It implements [iface@Gio.LoadableIcon]. + */ static void g_file_icon_icon_iface_init (GIconIface *iface); static void g_file_icon_loadable_icon_iface_init (GLoadableIconIface *iface); @@ -155,9 +153,7 @@ g_file_icon_class_init (GFileIconClass *klass) * The file containing the icon. */ g_object_class_install_property (gobject_class, PROP_FILE, - g_param_spec_object ("file", - P_("file"), - P_("The file containing the icon"), + g_param_spec_object ("file", NULL, NULL, G_TYPE_FILE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); } diff --git a/gio/gfileicon.h b/gio/gfileicon.h index 230acdf..971cf0c 100644 --- a/gio/gfileicon.h +++ b/gio/gfileicon.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_ICON)) #define G_FILE_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_ICON, GFileIconClass)) -/** - * GFileIcon: - * - * Gets an icon for a #GFile. Implements #GLoadableIcon. - **/ typedef struct _GFileIconClass GFileIconClass; GIO_AVAILABLE_IN_ALL diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c index af7828e..d2bab92 100644 --- a/gio/gfileinfo.c +++ b/gio/gfileinfo.c @@ -21,45 +21,44 @@ */ /** - * SECTION:gfileinfo - * @short_description: File Information and Attributes - * @include: gio/gio.h - * @see_also: #GFile, [GFileAttribute][gio-GFileAttribute] + * GFileInfo: * - * Functionality for manipulating basic metadata for files. #GFileInfo + * Stores information about a file system object referenced by a [iface@Gio.File]. + * + * Functionality for manipulating basic metadata for files. `GFileInfo` * implements methods for getting information that all files should * contain, and allows for manipulation of extended attributes. * - * See [GFileAttribute][gio-GFileAttribute] for more information on how - * GIO handles file attributes. + * See [file-attributes.html](file attributes) for more information on how GIO + * handles file attributes. * - * To obtain a #GFileInfo for a #GFile, use g_file_query_info() (or its - * async variant). To obtain a #GFileInfo for a file input or output - * stream, use g_file_input_stream_query_info() or - * g_file_output_stream_query_info() (or their async variants). + * To obtain a `GFileInfo` for a [iface@Gio.File], use + * [method@Gio.File.query_info] (or its async variant). To obtain a `GFileInfo` + * for a file input or output stream, use [method@Gio.FileInputStream.query_info] + * or [method@Gio.FileOutputStream.query_info] (or their async variants). * * To change the actual attributes of a file, you should then set the - * attribute in the #GFileInfo and call g_file_set_attributes_from_info() - * or g_file_set_attributes_async() on a GFile. + * attribute in the `GFileInfo` and call [method@Gio.File.set_attributes_from_info] + * or [method@Gio.File.set_attributes_async] on a `GFile`. * * However, not all attributes can be changed in the file. For instance, - * the actual size of a file cannot be changed via g_file_info_set_size(). - * You may call g_file_query_settable_attributes() and - * g_file_query_writable_namespaces() to discover the settable attributes + * the actual size of a file cannot be changed via [method@Gio.FileInfo.set_size]. + * You may call [method@Gio.File.query_settable_attributes] and + * [method@Gio.File.query_writable_namespaces] to discover the settable attributes * of a particular file at runtime. * - * The direct accessors, such as g_file_info_get_name(), are slightly more + * The direct accessors, such as [method@Gio.FileInfo.get_name], are slightly more * optimized than the generic attribute accessors, such as - * g_file_info_get_attribute_byte_string().This optimization will matter + * [method@Gio.FileInfo.get_attribute_byte_string].This optimization will matter * only if calling the API in a tight loop. * * It is an error to call these accessors without specifying their required file - * attributes when creating the #GFileInfo. Use g_file_info_has_attribute() or - * g_file_info_list_attributes() to check what attributes are specified for a - * #GFileInfo. + * attributes when creating the `GFileInfo`. Use + * [method@Gio.FileInfo.has_attribute] or [method@Gio.FileInfo.list_attributes] + * to check what attributes are specified for a `GFileInfo`. * - * #GFileAttributeMatcher allows for searching through a #GFileInfo for - * attributes. + * [struct@Gio.FileAttributeMatcher] allows for searching through a `GFileInfo` + * for attributes. **/ #include "config.h" @@ -763,7 +762,7 @@ g_file_info_remove_attribute (GFileInfo *info, * * Gets the attribute type, value and status for an attribute key. * - * Returns: (transfer none): %TRUE if @info has an attribute named @attribute, + * Returns: %TRUE if @info has an attribute named @attribute, * %FALSE otherwise. */ gboolean @@ -2067,7 +2066,7 @@ g_file_info_get_symlink_target (GFileInfo *info) * g_file_info_get_etag: * @info: a #GFileInfo. * - * Gets the [entity tag][gfile-etag] for a given + * Gets the [entity tag](iface.File.html#entity-tags) for a given * #GFileInfo. See %G_FILE_ATTRIBUTE_ETAG_VALUE. * * It is an error to call this if the #GFileInfo does not contain diff --git a/gio/gfileinfo.h b/gio/gfileinfo.h index 95207b8..6e4f02d 100644 --- a/gio/gfileinfo.h +++ b/gio/gfileinfo.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_INFO_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_INFO)) #define G_FILE_INFO_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_INFO, GFileInfoClass)) -/** - * GFileInfo: - * - * Stores information about a file system object referenced by a #GFile. - **/ typedef struct _GFileInfoClass GFileInfoClass; diff --git a/gio/gfileinputstream.c b/gio/gfileinputstream.c index a78db7e..d98b7cc 100644 --- a/gio/gfileinputstream.c +++ b/gio/gfileinputstream.c @@ -33,20 +33,17 @@ /** - * SECTION:gfileinputstream - * @short_description: File input streaming operations - * @include: gio/gio.h - * @see_also: #GInputStream, #GDataInputStream, #GSeekable + * GFileInputStream: * - * GFileInputStream provides input streams that take their + * `GFileInputStream` provides input streams that take their * content from a file. * - * GFileInputStream implements #GSeekable, which allows the input + * `GFileInputStream` implements [iface@Gio.Seekable], which allows the input * stream to jump to arbitrary positions in the file, provided the * filesystem of the file allows it. To find the position of a file - * input stream, use g_seekable_tell(). To find out if a file input - * stream supports seeking, use g_seekable_can_seek(). - * To position a file input stream, use g_seekable_seek(). + * input stream, use [method@Gio.Seekable.tell]. To find out if a file input + * stream supports seeking, use [iface@Gio.Seekable.can_seek]. + * To position a file input stream, use [iface@Gio.Seekable.seek]. **/ static void g_file_input_stream_seekable_iface_init (GSeekableIface *iface); diff --git a/gio/gfileinputstream.h b/gio/gfileinputstream.h index 5462695..a122765 100644 --- a/gio/gfileinputstream.h +++ b/gio/gfileinputstream.h @@ -38,14 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_INPUT_STREAM)) #define G_FILE_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_INPUT_STREAM, GFileInputStreamClass)) -/** - * GFileInputStream: - * - * A subclass of GInputStream for opened files. This adds - * a few file-specific operations and seeking. - * - * #GFileInputStream implements #GSeekable. - **/ typedef struct _GFileInputStreamClass GFileInputStreamClass; typedef struct _GFileInputStreamPrivate GFileInputStreamPrivate; diff --git a/gio/gfileiostream.c b/gio/gfileiostream.c index ecfbf64..4a030c0 100644 --- a/gio/gfileiostream.c +++ b/gio/gfileiostream.c @@ -34,31 +34,28 @@ /** - * SECTION:gfileiostream - * @short_description: File read and write streaming operations - * @include: gio/gio.h - * @see_also: #GIOStream, #GFileInputStream, #GFileOutputStream, #GSeekable + * GFileIOStream: * - * GFileIOStream provides io streams that both read and write to the same + * `GFileIOStream` provides I/O streams that both read and write to the same * file handle. * - * GFileIOStream implements #GSeekable, which allows the io + * `GFileIOStream` implements [iface@Gio.Seekable], which allows the I/O * stream to jump to arbitrary positions in the file and to truncate * the file, provided the filesystem of the file supports these * operations. * - * To find the position of a file io stream, use - * g_seekable_tell(). + * To find the position of a file I/O stream, use [method@Gio.Seekable.tell]. * - * To find out if a file io stream supports seeking, use g_seekable_can_seek(). - * To position a file io stream, use g_seekable_seek(). - * To find out if a file io stream supports truncating, use - * g_seekable_can_truncate(). To truncate a file io - * stream, use g_seekable_truncate(). + * To find out if a file I/O stream supports seeking, use + * [method@Gio.Seekable.can_seek]. To position a file I/O stream, use + * [method@Gio.Seekable.seek]. To find out if a file I/O stream supports + * truncating, use [method@Gio.Seekable.can_truncate]. To truncate a file I/O + * stream, use [method@Gio.Seekable.truncate]. + * + * The default implementation of all the `GFileIOStream` operations + * and the implementation of [iface@Gio.Seekable] just call into the same + * operations on the output stream. * - * The default implementation of all the #GFileIOStream operations - * and the implementation of #GSeekable just call into the same operations - * on the output stream. * Since: 2.22 **/ @@ -193,7 +190,8 @@ async_ready_callback_wrapper (GObject *source_object, * g_file_io_stream_query_info_async: * @stream: a #GFileIOStream. * @attributes: a file attribute query string. - * @io_priority: the [I/O priority][gio-GIOScheduler] of the request + * @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the + * request * @cancellable: (nullable): optional #GCancellable object, %NULL to ignore. * @callback: (scope async): a #GAsyncReadyCallback * to call when the request is satisfied diff --git a/gio/gfileiostream.h b/gio/gfileiostream.h index c1c70c5..c516fb2 100644 --- a/gio/gfileiostream.h +++ b/gio/gfileiostream.h @@ -38,14 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_IO_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_IO_STREAM)) #define G_FILE_IO_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_IO_STREAM, GFileIOStreamClass)) -/** - * GFileIOStream: - * - * A subclass of GIOStream for opened files. This adds - * a few file-specific operations and seeking and truncating. - * - * #GFileIOStream implements GSeekable. - **/ typedef struct _GFileIOStreamClass GFileIOStreamClass; typedef struct _GFileIOStreamPrivate GFileIOStreamPrivate; diff --git a/gio/gfilemonitor.c b/gio/gfilemonitor.c index 89c2ff6..6e26c8d 100644 --- a/gio/gfilemonitor.c +++ b/gio/gfilemonitor.c @@ -31,23 +31,20 @@ #include "glibintl.h" /** - * SECTION:gfilemonitor - * @short_description: File Monitor - * @include: gio/gio.h + * GFileMonitor: * * Monitors a file or directory for changes. * - * To obtain a #GFileMonitor for a file or directory, use - * g_file_monitor(), g_file_monitor_file(), or - * g_file_monitor_directory(). + * To obtain a `GFileMonitor` for a file or directory, use + * [method@Gio.File.monitor], [method@Gio.File.monitor_file], or + * [method@Gio.File.monitor_directory]. * * To get informed about changes to the file or directory you are - * monitoring, connect to the #GFileMonitor::changed signal. The - * signal will be emitted in the - * [thread-default main context][g-main-context-push-thread-default] - * of the thread that the monitor was created in - * (though if the global default main context is blocked, this may - * cause notifications to be blocked even if the thread-default + * monitoring, connect to the [signal@Gio.FileMonitor::changed] signal. The + * signal will be emitted in the thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) of the thread that the monitor + * was created in (though if the global default main context is blocked, this + * may cause notifications to be blocked even if the thread-default * context is still running). **/ @@ -191,17 +188,23 @@ g_file_monitor_class_init (GFileMonitorClass *klass) G_TYPE_FROM_CLASS (klass), _g_cclosure_marshal_VOID__OBJECT_OBJECT_ENUMv); + /** + * GFileMonitor:rate-limit: + * + * The limit of the monitor to watch for changes, in milliseconds. + */ g_object_class_install_property (object_class, PROP_RATE_LIMIT, - g_param_spec_int ("rate-limit", - P_("Rate limit"), - P_("The limit of the monitor to watch for changes, in milliseconds"), + g_param_spec_int ("rate-limit", NULL, NULL, 0, G_MAXINT, DEFAULT_RATE_LIMIT_MSECS, G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); + /** + * GFileMonitor:cancelled: + * + * Whether the monitor has been cancelled. + */ g_object_class_install_property (object_class, PROP_CANCELLED, - g_param_spec_boolean ("cancelled", - P_("Cancelled"), - P_("Whether the monitor has been cancelled"), + g_param_spec_boolean ("cancelled", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gfilemonitor.h b/gio/gfilemonitor.h index b677efc..63ab1e0 100644 --- a/gio/gfilemonitor.h +++ b/gio/gfilemonitor.h @@ -41,11 +41,6 @@ G_BEGIN_DECLS typedef struct _GFileMonitorClass GFileMonitorClass; typedef struct _GFileMonitorPrivate GFileMonitorPrivate; -/** - * GFileMonitor: - * - * Watches for changes to a file. - **/ struct _GFileMonitor { GObject parent_instance; diff --git a/gio/gfilenamecompleter.c b/gio/gfilenamecompleter.c index 4665be3..aca4249 100644 --- a/gio/gfilenamecompleter.c +++ b/gio/gfilenamecompleter.c @@ -32,15 +32,12 @@ /** - * SECTION:gfilenamecompleter - * @short_description: Filename Completer - * @include: gio/gio.h + * GFilenameCompleter: * * Completes partial file and directory names given a partial string by * looking in the file system for clues. Can return a list of possible * completion strings for widget implementations. - * - **/ + */ enum { GOT_COMPLETION_DATA, diff --git a/gio/gfilenamecompleter.h b/gio/gfilenamecompleter.h index b105e49..d835af8 100644 --- a/gio/gfilenamecompleter.h +++ b/gio/gfilenamecompleter.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILENAME_COMPLETER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_FILENAME_COMPLETER)) #define G_IS_FILENAME_COMPLETER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILENAME_COMPLETER)) -/** - * GFilenameCompleter: - * - * Completes filenames based on files that exist within the file system. - **/ typedef struct _GFilenameCompleterClass GFilenameCompleterClass; struct _GFilenameCompleterClass diff --git a/gio/gfileoutputstream.c b/gio/gfileoutputstream.c index d767c53..786d037 100644 --- a/gio/gfileoutputstream.c +++ b/gio/gfileoutputstream.c @@ -33,25 +33,22 @@ /** - * SECTION:gfileoutputstream - * @short_description: File output streaming operations - * @include: gio/gio.h - * @see_also: #GOutputStream, #GDataOutputStream, #GSeekable + * GFileOutputStream: * - * GFileOutputStream provides output streams that write their + * `GFileOutputStream` provides output streams that write their * content to a file. * - * GFileOutputStream implements #GSeekable, which allows the output + * `GFileOutputStream` implements [iface@Gio.Seekable], which allows the output * stream to jump to arbitrary positions in the file and to truncate * the file, provided the filesystem of the file supports these * operations. * - * To find the position of a file output stream, use g_seekable_tell(). + * To find the position of a file output stream, use [method@Gio.Seekable.tell]. * To find out if a file output stream supports seeking, use - * g_seekable_can_seek().To position a file output stream, use - * g_seekable_seek(). To find out if a file output stream supports - * truncating, use g_seekable_can_truncate(). To truncate a file output - * stream, use g_seekable_truncate(). + * [method@Gio.Seekable.can_seek].To position a file output stream, use + * [method@Gio.Seekable.seek]. To find out if a file output stream supports + * truncating, use [method@Gio.Seekable.can_truncate]. To truncate a file output + * stream, use [method@Gio.Seekable.truncate]. **/ static void g_file_output_stream_seekable_iface_init (GSeekableIface *iface); @@ -190,7 +187,8 @@ async_ready_callback_wrapper (GObject *source_object, * g_file_output_stream_query_info_async: * @stream: a #GFileOutputStream. * @attributes: a file attribute query string. - * @io_priority: the [I/O priority][gio-GIOScheduler] of the request + * @io_priority: the [I/O priority](iface.AsyncResult.html#io-priority) of the + * request * @cancellable: optional #GCancellable object, %NULL to ignore. * @callback: callback to call when the request is satisfied * @user_data: the data to pass to callback function diff --git a/gio/gfileoutputstream.h b/gio/gfileoutputstream.h index 576b21f..edc9b10 100644 --- a/gio/gfileoutputstream.h +++ b/gio/gfileoutputstream.h @@ -38,14 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILE_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILE_OUTPUT_STREAM)) #define G_FILE_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILE_OUTPUT_STREAM, GFileOutputStreamClass)) -/** - * GFileOutputStream: - * - * A subclass of GOutputStream for opened files. This adds - * a few file-specific operations and seeking and truncating. - * - * #GFileOutputStream implements GSeekable. - **/ typedef struct _GFileOutputStreamClass GFileOutputStreamClass; typedef struct _GFileOutputStreamPrivate GFileOutputStreamPrivate; diff --git a/gio/gfilterinputstream.c b/gio/gfilterinputstream.c index 46cb0ef..04ec541 100644 --- a/gio/gfilterinputstream.c +++ b/gio/gfilterinputstream.c @@ -27,9 +27,7 @@ /** - * SECTION:gfilterinputstream - * @short_description: Filter Input Stream - * @include: gio/gio.h + * GFilterInputStream: * * Base class for input stream implementations that perform some * kind of filtering operation on a base stream. Typical examples @@ -91,20 +89,26 @@ g_filter_input_stream_class_init (GFilterInputStreamClass *klass) istream_class->skip = g_filter_input_stream_skip; istream_class->close_fn = g_filter_input_stream_close; + /** + * GFilterInputStream:base-stream: + * + * The underlying base stream on which the I/O ops will be done. + */ g_object_class_install_property (object_class, PROP_BASE_STREAM, - g_param_spec_object ("base-stream", - P_("The Filter Base Stream"), - P_("The underlying base stream on which the io ops will be done."), + g_param_spec_object ("base-stream", NULL, NULL, G_TYPE_INPUT_STREAM, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + /** + * GFilterInputStream:close-base-stream: + * + * Whether the base stream should be closed when the filter stream is closed. + */ g_object_class_install_property (object_class, PROP_CLOSE_BASE, - g_param_spec_boolean ("close-base-stream", - P_("Close Base Stream"), - P_("If the base stream should be closed when the filter stream is closed."), + g_param_spec_boolean ("close-base-stream", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); } diff --git a/gio/gfilterinputstream.h b/gio/gfilterinputstream.h index df6032c..6009eea 100644 --- a/gio/gfilterinputstream.h +++ b/gio/gfilterinputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILTER_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILTER_INPUT_STREAM)) #define G_FILTER_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILTER_INPUT_STREAM, GFilterInputStreamClass)) -/** - * GFilterInputStream: - * - * A base class for all input streams that work on an underlying stream. - **/ typedef struct _GFilterInputStreamClass GFilterInputStreamClass; struct _GFilterInputStream diff --git a/gio/gfilteroutputstream.c b/gio/gfilteroutputstream.c index 637f448..074b8ce 100644 --- a/gio/gfilteroutputstream.c +++ b/gio/gfilteroutputstream.c @@ -27,9 +27,7 @@ /** - * SECTION:gfilteroutputstream - * @short_description: Filter Output Stream - * @include: gio/gio.h + * GFilterOutputStream: * * Base class for output stream implementations that perform some * kind of filtering operation on a base stream. Typical examples @@ -90,20 +88,26 @@ g_filter_output_stream_class_init (GFilterOutputStreamClass *klass) ostream_class->flush = g_filter_output_stream_flush; ostream_class->close_fn = g_filter_output_stream_close; + /** + * GFilterOutputStream:close-base-stream: + * + * The underlying base stream on which the I/O ops will be done. + */ g_object_class_install_property (object_class, PROP_BASE_STREAM, - g_param_spec_object ("base-stream", - P_("The Filter Base Stream"), - P_("The underlying base stream on which the io ops will be done."), + g_param_spec_object ("base-stream", NULL, NULL, G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); + /** + * GFilterOutputStream:close-base-stream: + * + * Whether the base stream should be closed when the filter stream is closed. + */ g_object_class_install_property (object_class, PROP_CLOSE_BASE, - g_param_spec_boolean ("close-base-stream", - P_("Close Base Stream"), - P_("If the base stream should be closed when the filter stream is closed."), + g_param_spec_boolean ("close-base-stream", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); } diff --git a/gio/gfilteroutputstream.h b/gio/gfilteroutputstream.h index 472f9d8..160e80d 100644 --- a/gio/gfilteroutputstream.h +++ b/gio/gfilteroutputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_FILTER_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_FILTER_OUTPUT_STREAM)) #define G_FILTER_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_FILTER_OUTPUT_STREAM, GFilterOutputStreamClass)) -/** - * GFilterOutputStream: - * - * A base class for all output streams that work on an underlying stream. - **/ typedef struct _GFilterOutputStreamClass GFilterOutputStreamClass; struct _GFilterOutputStream diff --git a/gio/gicon.c b/gio/gicon.c index cd69922..4031a7b 100644 --- a/gio/gicon.c +++ b/gio/gicon.c @@ -41,38 +41,37 @@ #define G_ICON_SERIALIZATION_MAGIC0 ". " /** - * SECTION:gicon - * @short_description: Interface for icons - * @include: gio/gio.h + * GIcon: * - * #GIcon is a very minimal interface for icons. It provides functions + * `GIcon` is a very minimal interface for icons. It provides functions * for checking the equality of two icons, hashing of icons and * serializing an icon to and from strings. * - * #GIcon does not provide the actual pixmap for the icon as this is out - * of GIO's scope, however implementations of #GIcon may contain the name - * of an icon (see #GThemedIcon), or the path to an icon (see #GLoadableIcon). + * `GIcon` does not provide the actual pixmap for the icon as this is out + * of GIO's scope, however implementations of `GIcon` may contain the name + * of an icon (see [class@Gio.ThemedIcon]), or the path to an icon + * (see [iface@Gio.LoadableIcon]). * - * To obtain a hash of a #GIcon, see g_icon_hash(). + * To obtain a hash of a `GIcon`, see [method@Gio.Icon.hash]. * - * To check if two #GIcons are equal, see g_icon_equal(). + * To check if two `GIcon`s are equal, see [method@Gio.Icon.equal]. * - * For serializing a #GIcon, use g_icon_serialize() and - * g_icon_deserialize(). + * For serializing a `GIcon`, use [method@Gio.Icon.serialize] and + * [func@Gio.Icon.deserialize]. * - * If you want to consume #GIcon (for example, in a toolkit) you must + * If you want to consume `GIcon` (for example, in a toolkit) you must * be prepared to handle at least the three following cases: - * #GLoadableIcon, #GThemedIcon and #GEmblemedIcon. It may also make - * sense to have fast-paths for other cases (like handling #GdkPixbuf - * directly, for example) but all compliant #GIcon implementations - * outside of GIO must implement #GLoadableIcon. + * [iface@Gio.LoadableIcon], [class@Gio.ThemedIcon] and [class@Gio.EmblemedIcon]. + * It may also make sense to have fast-paths for other cases (like handling + * [class@GdkPixbuf.Pixbuf] directly, for example) but all compliant `GIcon` + * implementations outside of GIO must implement [iface@Gio.LoadableIcon]. * - * If your application or library provides one or more #GIcon + * If your application or library provides one or more `GIcon` * implementations you need to ensure that your new implementation also - * implements #GLoadableIcon. Additionally, you must provide an - * implementation of g_icon_serialize() that gives a result that is - * understood by g_icon_deserialize(), yielding one of the built-in icon - * types. + * implements [iface@Gio.LoadableIcon]. Additionally, you must provide an + * implementation of [method@Gio.Icon.serialize] that gives a result that is + * understood by [func@Gio.Icon.deserialize], yielding one of the built-in + * icon types. **/ typedef GIconIface GIconInterface; @@ -84,14 +83,13 @@ g_icon_default_init (GIconInterface *iface) } /** - * g_icon_hash: + * g_icon_hash: (virtual hash) * @icon: (not nullable) (type Gio.Icon): #gconstpointer to an icon object. * * Gets a hash for an icon. * - * Virtual: hash * Returns: a #guint containing a hash for the @icon, suitable for - * use in a #GHashTable or similar data structure. + * use in a #GHashTable or similar data structure. **/ guint g_icon_hash (gconstpointer icon) diff --git a/gio/gicon.h b/gio/gicon.h index c971cb0..d6dd5fe 100644 --- a/gio/gicon.h +++ b/gio/gicon.h @@ -36,11 +36,6 @@ G_BEGIN_DECLS #define G_IS_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_ICON)) #define G_ICON_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_ICON, GIconIface)) -/** - * GIcon: - * - * An abstract type that specifies an icon. - **/ typedef struct _GIconIface GIconIface; /** diff --git a/gio/ginetaddress.c b/gio/ginetaddress.c index 66d8897..c0ba250 100644 --- a/gio/ginetaddress.c +++ b/gio/ginetaddress.c @@ -45,28 +45,20 @@ struct _GInetAddressPrivate }; /** - * SECTION:ginetaddress - * @short_description: An IPv4/IPv6 address - * @include: gio/gio.h + * GInetAddress: * - * #GInetAddress represents an IPv4 or IPv6 internet address. Use - * g_resolver_lookup_by_name() or g_resolver_lookup_by_name_async() to - * look up the #GInetAddress for a hostname. Use - * g_resolver_lookup_by_address() or - * g_resolver_lookup_by_address_async() to look up the hostname for a - * #GInetAddress. + * `GInetAddress` represents an IPv4 or IPv6 internet address. Use + * [method@Gio.Resolver.lookup_by_name] or + * [method@Gio.Resolver.lookup_by_name_async] to look up the `GInetAddress` for + * a hostname. Use [method@Gio.Resolver.lookup_by_address] or + * [method@Gio.Resolver.lookup_by_address_async] to look up the hostname for a + * `GInetAddress`. * * To actually connect to a remote host, you will need a - * #GInetSocketAddress (which includes a #GInetAddress as well as a + * [class@Gio.InetSocketAddress] (which includes a `GInetAddress` as well as a * port number). */ -/** - * GInetAddress: - * - * An IPv4 or IPv6 internet address. - */ - G_DEFINE_TYPE_WITH_CODE (GInetAddress, g_inet_address, G_TYPE_OBJECT, G_ADD_PRIVATE (GInetAddress) g_networking_init ();) @@ -193,20 +185,30 @@ g_inet_address_class_init (GInetAddressClass *klass) gobject_class->set_property = g_inet_address_set_property; gobject_class->get_property = g_inet_address_get_property; + /** + * GInetAddress:family: + * + * The address family (IPv4 or IPv6). + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_FAMILY, - g_param_spec_enum ("family", - P_("Address family"), - P_("The address family (IPv4 or IPv6)"), + g_param_spec_enum ("family", NULL, NULL, G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GInetAddress:bytes: + * + * The raw address data. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_BYTES, - g_param_spec_pointer ("bytes", - P_("Bytes"), - P_("The raw address data"), + g_param_spec_pointer ("bytes", NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -220,9 +222,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_ANY, - g_param_spec_boolean ("is-any", - P_("Is any"), - P_("Whether this is the \"any\" address for its family"), + g_param_spec_boolean ("is-any", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -236,9 +236,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_LINK_LOCAL, - g_param_spec_boolean ("is-link-local", - P_("Is link-local"), - P_("Whether this is a link-local address"), + g_param_spec_boolean ("is-link-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -252,9 +250,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_LOOPBACK, - g_param_spec_boolean ("is-loopback", - P_("Is loopback"), - P_("Whether this is the loopback address for its family"), + g_param_spec_boolean ("is-loopback", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -268,9 +264,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_SITE_LOCAL, - g_param_spec_boolean ("is-site-local", - P_("Is site-local"), - P_("Whether this is a site-local address"), + g_param_spec_boolean ("is-site-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -284,9 +278,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MULTICAST, - g_param_spec_boolean ("is-multicast", - P_("Is multicast"), - P_("Whether this is a multicast address"), + g_param_spec_boolean ("is-multicast", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -300,9 +292,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MC_GLOBAL, - g_param_spec_boolean ("is-mc-global", - P_("Is multicast global"), - P_("Whether this is a global multicast address"), + g_param_spec_boolean ("is-mc-global", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -317,9 +307,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MC_LINK_LOCAL, - g_param_spec_boolean ("is-mc-link-local", - P_("Is multicast link-local"), - P_("Whether this is a link-local multicast address"), + g_param_spec_boolean ("is-mc-link-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -333,9 +321,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MC_NODE_LOCAL, - g_param_spec_boolean ("is-mc-node-local", - P_("Is multicast node-local"), - P_("Whether this is a node-local multicast address"), + g_param_spec_boolean ("is-mc-node-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -349,9 +335,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MC_ORG_LOCAL, - g_param_spec_boolean ("is-mc-org-local", - P_("Is multicast org-local"), - P_("Whether this is an organization-local multicast address"), + g_param_spec_boolean ("is-mc-org-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -365,9 +349,7 @@ g_inet_address_class_init (GInetAddressClass *klass) * Since: 2.22 */ g_object_class_install_property (gobject_class, PROP_IS_MC_SITE_LOCAL, - g_param_spec_boolean ("is-mc-site-local", - P_("Is multicast site-local"), - P_("Whether this is a site-local multicast address"), + g_param_spec_boolean ("is-mc-site-local", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/ginetaddressmask.c b/gio/ginetaddressmask.c index c0704db..1431b94 100644 --- a/gio/ginetaddressmask.c +++ b/gio/ginetaddressmask.c @@ -31,21 +31,12 @@ #include "glibintl.h" /** - * SECTION:ginetaddressmask - * @short_description: An IPv4/IPv6 address mask - * @include: gio/gio.h + * GInetAddressMask: * - * #GInetAddressMask represents a range of IPv4 or IPv6 addresses + * `GInetAddressMask` represents a range of IPv4 or IPv6 addresses * described by a base address and a length indicating how many bits * of the base address are relevant for matching purposes. These are - * often given in string form. Eg, "10.0.0.0/8", or "fe80::/10". - */ - -/** - * GInetAddressMask: - * - * A combination of an IPv4 or IPv6 base address and a length, - * representing a range of IP addresses. + * often given in string form. For example, `10.0.0.0/8`, or `fe80::/10`. * * Since: 2.32 */ @@ -144,25 +135,42 @@ g_inet_address_mask_class_init (GInetAddressMaskClass *klass) gobject_class->get_property = g_inet_address_mask_get_property; gobject_class->dispose = g_inet_address_mask_dispose; + /** + * GInetAddressMask:family: + * + * The address family (IPv4 or IPv6). + * + * Since: 2.32 + */ g_object_class_install_property (gobject_class, PROP_FAMILY, - g_param_spec_enum ("family", - P_("Address family"), - P_("The address family (IPv4 or IPv6)"), + g_param_spec_enum ("family", NULL, NULL, G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GInetAddressMask:address: + * + * The base address. + * + * Since: 2.32 + */ g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_object ("address", - P_("Address"), - P_("The base address"), + g_param_spec_object ("address", NULL, NULL, G_TYPE_INET_ADDRESS, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /** + * GInetAddressMask:length: + * + * The prefix length, in bytes. + * + * Since: 2.32 + */ g_object_class_install_property (gobject_class, PROP_LENGTH, - g_param_spec_uint ("length", - P_("Length"), - P_("The prefix length"), + g_param_spec_uint ("length", NULL, NULL, 0, 128, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/ginetsocketaddress.c b/gio/ginetsocketaddress.c index 7693035..c17bd14 100644 --- a/gio/ginetsocketaddress.c +++ b/gio/ginetsocketaddress.c @@ -34,19 +34,13 @@ /** - * SECTION:ginetsocketaddress - * @short_description: Internet GSocketAddress - * @include: gio/gio.h - * - * An IPv4 or IPv6 socket address; that is, the combination of a - * #GInetAddress and a port number. - */ - -/** * GInetSocketAddress: * - * An IPv4 or IPv6 socket address, corresponding to a struct - * sockaddr_in or struct sockaddr_in6. + * An IPv4 or IPv6 socket address. That is, the combination of a + * [class@Gio.InetAddress] and a port number. + * + * In UNIX terms, `GInetSocketAddress` corresponds to a + * [`struct sockaddr_in` or `struct sockaddr_in6`](man:sockaddr(3type)). */ struct _GInetSocketAddressPrivate @@ -253,19 +247,29 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass) gsocketaddress_class->to_native = g_inet_socket_address_to_native; gsocketaddress_class->get_native_size = g_inet_socket_address_get_native_size; + /** + * GInetSocketAddress:address: + * + * The address. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_ADDRESS, - g_param_spec_object ("address", - P_("Address"), - P_("The address"), + g_param_spec_object ("address", NULL, NULL, G_TYPE_INET_ADDRESS, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GInetSocketAddress:port: + * + * The port. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PORT, - g_param_spec_uint ("port", - P_("Port"), - P_("The port"), + g_param_spec_uint ("port", NULL, NULL, 0, 65535, 0, @@ -281,9 +285,7 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass) * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_FLOWINFO, - g_param_spec_uint ("flowinfo", - P_("Flow info"), - P_("IPv6 flow info"), + g_param_spec_uint ("flowinfo", NULL, NULL, 0, G_MAXUINT32, 0, @@ -292,16 +294,14 @@ g_inet_socket_address_class_init (GInetSocketAddressClass *klass) G_PARAM_STATIC_STRINGS)); /** - * GInetSocketAddress:scope_id: + * GInetSocketAddress:scope-id: * * The `sin6_scope_id` field, for IPv6 addresses. * * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_SCOPE_ID, - g_param_spec_uint ("scope-id", - P_("Scope ID"), - P_("IPv6 scope ID"), + g_param_spec_uint ("scope-id", NULL, NULL, 0, G_MAXUINT32, 0, @@ -421,13 +421,13 @@ g_inet_socket_address_new_from_string (const char *address, * it will handle parsing a scope_id as well. */ - if (G_UNLIKELY (g_once_init_enter (&hints))) + if (G_UNLIKELY (g_once_init_enter_pointer (&hints))) { hints_struct.ai_family = AF_UNSPEC; hints_struct.ai_socktype = SOCK_STREAM; hints_struct.ai_protocol = 0; hints_struct.ai_flags = AI_NUMERICHOST; - g_once_init_leave (&hints, &hints_struct); + g_once_init_leave_pointer (&hints, &hints_struct); } status = getaddrinfo (address, NULL, hints, &res); diff --git a/gio/ginitable.c b/gio/ginitable.c index ef836e4..6dd09a9 100644 --- a/gio/ginitable.c +++ b/gio/ginitable.c @@ -26,35 +26,34 @@ /** - * SECTION:ginitable - * @short_description: Failable object initialization interface - * @include: gio/gio.h - * @see_also: #GAsyncInitable + * GInitable: * - * #GInitable is implemented by objects that can fail during + * `GInitable` is implemented by objects that can fail during * initialization. If an object implements this interface then * it must be initialized as the first thing after construction, - * either via g_initable_init() or g_async_initable_init_async() - * (the latter is only available if it also implements #GAsyncInitable). + * either via [method@Gio.Initable.init] or [method@Gio.AsyncInitable.init_async] + * (the latter is only available if it also implements [iface@Gio.AsyncInitable]). * * If the object is not initialized, or initialization returns with an - * error, then all operations on the object except g_object_ref() and - * g_object_unref() are considered to be invalid, and have undefined - * behaviour. They will often fail with g_critical() or g_warning(), but - * this must not be relied on. + * error, then all operations on the object except `g_object_ref()` and + * `g_object_unref()` are considered to be invalid, and have undefined + * behaviour. They will often fail with [func@GLib.critical] or + * [func@GLib.warning], but this must not be relied on. * * Users of objects implementing this are not intended to use * the interface method directly, instead it will be used automatically * in various ways. For C applications you generally just call - * g_initable_new() directly, or indirectly via a foo_thing_new() wrapper. - * This will call g_initable_init() under the cover, returning %NULL and - * setting a #GError on failure (at which point the instance is + * [func@Gio.Initable.new] directly, or indirectly via a `foo_thing_new()` wrapper. + * This will call [method@Gio.Initable.init] under the cover, returning `NULL` + * and setting a `GError` on failure (at which point the instance is * unreferenced). * * For bindings in languages where the native constructor supports - * exceptions the binding could check for objects implementing %GInitable + * exceptions the binding could check for objects implementing `GInitable` * during normal construction and automatically initialize them, throwing * an exception on failure. + * + * Since: 2.22 */ typedef GInitableIface GInitableInterface; diff --git a/gio/ginitable.h b/gio/ginitable.h index 9eb995c..5eee369 100644 --- a/gio/ginitable.h +++ b/gio/ginitable.h @@ -37,13 +37,6 @@ G_BEGIN_DECLS #define G_INITABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_INITABLE, GInitableIface)) #define G_TYPE_IS_INITABLE(type) (g_type_is_a ((type), G_TYPE_INITABLE)) -/** - * GInitable: - * - * Interface for initializable objects. - * - * Since: 2.22 - **/ typedef struct _GInitableIface GInitableIface; /** diff --git a/gio/ginputstream.c b/gio/ginputstream.c index e1da5fa..1f27bcf 100644 --- a/gio/ginputstream.c +++ b/gio/ginputstream.c @@ -33,19 +33,19 @@ #include "gpollableinputstream.h" /** - * SECTION:ginputstream - * @short_description: Base class for implementing streaming input - * @include: gio/gio.h + * GInputStream: * - * #GInputStream has functions to read from a stream (g_input_stream_read()), - * to close a stream (g_input_stream_close()) and to skip some content - * (g_input_stream_skip()). + * `GInputStream` is a base class for implementing streaming input. + * + * It has functions to read from a stream ([method@Gio.InputStream.read]), + * to close a stream ([method@Gio.InputStream.close]) and to skip some content + * ([method@Gio.InputStream.skip]). * * To copy the content of an input stream to an output stream without - * manually handling the reads and writes, use g_output_stream_splice(). + * manually handling the reads and writes, use [method@Gio.OutputStream.splice]. * - * See the documentation for #GIOStream for details of thread safety of - * streaming APIs. + * See the documentation for [class@Gio.IOStream] for details of thread safety + * of streaming APIs. * * All of these functions have async variants too. **/ diff --git a/gio/ginputstream.h b/gio/ginputstream.h index a7be768..f5cce17 100644 --- a/gio/ginputstream.h +++ b/gio/ginputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_INPUT_STREAM)) #define G_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_INPUT_STREAM, GInputStreamClass)) -/** - * GInputStream: - * - * Base class for streaming input operations. - **/ typedef struct _GInputStreamClass GInputStreamClass; typedef struct _GInputStreamPrivate GInputStreamPrivate; diff --git a/gio/gio-autocleanups.h b/gio/gio-autocleanups.h index 15e37d1..315288e 100644 --- a/gio/gio-autocleanups.h +++ b/gio/gio-autocleanups.h @@ -23,6 +23,8 @@ #error "Only can be included directly." #endif +#ifndef __GI_SCANNER__ + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAction, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GActionMap, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GAppInfo, g_object_unref) @@ -153,3 +155,5 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVolume, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GVolumeMonitor, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibCompressor, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GZlibDecompressor, g_object_unref) + +#endif /* __GI_SCANNER__ */ diff --git a/gio/gio-tool-copy.c b/gio/gio-tool-copy.c index 4a1dc43..1b7ab48 100644 --- a/gio/gio-tool-copy.c +++ b/gio/gio-tool-copy.c @@ -40,6 +40,7 @@ static gboolean preserve = FALSE; static gboolean backup = FALSE; static gboolean no_dereference = FALSE; static gboolean default_permissions = FALSE; +static gboolean default_modified_time = FALSE; static const GOptionEntry entries[] = { { "no-target-directory", 'T', 0, G_OPTION_ARG_NONE, &no_target_directory, N_("No target directory"), NULL }, @@ -49,6 +50,7 @@ static const GOptionEntry entries[] = { { "backup", 'b', 0, G_OPTION_ARG_NONE, &backup, N_("Backup existing destination files"), NULL }, { "no-dereference", 'P', 0, G_OPTION_ARG_NONE, &no_dereference, N_("Never follow symbolic links"), NULL }, { "default-permissions", 0, 0, G_OPTION_ARG_NONE, &default_permissions, N_("Use default permissions for the destination"), NULL }, + { "default-modified-time", 0, 0, G_OPTION_ARG_NONE, &default_modified_time, N_("Use default file modification timestamps for the destination"), NULL }, G_OPTION_ENTRY_NULL }; @@ -181,6 +183,8 @@ handle_copy (int argc, char *argv[], gboolean do_help) flags |= G_FILE_COPY_ALL_METADATA; if (default_permissions) flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS; + if (default_modified_time) + flags |= G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME; error = NULL; start_time = g_get_monotonic_time (); diff --git a/gio/gio-tool-info.c b/gio/gio-tool-info.c index dbdc6b6..a773d8d 100644 --- a/gio/gio-tool-info.c +++ b/gio/gio-tool-info.c @@ -177,7 +177,8 @@ show_info (GFile *file, GFileInfo *info) g_free (flatten); } - name = g_file_info_get_name (info); + name = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_NAME) ? + g_file_info_get_name (info) : NULL; if (name) { escaped = escape_string (name); diff --git a/gio/gio-tool.c b/gio/gio-tool.c index a970109..6315b48 100644 --- a/gio/gio-tool.c +++ b/gio/gio-tool.c @@ -219,35 +219,67 @@ handle_version (int argc, char *argv[], gboolean do_help) return 0; } +typedef int (*HandleSubcommand) (int argc, char *argv[], gboolean do_help); + +static const struct +{ + const char *name; /* as used on the command line */ + HandleSubcommand handle_func; /* (nullable) for "help" only */ + const char *description; /* translatable */ +} gio_subcommands[] = { + { "help", NULL, N_("Print help") }, + { "version", handle_version, N_("Print version") }, + { "cat", handle_cat, N_("Concatenate files to standard output") }, + { "copy", handle_copy, N_("Copy one or more files") }, + { "info", handle_info, N_("Show information about locations") }, + { "launch", handle_launch, N_("Launch an application from a desktop file") }, + { "list", handle_list, N_("List the contents of locations") }, + { "mime", handle_mime, N_("Get or set the handler for a mimetype") }, + { "mkdir", handle_mkdir, N_("Create directories") }, + { "monitor", handle_monitor, N_("Monitor files and directories for changes") }, + { "mount", handle_mount, N_("Mount or unmount the locations") }, + { "move", handle_move, N_("Move one or more files") }, + { "open", handle_open, N_("Open files with the default application") }, + { "rename", handle_rename, N_("Rename a file") }, + { "remove", handle_remove, N_("Delete one or more files") }, + { "save", handle_save, N_("Read from standard input and save") }, + { "set", handle_set, N_("Set a file attribute") }, + { "trash", handle_trash, N_("Move files or directories to the trash") }, + { "tree", handle_tree, N_("Lists the contents of locations in a tree") }, +}; + static void -usage (void) +usage (gboolean is_error) { - g_printerr ("%s\n", _("Usage:")); - g_printerr (" gio %s %s\n", _("COMMAND"), _("[ARGS…]")); - g_printerr ("\n"); - g_printerr ("%s\n", _("Commands:")); - g_printerr (" help %s\n", _("Print help")); - g_printerr (" version %s\n", _("Print version")); - g_printerr (" cat %s\n", _("Concatenate files to standard output")); - g_printerr (" copy %s\n", _("Copy one or more files")); - g_printerr (" info %s\n", _("Show information about locations")); - g_printerr (" launch %s\n", _("Launch an application from a desktop file")); - g_printerr (" list %s\n", _("List the contents of locations")); - g_printerr (" mime %s\n", _("Get or set the handler for a mimetype")); - g_printerr (" mkdir %s\n", _("Create directories")); - g_printerr (" monitor %s\n", _("Monitor files and directories for changes")); - g_printerr (" mount %s\n", _("Mount or unmount the locations")); - g_printerr (" move %s\n", _("Move one or more files")); - g_printerr (" open %s\n", _("Open files with the default application")); - g_printerr (" rename %s\n", _("Rename a file")); - g_printerr (" remove %s\n", _("Delete one or more files")); - g_printerr (" save %s\n", _("Read from standard input and save")); - g_printerr (" set %s\n", _("Set a file attribute")); - g_printerr (" trash %s\n", _("Move files or directories to the trash")); - g_printerr (" tree %s\n", _("Lists the contents of locations in a tree")); - g_printerr ("\n"); - g_printerr (_("Use %s to get detailed help.\n"), "“gio help COMMAND”"); - exit (1); + GString *out = NULL; + size_t name_width = 0; + + out = g_string_new (""); + g_string_append_printf (out, "%s\n", _("Usage:")); + g_string_append_printf (out, " gio %s %s\n", _("COMMAND"), _("[ARGS…]")); + g_string_append_c (out, '\n'); + g_string_append_printf (out, "%s\n", _("Commands:")); + + /* Work out the maximum name length for column alignment. */ + for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++) + name_width = MAX (name_width, strlen (gio_subcommands[i].name)); + + for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++) + { + g_string_append_printf (out, " %-*s %s\n", + (int) name_width, gio_subcommands[i].name, + _(gio_subcommands[i].description)); + } + + g_string_append_c (out, '\n'); + g_string_append_printf (out, _("Use %s to get detailed help.\n"), "“gio help COMMAND”"); + + if (is_error) + g_printerr ("%s", out->str); + else + g_print ("%s", out->str); + + g_string_free (out, TRUE); } int @@ -277,7 +309,7 @@ main (int argc, char **argv) if (argc < 2) { - usage (); + usage (TRUE); return 1; } @@ -290,7 +322,7 @@ main (int argc, char **argv) { if (argc == 1) { - usage (); + usage (FALSE); return 0; } else @@ -301,50 +333,24 @@ main (int argc, char **argv) } else if (g_str_equal (command, "--help")) { - usage (); + usage (FALSE); return 0; } else if (g_str_equal (command, "--version")) command = "version"; - if (g_str_equal (command, "version")) - return handle_version (argc, argv, do_help); - else if (g_str_equal (command, "cat")) - return handle_cat (argc, argv, do_help); - else if (g_str_equal (command, "copy")) - return handle_copy (argc, argv, do_help); - else if (g_str_equal (command, "info")) - return handle_info (argc, argv, do_help); - else if (g_str_equal (command, "launch")) - return handle_launch (argc, argv, do_help); - else if (g_str_equal (command, "list")) - return handle_list (argc, argv, do_help); - else if (g_str_equal (command, "mime")) - return handle_mime (argc, argv, do_help); - else if (g_str_equal (command, "mkdir")) - return handle_mkdir (argc, argv, do_help); - else if (g_str_equal (command, "monitor")) - return handle_monitor (argc, argv, do_help); - else if (g_str_equal (command, "mount")) - return handle_mount (argc, argv, do_help); - else if (g_str_equal (command, "move")) - return handle_move (argc, argv, do_help); - else if (g_str_equal (command, "open")) - return handle_open (argc, argv, do_help); - else if (g_str_equal (command, "rename")) - return handle_rename (argc, argv, do_help); - else if (g_str_equal (command, "remove")) - return handle_remove (argc, argv, do_help); - else if (g_str_equal (command, "save")) - return handle_save (argc, argv, do_help); - else if (g_str_equal (command, "set")) - return handle_set (argc, argv, do_help); - else if (g_str_equal (command, "trash")) - return handle_trash (argc, argv, do_help); - else if (g_str_equal (command, "tree")) - return handle_tree (argc, argv, do_help); - else - usage (); + /* Work out which subcommand it is. */ + for (size_t i = 0; i < G_N_ELEMENTS (gio_subcommands); i++) + { + if (g_str_equal (command, gio_subcommands[i].name)) + { + g_assert (gio_subcommands[i].handle_func != NULL); + return gio_subcommands[i].handle_func (argc, argv, do_help); + } + } + + /* Unknown subcommand. */ + usage (TRUE); return 1; } diff --git a/gio/gioenums.h b/gio/gioenums.h index c820cd3..4223253 100644 --- a/gio/gioenums.h +++ b/gio/gioenums.h @@ -314,6 +314,8 @@ typedef enum { * @G_FILE_COPY_ALL_METADATA: Copy all file metadata instead of just default set used for copy (see #GFileInfo). * @G_FILE_COPY_NO_FALLBACK_FOR_MOVE: Don't use copy and delete fallback if native move not supported. * @G_FILE_COPY_TARGET_DEFAULT_PERMS: Leaves target file with default perms, instead of setting the source file perms. + * @G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME: Use default modification + * timestamps instead of copying them from the source file. Since 2.80 * * Flags used when copying or moving files. */ @@ -324,7 +326,8 @@ typedef enum { G_FILE_COPY_NOFOLLOW_SYMLINKS = (1 << 2), G_FILE_COPY_ALL_METADATA = (1 << 3), G_FILE_COPY_NO_FALLBACK_FOR_MOVE = (1 << 4), - G_FILE_COPY_TARGET_DEFAULT_PERMS = (1 << 5) + G_FILE_COPY_TARGET_DEFAULT_PERMS = (1 << 5), + G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME GIO_AVAILABLE_ENUMERATOR_IN_2_80 = (1 << 6), } GFileCopyFlags; @@ -514,6 +517,7 @@ typedef enum { * @G_IO_ERROR_NOT_CONNECTED: Transport endpoint is not connected. Since 2.44 * @G_IO_ERROR_MESSAGE_TOO_LARGE: Message too large. Since 2.48. * @G_IO_ERROR_NO_SUCH_DEVICE: No such device found. Since 2.74 + * @G_IO_ERROR_DESTINATION_UNSET: Destination address unset. Since 2.80 * * Error codes returned by GIO functions. * @@ -584,6 +588,7 @@ typedef enum { G_IO_ERROR_NOT_CONNECTED, G_IO_ERROR_MESSAGE_TOO_LARGE, G_IO_ERROR_NO_SUCH_DEVICE GIO_AVAILABLE_ENUMERATOR_IN_2_74, + G_IO_ERROR_DESTINATION_UNSET GIO_AVAILABLE_ENUMERATOR_IN_2_80, } GIOErrorEnum; diff --git a/gio/gioenumtypes.c.template b/gio/gioenumtypes.c.template index 5e119a3..3176ead 100644 --- a/gio/gioenumtypes.c.template +++ b/gio/gioenumtypes.c.template @@ -38,9 +38,9 @@ GType @enum_name@_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { static const G@Type@Value values[] = { /*** END value-header ***/ @@ -54,7 +54,7 @@ GType }; GType g_define_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; diff --git a/gio/gioerror.c b/gio/gioerror.c index b4c0e70..1b64dfd 100644 --- a/gio/gioerror.c +++ b/gio/gioerror.c @@ -31,14 +31,6 @@ #endif /** - * SECTION:gioerror - * @short_description: Error helper functions - * @include: gio/gio.h - * - * Contains helper functions for reporting errors to the user. - **/ - -/** * g_io_error_quark: * * Gets the GIO Error Quark. @@ -51,15 +43,18 @@ G_DEFINE_QUARK (g-io-error-quark, g_io_error) * g_io_error_from_errno: * @err_no: Error number as defined in errno.h. * - * Converts errno.h error codes into GIO error codes. The fallback - * value %G_IO_ERROR_FAILED is returned for error codes not currently - * handled (but note that future GLib releases may return a more + * Converts `errno.h` error codes into GIO error codes. + * + * The fallback value %G_IO_ERROR_FAILED is returned for error codes not + * currently handled (but note that future GLib releases may return a more * specific value instead). * - * As %errno is global and may be modified by intermediate function - * calls, you should save its value as soon as the call which sets it - * returns: - * |[ + * As `errno` is global and may be modified by intermediate function + * calls, you should save its value immediately after the call returns, + * and use the saved value instead of `errno`: + * + * + * |[ * int saved_errno; * * ret = read (blah); @@ -68,8 +63,8 @@ G_DEFINE_QUARK (g-io-error-quark, g_io_error) * g_io_error_from_errno (saved_errno); * ]| * - * Returns: #GIOErrorEnum value for the given errno.h error number. - **/ + * Returns: #GIOErrorEnum value for the given `errno.h` error number + */ GIOErrorEnum g_io_error_from_errno (gint err_no) { @@ -225,6 +220,12 @@ g_io_error_from_errno (gint err_no) break; #endif +#ifdef EDESTADDRREQ + case EDESTADDRREQ: + return G_IO_ERROR_DESTINATION_UNSET; + break; +#endif + #ifdef EMSGSIZE case EMSGSIZE: return G_IO_ERROR_MESSAGE_TOO_LARGE; diff --git a/gio/giomodule.c b/gio/giomodule.c index 17fabe6..1e14955 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -77,53 +77,47 @@ #undef __GLIB_H_INSIDE__ /** - * SECTION:giomodule - * @short_description: Loadable GIO Modules - * @include: gio/gio.h + * GIOModule: * * Provides an interface and default functions for loading and unloading * modules. This is used internally to make GIO extensible, but can also * be used by others to implement module loading. - * - **/ + */ /** - * SECTION:extensionpoints - * @short_description: Extension Points - * @include: gio.h - * @see_also: [Extending GIO][extending-gio] + * GIOExtensionPoint: * - * #GIOExtensionPoint provides a mechanism for modules to extend the + * `GIOExtensionPoint` provides a mechanism for modules to extend the * functionality of the library or application that loaded it in an - * organized fashion. + * organized fashion. * * An extension point is identified by a name, and it may optionally * require that any implementation must be of a certain type (or derived - * thereof). Use g_io_extension_point_register() to register an - * extension point, and g_io_extension_point_set_required_type() to + * thereof). Use [func@Gio.IOExtensionPoint.register] to register an + * extension point, and [method@Gio.IOExtensionPoint.set_required_type] to * set a required type. * - * A module can implement an extension point by specifying the #GType - * that implements the functionality. Additionally, each implementation - * of an extension point has a name, and a priority. Use - * g_io_extension_point_implement() to implement an extension point. + * A module can implement an extension point by specifying the + * [type@GObject.Type] that implements the functionality. Additionally, each + * implementation of an extension point has a name, and a priority. Use + * [func@Gio.IOExtensionPoint.implement] to implement an extension point. * - * |[ - * GIOExtensionPoint *ep; - * - * // Register an extension point - * ep = g_io_extension_point_register ("my-extension-point"); - * g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE); - * ]| - * - * |[ - * // Implement an extension point - * G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE) - * g_io_extension_point_implement ("my-extension-point", - * my_example_impl_get_type (), - * "my-example", - * 10); - * ]| + * ```c + * GIOExtensionPoint *ep; + * + * // Register an extension point + * ep = g_io_extension_point_register ("my-extension-point"); + * g_io_extension_point_set_required_type (ep, MY_TYPE_EXAMPLE); + * ``` + * + * ```c + * // Implement an extension point + * G_DEFINE_TYPE (MyExampleImpl, my_example_impl, MY_TYPE_EXAMPLE) + * g_io_extension_point_implement ("my-extension-point", + * my_example_impl_get_type (), + * "my-example", + * 10); + * ``` * * It is up to the code that registered the extension point how * it uses the implementations that have been associated with it. @@ -133,7 +127,7 @@ * * To avoid opening all modules just to find out what extension * points they implement, GIO makes use of a caching mechanism, - * see [gio-querymodules][gio-querymodules]. + * see [gio-querymodules](gio-querymodules.html). * You are expected to run this command after installing a * GIO module. * @@ -267,12 +261,6 @@ struct _GIOExtension { gint priority; }; -/** - * GIOExtensionPoint: - * - * #GIOExtensionPoint is an opaque data structure and can only be accessed - * using the following functions. - */ struct _GIOExtensionPoint { GType required_type; char *name; @@ -1175,10 +1163,10 @@ void * _g_io_win32_get_module (void) { if (!gio_dll) - GetModuleHandleExA (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | - GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, - (const char *) _g_io_win32_get_module, - &gio_dll); + GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | + GET_MODULE_HANDLE_EX_FLAG_UNCHANGED_REFCOUNT, + (LPCWSTR) _g_io_win32_get_module, + &gio_dll); return gio_dll; } diff --git a/gio/giomodule.h b/gio/giomodule.h index 2fe7e1d..f1460de 100644 --- a/gio/giomodule.h +++ b/gio/giomodule.h @@ -49,11 +49,6 @@ void g_io_module_scope_block (GIOModuleScope *scope, #define G_IO_IS_MODULE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_IO_TYPE_MODULE)) #define G_IO_MODULE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_IO_TYPE_MODULE, GIOModuleClass)) -/** - * GIOModule: - * - * Opaque module base class for extending GIO. - **/ typedef struct _GIOModuleClass GIOModuleClass; GIO_AVAILABLE_IN_ALL diff --git a/gio/gioscheduler.c b/gio/gioscheduler.c index b2059e4..4363e23 100644 --- a/gio/gioscheduler.c +++ b/gio/gioscheduler.c @@ -26,18 +26,6 @@ #include "gcancellable.h" #include "gtask.h" -/** - * SECTION:gioscheduler - * @short_description: I/O Scheduler - * @include: gio/gio.h - * - * As of GLib 2.36, #GIOScheduler is deprecated in favor of - * #GThreadPool and #GTask. - * - * Schedules asynchronous I/O operations. #GIOScheduler integrates - * into the main event loop (#GMainLoop) and uses threads. - */ - struct _GIOSchedulerJob { GList *active_link; GTask *task; @@ -110,7 +98,7 @@ io_job_thread (GTask *task, * by calling g_cancellable_cancel() or by calling * g_io_scheduler_cancel_all_jobs(). * - * Deprecated: use #GThreadPool or g_task_run_in_thread() + * Deprecated: 2.36: use #GThreadPool or g_task_run_in_thread() **/ void g_io_scheduler_push_job (GIOSchedulerJobFunc job_func, @@ -157,7 +145,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS * A job is cancellable if a #GCancellable was passed into * g_io_scheduler_push_job(). * - * Deprecated: You should never call this function, since you don't + * Deprecated: 2.36: You should never call this function, since you don't * know how other libraries in your program might be making use of * gioscheduler. **/ @@ -236,7 +224,7 @@ mainloop_proxy_free (MainLoopProxy *proxy) * * Returns: The return value of @func * - * Deprecated: Use g_main_context_invoke(). + * Deprecated: 2.36: Use g_main_context_invoke(). **/ gboolean g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, @@ -295,7 +283,7 @@ g_io_scheduler_job_send_to_mainloop (GIOSchedulerJob *job, * @func is called, either by passing %NULL as @notify to * g_io_scheduler_push_job() or by using refcounting for @user_data. * - * Deprecated: Use g_main_context_invoke(). + * Deprecated: 2.36: Use g_main_context_invoke(). **/ void g_io_scheduler_job_send_to_mainloop_async (GIOSchedulerJob *job, diff --git a/gio/giostream.c b/gio/giostream.c index 194ba49..d9398fe 100644 --- a/gio/giostream.c +++ b/gio/giostream.c @@ -32,57 +32,56 @@ #include "gtask.h" /** - * SECTION:giostream - * @short_description: Base class for implementing read/write streams - * @include: gio/gio.h - * @see_also: #GInputStream, #GOutputStream + * GIOStream: * - * GIOStream represents an object that has both read and write streams. + * `GIOStream` represents an object that has both read and write streams. * Generally the two streams act as separate input and output streams, * but they share some common resources and state. For instance, for * seekable streams, both streams may use the same position. * - * Examples of #GIOStream objects are #GSocketConnection, which represents - * a two-way network connection; and #GFileIOStream, which represents a + * Examples of `GIOStream` objects are [class@Gio.SocketConnection], which represents + * a two-way network connection; and [class@Gio.FileIOStream], which represents a * file handle opened in read-write mode. * * To do the actual reading and writing you need to get the substreams - * with g_io_stream_get_input_stream() and g_io_stream_get_output_stream(). + * with [method@Gio.IOStream.get_input_stream] and + * [method@Gio.IOStream.get_output_stream]. * - * The #GIOStream object owns the input and the output streams, not the other - * way around, so keeping the substreams alive will not keep the #GIOStream - * object alive. If the #GIOStream object is freed it will be closed, thus + * The `GIOStream` object owns the input and the output streams, not the other + * way around, so keeping the substreams alive will not keep the `GIOStream` + * object alive. If the `GIOStream` object is freed it will be closed, thus * closing the substreams, so even if the substreams stay alive they will - * always return %G_IO_ERROR_CLOSED for all operations. + * always return `G_IO_ERROR_CLOSED` for all operations. * - * To close a stream use g_io_stream_close() which will close the common + * To close a stream use [method@Gio.IOStream.close] which will close the common * stream object and also the individual substreams. You can also close * the substreams themselves. In most cases this only marks the * substream as closed, so further I/O on it fails but common state in the - * #GIOStream may still be open. However, some streams may support - * "half-closed" states where one direction of the stream is actually shut down. - * - * Operations on #GIOStreams cannot be started while another operation on the - * #GIOStream or its substreams is in progress. Specifically, an application can - * read from the #GInputStream and write to the #GOutputStream simultaneously - * (either in separate threads, or as asynchronous operations in the same - * thread), but an application cannot start any #GIOStream operation while there - * is a #GIOStream, #GInputStream or #GOutputStream operation in progress, and - * an application can’t start any #GInputStream or #GOutputStream operation - * while there is a #GIOStream operation in progress. + * `GIOStream` may still be open. However, some streams may support + * ‘half-closed’ states where one direction of the stream is actually shut down. + * + * Operations on `GIOStream`s cannot be started while another operation on the + * `GIOStream` or its substreams is in progress. Specifically, an application can + * read from the [class@Gio.InputStream] and write to the + * [class@Gio.OutputStream] simultaneously (either in separate threads, or as + * asynchronous operations in the same thread), but an application cannot start + * any `GIOStream` operation while there is a `GIOStream`, `GInputStream` or + * `GOutputStream` operation in progress, and an application can’t start any + * `GInputStream` or `GOutputStream` operation while there is a `GIOStream` + * operation in progress. * * This is a product of individual stream operations being associated with a - * given #GMainContext (the thread-default context at the time the operation was - * started), rather than entire streams being associated with a single - * #GMainContext. + * given [type@GLib.MainContext] (the thread-default context at the time the + * operation was started), rather than entire streams being associated with a + * single `GMainContext`. * - * GIO may run operations on #GIOStreams from other (worker) threads, and this + * GIO may run operations on `GIOStream`s from other (worker) threads, and this * may be exposed to application code in the behaviour of wrapper streams, such - * as #GBufferedInputStream or #GTlsConnection. With such wrapper APIs, - * application code may only run operations on the base (wrapped) stream when - * the wrapper stream is idle. Note that the semantics of such operations may - * not be well-defined due to the state the wrapper stream leaves the base - * stream in (though they are guaranteed not to crash). + * as [class@Gio.BufferedInputStream] or [class@Gio.TlsConnection]. With such + * wrapper APIs, application code may only run operations on the base (wrapped) + * stream when the wrapper stream is idle. Note that the semantics of such + * operations may not be well-defined due to the state the wrapper stream leaves + * the base stream in (though they are guaranteed not to crash). * * Since: 2.22 */ @@ -172,23 +171,39 @@ g_io_stream_class_init (GIOStreamClass *klass) klass->close_async = g_io_stream_real_close_async; klass->close_finish = g_io_stream_real_close_finish; + /** + * GIOStream:closed: + * + * Whether the stream is closed. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_CLOSED, - g_param_spec_boolean ("closed", - P_("Closed"), - P_("Is the stream closed"), + g_param_spec_boolean ("closed", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * GIOStream:input-stream: + * + * The [class@Gio.InputStream] to read from. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_INPUT_STREAM, - g_param_spec_object ("input-stream", - P_("Input stream"), - P_("The GInputStream to read from"), + g_param_spec_object ("input-stream", NULL, NULL, G_TYPE_INPUT_STREAM, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + + /** + * GIOStream:output-stream: + * + * The [class@Gio.OutputStream] to write to. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM, - g_param_spec_object ("output-stream", - P_("Output stream"), - P_("The GOutputStream to write to"), + g_param_spec_object ("output-stream", NULL, NULL, G_TYPE_OUTPUT_STREAM, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/giostream.h b/gio/giostream.h index 52881c7..f8a958b 100644 --- a/gio/giostream.h +++ b/gio/giostream.h @@ -40,11 +40,6 @@ G_BEGIN_DECLS typedef struct _GIOStreamPrivate GIOStreamPrivate; typedef struct _GIOStreamClass GIOStreamClass; -/** - * GIOStream: - * - * Base class for read-write streams. - **/ struct _GIOStream { GObject parent_instance; diff --git a/gio/giotypes.h b/gio/giotypes.h index 82e091b..c2c09d1 100644 --- a/gio/giotypes.h +++ b/gio/giotypes.h @@ -65,24 +65,12 @@ typedef struct _GPermission GPermission; typedef struct _GMenuModel GMenuModel; typedef struct _GNotification GNotification; -/** - * GDrive: - * - * Opaque drive object. - **/ typedef struct _GDrive GDrive; /* Dummy typedef */ typedef struct _GFileEnumerator GFileEnumerator; typedef struct _GFileMonitor GFileMonitor; typedef struct _GFilterInputStream GFilterInputStream; typedef struct _GFilterOutputStream GFilterOutputStream; -/** - * GFile: - * - * A handle to an object implementing the #GFileIface interface. - * Generally stores a location within the file system. Handles do not - * necessarily represent files or directories that currently exist. - **/ typedef struct _GFile GFile; /* Dummy typedef */ typedef struct _GFileInfo GFileInfo; @@ -117,6 +105,9 @@ typedef struct _GIOExtension GIOExtension; * GIOSchedulerJob: * * Opaque class for defining and scheduling IO jobs. + * + * Deprecated: 2.36: Use [struct@GLib.ThreadPool] or + * [method@Gio.Task.run_in_thread] **/ typedef struct _GIOSchedulerJob GIOSchedulerJob; typedef struct _GIOStreamAdapter GIOStreamAdapter; @@ -125,11 +116,6 @@ typedef struct _GBytesIcon GBytesIcon; typedef struct _GMemoryInputStream GMemoryInputStream; typedef struct _GMemoryOutputStream GMemoryOutputStream; -/** - * GMount: - * - * A handle to an object implementing the #GMountIface interface. - **/ typedef struct _GMount GMount; /* Dummy typedef */ typedef struct _GMountOperation GMountOperation; typedef struct _GNetworkAddress GNetworkAddress; @@ -142,88 +128,24 @@ typedef struct _GPollableInputStream GPollableInputStream; /* Dummy typ typedef struct _GPollableOutputStream GPollableOutputStream; /* Dummy typedef */ typedef struct _GResolver GResolver; -/** - * GResource: - * - * A resource bundle. - * - * Since: 2.32 - */ typedef struct _GResource GResource; typedef struct _GSeekable GSeekable; typedef struct _GSimpleAsyncResult GSimpleAsyncResult; -/** - * GSocket: - * - * A lowlevel network socket object. - * - * Since: 2.22 - **/ typedef struct _GSocket GSocket; -/** - * GSocketControlMessage: - * - * Base class for socket-type specific control messages that can be sent and - * received over #GSocket. - **/ typedef struct _GSocketControlMessage GSocketControlMessage; -/** - * GSocketClient: - * - * A helper class for network clients to make connections. - * - * Since: 2.22 - **/ typedef struct _GSocketClient GSocketClient; -/** - * GSocketConnection: - * - * A socket connection GIOStream object for connection-oriented sockets. - * - * Since: 2.22 - **/ typedef struct _GSocketConnection GSocketConnection; -/** - * GSocketListener: - * - * A helper class for network servers to listen for and accept connections. - * - * Since: 2.22 - **/ typedef struct _GSocketListener GSocketListener; -/** - * GSocketService: - * - * A helper class for handling accepting incoming connections in the - * glib mainloop. - * - * Since: 2.22 - **/ typedef struct _GSocketService GSocketService; typedef struct _GSocketAddress GSocketAddress; typedef struct _GSocketAddressEnumerator GSocketAddressEnumerator; typedef struct _GSocketConnectable GSocketConnectable; typedef struct _GSrvTarget GSrvTarget; typedef struct _GTask GTask; -/** - * GTcpConnection: - * - * A #GSocketConnection for TCP/IP connections. - * - * Since: 2.22 - **/ typedef struct _GTcpConnection GTcpConnection; typedef struct _GTcpWrapperConnection GTcpWrapperConnection; -/** - * GThreadedSocketService: - * - * A helper class for handling accepting incoming connections in the - * glib mainloop and handling them in a thread. - * - * Since: 2.22 - **/ typedef struct _GThreadedSocketService GThreadedSocketService; typedef struct _GDtlsConnection GDtlsConnection; typedef struct _GDtlsClientConnection GDtlsClientConnection; /* Dummy typedef */ @@ -239,23 +161,11 @@ typedef struct _GTlsPassword GTlsPassword; typedef struct _GTlsServerConnection GTlsServerConnection; /* Dummy typedef */ typedef struct _GVfs GVfs; /* Dummy typedef */ -/** - * GProxyResolver: - * - * A helper class to enumerate proxies base on URI. - * - * Since: 2.26 - **/ typedef struct _GProxyResolver GProxyResolver; typedef struct _GProxy GProxy; typedef struct _GProxyAddress GProxyAddress; typedef struct _GProxyAddressEnumerator GProxyAddressEnumerator; -/** - * GVolume: - * - * Opaque mountable volume object. - **/ typedef struct _GVolume GVolume; /* Dummy typedef */ typedef struct _GVolumeMonitor GVolumeMonitor; @@ -370,6 +280,8 @@ typedef void (* GFileMeasureProgressCallback) (gboolean reporting, * * Returns: %TRUE if this function should be called again to * complete the job, %FALSE if the job is complete (or cancelled) + * Deprecated: 2.36: Use [struct@GLib.ThreadPool] or + * [method@Gio.Task.run_in_thread] **/ typedef gboolean (*GIOSchedulerJobFunc) (GIOSchedulerJob *job, GCancellable *cancellable, @@ -638,21 +550,7 @@ typedef GType (*GDBusProxyTypeFunc) (GDBusObjectManagerClient *manager, typedef struct _GTestDBus GTestDBus; -/** - * GSubprocess: - * - * A child process. - * - * Since: 2.40 - */ typedef struct _GSubprocess GSubprocess; -/** - * GSubprocessLauncher: - * - * Options for launching a child process. - * - * Since: 2.40 - */ typedef struct _GSubprocessLauncher GSubprocessLauncher; G_END_DECLS diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c index 79a0266..a86c4d9 100644 --- a/gio/gkeyfilesettingsbackend.c +++ b/gio/gkeyfilesettingsbackend.c @@ -898,9 +898,7 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class) */ g_object_class_install_property (object_class, PROP_FILENAME, - g_param_spec_string ("filename", - P_("Filename"), - P_("The filename"), + g_param_spec_string ("filename", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -916,9 +914,7 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class) */ g_object_class_install_property (object_class, PROP_ROOT_PATH, - g_param_spec_string ("root-path", - P_("Root path"), - P_("The root path"), + g_param_spec_string ("root-path", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -933,9 +929,7 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class) */ g_object_class_install_property (object_class, PROP_ROOT_GROUP, - g_param_spec_string ("root-group", - P_("Root group"), - P_("The root group"), + g_param_spec_string ("root-group", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -949,9 +943,7 @@ g_keyfile_settings_backend_class_init (GKeyfileSettingsBackendClass *class) */ g_object_class_install_property (object_class, PROP_DEFAULTS_DIR, - g_param_spec_string ("defaults-dir", - P_("Default dir"), - P_("Defaults dir"), + g_param_spec_string ("defaults-dir", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/gio/glib-compile-resources.c b/gio/glib-compile-resources.c index 46eec19..2ce9237 100644 --- a/gio/glib-compile-resources.c +++ b/gio/glib-compile-resources.c @@ -1196,7 +1196,7 @@ main (int argc, char **argv) "#include \n" "\n" "#if defined (__ELF__) && ( __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 6))\n" - "# define SECTION __attribute__ ((section (\".gresource.%s\"), aligned (8)))\n" + "# define SECTION __attribute__ ((section (\".gresource.%s\"), aligned (sizeof(void *) > 8 ? sizeof(void *) : 8)))\n" "#else\n" "# define SECTION\n" "#endif\n" diff --git a/gio/glistmodel.c b/gio/glistmodel.c index 349b08b..35a66e9 100644 --- a/gio/glistmodel.c +++ b/gio/glistmodel.c @@ -31,74 +31,72 @@ G_DEFINE_INTERFACE (GListModel, g_list_model, G_TYPE_OBJECT) /** - * SECTION:glistmodel - * @title: GListModel - * @short_description: An interface describing a dynamic list of objects - * @include: gio/gio.h - * @see_also: #GListStore - * - * #GListModel is an interface that represents a mutable list of - * #GObjects. Its main intention is as a model for various widgets in - * user interfaces, such as list views, but it can also be used as a + * GListModel: + * + * `GListModel` is an interface that represents a mutable list of + * [class@GObject.Object]. Its main intention is as a model for various widgets + * in user interfaces, such as list views, but it can also be used as a * convenient method of returning lists of data, with support for * updates. * * Each object in the list may also report changes in itself via some - * mechanism (normally the #GObject::notify signal). Taken together - * with the #GListModel::items-changed signal, this provides for a list - * that can change its membership, and in which the members can change - * their individual properties. + * mechanism (normally the [signal@GObject.Object::notify] signal). Taken + * together with the [signal@Gio.ListModel::items-changed] signal, this provides + * for a list that can change its membership, and in which the members can + * change their individual properties. * * A good example would be the list of visible wireless network access * points, where each access point can report dynamic properties such as * signal strength. * - * It is important to note that the #GListModel itself does not report + * It is important to note that the `GListModel` itself does not report * changes to the individual items. It only reports changes to the list * membership. If you want to observe changes to the objects themselves * then you need to connect signals to the objects that you are * interested in. * - * All items in a #GListModel are of (or derived from) the same type. - * g_list_model_get_item_type() returns that type. The type may be an + * All items in a `GListModel` are of (or derived from) the same type. + * [method@Gio.ListModel.get_item_type] returns that type. The type may be an * interface, in which case all objects in the list must implement it. * * The semantics are close to that of an array: - * g_list_model_get_n_items() returns the number of items in the list and - * g_list_model_get_item() returns an item at a (0-based) position. In - * order to allow implementations to calculate the list length lazily, + * [method@Gio.ListModel.get_n_items] returns the number of items in the list + * and [method@Gio.ListModel.get_item] returns an item at a (0-based) position. + * In order to allow implementations to calculate the list length lazily, * you can also iterate over items: starting from 0, repeatedly call - * g_list_model_get_item() until it returns %NULL. + * [method@Gio.ListModel.get_item] until it returns `NULL`. * * An implementation may create objects lazily, but must take care to * return the same object for a given position until all references to * it are gone. * * On the other side, a consumer is expected only to hold references on - * objects that are currently "user visible", in order to facilitate the + * objects that are currently ‘user visible’, in order to facilitate the * maximum level of laziness in the implementation of the list and to * reduce the required number of signal connections at a given time. * * This interface is intended only to be used from a single thread. The * thread in which it is appropriate to use it depends on the particular * implementation, but typically it will be from the thread that owns - * the [thread-default main context][g-main-context-push-thread-default] - * in effect at the time that the model was created. + * the thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) in effect at the time that the + * model was created. * - * Over time, it has established itself as good practice for listmodel + * Over time, it has established itself as good practice for list model * implementations to provide properties `item-type` and `n-items` to * ease working with them. While it is not required, it is recommended * that implementations provide these two properties. They should return - * the values of g_list_model_get_item_type() and g_list_model_get_n_items() - * respectively and be defined as such: - * |[ + * the values of [method@Gio.ListModel.get_item_type] and + * [method@Gio.ListModel.get_n_items] respectively and be defined as such: + * + * ```c * properties[PROP_ITEM_TYPE] = - * g_param_spec_gtype ("item-type", "", "", G_TYPE_OBJECT, + * g_param_spec_gtype ("item-type", NULL, NULL, G_TYPE_OBJECT, * G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); * properties[PROP_N_ITEMS] = - * g_param_spec_uint ("n-items", "", "", 0, G_MAXUINT, 0, + * g_param_spec_uint ("n-items", NULL, NULL, 0, G_MAXUINT, 0, * G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - * ]| + * ``` */ /** @@ -131,13 +129,6 @@ G_DEFINE_INTERFACE (GListModel, g_list_model, G_TYPE_OBJECT) * Since: 2.44 */ -/** - * GListModel: - * - * #GListModel is an opaque data structure and can only be accessed - * using the following functions. - **/ - static guint g_list_model_changed_signal; static void diff --git a/gio/gliststore.c b/gio/gliststore.c index 497dfb5..41450f6 100644 --- a/gio/gliststore.c +++ b/gio/gliststore.c @@ -28,25 +28,15 @@ #include "glistmodel.h" /** - * SECTION:gliststore - * @title: GListStore - * @short_description: A simple implementation of #GListModel - * @include: gio/gio.h + * GListStore: * - * #GListStore is a simple implementation of #GListModel that stores all - * items in memory. + * `GListStore` is a simple implementation of [iface@Gio.ListModel] that stores + * all items in memory. * * It provides insertions, deletions, and lookups in logarithmic time * with a fast path for the common case of iterating the list linearly. */ -/** - * GListStore: - * - * #GListStore is an opaque data structure and can only be accessed - * using the following functions. - **/ - struct _GListStore { GObject parent_instance; @@ -165,7 +155,7 @@ g_list_store_class_init (GListStoreClass *klass) * Since: 2.44 **/ properties[PROP_ITEM_TYPE] = - g_param_spec_gtype ("item-type", "", "", G_TYPE_OBJECT, + g_param_spec_gtype ("item-type", NULL, NULL, G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); /** @@ -176,7 +166,7 @@ g_list_store_class_init (GListStoreClass *klass) * Since: 2.74 **/ properties[PROP_N_ITEMS] = - g_param_spec_uint ("n-items", "", "", 0, G_MAXUINT, 0, + g_param_spec_uint ("n-items", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); g_object_class_install_properties (object_class, N_PROPERTIES, properties); diff --git a/gio/gloadableicon.c b/gio/gloadableicon.c index 1d3460d..13012ba 100644 --- a/gio/gloadableicon.c +++ b/gio/gloadableicon.c @@ -29,13 +29,10 @@ /** - * SECTION:gloadableicon - * @short_description: Loadable Icons - * @include: gio/gio.h - * @see_also: #GIcon, #GThemedIcon + * GLoadableIcon: * - * Extends the #GIcon interface and adds the ability to - * load icons from streams. + * `GLoadableIcon` extends the [iface@Gio.Icon] interface and adds the ability + * to load icons from streams. **/ static void g_loadable_icon_real_load_async (GLoadableIcon *icon, diff --git a/gio/gloadableicon.h b/gio/gloadableicon.h index 7a576ef..bde104b 100644 --- a/gio/gloadableicon.h +++ b/gio/gloadableicon.h @@ -36,12 +36,6 @@ G_BEGIN_DECLS #define G_IS_LOADABLE_ICON(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_LOADABLE_ICON)) #define G_LOADABLE_ICON_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_LOADABLE_ICON, GLoadableIconIface)) -/** - * GLoadableIcon: - * - * Generic type for all kinds of icons that can be loaded - * as a stream. - **/ typedef struct _GLoadableIconIface GLoadableIconIface; /** diff --git a/gio/glocalfile.c b/gio/glocalfile.c index dbb5690..b7b9b62 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -105,7 +105,7 @@ static void g_local_file_file_iface_init (GFileIface *iface); static GFileAttributeInfoList *local_writable_attributes = NULL; -static /* GFileAttributeInfoList * */ gsize local_writable_namespaces = 0; +static GFileAttributeInfoList *local_writable_namespaces = NULL; struct _GLocalFile { @@ -1274,7 +1274,7 @@ g_local_file_query_writable_namespaces (GFile *file, GVfsClass *class; GVfs *vfs; - if (g_once_init_enter (&local_writable_namespaces)) + if (g_once_init_enter_pointer (&local_writable_namespaces)) { /* Writable namespaces: */ @@ -1297,7 +1297,7 @@ g_local_file_query_writable_namespaces (GFile *file, if (class->add_writable_namespaces) class->add_writable_namespaces (vfs, list); - g_once_init_leave (&local_writable_namespaces, (gsize)list); + g_once_init_leave_pointer (&local_writable_namespaces, list); } list = (GFileAttributeInfoList *)local_writable_namespaces; diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 4f51427..2df7c91 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -1345,7 +1345,11 @@ get_content_type (const char *basename, #if !defined(G_OS_WIN32) && !defined(__APPLE__) if (!fast && result_uncertain && path != NULL) { - guchar sniff_buffer[4096]; + /* Sniff the first 16KiB of the file (sometimes less, if xdgmime + * says it doesn’t need so much). Most files need less than 4KiB of + * sniffing, but some disk images need more (see + * https://gitlab.gnome.org/GNOME/glib/-/issues/3186). */ + guchar sniff_buffer[16384]; gsize sniff_length; #ifdef O_NOATIME int errsv; @@ -1353,8 +1357,8 @@ get_content_type (const char *basename, int fd; sniff_length = _g_unix_content_type_get_sniff_len (); - if (sniff_length == 0 || sniff_length > 4096) - sniff_length = 4096; + if (sniff_length == 0 || sniff_length > sizeof (sniff_buffer)) + sniff_length = sizeof (sniff_buffer); #ifdef O_NOATIME fd = g_open (path, O_RDONLY | O_NOATIME | O_CLOEXEC, 0); diff --git a/gio/glocalvfs.c b/gio/glocalvfs.c index 00fec8e..7266ee0 100644 --- a/gio/glocalvfs.c +++ b/gio/glocalvfs.c @@ -94,32 +94,9 @@ g_local_vfs_get_file_for_uri (GVfs *vfs, { char *path; GFile *file; - char *stripped_uri, *hash, *question_mark; - /* As per https://url.spec.whatwg.org/#file-state, file: URIs can contain - * query and fragment sections. We ignore them in order to get only the file - * path. Compliance to this part of the WhatWG spec doesn’t necessarily mean - * we comply with the entire spec. */ - if (strchr (uri, '#') != NULL) - { - stripped_uri = g_strdup (uri); - hash = strchr (stripped_uri, '#'); - *hash = 0; - } - else if (strchr (uri, '?') != NULL) - { - stripped_uri = g_strdup (uri); - question_mark = strchr (stripped_uri, '?'); - *question_mark = 0; - } - else - stripped_uri = (char *)uri; - - path = g_filename_from_uri (stripped_uri, NULL, NULL); + path = g_filename_from_uri (uri, NULL, NULL); - if (stripped_uri != uri) - g_free (stripped_uri); - if (path != NULL) file = _g_local_file_new (path); else diff --git a/gio/gmemoryinputstream.c b/gio/gmemoryinputstream.c index 80f77d1..de16454 100644 --- a/gio/gmemoryinputstream.c +++ b/gio/gmemoryinputstream.c @@ -32,16 +32,13 @@ /** - * SECTION:gmemoryinputstream - * @short_description: Streaming input operations on memory chunks - * @include: gio/gio.h - * @see_also: #GMemoryOutputStream + * GMemoryInputStream: * - * #GMemoryInputStream is a class for using arbitrary + * `GMemoryInputStream` is a class for using arbitrary * memory chunks as input for GIO streaming input operations. * - * As of GLib 2.34, #GMemoryInputStream implements - * #GPollableInputStream. + * As of GLib 2.34, `GMemoryInputStream` implements + * [iface@Gio.PollableInputStream]. */ struct _GMemoryInputStreamPrivate { diff --git a/gio/gmemoryinputstream.h b/gio/gmemoryinputstream.h index fb72f23..b346567 100644 --- a/gio/gmemoryinputstream.h +++ b/gio/gmemoryinputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_MEMORY_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_MEMORY_INPUT_STREAM)) #define G_MEMORY_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_MEMORY_INPUT_STREAM, GMemoryInputStreamClass)) -/** - * GMemoryInputStream: - * - * Implements #GInputStream for arbitrary memory chunks. - **/ typedef struct _GMemoryInputStreamClass GMemoryInputStreamClass; typedef struct _GMemoryInputStreamPrivate GMemoryInputStreamPrivate; diff --git a/gio/gmemorymonitor.c b/gio/gmemorymonitor.c index fe555c8..148ada6 100644 --- a/gio/gmemorymonitor.c +++ b/gio/gmemorymonitor.c @@ -31,14 +31,12 @@ #include "gtask.h" /** - * SECTION:gmemorymonitor - * @title: GMemoryMonitor - * @short_description: Memory usage monitor - * @include: gio/gio.h + * GMemoryMonitor: * - * #GMemoryMonitor will monitor system memory and suggest to the application + * `GMemoryMonitor` will monitor system memory and suggest to the application * when to free memory so as to leave more room for other applications. - * It is implemented on Linux using the [Low Memory Monitor](https://gitlab.freedesktop.org/hadess/low-memory-monitor/) + * It is implemented on Linux using the + * [Low Memory Monitor](https://gitlab.freedesktop.org/hadess/low-memory-monitor/) * ([API documentation](https://hadess.pages.freedesktop.org/low-memory-monitor/)). * * There is also an implementation for use inside Flatpak sandboxes. @@ -46,11 +44,11 @@ * Possible actions to take when the signal is received are: * * - Free caches - * - Save files that haven't been looked at in a while to disk, ready to be reopened when needed + * - Save files that haven’t been looked at in a while to disk, ready to be reopened when needed * - Run a garbage collection cycle * - Try and compress fragmented allocations * - Exit on idle if the process has no reason to stay around - * - Call [`malloc_trim(3)`](man:malloc_trim) to return cached heap pages to + * - Call [`malloc_trim(3)`](man:malloc_trim(3)) to return cached heap pages to * the kernel (if supported by your libc) * * Note that some actions may not always improve system performance, and so @@ -58,9 +56,10 @@ * make future heap allocations slower (due to releasing cached heap pages back * to the kernel). * - * See #GMemoryMonitorWarningLevel for details on the various warning levels. + * See [type@Gio.MemoryMonitorWarningLevel] for details on the various warning + * levels. * - * |[ + * ```c * static void * warning_cb (GMemoryMonitor *m, GMemoryMonitorWarningLevel level) * { @@ -78,19 +77,10 @@ * G_CALLBACK (warning_cb), NULL); * return m; * } - * ]| - * - * Don't forget to disconnect the #GMemoryMonitor::low-memory-warning - * signal, and unref the #GMemoryMonitor itself when exiting. - * - * Since: 2.64 - */ - -/** - * GMemoryMonitor: + * ``` * - * #GMemoryMonitor monitors system memory and indicates when - * the system is low on memory. + * Don’t forget to disconnect the [signal@Gio.MemoryMonitor::low-memory-warning] + * signal, and unref the `GMemoryMonitor` itself when exiting. * * Since: 2.64 */ diff --git a/gio/gmemoryoutputstream.c b/gio/gmemoryoutputstream.c index 0339a7a..bf08085 100644 --- a/gio/gmemoryoutputstream.c +++ b/gio/gmemoryoutputstream.c @@ -35,16 +35,13 @@ /** - * SECTION:gmemoryoutputstream - * @short_description: Streaming output operations on memory chunks - * @include: gio/gio.h - * @see_also: #GMemoryInputStream + * GMemoryOutputStream: * - * #GMemoryOutputStream is a class for using arbitrary + * `GMemoryOutputStream` is a class for using arbitrary * memory chunks as output for GIO streaming output operations. * - * As of GLib 2.34, #GMemoryOutputStream trivially implements - * #GPollableOutputStream: it always polls as ready. + * As of GLib 2.34, `GMemoryOutputStream` trivially implements + * [iface@Gio.PollableOutputStream]: it always polls as ready. */ #define MIN_ARRAY_SIZE 16 @@ -154,9 +151,7 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) **/ g_object_class_install_property (gobject_class, PROP_DATA, - g_param_spec_pointer ("data", - P_("Data Buffer"), - P_("Pointer to buffer where data will be written."), + g_param_spec_pointer ("data", NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -169,9 +164,7 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) **/ g_object_class_install_property (gobject_class, PROP_SIZE, - g_param_spec_ulong ("size", - P_("Data Buffer Size"), - P_("Current size of the data buffer."), + g_param_spec_ulong ("size", NULL, NULL, 0, G_MAXULONG, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -185,9 +178,7 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) **/ g_object_class_install_property (gobject_class, PROP_DATA_SIZE, - g_param_spec_ulong ("data-size", - P_("Data Size"), - P_("Size of data written to the buffer."), + g_param_spec_ulong ("data-size", NULL, NULL, 0, G_MAXULONG, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -201,9 +192,7 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) **/ g_object_class_install_property (gobject_class, PROP_REALLOC_FUNCTION, - g_param_spec_pointer ("realloc-function", - P_("Memory Reallocation Function"), - P_("Function with realloc semantics called to enlarge the buffer."), + g_param_spec_pointer ("realloc-function", NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); @@ -216,9 +205,7 @@ g_memory_output_stream_class_init (GMemoryOutputStreamClass *klass) **/ g_object_class_install_property (gobject_class, PROP_DESTROY_FUNCTION, - g_param_spec_pointer ("destroy-function", - P_("Destroy Notification Function"), - P_("Function called with the buffer as argument when the stream is destroyed."), + g_param_spec_pointer ("destroy-function", NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gmemoryoutputstream.h b/gio/gmemoryoutputstream.h index 08f5dcf..6fb077b 100644 --- a/gio/gmemoryoutputstream.h +++ b/gio/gmemoryoutputstream.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_MEMORY_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_MEMORY_OUTPUT_STREAM)) #define G_MEMORY_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_MEMORY_OUTPUT_STREAM, GMemoryOutputStreamClass)) -/** - * GMemoryOutputStream: - * - * Implements #GOutputStream for arbitrary memory chunks. - **/ typedef struct _GMemoryOutputStreamClass GMemoryOutputStreamClass; typedef struct _GMemoryOutputStreamPrivate GMemoryOutputStreamPrivate; diff --git a/gio/gmenu.c b/gio/gmenu.c index adef4cc..dd4daee 100644 --- a/gio/gmenu.c +++ b/gio/gmenu.c @@ -29,26 +29,16 @@ #include "gicon.h" /** - * SECTION:gmenu - * @title: GMenu - * @short_description: A simple implementation of GMenuModel - * @include: gio/gio.h + * GMenu: * - * #GMenu is a simple implementation of #GMenuModel. - * You populate a #GMenu by adding #GMenuItem instances to it. + * `GMenu` is a simple implementation of [class@Gio.MenuModel]. + * You populate a `GMenu` by adding [class@Gio.MenuItem] instances to it. * * There are some convenience functions to allow you to directly - * add items (avoiding #GMenuItem) for the common cases. To add - * a regular item, use g_menu_insert(). To add a section, use - * g_menu_insert_section(). To add a submenu, use - * g_menu_insert_submenu(). - */ - -/** - * GMenu: - * - * #GMenu is an opaque structure type. You must access it using the - * functions below. + * add items (avoiding [class@Gio.MenuItem]) for the common cases. To add + * a regular item, use [method@Gio.Menu.insert]. To add a section, use + * [method@Gio.Menu.insert_section]. To add a submenu, use + * [method@Gio.Menu.insert_submenu]. * * Since: 2.32 */ diff --git a/gio/gmenuexporter.c b/gio/gmenuexporter.c index 67aac19..909780c 100644 --- a/gio/gmenuexporter.c +++ b/gio/gmenuexporter.c @@ -28,21 +28,6 @@ #include "gdbusnamewatching.h" #include "gdbuserror.h" -/** - * SECTION:gmenuexporter - * @title: GMenuModel exporter - * @short_description: Export GMenuModels on D-Bus - * @include: gio/gio.h - * @see_also: #GMenuModel, #GDBusMenuModel - * - * These functions support exporting a #GMenuModel on D-Bus. - * The D-Bus interface that is used is a private implementation - * detail. - * - * To access an exported #GMenuModel remotely, use - * g_dbus_menu_model_get() to obtain a #GDBusMenuModel. - */ - /* {{{1 D-Bus Interface description */ /* For documentation of this interface, see diff --git a/gio/gmenumodel.c b/gio/gmenumodel.c index a8c0cfd..9779536 100644 --- a/gio/gmenumodel.c +++ b/gio/gmenumodel.c @@ -27,13 +27,9 @@ #include "gmarshal-internal.h" /** - * SECTION:gmenumodel - * @title: GMenuModel - * @short_description: An abstract class representing the contents of a menu - * @include: gio/gio.h - * @see_also: #GActionGroup + * GMenuModel: * - * #GMenuModel represents the contents of a menu -- an ordered list of + * `GMenuModel` represents the contents of a menu — an ordered list of * menu items. The items are associated with actions, which can be * activated through them. Items can be grouped in sections, and may * have submenus associated with them. Both items and sections usually @@ -41,20 +37,20 @@ * the associated action (ie whether it is stateful, and what kind of * state it has) can influence the representation of the item. * - * The conceptual model of menus in #GMenuModel is hierarchical: - * sections and submenus are again represented by #GMenuModels. + * The conceptual model of menus in `GMenuModel` is hierarchical: + * sections and submenus are again represented by `GMenuModel`s. * Menus themselves do not define their own roles. Rather, the role - * of a particular #GMenuModel is defined by the item that references - * it (or, in the case of the 'root' menu, is defined by the context + * of a particular `GMenuModel` is defined by the item that references + * it (or, in the case of the ‘root’ menu, is defined by the context * in which it is used). * * As an example, consider the visible portions of this menu: * - * ## An example menu # {#menu-example} + * ## An example menu * * ![](menu-example.png) * - * There are 8 "menus" visible in the screenshot: one menubar, two + * There are 8 ‘menus’ visible in the screenshot: one menubar, two * submenus and 5 sections: * * - the toplevel menubar (containing 4 items) @@ -66,17 +62,17 @@ * - the Sources section (containing 2 items) * - the Markup section (containing 2 items) * - * The [example][menu-model] illustrates the conceptual connection between + * The [example](#a-menu-example) illustrates the conceptual connection between * these 8 menus. Each large block in the figure represents a menu and the * smaller blocks within the large block represent items in that menu. Some * items contain references to other menus. * - * ## A menu example # {#menu-model} + * ## A menu example * * ![](menu-model.png) * - * Notice that the separators visible in the [example][menu-example] - * appear nowhere in the [menu model][menu-model]. This is because + * Notice that the separators visible in the [example](#an-example-menu) + * appear nowhere in the [menu model](#a-menu-example). This is because * separators are not explicitly represented in the menu model. Instead, * a separator is inserted between any two non-empty sections of a menu. * Section items can have labels just like any other item. In that case, @@ -85,32 +81,32 @@ * The motivation for this abstract model of application controls is * that modern user interfaces tend to make these controls available * outside the application. Examples include global menus, jumplists, - * dash boards, etc. To support such uses, it is necessary to 'export' + * dash boards, etc. To support such uses, it is necessary to ‘export’ * information about actions and their representation in menus, which - * is exactly what the [GActionGroup exporter][gio-GActionGroup-exporter] - * and the [GMenuModel exporter][gio-GMenuModel-exporter] do for - * #GActionGroup and #GMenuModel. The client-side counterparts to - * make use of the exported information are #GDBusActionGroup and - * #GDBusMenuModel. - * - * The API of #GMenuModel is very generic, with iterators for the - * attributes and links of an item, see g_menu_model_iterate_item_attributes() - * and g_menu_model_iterate_item_links(). The 'standard' attributes and - * link types have predefined names: %G_MENU_ATTRIBUTE_LABEL, - * %G_MENU_ATTRIBUTE_ACTION, %G_MENU_ATTRIBUTE_TARGET, %G_MENU_LINK_SECTION - * and %G_MENU_LINK_SUBMENU. - * - * Items in a #GMenuModel represent active controls if they refer to + * is exactly what the action group exporter and the menu model exporter do for + * [iface@Gio.ActionGroup] and [class@Gio.MenuModel]. The client-side + * counterparts to make use of the exported information are + * [class@Gio.DBusActionGroup] and [class@Gio.DBusMenuModel]. + * + * The API of `GMenuModel` is very generic, with iterators for the + * attributes and links of an item, see + * [method@Gio.MenuModel.iterate_item_attributes] and + * [method@Gio.MenuModel.iterate_item_links]. The ‘standard’ attributes and + * link types have predefined names: `G_MENU_ATTRIBUTE_LABEL`, + * `G_MENU_ATTRIBUTE_ACTION`, `G_MENU_ATTRIBUTE_TARGET`, `G_MENU_LINK_SECTION` + * and `G_MENU_LINK_SUBMENU`. + * + * Items in a `GMenuModel` represent active controls if they refer to * an action that can get activated when the user interacts with the - * menu item. The reference to the action is encoded by the string id - * in the %G_MENU_ATTRIBUTE_ACTION attribute. An action id uniquely + * menu item. The reference to the action is encoded by the string ID + * in the `G_MENU_ATTRIBUTE_ACTION` attribute. An action ID uniquely * identifies an action in an action group. Which action group(s) provide * actions depends on the context in which the menu model is used. * E.g. when the model is exported as the application menu of a - * #GtkApplication, actions can be application-wide or window-specific + * [class@Gtk.Application], actions can be application-wide or window-specific * (and thus come from two different action groups). By convention, the - * application-wide actions have names that start with "app.", while the - * names of window-specific actions start with "win.". + * application-wide actions have names that start with `app.`, while the + * names of window-specific actions start with `win.`. * * While a wide variety of stateful actions is possible, the following * is the minimum that is expected to be supported by all users of exported @@ -119,7 +115,7 @@ * - an action with no parameter type and boolean state * - an action with string parameter type and string state * - * ## Stateless + * ## Stateless * * A stateless action typically corresponds to an ordinary menu item. * @@ -127,12 +123,12 @@ * * ## Boolean State * - * An action with a boolean state will most typically be used with a "toggle" - * or "switch" menu item. The state can be set directly, but activating the + * An action with a boolean state will most typically be used with a ‘toggle’ + * or ‘switch’ menu item. The state can be set directly, but activating the * action (with no parameter) results in the state being toggled. * * Selecting a toggle menu item will activate the action. The menu item should - * be rendered as "checked" when the state is true. + * be rendered as ‘checked’ when the state is true. * * ## String Parameter and State * @@ -144,15 +140,8 @@ * Radio menu items, in addition to being associated with the action, will * have a target value. Selecting that menu item will result in activation * of the action with the target value as the parameter. The menu item should - * be rendered as "selected" when the state of the action is equal to the + * be rendered as ‘selected’ when the state of the action is equal to the * target value of the menu item. - */ - -/** - * GMenuModel: - * - * #GMenuModel is an opaque structure type. You must access it using the - * functions below. * * Since: 2.32 */ diff --git a/gio/gmount.c b/gio/gmount.c index 75d2ce6..9bd8a7d 100644 --- a/gio/gmount.c +++ b/gio/gmount.c @@ -37,30 +37,29 @@ /** - * SECTION:gmount - * @short_description: Mount management - * @include: gio/gio.h - * @see_also: GVolume, GUnixMountEntry, GUnixMountPoint + * GMount: * - * The #GMount interface represents user-visible mounts. Note, when - * porting from GnomeVFS, #GMount is the moral equivalent of #GnomeVFSVolume. + * The `GMount` interface represents user-visible mounts. Note, when + * [porting from GnomeVFS](migrating-gnome-vfs.html), `GMount` is the moral + * equivalent of `GnomeVFSVolume`. * - * #GMount is a "mounted" filesystem that you can access. Mounted is in - * quotes because it's not the same as a unix mount, it might be a gvfs + * `GMount` is a ‘mounted’ filesystem that you can access. Mounted is in + * quotes because it’s not the same as a UNIX mount, it might be a GVFS * mount, but you can still access the files on it if you use GIO. Might or * might not be related to a volume object. * - * Unmounting a #GMount instance is an asynchronous operation. For - * more information about asynchronous operations, see #GAsyncResult - * and #GTask. To unmount a #GMount instance, first call - * g_mount_unmount_with_operation() with (at least) the #GMount instance and a - * #GAsyncReadyCallback. The callback will be fired when the - * operation has resolved (either with success or failure), and a - * #GAsyncResult structure will be passed to the callback. That - * callback should then call g_mount_unmount_with_operation_finish() with the #GMount - * and the #GAsyncResult data to see if the operation was completed - * successfully. If an @error is present when g_mount_unmount_with_operation_finish() - * is called, then it will be filled with any error information. + * Unmounting a `GMount` instance is an asynchronous operation. For + * more information about asynchronous operations, see [iface@Gio.AsyncResult] + * and [class@Gio.Task]. To unmount a `GMount` instance, first call + * [method@Gio.Mount.unmount_with_operation] with (at least) the `GMount` + * instance and a [type@Gio.AsyncReadyCallback]. The callback will be fired + * when the operation has resolved (either with success or failure), and a + * [iface@Gio.AsyncResult] structure will be passed to the callback. That + * callback should then call [method@Gio.Mount.unmount_with_operation_finish] + * with the `GMount` and the [iface@Gio.AsyncResult] data to see if the + * operation was completed successfully. If an `error` is present when + * [method@Gio.Mount.unmount_with_operation_finish] is called, then it will be + * filled with any error information. **/ typedef GMountIface GMountInterface; diff --git a/gio/gmountoperation.c b/gio/gmountoperation.c index d8f5449..a3a74ef 100644 --- a/gio/gmountoperation.c +++ b/gio/gmountoperation.c @@ -31,27 +31,25 @@ /** - * SECTION:gmountoperation - * @short_description: Object used for authentication and user interaction - * @include: gio/gio.h + * GMountOperation: * - * #GMountOperation provides a mechanism for interacting with the user. + * `GMountOperation` provides a mechanism for interacting with the user. * It can be used for authenticating mountable operations, such as loop * mounting files, hard drive partitions or server locations. It can * also be used to ask the user questions or show a list of applications * preventing unmount or eject operations from completing. * - * Note that #GMountOperation is used for more than just #GMount - * objects – for example it is also used in g_drive_start() and - * g_drive_stop(). + * Note that `GMountOperation` is used for more than just [iface@Gio.Mount] + * objects – for example it is also used in [method@Gio.Drive.start] and + * [method@Gio.Drive.stop]. * * Users should instantiate a subclass of this that implements all the * various callbacks to show the required dialogs, such as - * #GtkMountOperation. If no user interaction is desired (for example - * when automounting filesystems at login time), usually %NULL can be - * passed, see each method taking a #GMountOperation for details. + * [class@Gtk.MountOperation]. If no user interaction is desired (for example + * when automounting filesystems at login time), usually `NULL` can be + * passed, see each method taking a `GMountOperation` for details. * - * The term ‘TCRYPT’ is used to mean ‘compatible with TrueCrypt and VeraCrypt’. + * Throughout the API, the term ‘TCRYPT’ is used to mean ‘compatible with TrueCrypt and VeraCrypt’. * [TrueCrypt](https://en.wikipedia.org/wiki/TrueCrypt) is a discontinued system for * encrypting file containers, partitions or whole disks, typically used with Windows. * [VeraCrypt](https://www.veracrypt.fr/) is a maintained fork of TrueCrypt with various @@ -480,9 +478,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_USERNAME, - g_param_spec_string ("username", - P_("Username"), - P_("The user name"), + g_param_spec_string ("username", NULL, NULL, NULL, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -495,9 +491,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_PASSWORD, - g_param_spec_string ("password", - P_("Password"), - P_("The password"), + g_param_spec_string ("password", NULL, NULL, NULL, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -509,9 +503,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_ANONYMOUS, - g_param_spec_boolean ("anonymous", - P_("Anonymous"), - P_("Whether to use an anonymous user"), + g_param_spec_boolean ("anonymous", NULL, NULL, FALSE, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -523,9 +515,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_DOMAIN, - g_param_spec_string ("domain", - P_("Domain"), - P_("The domain of the mount operation"), + g_param_spec_string ("domain", NULL, NULL, NULL, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -537,9 +527,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_PASSWORD_SAVE, - g_param_spec_enum ("password-save", - P_("Password save"), - P_("How passwords should be saved"), + g_param_spec_enum ("password-save", NULL, NULL, G_TYPE_PASSWORD_SAVE, G_PASSWORD_SAVE_NEVER, G_PARAM_READWRITE| @@ -553,9 +541,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_CHOICE, - g_param_spec_int ("choice", - P_("Choice"), - P_("The users choice"), + g_param_spec_int ("choice", NULL, NULL, 0, G_MAXINT, 0, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -570,9 +556,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_IS_TCRYPT_HIDDEN_VOLUME, - g_param_spec_boolean ("is-tcrypt-hidden-volume", - P_("TCRYPT Hidden Volume"), - P_("Whether to unlock a TCRYPT hidden volume. See https://www.veracrypt.fr/en/Hidden%20Volume.html."), + g_param_spec_boolean ("is-tcrypt-hidden-volume", NULL, NULL, FALSE, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -590,9 +574,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_IS_TCRYPT_SYSTEM_VOLUME, - g_param_spec_boolean ("is-tcrypt-system-volume", - P_("TCRYPT System Volume"), - P_("Whether to unlock a TCRYPT system volume. Only supported for unlocking Windows system volumes. See https://www.veracrypt.fr/en/System%20Encryption.html."), + g_param_spec_boolean ("is-tcrypt-system-volume", NULL, NULL, FALSE, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); @@ -607,9 +589,7 @@ g_mount_operation_class_init (GMountOperationClass *klass) */ g_object_class_install_property (object_class, PROP_PIM, - g_param_spec_uint ("pim", - P_("PIM"), - P_("The VeraCrypt PIM value"), + g_param_spec_uint ("pim", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE| G_PARAM_STATIC_NAME|G_PARAM_STATIC_NICK|G_PARAM_STATIC_BLURB)); diff --git a/gio/gmountoperation.h b/gio/gmountoperation.h index b763f0d..3302ec5 100644 --- a/gio/gmountoperation.h +++ b/gio/gmountoperation.h @@ -38,12 +38,6 @@ G_BEGIN_DECLS #define G_IS_MOUNT_OPERATION_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_MOUNT_OPERATION)) #define G_MOUNT_OPERATION_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_MOUNT_OPERATION, GMountOperationClass)) -/** - * GMountOperation: - * - * Class for providing authentication methods for mounting operations, - * such as mounting a file locally, or authenticating with a server. - **/ typedef struct _GMountOperationClass GMountOperationClass; typedef struct _GMountOperationPrivate GMountOperationPrivate; diff --git a/gio/gnativesocketaddress.c b/gio/gnativesocketaddress.c index 28b90a8..c2c47a1 100644 --- a/gio/gnativesocketaddress.c +++ b/gio/gnativesocketaddress.c @@ -32,18 +32,14 @@ /** - * SECTION:gnativesocketaddress - * @short_description: Native GSocketAddress - * @include: gio/gio.h + * GNativeSocketAddress: * * A socket address of some unknown native type. - */ - -/** - * GNativeSocketAddress: * - * A socket address, corresponding to a general struct - * sockadd address of a type not otherwise handled by glib. + * This corresponds to a general `struct sockaddr` of a type not otherwise + * handled by GLib. + * + * Since: 2.46 */ struct _GNativeSocketAddressPrivate diff --git a/gio/gnetworkaddress.c b/gio/gnetworkaddress.c index a4ee538..adff705 100644 --- a/gio/gnetworkaddress.c +++ b/gio/gnetworkaddress.c @@ -46,11 +46,9 @@ #define HAPPY_EYEBALLS_RESOLUTION_DELAY_MS 50 /** - * SECTION:gnetworkaddress - * @short_description: A GSocketConnectable for resolving hostnames - * @include: gio/gio.h + * GNetworkAddress: * - * #GNetworkAddress provides an easy way to resolve a hostname and + * `GNetworkAddress` provides an easy way to resolve a hostname and * then attempt to connect to that host, handling the possibility of * multiple IP addresses and multiple address families. * @@ -58,17 +56,10 @@ * as this object is kept alive which may have unexpected results if * alive for too long. * - * See #GSocketConnectable for an example of using the connectable + * See [iface@Gio.SocketConnectable] for an example of using the connectable * interface. */ -/** - * GNetworkAddress: - * - * A #GSocketConnectable for resolving a hostname and connecting to - * that host. - */ - struct _GNetworkAddressPrivate { gchar *hostname; guint16 port; @@ -125,27 +116,43 @@ g_network_address_class_init (GNetworkAddressClass *klass) gobject_class->get_property = g_network_address_get_property; gobject_class->finalize = g_network_address_finalize; + /** + * GNetworkAddress:hostname: + * + * Hostname to resolve. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_HOSTNAME, - g_param_spec_string ("hostname", - P_("Hostname"), - P_("Hostname to resolve"), + g_param_spec_string ("hostname", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GNetworkAddress:port: + * + * Network port. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PORT, - g_param_spec_uint ("port", - P_("Port"), - P_("Network port"), + g_param_spec_uint ("port", NULL, NULL, 0, 65535, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GNetworkAddress:scheme: + * + * URI scheme. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_SCHEME, - g_param_spec_string ("scheme", - P_("Scheme"), - P_("URI Scheme"), + g_param_spec_string ("scheme", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gnetworking.c b/gio/gnetworking.c index d0c00c9..08346cd 100644 --- a/gio/gnetworking.c +++ b/gio/gnetworking.c @@ -26,31 +26,6 @@ #include "gnetworkingprivate.h" /** - * SECTION:gnetworking - * @title: gnetworking.h - * @short_description: System networking includes - * @include: gio/gnetworking.h - * - * The `` header can be included to get - * various low-level networking-related system headers, automatically - * taking care of certain portability issues for you. - * - * This can be used, for example, if you want to call setsockopt() - * on a #GSocket. - * - * Note that while WinSock has many of the same APIs as the - * traditional UNIX socket API, most of them behave at least slightly - * differently (particularly with respect to error handling). If you - * want your code to work under both UNIX and Windows, you will need - * to take these differences into account. - * - * Also, under GNU libc, certain non-portable functions are only visible - * in the headers if you define %_GNU_SOURCE before including them. Note - * that this symbol must be defined before including any headers, or it - * may not take effect. - */ - -/** * g_networking_init: * * Initializes the platform networking libraries (eg, on Windows, this diff --git a/gio/gnetworking.h.in b/gio/gnetworking.h.in index 3561239..3dddd90 100644 --- a/gio/gnetworking.h.in +++ b/gio/gnetworking.h.in @@ -49,6 +49,8 @@ #include @NAMESER_COMPAT_INCLUDE@ +#ifndef __GI_SCANNER__ + #ifndef T_SRV #define T_SRV 33 #endif @@ -71,6 +73,8 @@ #endif #endif +#endif /* !__GI_SCANNER__ */ + G_BEGIN_DECLS GIO_AVAILABLE_IN_2_36 diff --git a/gio/gnetworkmonitor.c b/gio/gnetworkmonitor.c index 37f2faa..5065041 100644 --- a/gio/gnetworkmonitor.c +++ b/gio/gnetworkmonitor.c @@ -31,24 +31,14 @@ #include "gtask.h" /** - * SECTION:gnetworkmonitor - * @title: GNetworkMonitor - * @short_description: Network status monitor - * @include: gio/gio.h + * GNetworkMonitor: * - * #GNetworkMonitor provides an easy-to-use cross-platform API + * `GNetworkMonitor` provides an easy-to-use cross-platform API * for monitoring network connectivity. On Linux, the available * implementations are based on the kernel's netlink interface and * on NetworkManager. * * There is also an implementation for use inside Flatpak sandboxes. - */ - -/** - * GNetworkMonitor: - * - * #GNetworkMonitor monitors the status of network connections and - * indicates when a possibly-user-visible change has occurred. * * Since: 2.32 */ @@ -94,7 +84,7 @@ static GNetworkMonitor *network_monitor_default_singleton = NULL; /* (owned) (a GNetworkMonitor * g_network_monitor_get_default (void) { - if (g_once_init_enter (&network_monitor_default_singleton)) + if (g_once_init_enter_pointer (&network_monitor_default_singleton)) { GNetworkMonitor *singleton; @@ -102,7 +92,7 @@ g_network_monitor_get_default (void) "GIO_USE_NETWORK_MONITOR", NULL); - g_once_init_leave (&network_monitor_default_singleton, singleton); + g_once_init_leave_pointer (&network_monitor_default_singleton, singleton); } return network_monitor_default_singleton; @@ -362,9 +352,7 @@ g_network_monitor_default_init (GNetworkMonitorInterface *iface) * Since: 2.32 */ g_object_interface_install_property (iface, - g_param_spec_boolean ("network-available", - P_("Network available"), - P_("Whether the network is available"), + g_param_spec_boolean ("network-available", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -397,9 +385,7 @@ g_network_monitor_default_init (GNetworkMonitorInterface *iface) * Since: 2.46 */ g_object_interface_install_property (iface, - g_param_spec_boolean ("network-metered", - P_("Network metered"), - P_("Whether the network is metered"), + g_param_spec_boolean ("network-metered", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -414,9 +400,7 @@ g_network_monitor_default_init (GNetworkMonitorInterface *iface) * Since: 2.44 */ g_object_interface_install_property (iface, - g_param_spec_enum ("connectivity", - P_("Network connectivity"), - P_("Level of network connectivity"), + g_param_spec_enum ("connectivity", NULL, NULL, G_TYPE_NETWORK_CONNECTIVITY, G_NETWORK_CONNECTIVITY_FULL, G_PARAM_READABLE | diff --git a/gio/gnetworkmonitorbase.c b/gio/gnetworkmonitorbase.c index 4654d22..78e2634 100644 --- a/gio/gnetworkmonitorbase.c +++ b/gio/gnetworkmonitorbase.c @@ -285,8 +285,9 @@ can_reach_async_got_address (GObject *object, else { /* Resolved all addresses, none matched */ - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, - _("Host unreachable")); + g_task_return_new_error_literal (task, G_IO_ERROR, + G_IO_ERROR_HOST_UNREACHABLE, + _("Host unreachable")); g_object_unref (task); return; } @@ -321,8 +322,8 @@ g_network_monitor_base_can_reach_async (GNetworkMonitor *monitor, if (g_hash_table_size (G_NETWORK_MONITOR_BASE (monitor)->priv->networks) == 0) { - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE, - _("Network unreachable")); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_NETWORK_UNREACHABLE, + _("Network unreachable")); g_object_unref (task); return; } diff --git a/gio/gnetworkmonitorportal.c b/gio/gnetworkmonitorportal.c index bc51178..f48d3e6 100644 --- a/gio/gnetworkmonitorportal.c +++ b/gio/gnetworkmonitorportal.c @@ -561,9 +561,9 @@ can_reach_done (GObject *source, if (reachable) g_task_return_boolean (task, TRUE); else - g_task_return_new_error (task, - G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, - "Can't reach host"); + g_task_return_new_error_literal (task, + G_IO_ERROR, G_IO_ERROR_HOST_UNREACHABLE, + "Can't reach host"); g_object_unref (task); } diff --git a/gio/gnetworkservice.c b/gio/gnetworkservice.c index dac0814..39c9df1 100644 --- a/gio/gnetworkservice.c +++ b/gio/gnetworkservice.c @@ -43,28 +43,19 @@ /** - * SECTION:gnetworkservice - * @short_description: A GSocketConnectable for resolving SRV records - * @include: gio/gio.h + * GNetworkService: * - * Like #GNetworkAddress does with hostnames, #GNetworkService + * Like [class@Gio.NetworkAddress] does with hostnames, `GNetworkService` * provides an easy way to resolve a SRV record, and then attempt to * connect to one of the hosts that implements that service, handling * service priority/weighting, multiple IP addresses, and multiple * address families. * - * See #GSrvTarget for more information about SRV records, and see - * #GSocketConnectable for an example of using the connectable + * See [struct@Gio.SrvTarget] for more information about SRV records, and see + * [iface@Gio.SocketConnectable] for an example of using the connectable * interface. */ -/** - * GNetworkService: - * - * A #GSocketConnectable for resolving a SRV record and connecting to - * that service. - */ - struct _GNetworkServicePrivate { gchar *service, *protocol, *domain, *scheme; @@ -123,34 +114,57 @@ g_network_service_class_init (GNetworkServiceClass *klass) gobject_class->get_property = g_network_service_get_property; gobject_class->finalize = g_network_service_finalize; + /** + * GNetworkService:service: + * + * Service name, for example `ldap`. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_SERVICE, - g_param_spec_string ("service", - P_("Service"), - P_("Service name, eg \"ldap\""), + g_param_spec_string ("service", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GNetworkService:protocol: + * + * Network protocol, for example `tcp`. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PROTOCOL, - g_param_spec_string ("protocol", - P_("Protocol"), - P_("Network protocol, eg \"tcp\""), + g_param_spec_string ("protocol", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GNetworkService:domain: + * + * Network domain, for example `example.com`. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_DOMAIN, - g_param_spec_string ("domain", - P_("Domain"), - P_("Network domain, eg, \"example.com\""), + g_param_spec_string ("domain", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GNetworkService:scheme: + * + * Network scheme (default is to use service). + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_DOMAIN, - g_param_spec_string ("scheme", - P_("Scheme"), - P_("Network scheme (default is to use service)"), + g_param_spec_string ("scheme", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gnotification.c b/gio/gnotification.c index abe68a2..0e48ef0 100644 --- a/gio/gnotification.c +++ b/gio/gnotification.c @@ -28,63 +28,53 @@ #include "gioenumtypes.h" /** - * SECTION:gnotification - * @short_description: User Notifications (pop up messages) - * @include: gio/gio.h + * GNotification: * - * #GNotification is a mechanism for creating a notification to be shown - * to the user -- typically as a pop-up notification presented by the + * `GNotification` is a mechanism for creating a notification to be shown + * to the user — typically as a pop-up notification presented by the * desktop environment shell. * - * The key difference between #GNotification and other similar APIs is + * The key difference between `GNotification` and other similar APIs is * that, if supported by the desktop environment, notifications sent - * with #GNotification will persist after the application has exited, + * with `GNotification` will persist after the application has exited, * and even across system reboots. * * Since the user may click on a notification while the application is - * not running, applications using #GNotification should be able to be - * started as a D-Bus service, using #GApplication. + * not running, applications using `GNotification` should be able to be + * started as a D-Bus service, using [class@Gio.Application]. * - * In order for #GNotification to work, the application must have installed + * In order for `GNotification` to work, the application must have installed * a `.desktop` file. For example: - * |[ - * [Desktop Entry] - * Name=Test Application - * Comment=Description of what Test Application does - * Exec=gnome-test-application - * Icon=org.gnome.TestApplication - * Terminal=false - * Type=Application - * Categories=GNOME;GTK;TestApplication Category; - * StartupNotify=true - * DBusActivatable=true - * X-GNOME-UsesNotifications=true - * ]| + * ``` + * [Desktop Entry] + * Name=Test Application + * Comment=Description of what Test Application does + * Exec=gnome-test-application + * Icon=org.gnome.TestApplication + * Terminal=false + * Type=Application + * Categories=GNOME;GTK;TestApplication Category; + * StartupNotify=true + * DBusActivatable=true + * X-GNOME-UsesNotifications=true + * ``` * * The `X-GNOME-UsesNotifications` key indicates to GNOME Control Center * that this application uses notifications, so it can be listed in the * Control Center’s ‘Notifications’ panel. * * The `.desktop` file must be named as `org.gnome.TestApplication.desktop`, - * where `org.gnome.TestApplication` is the ID passed to g_application_new(). + * where `org.gnome.TestApplication` is the ID passed to + * [ctor@Gio.Application.new]. * * User interaction with a notification (either the default action, or * buttons) must be associated with actions on the application (ie: - * "app." actions). It is not possible to route user interaction + * `app.` actions). It is not possible to route user interaction * through the notification itself, because the object will not exist if * the application is autostarted as a result of a notification being * clicked. * - * A notification can be sent with g_application_send_notification(). - * - * Since: 2.40 - **/ - -/** - * GNotification: - * - * This structure type is private and should only be accessed using the - * public APIs. + * A notification can be sent with [method@Gio.Application.send_notification]. * * Since: 2.40 **/ diff --git a/gio/gopenuriportal.c b/gio/gopenuriportal.c index c0f44a9..083d271 100644 --- a/gio/gopenuriportal.c +++ b/gio/gopenuriportal.c @@ -182,11 +182,11 @@ response_received (GDBusConnection *connection, g_task_return_boolean (task, TRUE); break; case XDG_DESKTOP_PORTAL_CANCELLED: - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Launch cancelled"); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_CANCELLED, "Launch cancelled"); break; case XDG_DESKTOP_PORTAL_FAILED: default: - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Launch failed"); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, "Launch failed"); break; } diff --git a/gio/gosxappinfo.m b/gio/gosxappinfo.m index 60b0886..50b08e0 100644 --- a/gio/gosxappinfo.m +++ b/gio/gosxappinfo.m @@ -33,12 +33,10 @@ #import /** - * SECTION:gosxappinfo - * @title: GOsxAppInfo - * @short_description: Application information from NSBundles - * @include: gio/gosxappinfo.h + * GOsxAppInfo: * - * #GOsxAppInfo is an implementation of #GAppInfo based on NSBundle information. + * `GOsxAppInfo` is an implementation of [iface@Gio.AppInfo] based on `NSBundle` + * information. * * Note that `` is unique to OSX. */ @@ -46,11 +44,6 @@ static void g_osx_app_info_iface_init (GAppInfoIface *iface); static const char *g_osx_app_info_get_id (GAppInfo *appinfo); -/** - * GOsxAppInfo: - * - * Information about an installed application from a NSBundle. - */ struct _GOsxAppInfo { GObject parent_instance; diff --git a/gio/goutputstream.c b/gio/goutputstream.c index 3674a92..1348208 100644 --- a/gio/goutputstream.c +++ b/gio/goutputstream.c @@ -33,21 +33,25 @@ #include "gpollableoutputstream.h" /** - * SECTION:goutputstream - * @short_description: Base class for implementing streaming output - * @include: gio/gio.h + * GOutputStream: * - * #GOutputStream has functions to write to a stream (g_output_stream_write()), - * to close a stream (g_output_stream_close()) and to flush pending writes - * (g_output_stream_flush()). + * `GOutputStream` is a base class for implementing streaming output. + * + * It has functions to write to a stream ([method@Gio.OutputStream.write]), + * to close a stream ([method@Gio.OutputStream.close]) and to flush pending + * writes ([method@Gio.OutputStream.flush]). * * To copy the content of an input stream to an output stream without - * manually handling the reads and writes, use g_output_stream_splice(). + * manually handling the reads and writes, use [method@Gio.OutputStream.splice]. * - * See the documentation for #GIOStream for details of thread safety of - * streaming APIs. + * See the documentation for [class@Gio.IOStream] for details of thread safety + * of streaming APIs. * * All of these functions have async variants too. + * + * All classes derived from `GOutputStream` *should* implement synchronous + * writing, splicing, flushing and closing streams, but *may* implement + * asynchronous versions. **/ struct _GOutputStreamPrivate { @@ -171,7 +175,7 @@ g_output_stream_init (GOutputStream *stream) } /** - * g_output_stream_write: + * g_output_stream_write: (virtual write_fn) * @stream: a #GOutputStream. * @buffer: (array length=count) (element-type guint8): the buffer containing the data to write. * @count: the number of bytes to write @@ -199,8 +203,6 @@ g_output_stream_init (GOutputStream *stream) * * On error -1 is returned and @error is set accordingly. * - * Virtual: write_fn - * * Returns: Number of bytes written, or -1 on error **/ gssize @@ -320,7 +322,7 @@ g_output_stream_write_all (GOutputStream *stream, } /** - * g_output_stream_writev: + * g_output_stream_writev: (virtual writev_fn) * @stream: a #GOutputStream. * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write. * @n_vectors: the number of vectors to write @@ -353,8 +355,6 @@ g_output_stream_write_all (GOutputStream *stream, * are exceeded. For example, when writing to a local file on UNIX platforms, * the aggregate buffer size must not exceed %G_MAXSSIZE bytes. * - * Virtual: writev_fn - * * Returns: %TRUE on success, %FALSE if there was an error * * Since: 2.60 @@ -1764,9 +1764,9 @@ g_output_stream_splice_async (GOutputStream *stream, if (g_input_stream_is_closed (source)) { - g_task_return_new_error (task, - G_IO_ERROR, G_IO_ERROR_CLOSED, - _("Source stream is already closed")); + g_task_return_new_error_literal (task, + G_IO_ERROR, G_IO_ERROR_CLOSED, + _("Source stream is already closed")); g_object_unref (task); return; } diff --git a/gio/goutputstream.h b/gio/goutputstream.h index b5fafe9..2ee1cbb 100644 --- a/gio/goutputstream.h +++ b/gio/goutputstream.h @@ -38,15 +38,6 @@ G_BEGIN_DECLS #define G_IS_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_OUTPUT_STREAM)) #define G_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_OUTPUT_STREAM, GOutputStreamClass)) -/** - * GOutputStream: - * - * Base class for writing output. - * - * All classes derived from GOutputStream should implement synchronous - * writing, splicing, flushing and closing streams, but may implement - * asynchronous versions. - **/ typedef struct _GOutputStreamClass GOutputStreamClass; typedef struct _GOutputStreamPrivate GOutputStreamPrivate; diff --git a/gio/gpermission.c b/gio/gpermission.c index 957e57f..da82d4b 100644 --- a/gio/gpermission.c +++ b/gio/gpermission.c @@ -31,13 +31,9 @@ /** - * SECTION:gpermission - * @title: GPermission - * @short_description: An object representing the permission - * to perform a certain action - * @include: gio/gio.h + * GPermission: * - * A #GPermission represents the status of the caller's permission to + * A `GPermission` represents the status of the caller’s permission to * perform a certain action. * * You can query if the action is currently allowed and if it is @@ -47,20 +43,13 @@ * There is also an API to actually acquire the permission and one to * release it. * - * As an example, a #GPermission might represent the ability for the - * user to write to a #GSettings object. This #GPermission object could - * then be used to decide if it is appropriate to show a "Click here to - * unlock" button in a dialog and to provide the mechanism to invoke + * As an example, a `GPermission` might represent the ability for the + * user to write to a [class@Gio.Settings] object. This `GPermission` object + * could then be used to decide if it is appropriate to show a “Click here to + * unlock” button in a dialog and to provide the mechanism to invoke * when that button is clicked. **/ -/** - * GPermission: - * - * #GPermission is an opaque data structure and can only be accessed - * using the following functions. - **/ - struct _GPermissionPrivate { gboolean allowed; @@ -444,9 +433,7 @@ g_permission_class_init (GPermissionClass *class) * @permission represents the permission to perform. */ g_object_class_install_property (object_class, PROP_ALLOWED, - g_param_spec_boolean ("allowed", - P_("Is allowed"), - P_("If the caller is allowed to perform the action"), + g_param_spec_boolean ("allowed", NULL, NULL, FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); @@ -457,9 +444,7 @@ g_permission_class_init (GPermissionClass *class) * g_permission_acquire(). */ g_object_class_install_property (object_class, PROP_CAN_ACQUIRE, - g_param_spec_boolean ("can-acquire", - P_("Can acquire"), - P_("If calling g_permission_acquire() makes sense"), + g_param_spec_boolean ("can-acquire", NULL, NULL, FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); @@ -470,9 +455,7 @@ g_permission_class_init (GPermissionClass *class) * g_permission_release(). */ g_object_class_install_property (object_class, PROP_CAN_RELEASE, - g_param_spec_boolean ("can-release", - P_("Can release"), - P_("If calling g_permission_release() makes sense"), + g_param_spec_boolean ("can-release", NULL, NULL, FALSE, G_PARAM_STATIC_STRINGS | G_PARAM_READABLE)); } diff --git a/gio/gpollableinputstream.c b/gio/gpollableinputstream.c index 3f76cb6..a57d5ab 100644 --- a/gio/gpollableinputstream.c +++ b/gio/gpollableinputstream.c @@ -27,19 +27,16 @@ #include "glibintl.h" /** - * SECTION:gpollableinputstream - * @short_description: Interface for pollable input streams - * @include: gio/gio.h - * @see_also: #GInputStream, #GPollableOutputStream, #GFileDescriptorBased + * GPollableInputStream: * - * #GPollableInputStream is implemented by #GInputStreams that + * `GPollableInputStream` is implemented by [class@Gio.InputStream]s that * can be polled for readiness to read. This can be used when * interfacing with a non-GIO API that expects * UNIX-file-descriptor-style asynchronous I/O rather than GIO-style. * - * Some classes may implement #GPollableInputStream but have only certain - * instances of that class be pollable. If g_pollable_input_stream_can_poll() - * returns %FALSE, then the behavior of other #GPollableInputStream methods is + * Some classes may implement `GPollableInputStream` but have only certain + * instances of that class be pollable. If [method@Gio.PollableInputStream.can_poll] + * returns false, then the behavior of other `GPollableInputStream` methods is * undefined. * * Since: 2.28 @@ -170,7 +167,7 @@ g_pollable_input_stream_default_read_nonblocking (GPollableInputStream *stream, } /** - * g_pollable_input_stream_read_nonblocking: + * g_pollable_input_stream_read_nonblocking: (virtual read_nonblocking) * @stream: a #GPollableInputStream * @buffer: (array length=count) (element-type guint8) (out caller-allocates): a * buffer to read data into (which should be at least @count bytes long). @@ -193,7 +190,6 @@ g_pollable_input_stream_default_read_nonblocking (GPollableInputStream *stream, * The behaviour of this method is undefined if * g_pollable_input_stream_can_poll() returns %FALSE for @stream. * - * Virtual: read_nonblocking * Returns: the number of bytes read, or -1 on error (including * %G_IO_ERROR_WOULD_BLOCK). */ diff --git a/gio/gpollableinputstream.h b/gio/gpollableinputstream.h index 7b65947..924b52e 100644 --- a/gio/gpollableinputstream.h +++ b/gio/gpollableinputstream.h @@ -34,13 +34,6 @@ G_BEGIN_DECLS #define G_IS_POLLABLE_INPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_POLLABLE_INPUT_STREAM)) #define G_POLLABLE_INPUT_STREAM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_POLLABLE_INPUT_STREAM, GPollableInputStreamInterface)) -/** - * GPollableInputStream: - * - * An interface for a #GInputStream that can be polled for readability. - * - * Since: 2.28 - */ typedef struct _GPollableInputStreamInterface GPollableInputStreamInterface; /** diff --git a/gio/gpollableoutputstream.c b/gio/gpollableoutputstream.c index f33267a..f36ac13 100644 --- a/gio/gpollableoutputstream.c +++ b/gio/gpollableoutputstream.c @@ -28,19 +28,16 @@ #include "glibintl.h" /** - * SECTION:gpollableoutputstream - * @short_description: Interface for pollable output streams - * @include: gio/gio.h - * @see_also: #GOutputStream, #GFileDescriptorBased, #GPollableInputStream + * GPollableOutputStream: * - * #GPollableOutputStream is implemented by #GOutputStreams that + * `GPollableOutputStream` is implemented by [class@Gio.OutputStream]s that * can be polled for readiness to write. This can be used when * interfacing with a non-GIO API that expects * UNIX-file-descriptor-style asynchronous I/O rather than GIO-style. * - * Some classes may implement #GPollableOutputStream but have only certain - * instances of that class be pollable. If g_pollable_output_stream_can_poll() - * returns %FALSE, then the behavior of other #GPollableOutputStream methods is + * Some classes may implement `GPollableOutputStream` but have only certain + * instances of that class be pollable. If [method@Gio.PollableOutputStream.can_poll] + * returns false, then the behavior of other `GPollableOutputStream` methods is * undefined. * * Since: 2.28 @@ -238,7 +235,7 @@ g_pollable_output_stream_default_writev_nonblocking (GPollableOutputStream *str } /** - * g_pollable_output_stream_write_nonblocking: + * g_pollable_output_stream_write_nonblocking: (virtual write_nonblocking) * @stream: a #GPollableOutputStream * @buffer: (array length=count) (element-type guint8): a buffer to write * data from @@ -265,7 +262,6 @@ g_pollable_output_stream_default_writev_nonblocking (GPollableOutputStream *str * The behaviour of this method is undefined if * g_pollable_output_stream_can_poll() returns %FALSE for @stream. * - * Virtual: write_nonblocking * Returns: the number of bytes written, or -1 on error (including * %G_IO_ERROR_WOULD_BLOCK). */ @@ -307,7 +303,7 @@ g_pollable_output_stream_write_nonblocking (GPollableOutputStream *stream, } /** - * g_pollable_output_stream_writev_nonblocking: + * g_pollable_output_stream_writev_nonblocking: (virtual writev_nonblocking) * @stream: a #GPollableOutputStream * @vectors: (array length=n_vectors): the buffer containing the #GOutputVectors to write. * @n_vectors: the number of vectors to write @@ -336,8 +332,6 @@ g_pollable_output_stream_write_nonblocking (GPollableOutputStream *stream, * The behaviour of this method is undefined if * g_pollable_output_stream_can_poll() returns %FALSE for @stream. * - * Virtual: writev_nonblocking - * * Returns: %@G_POLLABLE_RETURN_OK on success, %G_POLLABLE_RETURN_WOULD_BLOCK * if the stream is not currently writable (and @error is *not* set), or * %G_POLLABLE_RETURN_FAILED if there was an error in which case @error will diff --git a/gio/gpollableoutputstream.h b/gio/gpollableoutputstream.h index a98bfa2..e20c2f3 100644 --- a/gio/gpollableoutputstream.h +++ b/gio/gpollableoutputstream.h @@ -34,13 +34,6 @@ G_BEGIN_DECLS #define G_IS_POLLABLE_OUTPUT_STREAM(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_POLLABLE_OUTPUT_STREAM)) #define G_POLLABLE_OUTPUT_STREAM_GET_INTERFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_POLLABLE_OUTPUT_STREAM, GPollableOutputStreamInterface)) -/** - * GPollableOutputStream: - * - * An interface for a #GOutputStream that can be polled for writeability. - * - * Since: 2.28 - */ typedef struct _GPollableOutputStreamInterface GPollableOutputStreamInterface; /** diff --git a/gio/gpollableutils.c b/gio/gpollableutils.c index 376a1cf..214b437 100644 --- a/gio/gpollableutils.c +++ b/gio/gpollableutils.c @@ -26,15 +26,6 @@ #include "gasynchelper.h" #include "glibintl.h" -/** - * SECTION:gpollableutils - * @short_description: Utilities for pollable streams - * @include: gio/gio.h - * - * Utility functions for #GPollableInputStream and - * #GPollableOutputStream implementations. - */ - typedef struct { GSource source; diff --git a/gio/gportalsupport.c b/gio/gportalsupport.c index 7e1da22..b002e93 100644 --- a/gio/gportalsupport.c +++ b/gio/gportalsupport.c @@ -125,7 +125,7 @@ sandbox_info_read (void) { const char *var; - var = g_getenv ("GTK_USE_PORTAL"); + var = g_getenv ("GIO_USE_PORTALS"); if (var && var[0] == '1') use_portal = TRUE; network_available = TRUE; diff --git a/gio/gpowerprofilemonitor.c b/gio/gpowerprofilemonitor.c index 9c22411..12f7dd6 100644 --- a/gio/gpowerprofilemonitor.c +++ b/gio/gpowerprofilemonitor.c @@ -32,15 +32,12 @@ #include "gtask.h" /** - * SECTION:gpowerprofilemonitor - * @title: GPowerProfileMonitor - * @short_description: Power profile monitor - * @include: gio/gio.h + * GPowerProfileMonitor: * - * #GPowerProfileMonitor makes it possible for applications as well as OS components - * to monitor system power profiles and act upon them. It currently only exports - * whether the system is in “Power Saver” mode (known as “Low Power” mode on - * some systems). + * `GPowerProfileMonitor` makes it possible for applications as well as OS + * components to monitor system power profiles and act upon them. It currently + * only exports whether the system is in “Power Saver” mode (known as + * “Low Power” mode on some systems). * * When in “Low Power” mode, it is recommended that applications: * - disable automatic downloads; @@ -57,17 +54,9 @@ * or activity at all), `sysprof` to inspect CPU usage, and `intel_gpu_time` to * profile GPU usage. * - * Don't forget to disconnect the #GPowerProfileMonitor::notify::power-saver-enabled - * signal, and unref the #GPowerProfileMonitor itself when exiting. - * - * Since: 2.70 - */ - -/** - * GPowerProfileMonitor: - * - * #GPowerProfileMonitor monitors system power profile and notifies on - * changes. + * Don’t forget to disconnect the [signal@GObject.Object::notify] signal for + * [property@Gio.PowerProfileMonitor:power-saver-enabled], and unref the + * `GPowerProfileMonitor` itself when exiting. * * Since: 2.70 */ @@ -135,9 +124,7 @@ g_power_profile_monitor_default_init (GPowerProfileMonitorInterface *iface) * Since: 2.70 */ g_object_interface_install_property (iface, - g_param_spec_boolean ("power-saver-enabled", - "power-saver-enabled", - "Power Saver Enabled", + g_param_spec_boolean ("power-saver-enabled", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY)); } diff --git a/gio/gpropertyaction.c b/gio/gpropertyaction.c index 52eae84..a249806 100644 --- a/gio/gpropertyaction.c +++ b/gio/gpropertyaction.c @@ -28,17 +28,14 @@ #include "glibintl.h" /** - * SECTION:gpropertyaction - * @title: GPropertyAction - * @short_description: A GAction reflecting a GObject property - * @include: gio/gio.h + * GPropertyAction: * - * A #GPropertyAction is a way to get a #GAction with a state value - * reflecting and controlling the value of a #GObject property. + * A `GPropertyAction` is a way to get a [iface@Gio.Action] with a state value + * reflecting and controlling the value of a [class@GObject.Object] property. * * The state of the action will correspond to the value of the property. * Changing it will change the property (assuming the requested value - * matches the requirements as specified in the #GParamSpec). + * matches the requirements as specified in the [type@GObject.ParamSpec]). * * Only the most common types are presently supported. Booleans are * mapped to booleans, strings to strings, signed/unsigned integers to @@ -46,16 +43,16 @@ * * If the property is an enum then the state will be string-typed and * conversion will automatically be performed between the enum value and - * "nick" string as per the #GEnumValue table. + * ‘nick’ string as per the [type@GObject.EnumValue] table. * * Flags types are not currently supported. * * Properties of object types, boxed types and pointer types are not * supported and probably never will be. * - * Properties of #GVariant types are not currently supported. + * Properties of [type@GLib.Variant] types are not currently supported. * - * If the property is boolean-valued then the action will have a NULL + * If the property is boolean-valued then the action will have a `NULL` * parameter type, and activating the action (with no parameter) will * toggle the value of the property. * @@ -64,26 +61,26 @@ * * The general idea here is to reduce the number of locations where a * particular piece of state is kept (and therefore has to be synchronised - * between). #GPropertyAction does not have a separate state that is kept - * in sync with the property value -- its state is the property value. + * between). `GPropertyAction` does not have a separate state that is kept + * in sync with the property value — its state is the property value. * - * For example, it might be useful to create a #GAction corresponding to - * the "visible-child-name" property of a #GtkStack so that the current - * page can be switched from a menu. The active radio indication in the + * For example, it might be useful to create a [iface@Gio.Action] corresponding + * to the `visible-child-name` property of a [class@Gtk.Stack] so that the + * current page can be switched from a menu. The active radio indication in the * menu is then directly determined from the active page of the - * #GtkStack. + * [class@Gtk.Stack]. * - * An anti-example would be binding the "active-id" property on a - * #GtkComboBox. This is because the state of the combobox itself is + * An anti-example would be binding the `active-id` property on a + * [class@Gtk.ComboBox]. This is because the state of the combobox itself is * probably uninteresting and is actually being used to control * something else. * - * Another anti-example would be to bind to the "visible-child-name" - * property of a #GtkStack if this value is actually stored in - * #GSettings. In that case, the real source of the value is - * #GSettings. If you want a #GAction to control a setting stored in - * #GSettings, see g_settings_create_action() instead, and possibly - * combine its use with g_settings_bind(). + * Another anti-example would be to bind to the `visible-child-name` + * property of a [class@Gtk.Stack] if this value is actually stored in + * [class@Gio.Settings]. In that case, the real source of the value is + * [class@Gio.Settings]. If you want a [iface@Gio.Action] to control a setting + * stored in [class@Gio.Settings], see [method@Gio.Settings.create_action] + * instead, and possibly combine its use with [method@Gio.Settings.bind]. * * Since: 2.38 **/ @@ -98,14 +95,6 @@ struct _GPropertyAction gboolean invert_boolean; }; -/** - * GPropertyAction: - * - * This type is opaque. - * - * Since: 2.38 - **/ - typedef GObjectClass GPropertyActionClass; static void g_property_action_iface_init (GActionInterface *iface); @@ -478,9 +467,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_NAME, - g_param_spec_string ("name", - P_("Action Name"), - P_("The name used to invoke the action"), + g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -495,9 +482,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_PARAMETER_TYPE, - g_param_spec_boxed ("parameter-type", - P_("Parameter Type"), - P_("The type of GVariant passed to activate()"), + g_param_spec_boxed ("parameter-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -513,9 +498,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_ENABLED, - g_param_spec_boolean ("enabled", - P_("Enabled"), - P_("If the action can be activated"), + g_param_spec_boolean ("enabled", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -529,9 +512,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_STATE_TYPE, - g_param_spec_boxed ("state-type", - P_("State Type"), - P_("The type of the state kept by the action"), + g_param_spec_boxed ("state-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -544,9 +525,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_STATE, - g_param_spec_variant ("state", - P_("State"), - P_("The state the action is in"), + g_param_spec_variant ("state", NULL, NULL, G_VARIANT_TYPE_ANY, NULL, G_PARAM_READABLE | @@ -562,9 +541,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_OBJECT, - g_param_spec_object ("object", - P_("Object"), - P_("The object with the property to wrap"), + g_param_spec_object ("object", NULL, NULL, G_TYPE_OBJECT, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -581,9 +558,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.38 **/ g_object_class_install_property (object_class, PROP_PROPERTY_NAME, - g_param_spec_string ("property-name", - P_("Property name"), - P_("The name of the property to wrap"), + g_param_spec_string ("property-name", NULL, NULL, NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -598,9 +573,7 @@ g_property_action_class_init (GPropertyActionClass *class) * Since: 2.46 */ g_object_class_install_property (object_class, PROP_INVERT_BOOLEAN, - g_param_spec_boolean ("invert-boolean", - P_("Invert boolean"), - P_("Whether to invert the value of a boolean property"), + g_param_spec_boolean ("invert-boolean", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gproxy.c b/gio/gproxy.c index 40ba78f..31d3224 100644 --- a/gio/gproxy.c +++ b/gio/gproxy.c @@ -29,16 +29,14 @@ #include "glibintl.h" /** - * SECTION:gproxy - * @short_description: Interface for proxy handling - * @include: gio/gio.h + * GProxy: * - * A #GProxy handles connecting to a remote host via a given type of - * proxy server. It is implemented by the 'gio-proxy' extension point. + * A `GProxy` handles connecting to a remote host via a given type of + * proxy server. It is implemented by the `gio-proxy` extension point. * The extensions are named after their proxy protocol name. As an * example, a SOCKS5 proxy implementation can be retrieved with the - * name 'socks5' using the function - * g_io_extension_point_get_extension_by_name(). + * name `socks5` using the function + * [method@Gio.IOExtensionPoint.get_extension_by_name]. * * Since: 2.26 **/ diff --git a/gio/gproxy.h b/gio/gproxy.h index de82410..9fcf7cc 100644 --- a/gio/gproxy.h +++ b/gio/gproxy.h @@ -48,13 +48,6 @@ G_BEGIN_DECLS */ #define G_PROXY_EXTENSION_POINT_NAME "gio-proxy" -/** - * GProxy: - * - * Interface that handles proxy connection and payload. - * - * Since: 2.26 - */ typedef struct _GProxyInterface GProxyInterface; /** diff --git a/gio/gproxyaddress.c b/gio/gproxyaddress.c index 764e6f5..690dc7b 100644 --- a/gio/gproxyaddress.c +++ b/gio/gproxyaddress.c @@ -30,20 +30,12 @@ #include "glibintl.h" /** - * SECTION:gproxyaddress - * @short_description: An internet address with proxy information - * @include: gio/gio.h - * - * Support for proxied #GInetSocketAddress. - */ - -/** * GProxyAddress: * - * A #GInetSocketAddress representing a connection via a proxy server + * A [class@Gio.InetSocketAddress] representing a connection via a proxy server. * * Since: 2.26 - **/ + */ /** * GProxyAddressClass: @@ -194,31 +186,46 @@ g_proxy_address_class_init (GProxyAddressClass *klass) gobject_class->set_property = g_proxy_address_set_property; gobject_class->get_property = g_proxy_address_get_property; + /** + * GProxyAddress:protocol: + * + * The proxy protocol. + * + * Since: 2.26 + */ g_object_class_install_property (gobject_class, PROP_PROTOCOL, - g_param_spec_string ("protocol", - P_("Protocol"), - P_("The proxy protocol"), + g_param_spec_string ("protocol", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GProxyAddress:username: + * + * The proxy username. + * + * Since: 2.26 + */ g_object_class_install_property (gobject_class, PROP_USERNAME, - g_param_spec_string ("username", - P_("Username"), - P_("The proxy username"), + g_param_spec_string ("username", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GProxyAddress:password: + * + * The proxy password. + * + * Since: 2.26 + */ g_object_class_install_property (gobject_class, PROP_PASSWORD, - g_param_spec_string ("password", - P_("Password"), - P_("The proxy password"), + g_param_spec_string ("password", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -234,29 +241,37 @@ g_proxy_address_class_init (GProxyAddressClass *klass) */ g_object_class_install_property (gobject_class, PROP_DESTINATION_PROTOCOL, - g_param_spec_string ("destination-protocol", - P_("Destination Protocol"), - P_("The proxy destination protocol"), + g_param_spec_string ("destination-protocol", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GProxyAddress:destination-hostname: + * + * The proxy destination hostname. + * + * Since: 2.26 + */ g_object_class_install_property (gobject_class, PROP_DESTINATION_HOSTNAME, - g_param_spec_string ("destination-hostname", - P_("Destination Hostname"), - P_("The proxy destination hostname"), + g_param_spec_string ("destination-hostname", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GProxyAddress:destination-port: + * + * The proxy destination port. + * + * Since: 2.26 + */ g_object_class_install_property (gobject_class, PROP_DESTINATION_PORT, - g_param_spec_uint ("destination-port", - P_("Destination Port"), - P_("The proxy destination port"), + g_param_spec_uint ("destination-port", NULL, NULL, 0, 65535, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -272,9 +287,7 @@ g_proxy_address_class_init (GProxyAddressClass *klass) */ g_object_class_install_property (gobject_class, PROP_URI, - g_param_spec_string ("uri", - P_("URI"), - P_("The proxy’s URI"), + g_param_spec_string ("uri", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | diff --git a/gio/gproxyaddressenumerator.c b/gio/gproxyaddressenumerator.c index 98987f2..0d1539a 100644 --- a/gio/gproxyaddressenumerator.c +++ b/gio/gproxyaddressenumerator.c @@ -42,19 +42,18 @@ #include "gsocketconnectable.h" /** - * SECTION:gproxyaddressenumerator - * @short_description: Proxy wrapper enumerator for socket addresses - * @include: gio/gio.h + * GProxyAddressEnumerator: * - * #GProxyAddressEnumerator is a wrapper around #GSocketAddressEnumerator which - * takes the #GSocketAddress instances returned by the #GSocketAddressEnumerator - * and wraps them in #GProxyAddress instances, using the given - * #GProxyAddressEnumerator:proxy-resolver. + * `GProxyAddressEnumerator` is a wrapper around + * [class@Gio.SocketAddressEnumerator] which takes the [class@Gio.SocketAddress] + * instances returned by the [class@Gio.SocketAddressEnumerator] + * and wraps them in [class@Gio.ProxyAddress] instances, using the given + * [property@Gio.ProxyAddressEnumerator:proxy-resolver]. * * This enumerator will be returned (for example, by - * g_socket_connectable_enumerate()) as appropriate when a proxy is configured; - * there should be no need to manually wrap a #GSocketAddressEnumerator instance - * with one. + * [method@Gio.SocketConnectable.enumerate]) as appropriate when a proxy is + * configured; there should be no need to manually wrap a + * [class@Gio.SocketAddressEnumerator] instance with one. */ #define GET_PRIVATE(o) (G_PROXY_ADDRESS_ENUMERATOR (o)->priv) @@ -344,9 +343,14 @@ complete_async (GTask *task) priv->last_error = NULL; } else if (!priv->ever_enumerated) - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, _("Unspecified proxy lookup failure")); + { + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, + _("Unspecified proxy lookup failure")); + } else - g_task_return_pointer (task, NULL, NULL); + { + g_task_return_pointer (task, NULL, NULL); + } priv->ever_enumerated = TRUE; @@ -751,11 +755,14 @@ g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enume enumerator_class->next_async = g_proxy_address_enumerator_next_async; enumerator_class->next_finish = g_proxy_address_enumerator_next_finish; + /** + * GProxyAddressEnumerator:uri: + * + * The destination URI. Use `none://` for a generic socket. + */ g_object_class_install_property (object_class, PROP_URI, - g_param_spec_string ("uri", - P_("URI"), - P_("The destination URI, use none:// for generic socket"), + g_param_spec_string ("uri", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -771,19 +778,20 @@ g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enume */ g_object_class_install_property (object_class, PROP_DEFAULT_PORT, - g_param_spec_uint ("default-port", - P_("Default port"), - P_("The default port to use if uri does not specify one"), + g_param_spec_uint ("default-port", NULL, NULL, 0, 65535, 0, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** + * GProxyAddressEnumerator:connectable: + * + * The connectable being enumerated. + */ g_object_class_install_property (object_class, PROP_CONNECTABLE, - g_param_spec_object ("connectable", - P_("Connectable"), - P_("The connectable being enumerated."), + g_param_spec_object ("connectable", NULL, NULL, G_TYPE_SOCKET_CONNECTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -798,9 +806,7 @@ g_proxy_address_enumerator_class_init (GProxyAddressEnumeratorClass *proxy_enume */ g_object_class_install_property (object_class, PROP_PROXY_RESOLVER, - g_param_spec_object ("proxy-resolver", - P_("Proxy resolver"), - P_("The proxy resolver to use."), + g_param_spec_object ("proxy-resolver", NULL, NULL, G_TYPE_PROXY_RESOLVER, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | diff --git a/gio/gproxyaddressenumerator.h b/gio/gproxyaddressenumerator.h index b8d36a6..7d36ef0 100644 --- a/gio/gproxyaddressenumerator.h +++ b/gio/gproxyaddressenumerator.h @@ -38,14 +38,6 @@ G_BEGIN_DECLS #define G_IS_PROXY_ADDRESS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_PROXY_ADDRESS_ENUMERATOR)) #define G_PROXY_ADDRESS_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_PROXY_ADDRESS_ENUMERATOR, GProxyAddressEnumeratorClass)) -/** - * GProxyAddressEnumerator: - * - * A subclass of #GSocketAddressEnumerator that takes another address - * enumerator and wraps each of its results in a #GProxyAddress as - * directed by the default #GProxyResolver. - */ - typedef struct _GProxyAddressEnumeratorClass GProxyAddressEnumeratorClass; typedef struct _GProxyAddressEnumeratorPrivate GProxyAddressEnumeratorPrivate; diff --git a/gio/gproxyresolver.c b/gio/gproxyresolver.c index 4a4855a..27908bb 100644 --- a/gio/gproxyresolver.c +++ b/gio/gproxyresolver.c @@ -36,17 +36,18 @@ #include "gnetworkingprivate.h" /** - * SECTION:gproxyresolver - * @short_description: Asynchronous and cancellable network proxy resolver - * @include: gio/gio.h + * GProxyResolver: * - * #GProxyResolver provides synchronous and asynchronous network proxy - * resolution. #GProxyResolver is used within #GSocketClient through - * the method g_socket_connectable_proxy_enumerate(). + * `GProxyResolver` provides synchronous and asynchronous network proxy + * resolution. `GProxyResolver` is used within [class@Gio.SocketClient] through + * the method [method@Gio.SocketConnectable.proxy_enumerate]. * - * Implementations of #GProxyResolver based on libproxy and GNOME settings can - * be found in glib-networking. GIO comes with an implementation for use inside - * Flatpak portals. + * Implementations of `GProxyResolver` based on + * [libproxy](https://github.com/libproxy/libproxy) and GNOME settings can be + * found in [glib-networking](https://gitlab.gnome.org/GNOME/glib-networking). + * GIO comes with an implementation for use inside Flatpak portals. + * + * Since: 2.26 */ /** @@ -84,7 +85,7 @@ static GProxyResolver *proxy_resolver_default_singleton = NULL; /* (owned) (ato GProxyResolver * g_proxy_resolver_get_default (void) { - if (g_once_init_enter (&proxy_resolver_default_singleton)) + if (g_once_init_enter_pointer (&proxy_resolver_default_singleton)) { GProxyResolver *singleton; @@ -92,7 +93,7 @@ g_proxy_resolver_get_default (void) "GIO_USE_PROXY_RESOLVER", (GIOModuleVerifyFunc) g_proxy_resolver_is_supported); - g_once_init_leave (&proxy_resolver_default_singleton, singleton); + g_once_init_leave_pointer (&proxy_resolver_default_singleton, singleton); } return proxy_resolver_default_singleton; diff --git a/gio/gregistrysettingsbackend.c b/gio/gregistrysettingsbackend.c index 88ae913..3ed384f 100644 --- a/gio/gregistrysettingsbackend.c +++ b/gio/gregistrysettingsbackend.c @@ -443,7 +443,7 @@ typedef struct gint32 ref_count : 9; - gint32 readable : 1; + guint32 readable : 1; RegistryValue value; } RegistryCacheItem; diff --git a/gio/gremoteactiongroup.c b/gio/gremoteactiongroup.c index 81971d0..079f6fc 100644 --- a/gio/gremoteactiongroup.c +++ b/gio/gremoteactiongroup.c @@ -27,30 +27,27 @@ #include "gaction.h" /** - * SECTION:gremoteactiongroup - * @title: GRemoteActionGroup - * @short_description: A GActionGroup that interacts with other processes - * @include: gio/gio.h + * GRemoteActionGroup: * - * The GRemoteActionGroup interface is implemented by #GActionGroup + * The `GRemoteActionGroup` interface is implemented by [iface@Gio.ActionGroup] * instances that either transmit action invocations to other processes * or receive action invocations in the local process from other * processes. * * The interface has `_full` variants of the two - * methods on #GActionGroup used to activate actions: - * g_action_group_activate_action() and - * g_action_group_change_action_state(). These variants allow a - * "platform data" #GVariant to be specified: a dictionary providing + * methods on [iface@Gio.ActionGroup] used to activate actions: + * [method@Gio.ActionGroup.activate_action] and + * [method@Gio.ActionGroup.change_action_state]. These variants allow a + * ‘platform data’ [struct@GLib.Variant] to be specified: a dictionary providing * context for the action invocation (for example: timestamps, startup * notification IDs, etc). * - * #GDBusActionGroup implements #GRemoteActionGroup. This provides a + * [class@Gio.DBusActionGroup] implements `GRemoteActionGroup`. This provides a * mechanism to send platform data for action invocations over D-Bus. * - * Additionally, g_dbus_connection_export_action_group() will check if - * the exported #GActionGroup implements #GRemoteActionGroup and use the - * `_full` variants of the calls if available. This + * Additionally, [method@Gio.DBusConnection.export_action_group] will check if + * the exported [iface@Gio.ActionGroup] implements `GRemoteActionGroup` and use + * the `_full` variants of the calls if available. This * provides a mechanism by which to receive platform data for action * invocations that arrive by way of D-Bus. * @@ -58,13 +55,6 @@ **/ /** - * GRemoteActionGroup: - * - * #GRemoteActionGroup is an opaque data structure and can only be accessed - * using the following functions. - **/ - -/** * GRemoteActionGroupInterface: * @activate_action_full: the virtual function pointer for g_remote_action_group_activate_action_full() * @change_action_state_full: the virtual function pointer for g_remote_action_group_change_action_state_full() diff --git a/gio/gresolver.c b/gio/gresolver.c index 4c29d58..60fbb4b 100644 --- a/gio/gresolver.c +++ b/gio/gresolver.c @@ -43,22 +43,27 @@ /** - * SECTION:gresolver - * @short_description: Asynchronous and cancellable DNS resolver - * @include: gio/gio.h - * - * #GResolver provides cancellable synchronous and asynchronous DNS - * resolution, for hostnames (g_resolver_lookup_by_address(), - * g_resolver_lookup_by_name() and their async variants) and SRV - * (service) records (g_resolver_lookup_service()). - * - * #GNetworkAddress and #GNetworkService provide wrappers around - * #GResolver functionality that also implement #GSocketConnectable, - * making it easy to connect to a remote host/service. - * - * The default resolver (see g_resolver_get_default()) has a timeout of 30s set - * on it since GLib 2.78. Earlier versions of GLib did not support resolver - * timeouts. + * GResolver: + * + * The object that handles DNS resolution. Use [func@Gio.Resolver.get_default] + * to get the default resolver. + * + * `GResolver` provides cancellable synchronous and asynchronous DNS + * resolution, for hostnames ([method@Gio.Resolver.lookup_by_address], + * [method@Gio.Resolver.lookup_by_name] and their async variants) and SRV + * (service) records ([method@Gio.Resolver.lookup_service]). + * + * [class@Gio.NetworkAddress] and [class@Gio.NetworkService] provide wrappers + * around `GResolver` functionality that also implement + * [iface@Gio.SocketConnectable], making it easy to connect to a remote + * host/service. + * + * The default resolver (see [func@Gio.Resolver.get_default]) has a timeout of + * 30s set on it since GLib 2.78. Earlier versions of GLib did not support + * resolver timeouts. + * + * This is an abstract type; subclasses of it implement different resolvers for + * different platforms and situations. */ typedef enum { @@ -83,15 +88,6 @@ struct _GResolverPrivate { #endif }; -/** - * GResolver: - * - * The object that handles DNS resolution. Use g_resolver_get_default() - * to get the default resolver. - * - * This is an abstract type; subclasses of it implement different resolvers for - * different platforms and situations. - */ G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GResolver, g_resolver, G_TYPE_OBJECT, G_ADD_PRIVATE (GResolver) g_networking_init ();) @@ -240,9 +236,7 @@ g_resolver_class_init (GResolverClass *resolver_class) * Since: 2.78 */ props[PROP_TIMEOUT] = - g_param_spec_uint ("timeout", - P_("Timeout"), - P_("Timeout (ms) applied to all resolver lookups"), + g_param_spec_uint ("timeout", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY); diff --git a/gio/gresource.c b/gio/gresource.c index a67df11..042e820 100644 --- a/gio/gresource.c +++ b/gio/gresource.c @@ -48,69 +48,72 @@ static void register_lazy_static_resources (void); G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref) /** - * SECTION:gresource - * @short_description: Resource framework - * @include: gio/gio.h + * GResource: * * Applications and libraries often contain binary or textual data that is * really part of the application, rather than user data. For instance - * #GtkBuilder .ui files, splashscreen images, GMenu markup XML, CSS files, - * icons, etc. These are often shipped as files in `$datadir/appname`, or - * manually included as literal strings in the code. - * - * The #GResource API and the [glib-compile-resources][glib-compile-resources] program - * provide a convenient and efficient alternative to this which has some nice properties. You - * maintain the files as normal files, so its easy to edit them, but during the build the files - * are combined into a binary bundle that is linked into the executable. This means that loading - * the resource files are efficient (as they are already in memory, shared with other instances) and - * simple (no need to check for things like I/O errors or locate the files in the filesystem). It + * [class@Gtk.Builder] `.ui` files, splashscreen images, [class@Gio.Menu] markup + * XML, CSS files, icons, etc. These are often shipped as files in + * `$datadir/appname`, or manually included as literal strings in the code. + * + * The `GResource` API and the + * [`glib-compile-resources`](glib-compile-resources.html) program provide a + * convenient and efficient alternative to this which has some nice properties. + * You maintain the files as normal files, so it’s easy to edit them, but during + * the build the files are combined into a binary bundle that is linked into the + * executable. This means that loading the resource files are efficient (as they + * are already in memory, shared with other instances) and simple (no need to + * check for things like I/O errors or locate the files in the filesystem). It * also makes it easier to create relocatable applications. * - * Resource files can also be marked as compressed. Such files will be included in the resource bundle - * in a compressed form, but will be automatically uncompressed when the resource is used. This - * is very useful e.g. for larger text files that are parsed once (or rarely) and then thrown away. + * Resource files can also be marked as compressed. Such files will be included + * in the resource bundle in a compressed form, but will be automatically + * uncompressed when the resource is used. This is very useful e.g. for larger + * text files that are parsed once (or rarely) and then thrown away. * * Resource files can also be marked to be preprocessed, by setting the value of the * `preprocess` attribute to a comma-separated list of preprocessing options. * The only options currently supported are: * - * `xml-stripblanks` which will use the xmllint command - * to strip ignorable whitespace from the XML file. For this to work, - * the `XMLLINT` environment variable must be set to the full path to - * the xmllint executable, or xmllint must be in the `PATH`; otherwise - * the preprocessing step is skipped. - * - * `to-pixdata` (deprecated since gdk-pixbuf 2.32) which will use the - * `gdk-pixbuf-pixdata` command to convert images to the #GdkPixdata format, - * which allows you to create pixbufs directly using the data inside the - * resource file, rather than an (uncompressed) copy of it. For this, the - * `gdk-pixbuf-pixdata` program must be in the `PATH`, or the - * `GDK_PIXBUF_PIXDATA` environment variable must be set to the full path to the - * `gdk-pixbuf-pixdata` executable; otherwise the resource compiler will abort. - * `to-pixdata` has been deprecated since gdk-pixbuf 2.32, as #GResource - * supports embedding modern image formats just as well. Instead of using it, - * embed a PNG or SVG file in your #GResource. - * - * `json-stripblanks` which will use the `json-glib-format` command to strip - * ignorable whitespace from the JSON file. For this to work, the - * `JSON_GLIB_FORMAT` environment variable must be set to the full path to the - * `json-glib-format` executable, or it must be in the `PATH`; - * otherwise the preprocessing step is skipped. In addition, at least version - * 1.6 of `json-glib-format` is required. - * - * Resource files will be exported in the GResource namespace using the + * - `xml-stripblanks` which will use the [`xmllint`](man:xmllint(1)) command + * to strip ignorable whitespace from the XML file. For this to work, + * the `XMLLINT` environment variable must be set to the full path to + * the xmllint executable, or xmllint must be in the `PATH`; otherwise + * the preprocessing step is skipped. + * + * - `to-pixdata` (deprecated since gdk-pixbuf 2.32) which will use the + * `gdk-pixbuf-pixdata` command to convert images to the [class@Gdk.Pixdata] + * format, which allows you to create pixbufs directly using the data inside + * the resource file, rather than an (uncompressed) copy of it. For this, the + * `gdk-pixbuf-pixdata` program must be in the `PATH`, or the + * `GDK_PIXBUF_PIXDATA` environment variable must be set to the full path to + * the `gdk-pixbuf-pixdata` executable; otherwise the resource compiler will + * abort. `to-pixdata` has been deprecated since gdk-pixbuf 2.32, as + * `GResource` supports embedding modern image formats just as well. Instead + * of using it, embed a PNG or SVG file in your `GResource`. + * + * - `json-stripblanks` which will use the + * [`json-glib-format`](man:json-glib-format(1)) command to strip ignorable + * whitespace from the JSON file. For this to work, the `JSON_GLIB_FORMAT` + * environment variable must be set to the full path to the + * `json-glib-format` executable, or it must be in the `PATH`; otherwise the + * preprocessing step is skipped. In addition, at least version 1.6 of + * `json-glib-format` is required. + * + * Resource files will be exported in the `GResource` namespace using the * combination of the given `prefix` and the filename from the `file` element. * The `alias` attribute can be used to alter the filename to expose them at a * different location in the resource namespace. Typically, this is used to * include files from a different source directory without exposing the source * directory in the resource namespace, as in the example below. * - * Resource bundles are created by the [glib-compile-resources][glib-compile-resources] program - * which takes an XML file that describes the bundle, and a set of files that the XML references. These - * are combined into a binary resource bundle. + * Resource bundles are created by the + * [`glib-compile-resources`](glib-compile-resources.html) program + * which takes an XML file that describes the bundle, and a set of files that + * the XML references. These are combined into a binary resource bundle. * * An example resource description: - * |[ + * ```xml * * * @@ -120,74 +123,92 @@ G_DEFINE_BOXED_TYPE (GResource, g_resource, g_resource_ref, g_resource_unref) * data/example.css * * - * ]| + * ``` * * This will create a resource bundle with the following files: - * |[ + * ``` * /org/gtk/Example/data/splashscreen.png * /org/gtk/Example/dialog.ui * /org/gtk/Example/menumarkup.xml * /org/gtk/Example/example.css - * ]| + * ``` * - * Note that all resources in the process share the same namespace, so use Java-style - * path prefixes (like in the above example) to avoid conflicts. + * Note that all resources in the process share the same namespace, so use + * Java-style path prefixes (like in the above example) to avoid conflicts. * - * You can then use [glib-compile-resources][glib-compile-resources] to compile the XML to a - * binary bundle that you can load with g_resource_load(). However, its more common to use the --generate-source and - * --generate-header arguments to create a source file and header to link directly into your application. + * You can then use [`glib-compile-resources`](glib-compile-resources.html) to + * compile the XML to a binary bundle that you can load with + * [func@Gio.Resource.load]. However, it’s more common to use the + * `--generate-source` and `--generate-header` arguments to create a source file + * and header to link directly into your application. * This will generate `get_resource()`, `register_resource()` and * `unregister_resource()` functions, prefixed by the `--c-name` argument passed - * to [glib-compile-resources][glib-compile-resources]. `get_resource()` returns - * the generated #GResource object. The register and unregister functions - * register the resource so its files can be accessed using - * g_resources_lookup_data(). - * - * Once a #GResource has been created and registered all the data in it can be accessed globally in the process by - * using API calls like g_resources_open_stream() to stream the data or g_resources_lookup_data() to get a direct pointer - * to the data. You can also use URIs like "resource:///org/gtk/Example/data/splashscreen.png" with #GFile to access - * the resource data. - * - * Some higher-level APIs, such as #GtkApplication, will automatically load - * resources from certain well-known paths in the resource namespace as a + * to [`glib-compile-resources`](glib-compile-resources.html). `get_resource()` + * returns the generated `GResource` object. The register and unregister + * functions register the resource so its files can be accessed using + * [func@Gio.resources_lookup_data]. + * + * Once a `GResource` has been created and registered all the data in it can be + * accessed globally in the process by using API calls like + * [func@Gio.resources_open_stream] to stream the data or + * [func@Gio.resources_lookup_data] to get a direct pointer to the data. You can + * also use URIs like `resource:///org/gtk/Example/data/splashscreen.png` with + * [iface@Gio.File] to access the resource data. + * + * Some higher-level APIs, such as [class@Gtk.Application], will automatically + * load resources from certain well-known paths in the resource namespace as a * convenience. See the documentation for those APIs for details. * - * There are two forms of the generated source, the default version uses the compiler support for constructor - * and destructor functions (where available) to automatically create and register the #GResource on startup - * or library load time. If you pass `--manual-register`, two functions to register/unregister the resource are created - * instead. This requires an explicit initialization call in your application/library, but it works on all platforms, - * even on the minor ones where constructors are not supported. (Constructor support is available for at least Win32, Mac OS and Linux.) - * - * Note that resource data can point directly into the data segment of e.g. a library, so if you are unloading libraries - * during runtime you need to be very careful with keeping around pointers to data from a resource, as this goes away - * when the library is unloaded. However, in practice this is not generally a problem, since most resource accesses - * are for your own resources, and resource data is often used once, during parsing, and then released. - * - * When debugging a program or testing a change to an installed version, it is often useful to be able to - * replace resources in the program or library, without recompiling, for debugging or quick hacking and testing - * purposes. Since GLib 2.50, it is possible to use the `G_RESOURCE_OVERLAYS` environment variable to selectively overlay - * resources with replacements from the filesystem. It is a %G_SEARCHPATH_SEPARATOR-separated list of substitutions to perform - * during resource lookups. It is ignored when running in a setuid process. + * There are two forms of the generated source, the default version uses the + * compiler support for constructor and destructor functions (where available) + * to automatically create and register the `GResource` on startup or library + * load time. If you pass `--manual-register`, two functions to + * register/unregister the resource are created instead. This requires an + * explicit initialization call in your application/library, but it works on all + * platforms, even on the minor ones where constructors are not supported. + * (Constructor support is available for at least Win32, Mac OS and Linux.) + * + * Note that resource data can point directly into the data segment of e.g. a + * library, so if you are unloading libraries during runtime you need to be very + * careful with keeping around pointers to data from a resource, as this goes + * away when the library is unloaded. However, in practice this is not generally + * a problem, since most resource accesses are for your own resources, and + * resource data is often used once, during parsing, and then released. + * + * # Overlays + * + * When debugging a program or testing a change to an installed version, it is + * often useful to be able to replace resources in the program or library, + * without recompiling, for debugging or quick hacking and testing purposes. + * Since GLib 2.50, it is possible to use the `G_RESOURCE_OVERLAYS` environment + * variable to selectively overlay resources with replacements from the + * filesystem. It is a `G_SEARCHPATH_SEPARATOR`-separated list of substitutions + * to perform during resource lookups. It is ignored when running in a setuid + * process. * * A substitution has the form * - * |[ - * /org/gtk/libgtk=/home/desrt/gtk-overlay - * ]| + * ``` + * /org/gtk/libgtk=/home/desrt/gtk-overlay + * ``` * - * The part before the `=` is the resource subpath for which the overlay applies. The part after is a - * filesystem path which contains files and subdirectories as you would like to be loaded as resources with the + * The part before the `=` is the resource subpath for which the overlay + * applies. The part after is a filesystem path which contains files and + * subdirectories as you would like to be loaded as resources with the * equivalent names. * - * In the example above, if an application tried to load a resource with the resource path - * `/org/gtk/libgtk/ui/gtkdialog.ui` then GResource would check the filesystem path - * `/home/desrt/gtk-overlay/ui/gtkdialog.ui`. If a file was found there, it would be used instead. This is an - * overlay, not an outright replacement, which means that if a file is not found at that path, the built-in - * version will be used instead. Whiteouts are not currently supported. + * In the example above, if an application tried to load a resource with the + * resource path `/org/gtk/libgtk/ui/gtkdialog.ui` then `GResource` would check + * the filesystem path `/home/desrt/gtk-overlay/ui/gtkdialog.ui`. If a file was + * found there, it would be used instead. This is an overlay, not an outright + * replacement, which means that if a file is not found at that path, the + * built-in version will be used instead. Whiteouts are not currently + * supported. * - * Substitutions must start with a slash, and must not contain a trailing slash before the '='. The path after - * the slash should ideally be absolute, but this is not strictly required. It is possible to overlay the - * location of a single resource with an individual file. + * Substitutions must start with a slash, and must not contain a trailing slash + * before the `=`. The path after the slash should ideally be absolute, but + * this is not strictly required. It is possible to overlay the location of a + * single resource with an individual file. * * Since: 2.32 */ @@ -336,7 +357,7 @@ g_resource_find_overlay (const gchar *path, * we can take a bit more time... */ - if (g_once_init_enter (&overlay_dirs)) + if (g_once_init_enter_pointer (&overlay_dirs)) { gboolean is_setuid = GLIB_PRIVATE_CALL (g_check_setuid) (); const gchar * const *result; @@ -420,7 +441,7 @@ g_resource_find_overlay (const gchar *path, result = empty_strv; } - g_once_init_leave (&overlay_dirs, result); + g_once_init_leave_pointer (&overlay_dirs, result); } for (i = 0; overlay_dirs[i]; i++) diff --git a/gio/gseekable.c b/gio/gseekable.c index 805e0a0..0b0ec27 100644 --- a/gio/gseekable.c +++ b/gio/gseekable.c @@ -26,25 +26,22 @@ /** - * SECTION:gseekable - * @short_description: Stream seeking interface - * @include: gio/gio.h - * @see_also: #GInputStream, #GOutputStream + * GSeekable: * - * #GSeekable is implemented by streams (implementations of - * #GInputStream or #GOutputStream) that support seeking. + * `GSeekable` is implemented by streams (implementations of + * [class@Gio.InputStream] or [class@Gio.OutputStream]) that support seeking. * * Seekable streams largely fall into two categories: resizable and * fixed-size. * - * #GSeekable on fixed-sized streams is approximately the same as POSIX - * lseek() on a block device (for example: attempting to seek past the - * end of the device is an error). Fixed streams typically cannot be + * `GSeekable` on fixed-sized streams is approximately the same as POSIX + * [`lseek()`](man:lseek(2)) on a block device (for example: attempting to seek + * past the end of the device is an error). Fixed streams typically cannot be * truncated. * - * #GSeekable on resizable streams is approximately the same as POSIX - * lseek() on a normal file. Seeking past the end and writing data will - * usually cause the stream to resize by introducing zero bytes. + * `GSeekable` on resizable streams is approximately the same as POSIX + * [`lseek()`](man:lseek(2)) on a normal file. Seeking past the end and writing + * data will usually cause the stream to resize by introducing zero bytes. **/ typedef GSeekableIface GSeekableInterface; diff --git a/gio/gseekable.h b/gio/gseekable.h index 34510de..e997801 100644 --- a/gio/gseekable.h +++ b/gio/gseekable.h @@ -36,11 +36,6 @@ G_BEGIN_DECLS #define G_IS_SEEKABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_SEEKABLE)) #define G_SEEKABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_SEEKABLE, GSeekableIface)) -/** - * GSeekable: - * - * Seek object for streaming operations. - **/ typedef struct _GSeekableIface GSeekableIface; /** diff --git a/gio/gsettings.c b/gio/gsettings.c index a2c3dd0..a14ba80 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -37,116 +37,115 @@ #include "strinfo.c" /** - * SECTION:gsettings - * @short_description: High-level API for application settings - * @include: gio/gio.h + * GSettings: * - * The #GSettings class provides a convenient API for storing and retrieving + * The `GSettings` class provides a convenient API for storing and retrieving * application settings. * * Reads and writes can be considered to be non-blocking. Reading - * settings with #GSettings is typically extremely fast: on + * settings with `GSettings` is typically extremely fast: on * approximately the same order of magnitude (but slower than) a - * #GHashTable lookup. Writing settings is also extremely fast in terms - * of time to return to your application, but can be extremely expensive + * [struct@GLib.HashTable] lookup. Writing settings is also extremely fast in + * terms of time to return to your application, but can be extremely expensive * for other threads and other processes. Many settings backends * (including dconf) have lazy initialisation which means in the common * case of the user using their computer without modifying any settings - * a lot of work can be avoided. For dconf, the D-Bus service doesn't + * a lot of work can be avoided. For dconf, the D-Bus service doesn’t * even need to be started in this case. For this reason, you should - * only ever modify #GSettings keys in response to explicit user action. + * only ever modify `GSettings` keys in response to explicit user action. * Particular care should be paid to ensure that modifications are not - * made during startup -- for example, when setting the initial value - * of preferences widgets. The built-in g_settings_bind() functionality - * is careful not to write settings in response to notify signals as a - * result of modifications that it makes to widgets. + * made during startup — for example, when setting the initial value + * of preferences widgets. The built-in [method@Gio.Settings.bind] + * functionality is careful not to write settings in response to notify signals + * as a result of modifications that it makes to widgets. * - * When creating a GSettings instance, you have to specify a schema + * When creating a `GSettings` instance, you have to specify a schema * that describes the keys in your settings and their types and default * values, as well as some other information. * * Normally, a schema has a fixed path that determines where the settings * are stored in the conceptual global tree of settings. However, schemas - * can also be '[relocatable][gsettings-relocatable]', i.e. not equipped with + * can also be ‘[relocatable](#relocatable-schemas)’, i.e. not equipped with * a fixed path. This is - * useful e.g. when the schema describes an 'account', and you want to be + * useful e.g. when the schema describes an ‘account’, and you want to be * able to store a arbitrary number of accounts. * - * Paths must start with and end with a forward slash character ('/') + * Paths must start with and end with a forward slash character (`/`) * and must not contain two sequential slash characters. Paths should * be chosen based on a domain name associated with the program or * library to which the settings belong. Examples of paths are - * "/org/gtk/settings/file-chooser/" and "/ca/desrt/dconf-editor/". - * Paths should not start with "/apps/", "/desktop/" or "/system/" as + * `/org/gtk/settings/file-chooser/` and `/ca/desrt/dconf-editor/`. + * Paths should not start with `/apps/`, `/desktop/` or `/system/` as * they often did in GConf. * * Unlike other configuration systems (like GConf), GSettings does not * restrict keys to basic types like strings and numbers. GSettings stores - * values as #GVariant, and allows any #GVariantType for keys. Key names - * are restricted to lowercase characters, numbers and '-'. Furthermore, - * the names must begin with a lowercase character, must not end - * with a '-', and must not contain consecutive dashes. + * values as [struct@GLib.Variant], and allows any [type@GLib.VariantType] for + * keys. Key names are restricted to lowercase characters, numbers and `-`. + * Furthermore, the names must begin with a lowercase character, must not end + * with a `-`, and must not contain consecutive dashes. * * Similar to GConf, the default values in GSettings schemas can be * localized, but the localized values are stored in gettext catalogs * and looked up with the domain that is specified in the - * `gettext-domain` attribute of the or + * `gettext-domain` attribute of the `` or `` * elements and the category that is specified in the `l10n` attribute of - * the element. The string which is translated includes all text in - * the element, including any surrounding quotation marks. + * the `` element. The string which is translated includes all text in + * the `` element, including any surrounding quotation marks. * * The `l10n` attribute must be set to `messages` or `time`, and sets the * [locale category for * translation](https://www.gnu.org/software/gettext/manual/html_node/Aspects.html#index-locale-categories-1). * The `messages` category should be used by default; use `time` for * translatable date or time formats. A translation comment can be added as an - * XML comment immediately above the element — it is recommended to + * XML comment immediately above the `` element — it is recommended to * add these comments to aid translators understand the meaning and * implications of the default value. An optional translation `context` - * attribute can be set on the element to disambiguate multiple + * attribute can be set on the `` element to disambiguate multiple * defaults which use the same string. * * For example: - * |[ + * ```xml * * ['bad', 'words'] - * ]| + * ``` * * Translations of default values must remain syntactically valid serialized - * #GVariants (e.g. retaining any surrounding quotation marks) or runtime - * errors will occur. + * [struct@GLib.Variant]s (e.g. retaining any surrounding quotation marks) or + * runtime errors will occur. * * GSettings uses schemas in a compact binary form that is created - * by the [glib-compile-schemas][glib-compile-schemas] + * by the [`glib-compile-schemas`](glib-compile-schemas.html) * utility. The input is a schema description in an XML format. * * A DTD for the gschema XML format can be found here: * [gschema.dtd](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/gio/gschema.dtd) * - * The [glib-compile-schemas][glib-compile-schemas] tool expects schema + * The [`glib-compile-schemas`](glib-compile-schemas.html) tool expects schema * files to have the extension `.gschema.xml`. * - * At runtime, schemas are identified by their id (as specified in the - * id attribute of the element). The convention for schema - * ids is to use a dotted name, similar in style to a D-Bus bus name, - * e.g. "org.gnome.SessionManager". In particular, if the settings are + * At runtime, schemas are identified by their ID (as specified in the + * `id` attribute of the `` element). The convention for schema + * IDs is to use a dotted name, similar in style to a D-Bus bus name, + * e.g. `org.gnome.SessionManager`. In particular, if the settings are * for a specific service that owns a D-Bus bus name, the D-Bus bus name - * and schema id should match. For schemas which deal with settings not - * associated with one named application, the id should not use - * StudlyCaps, e.g. "org.gnome.font-rendering". - * - * In addition to #GVariant types, keys can have types that have - * enumerated types. These can be described by a , - * or element, as seen in the - * [example][schema-enumerated]. The underlying type of such a key - * is string, but you can use g_settings_get_enum(), g_settings_set_enum(), - * g_settings_get_flags(), g_settings_set_flags() access the numeric values - * corresponding to the string value of enum and flags keys. + * and schema ID should match. For schemas which deal with settings not + * associated with one named application, the ID should not use + * StudlyCaps, e.g. `org.gnome.font-rendering`. + * + * In addition to [struct@GLib.Variant] types, keys can have types that have + * enumerated types. These can be described by a ``, + * `` or `` element, as seen in the + * second example below. The underlying type of such a key + * is string, but you can use [method@Gio.Settings.get_enum], + * [method@Gio.Settings.set_enum], [method@Gio.Settings.get_flags], + * [method@Gio.Settings.set_flags] access the numeric values corresponding to + * the string value of enum and flags keys. * * An example for default value: - * |[ + * ```xml * * * @@ -169,10 +168,10 @@ * * * - * ]| + * ``` * * An example for ranges, choices and enumerated types: - * |[ + * ```xml * * * @@ -215,7 +214,7 @@ * * * - * ]| + * ``` * * ## Vendor overrides * @@ -223,41 +222,42 @@ * an application. Sometimes, it is necessary for a vendor or distributor * to adjust these defaults. Since patching the XML source for the schema * is inconvenient and error-prone, - * [glib-compile-schemas][glib-compile-schemas] reads so-called vendor - * override' files. These are keyfiles in the same directory as the XML - * schema sources which can override default values. The schema id serves + * [`glib-compile-schemas`](glib-compile-schemas.html) reads so-called ‘vendor + * override’ files. These are keyfiles in the same directory as the XML + * schema sources which can override default values. The schema ID serves * as the group name in the key file, and the values are expected in - * serialized GVariant form, as in the following example: - * |[ - * [org.gtk.Example] - * key1='string' - * key2=1.5 - * ]| - * - * glib-compile-schemas expects schema files to have the extension + * serialized [struct@GLib.Variant] form, as in the following example: + * ``` + * [org.gtk.Example] + * key1='string' + * key2=1.5 + * ``` + * + * `glib-compile-schemas` expects schema files to have the extension * `.gschema.override`. * * ## Binding * - * A very convenient feature of GSettings lets you bind #GObject properties - * directly to settings, using g_settings_bind(). Once a GObject property - * has been bound to a setting, changes on either side are automatically - * propagated to the other side. GSettings handles details like mapping - * between GObject and GVariant types, and preventing infinite cycles. + * A very convenient feature of GSettings lets you bind [class@GObject.Object] + * properties directly to settings, using [method@Gio.Settings.bind]. Once a + * [class@GObject.Object] property has been bound to a setting, changes on + * either side are automatically propagated to the other side. GSettings handles + * details like mapping between [class@GObject.Object] and [struct@GLib.Variant] + * types, and preventing infinite cycles. * * This makes it very easy to hook up a preferences dialog to the * underlying settings. To make this even more convenient, GSettings - * looks for a boolean property with the name "sensitivity" and + * looks for a boolean property with the name `sensitivity` and * automatically binds it to the writability of the bound setting. - * If this 'magic' gets in the way, it can be suppressed with the - * %G_SETTINGS_BIND_NO_SENSITIVITY flag. + * If this ‘magic’ gets in the way, it can be suppressed with the + * `G_SETTINGS_BIND_NO_SENSITIVITY` flag. * - * ## Relocatable schemas # {#gsettings-relocatable} + * ## Relocatable schemas * * A relocatable schema is one with no `path` attribute specified on its - * element. By using g_settings_new_with_path(), a #GSettings object - * can be instantiated for a relocatable schema, assigning a path to the - * instance. Paths passed to g_settings_new_with_path() will typically be + * `` element. By using [ctor@Gio.Settings.new_with_path], a `GSettings` + * object can be instantiated for a relocatable schema, assigning a path to the + * instance. Paths passed to [ctor@Gio.Settings.new_with_path] will typically be * constructed dynamically from a constant prefix plus some form of instance * identifier; but they must still be valid GSettings paths. Paths could also * be constant and used with a globally installed schema originating from a @@ -268,59 +268,59 @@ * `org.foo.MyApp.Window`, it could be instantiated for paths * `/org/foo/MyApp/main/`, `/org/foo/MyApp/document-1/`, * `/org/foo/MyApp/document-2/`, etc. If any of the paths are well-known - * they can be specified as elements in the parent schema, e.g.: - * |[ + * they can be specified as `` elements in the parent schema, e.g.: + * ```xml * * * - * ]| + * ``` * - * ## Build system integration # {#gsettings-build-system} + * ## Build system integration * * GSettings comes with autotools integration to simplify compiling and * installing schemas. To add GSettings support to an application, add the * following to your `configure.ac`: - * |[ + * ``` * GLIB_GSETTINGS - * ]| + * ``` * * In the appropriate `Makefile.am`, use the following snippet to compile and * install the named schema: - * |[ + * ``` * gsettings_SCHEMAS = org.foo.MyApp.gschema.xml * EXTRA_DIST = $(gsettings_SCHEMAS) * * @GSETTINGS_RULES@ - * ]| + * ``` * * No changes are needed to the build system to mark a schema XML file for * translation. Assuming it sets the `gettext-domain` attribute, a schema may * be marked for translation by adding it to `POTFILES.in`, assuming gettext * 0.19 is in use (the preferred method for translation): - * |[ + * ``` * data/org.foo.MyApp.gschema.xml - * ]| + * ``` * * Alternatively, if intltool 0.50.1 is in use: - * |[ + * ``` * [type: gettext/gsettings]data/org.foo.MyApp.gschema.xml - * ]| + * ``` * - * GSettings will use gettext to look up translations for the and - * elements, and also any elements which have a `l10n` - * attribute set. Translations must not be included in the `.gschema.xml` file - * by the build system, for example by using intltool XML rules with a + * GSettings will use gettext to look up translations for the `` and + * `` elements, and also any `` elements which have a + * `l10n` attribute set. Translations must not be included in the `.gschema.xml` + * file by the build system, for example by using intltool XML rules with a * `.gschema.xml.in` template. * * If an enumerated type defined in a C header file is to be used in a GSettings - * schema, it can either be defined manually using an element in the + * schema, it can either be defined manually using an `` element in the * schema XML, or it can be extracted automatically from the C header. This * approach is preferred, as it ensures the two representations are always * synchronised. To do so, add the following to the relevant `Makefile.am`: - * |[ + * ``` * gsettings_ENUM_NAMESPACE = org.foo.MyApp * gsettings_ENUM_FILES = my-app-enums.h my-app-misc.h - * ]| + * ``` * * `gsettings_ENUM_NAMESPACE` specifies the schema namespace for the enum files, * which are specified in `gsettings_ENUM_FILES`. This will generate a @@ -330,13 +330,6 @@ * `EXTRA_DIST`. */ -/** - * GSettings: - * - * #GSettings is an opaque data structure and can only be accessed - * using the following functions. - **/ - struct _GSettingsPrivate { /* where the signals go... */ @@ -848,9 +841,7 @@ g_settings_class_init (GSettingsClass *class) * The name of the context that the settings are stored in. */ g_object_class_install_property (object_class, PROP_BACKEND, - g_param_spec_object ("backend", - P_("GSettingsBackend"), - P_("The GSettingsBackend for this settings object"), + g_param_spec_object ("backend", NULL, NULL, G_TYPE_SETTINGS_BACKEND, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -866,9 +857,7 @@ g_settings_class_init (GSettingsClass *class) * than the schema itself. Take care. */ g_object_class_install_property (object_class, PROP_SCHEMA, - g_param_spec_boxed ("settings-schema", - P_("schema"), - P_("The GSettingsSchema for this settings object"), + g_param_spec_boxed ("settings-schema", NULL, NULL, G_TYPE_SETTINGS_SCHEMA, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -890,9 +879,7 @@ g_settings_class_init (GSettingsClass *class) * version, this property may instead refer to a #GSettingsSchema. */ g_object_class_install_property (object_class, PROP_SCHEMA_ID, - g_param_spec_string ("schema", - P_("Schema name"), - P_("The name of the schema for this settings object"), + g_param_spec_string ("schema", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_DEPRECATED | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -904,9 +891,7 @@ g_settings_class_init (GSettingsClass *class) * for this #GSettings object. */ g_object_class_install_property (object_class, PROP_SCHEMA_ID, - g_param_spec_string ("schema-id", - P_("Schema name"), - P_("The name of the schema for this settings object"), + g_param_spec_string ("schema-id", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -917,9 +902,7 @@ g_settings_class_init (GSettingsClass *class) * The path within the backend where the settings are stored. */ g_object_class_install_property (object_class, PROP_PATH, - g_param_spec_string ("path", - P_("Base path"), - P_("The path within the backend where the settings are"), + g_param_spec_string ("path", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -931,9 +914,7 @@ g_settings_class_init (GSettingsClass *class) * changes that will be applied when g_settings_apply() is called. */ g_object_class_install_property (object_class, PROP_HAS_UNAPPLIED, - g_param_spec_boolean ("has-unapplied", - P_("Has unapplied changes"), - P_("TRUE if there are outstanding changes to apply()"), + g_param_spec_boolean ("has-unapplied", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -946,9 +927,7 @@ g_settings_class_init (GSettingsClass *class) * Since: 2.28 */ g_object_class_install_property (object_class, PROP_DELAY_APPLY, - g_param_spec_boolean ("delay-apply", - P_("Delay-apply mode"), - P_("Whether this settings object is in “delay-apply” mode"), + g_param_spec_boolean ("delay-apply", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c index 2db6c58..d11d1fd 100644 --- a/gio/gsettingsbackend.c +++ b/gio/gsettingsbackend.c @@ -52,17 +52,13 @@ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GSettingsBackend, g_settings_backend, G_TYP static gboolean g_settings_has_backend; /** - * SECTION:gsettingsbackend - * @title: GSettingsBackend - * @short_description: Interface for settings backend implementations - * @include: gio/gsettingsbackend.h - * @see_also: #GSettings, #GIOExtensionPoint + * GSettingsBackend: * - * The #GSettingsBackend interface defines a generic interface for + * The `GSettingsBackend` interface defines a generic interface for * non-strictly-typed data that is stored in a hierarchy. To implement - * an alternative storage backend for #GSettings, you need to implement - * the #GSettingsBackend interface and then make it implement the - * extension point %G_SETTINGS_BACKEND_EXTENSION_POINT_NAME. + * an alternative storage backend for [class@Gio.Settings], you need to + * implement the `GSettingsBackend` interface and then make it implement the + * extension point `G_SETTINGS_BACKEND_EXTENSION_POINT_NAME`. * * The interface defines methods for reading and writing values, a * method for determining if writing of certain values will fail @@ -72,15 +68,14 @@ static gboolean g_settings_has_backend; * implementations must carefully adhere to the expectations of * callers that are documented on each of the interface methods. * - * Some of the #GSettingsBackend functions accept or return a #GTree. - * These trees always have strings as keys and #GVariant as values. - * g_settings_backend_create_tree() is a convenience function to create - * suitable trees. + * Some of the `GSettingsBackend` functions accept or return a + * [struct@GLib.Tree]. These trees always have strings as keys and + * [struct@GLib.Variant] as values. * - * The #GSettingsBackend API is exported to allow third-party + * The `GSettingsBackend` API is exported to allow third-party * implementations, but does not carry the same stability guarantees * as the public GIO API. For this reason, you have to define the - * C preprocessor symbol %G_SETTINGS_ENABLE_BACKEND before including + * C preprocessor symbol `G_SETTINGS_ENABLE_BACKEND` before including * `gio/gsettingsbackend.h`. **/ @@ -1018,7 +1013,7 @@ static GSettingsBackend *settings_backend_default_singleton = NULL; /* (owned) GSettingsBackend * g_settings_backend_get_default (void) { - if (g_once_init_enter (&settings_backend_default_singleton)) + if (g_once_init_enter_pointer (&settings_backend_default_singleton)) { GSettingsBackend *singleton; @@ -1026,7 +1021,7 @@ g_settings_backend_get_default (void) "GSETTINGS_BACKEND", g_settings_backend_verify); - g_once_init_leave (&settings_backend_default_singleton, singleton); + g_once_init_leave_pointer (&settings_backend_default_singleton, singleton); } return g_object_ref (settings_backend_default_singleton); diff --git a/gio/gsettingsbackend.h b/gio/gsettingsbackend.h index f579bf6..2649605 100644 --- a/gio/gsettingsbackend.h +++ b/gio/gsettingsbackend.h @@ -53,11 +53,6 @@ G_BEGIN_DECLS **/ #define G_SETTINGS_BACKEND_EXTENSION_POINT_NAME "gsettings-backend" -/** - * GSettingsBackend: - * - * An implementation of a settings storage repository. - **/ typedef struct _GSettingsBackendPrivate GSettingsBackendPrivate; typedef struct _GSettingsBackendClass GSettingsBackendClass; diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c index b3ac2f1..b191865 100644 --- a/gio/gsettingsschema.c +++ b/gio/gsettingsschema.c @@ -38,12 +38,9 @@ #endif /** - * SECTION:gsettingsschema - * @short_description: Introspecting and controlling the loading - * of GSettings schemas - * @include: gio/gio.h + * GSettingsSchema: * - * The #GSettingsSchemaSource and #GSettingsSchema APIs provide a + * The [struct@Gio.SettingsSchemaSource] and `GSettingsSchema` APIs provide a * mechanism for advanced control over the loading of schemas and a * mechanism for introspecting their content. * @@ -53,20 +50,20 @@ * the schema along with itself and it won't be installed into the * standard system directories for schemas. * - * #GSettingsSchemaSource provides a mechanism for dealing with this by - * allowing the creation of a new 'schema source' from which schemas can + * [struct@Gio.SettingsSchemaSource] provides a mechanism for dealing with this + * by allowing the creation of a new ‘schema source’ from which schemas can * be acquired. This schema source can then become part of the metadata * associated with the plugin and queried whenever the plugin requires * access to some settings. * * Consider the following example: * - * |[ + * ```c * typedef struct * { - * ... + * … * GSettingsSchemaSource *schema_source; - * ... + * … * } Plugin; * * Plugin * @@ -74,18 +71,18 @@ * { * Plugin *plugin; * - * ... + * … * * plugin->schema_source = * g_settings_schema_source_new_from_directory (dir, * g_settings_schema_source_get_default (), FALSE, NULL); * - * ... + * … * * return plugin; * } * - * ... + * … * * GSettings * * plugin_get_settings (Plugin *plugin, @@ -101,12 +98,12 @@ * * if (schema == NULL) * { - * ... disable the plugin or abort, etc ... + * … disable the plugin or abort, etc … * } * * return g_settings_new_full (schema, NULL, NULL); * } - * ]| + * ``` * * The code above shows how hooks should be added to the code that * initialises (or enables) the plugin to create the schema source and @@ -118,19 +115,19 @@ * ships a gschemas.compiled file as part of itself, and then simply do * the following: * - * |[ + * ```c * { * GSettings *settings; * gint some_value; * * settings = plugin_get_settings (self, NULL); * some_value = g_settings_get_int (settings, "some-value"); - * ... + * … * } - * ]| + * ``` * * It's also possible that the plugin system expects the schema source - * files (ie: .gschema.xml files) instead of a gschemas.compiled file. + * files (ie: `.gschema.xml` files) instead of a `gschemas.compiled` file. * In that case, the plugin loading system must compile the schemas for * itself before attempting to create the settings source. * @@ -144,13 +141,6 @@ * using the following functions. **/ -/** - * GSettingsSchema: - * - * This is an opaque structure type. You may not access it directly. - * - * Since: 2.32 - **/ struct _GSettingsSchema { GSettingsSchemaSource *source; @@ -580,7 +570,7 @@ normalise_whitespace (const gchar *orig) gchar *result; gint i; - if (g_once_init_enter (&splitter)) + if (g_once_init_enter_pointer (&splitter)) { GRegex *s; @@ -593,7 +583,7 @@ normalise_whitespace (const gchar *orig) s = g_regex_new ("\\n\\s*\\n+", G_REGEX_DEFAULT, G_REGEX_MATCH_DEFAULT, NULL); - g_once_init_leave (&splitter, s); + g_once_init_leave_pointer (&splitter, s); } lines = g_regex_split (splitter, orig, 0); @@ -744,7 +734,7 @@ parse_into_text_tables (const gchar *directory, static GHashTable ** g_settings_schema_source_get_text_tables (GSettingsSchemaSource *source) { - if (g_once_init_enter (&source->text_tables)) + if (g_once_init_enter_pointer (&source->text_tables)) { GHashTable **text_tables; @@ -755,7 +745,7 @@ g_settings_schema_source_get_text_tables (GSettingsSchemaSource *source) if (source->directory) parse_into_text_tables (source->directory, text_tables[0], text_tables[1]); - g_once_init_leave (&source->text_tables, text_tables); + g_once_init_leave_pointer (&source->text_tables, text_tables); } return source->text_tables; @@ -1496,7 +1486,7 @@ g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key) if (!key->desktop_overrides) return NULL; - if (g_once_init_enter (¤t_desktops)) + if (g_once_init_enter_pointer (¤t_desktops)) { const gchar *xdg_current_desktop = g_getenv ("XDG_CURRENT_DESKTOP"); gchar **tmp; @@ -1506,7 +1496,7 @@ g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key) else tmp = g_new0 (gchar *, 0 + 1); - g_once_init_leave (¤t_desktops, (const gchar **) tmp); + g_once_init_leave_pointer (¤t_desktops, (const gchar **) tmp); } for (i = 0; value == NULL && current_desktops[i] != NULL; i++) diff --git a/gio/gsimpleaction.c b/gio/gsimpleaction.c index 4e7e5b5..9d6039b 100644 --- a/gio/gsimpleaction.c +++ b/gio/gsimpleaction.c @@ -27,25 +27,15 @@ #include "glibintl.h" /** - * SECTION:gsimpleaction - * @title: GSimpleAction - * @short_description: A simple GAction implementation - * @include: gio/gio.h + * GSimpleAction: * - * A #GSimpleAction is the obvious simple implementation of the #GAction - * interface. This is the easiest way to create an action for purposes of - * adding it to a #GSimpleActionGroup. + * A `GSimpleAction` is the obvious simple implementation of the + * [iface@Gio.Action] interface. This is the easiest way to create an action for + * purposes of adding it to a [class@Gio.SimpleActionGroup]. * - * See also #GtkAction. + * See also [class@Gtk.Action]. */ -/** - * GSimpleAction: - * - * #GSimpleAction is an opaque data structure and can only be accessed - * using the following functions. - **/ - struct _GSimpleAction { GObject parent_instance; @@ -460,9 +450,7 @@ g_simple_action_class_init (GSimpleActionClass *class) * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_NAME, - g_param_spec_string ("name", - P_("Action Name"), - P_("The name used to invoke the action"), + g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -477,9 +465,7 @@ g_simple_action_class_init (GSimpleActionClass *class) * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_PARAMETER_TYPE, - g_param_spec_boxed ("parameter-type", - P_("Parameter Type"), - P_("The type of GVariant passed to activate()"), + g_param_spec_boxed ("parameter-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -496,9 +482,7 @@ g_simple_action_class_init (GSimpleActionClass *class) * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_ENABLED, - g_param_spec_boolean ("enabled", - P_("Enabled"), - P_("If the action can be activated"), + g_param_spec_boolean ("enabled", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -512,9 +496,7 @@ g_simple_action_class_init (GSimpleActionClass *class) * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_STATE_TYPE, - g_param_spec_boxed ("state-type", - P_("State Type"), - P_("The type of the state kept by the action"), + g_param_spec_boxed ("state-type", NULL, NULL, G_TYPE_VARIANT_TYPE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -527,9 +509,7 @@ g_simple_action_class_init (GSimpleActionClass *class) * Since: 2.28 **/ g_object_class_install_property (object_class, PROP_STATE, - g_param_spec_variant ("state", - P_("State"), - P_("The state the action is in"), + g_param_spec_variant ("state", NULL, NULL, G_VARIANT_TYPE_ANY, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | diff --git a/gio/gsimpleactiongroup.c b/gio/gsimpleactiongroup.c index 28ca21a..cd768a0 100644 --- a/gio/gsimpleactiongroup.c +++ b/gio/gsimpleactiongroup.c @@ -28,13 +28,13 @@ #include "gaction.h" /** - * SECTION:gsimpleactiongroup - * @title: GSimpleActionGroup - * @short_description: A simple GActionGroup implementation - * @include: gio/gio.h + * GSimpleActionGroup: * - * #GSimpleActionGroup is a hash table filled with #GAction objects, - * implementing the #GActionGroup and #GActionMap interfaces. + * `GSimpleActionGroup` is a hash table filled with [iface@Gio.Action] objects, + * implementing the [iface@Gio.ActionGroup] and [iface@Gio.ActionMap] + * interfaces. + * + * Since: 2.28 **/ struct _GSimpleActionGroupPrivate diff --git a/gio/gsimpleactiongroup.h b/gio/gsimpleactiongroup.h index 99282ba..48f669d 100644 --- a/gio/gsimpleactiongroup.h +++ b/gio/gsimpleactiongroup.h @@ -46,13 +46,6 @@ G_BEGIN_DECLS typedef struct _GSimpleActionGroupPrivate GSimpleActionGroupPrivate; typedef struct _GSimpleActionGroupClass GSimpleActionGroupClass; -/** - * GSimpleActionGroup: - * - * The #GSimpleActionGroup structure contains private data and should only be accessed using the provided API. - * - * Since: 2.28 - */ struct _GSimpleActionGroup { /*< private >*/ diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c index 43a063a..ef5492f 100644 --- a/gio/gsimpleasyncresult.c +++ b/gio/gsimpleasyncresult.c @@ -33,83 +33,81 @@ /** - * SECTION:gsimpleasyncresult - * @short_description: Simple asynchronous results implementation - * @include: gio/gio.h - * @see_also: #GAsyncResult, #GTask + * GSimpleAsyncResult: * - * As of GLib 2.46, #GSimpleAsyncResult is deprecated in favor of - * #GTask, which provides a simpler API. + * As of GLib 2.46, `GSimpleAsyncResult` is deprecated in favor of + * [class@Gio.Task], which provides a simpler API. * - * #GSimpleAsyncResult implements #GAsyncResult. + * `GSimpleAsyncResult` implements [iface@Gio.AsyncResult]. * - * GSimpleAsyncResult handles #GAsyncReadyCallbacks, error + * `GSimpleAsyncResult` handles [type@Gio.AsyncReadyCallback]s, error * reporting, operation cancellation and the final state of an operation, * completely transparent to the application. Results can be returned * as a pointer e.g. for functions that return data that is collected * asynchronously, a boolean value for checking the success or failure - * of an operation, or a #gssize for operations which return the number + * of an operation, or a `gssize` for operations which return the number * of bytes modified by the operation; all of the simple return cases * are covered. * * Most of the time, an application will not need to know of the details * of this API; it is handled transparently, and any necessary operations - * are handled by #GAsyncResult's interface. However, if implementing a - * new GIO module, for writing language bindings, or for complex + * are handled by [iface@Gio.AsyncResult]’s interface. However, if implementing + * a new GIO module, for writing language bindings, or for complex * applications that need better control of how asynchronous operations * are completed, it is important to understand this functionality. * - * GSimpleAsyncResults are tagged with the calling function to ensure + * `GSimpleAsyncResult`s are tagged with the calling function to ensure * that asynchronous functions and their finishing functions are used * together correctly. * - * To create a new #GSimpleAsyncResult, call g_simple_async_result_new(). - * If the result needs to be created for a #GError, use - * g_simple_async_result_new_from_error() or - * g_simple_async_result_new_take_error(). If a #GError is not available - * (e.g. the asynchronous operation's doesn't take a #GError argument), + * To create a new `GSimpleAsyncResult`, call [ctor@Gio.SimpleAsyncResult.new]. + * If the result needs to be created for a `GError`, use + * [ctor@Gio.SimpleAsyncResult.new_from_error] or + * [ctor@Gio.SimpleAsyncResult.new_take_error]. If a `GError` is not available + * (e.g. the asynchronous operation doesn’t take a `GError` argument), * but the result still needs to be created for an error condition, use - * g_simple_async_result_new_error() (or g_simple_async_result_set_error_va() - * if your application or binding requires passing a variable argument list - * directly), and the error can then be propagated through the use of - * g_simple_async_result_propagate_error(). + * [ctor@Gio.SimpleAsyncResult.new_error] (or + * [method@Gio.SimpleAsyncResult.set_error_va] if your application or binding + * requires passing a variable argument list directly), and the error can then + * be propagated through the use of + * [method@Gio.SimpleAsyncResult.propagate_error]. * * An asynchronous operation can be made to ignore a cancellation event by - * calling g_simple_async_result_set_handle_cancellation() with a - * #GSimpleAsyncResult for the operation and %FALSE. This is useful for + * calling [method@Gio.SimpleAsyncResult.set_handle_cancellation] with a + * `GSimpleAsyncResult` for the operation and `FALSE`. This is useful for * operations that are dangerous to cancel, such as close (which would * cause a leak if cancelled before being run). * - * GSimpleAsyncResult can integrate into GLib's event loop, #GMainLoop, - * or it can use #GThreads. - * g_simple_async_result_complete() will finish an I/O task directly - * from the point where it is called. g_simple_async_result_complete_in_idle() - * will finish it from an idle handler in the - * [thread-default main context][g-main-context-push-thread-default] - * where the #GSimpleAsyncResult was created. - * g_simple_async_result_run_in_thread() will run the job in a - * separate thread and then use - * g_simple_async_result_complete_in_idle() to deliver the result. + * `GSimpleAsyncResult` can integrate into GLib’s event loop, + * [type@GLib.MainLoop], or it can use [type@GLib.Thread]s. + * [method@Gio.SimpleAsyncResult.complete] will finish an I/O task directly + * from the point where it is called. + * [method@Gio.SimpleAsyncResult.complete_in_idle] will finish it from an idle + * handler in the thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) where the `GSimpleAsyncResult` + * was created. [method@Gio.SimpleAsyncResult.run_in_thread] will run the job in + * a separate thread and then use + * [method@Gio.SimpleAsyncResult.complete_in_idle] to deliver the result. * * To set the results of an asynchronous function, - * g_simple_async_result_set_op_res_gpointer(), - * g_simple_async_result_set_op_res_gboolean(), and - * g_simple_async_result_set_op_res_gssize() - * are provided, setting the operation's result to a gpointer, gboolean, or - * gssize, respectively. + * [method@Gio.SimpleAsyncResult.set_op_res_gpointer], + * [method@Gio.SimpleAsyncResult.set_op_res_gboolean], and + * [method@Gio.SimpleAsyncResult.set_op_res_gssize] + * are provided, setting the operation's result to a `gpointer`, `gboolean`, or + * `gssize`, respectively. * * Likewise, to get the result of an asynchronous function, - * g_simple_async_result_get_op_res_gpointer(), - * g_simple_async_result_get_op_res_gboolean(), and - * g_simple_async_result_get_op_res_gssize() are - * provided, getting the operation's result as a gpointer, gboolean, and - * gssize, respectively. + * [method@Gio.SimpleAsyncResult.get_op_res_gpointer], + * [method@Gio.SimpleAsyncResult.get_op_res_gboolean], and + * [method@Gio.SimpleAsyncResult.get_op_res_gssize] are + * provided, getting the operation’s result as a `gpointer`, `gboolean`, and + * `gssize`, respectively. * * For the details of the requirements implementations must respect, see - * #GAsyncResult. A typical implementation of an asynchronous operation - * using GSimpleAsyncResult looks something like this: + * [iface@Gio.AsyncResult]. A typical implementation of an asynchronous + * operation using `GSimpleAsyncResult` looks something like this: * - * |[ + * ```c * static void * baked_cb (Cake *cake, * gpointer user_data) @@ -202,7 +200,7 @@ * cake = CAKE (g_simple_async_result_get_op_res_gpointer (simple)); * return g_object_ref (cake); * } - * ]| + * ``` */ G_GNUC_BEGIN_IGNORE_DEPRECATIONS diff --git a/gio/gsimpleasyncresult.h b/gio/gsimpleasyncresult.h index 12efb9c..94ad355 100644 --- a/gio/gsimpleasyncresult.h +++ b/gio/gsimpleasyncresult.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_SIMPLE_ASYNC_RESULT_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SIMPLE_ASYNC_RESULT)) #define G_SIMPLE_ASYNC_RESULT_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SIMPLE_ASYNC_RESULT, GSimpleAsyncResultClass)) -/** - * GSimpleAsyncResult: - * - * A simple implementation of #GAsyncResult. - **/ typedef struct _GSimpleAsyncResultClass GSimpleAsyncResultClass; diff --git a/gio/gsimpleiostream.c b/gio/gsimpleiostream.c index da6df24..f46d6e2 100644 --- a/gio/gsimpleiostream.c +++ b/gio/gsimpleiostream.c @@ -28,27 +28,16 @@ #include "gtask.h" /** - * SECTION:gsimpleiostream - * @short_description: A wrapper around an input and an output stream. - * @include: gio/gio.h - * @see_also: #GIOStream - * - * GSimpleIOStream creates a #GIOStream from an arbitrary #GInputStream and - * #GOutputStream. This allows any pair of input and output streams to be used - * with #GIOStream methods. - * - * This is useful when you obtained a #GInputStream and a #GOutputStream - * by other means, for instance creating them with platform specific methods as - * g_unix_input_stream_new() or g_win32_input_stream_new(), and you want - * to take advantage of the methods provided by #GIOStream. - * - * Since: 2.44 - */ - -/** * GSimpleIOStream: * - * A wrapper around a #GInputStream and a #GOutputStream. + * `GSimpleIOStream` creates a [class@Gio.IOStream] from an arbitrary + * [class@Gio.InputStream] and [class@Gio.OutputStream]. This allows any pair of + * input and output streams to be used with [class@Gio.IOStream] methods. + * + * This is useful when you obtained a [class@Gio.InputStream] and a + * [class@Gio.OutputStream] by other means, for instance creating them with + * platform specific methods as [ctor@Gio.UnixInputStream.new], and you want to + * take advantage of the methods provided by [class@Gio.IOStream]. * * Since: 2.44 */ @@ -170,12 +159,12 @@ g_simple_io_stream_class_init (GSimpleIOStreamClass *class) /** * GSimpleIOStream:input-stream: * + * The [class@Gio.InputStream] to read from. + * * Since: 2.44 */ g_object_class_install_property (gobject_class, PROP_INPUT_STREAM, - g_param_spec_object ("input-stream", - P_("Input stream"), - P_("The GInputStream to read from"), + g_param_spec_object ("input-stream", NULL, NULL, G_TYPE_INPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | @@ -184,12 +173,12 @@ g_simple_io_stream_class_init (GSimpleIOStreamClass *class) /** * GSimpleIOStream:output-stream: * + * The [class@Gio.OutputStream] to write to. + * * Since: 2.44 */ g_object_class_install_property (gobject_class, PROP_OUTPUT_STREAM, - g_param_spec_object ("output-stream", - P_("Output stream"), - P_("The GOutputStream to write to"), + g_param_spec_object ("output-stream", NULL, NULL, G_TYPE_OUTPUT_STREAM, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | diff --git a/gio/gsimplepermission.c b/gio/gsimplepermission.c index 36358eb..3165509 100644 --- a/gio/gsimplepermission.c +++ b/gio/gsimplepermission.c @@ -26,23 +26,14 @@ /** - * SECTION:gsimplepermission - * @title: GSimplePermission - * @short_description: A GPermission that doesn't change value - * @include: gio/gio.h - * - * #GSimplePermission is a trivial implementation of #GPermission that - * represents a permission that is either always or never allowed. The - * value is given at construction and doesn't change. - * - * Calling request or release will result in errors. - **/ - -/** * GSimplePermission: * - * #GSimplePermission is an opaque data structure. There are no methods - * except for those defined by #GPermission. + * `GSimplePermission` is a trivial implementation of [class@Gio.Permission] + * that represents a permission that is either always or never allowed. The + * value is given at construction and doesn’t change. + * + * Calling [method@Gio.Permission.acquire] or [method@Gio.Permission.release] + * on a `GSimplePermission` will result in errors. **/ typedef GPermissionClass GSimplePermissionClass; diff --git a/gio/gsimpleproxyresolver.c b/gio/gsimpleproxyresolver.c index 8de26cb..4113652 100644 --- a/gio/gsimpleproxyresolver.c +++ b/gio/gsimpleproxyresolver.c @@ -33,19 +33,16 @@ #include "glibintl.h" /** - * SECTION:gsimpleproxyresolver - * @short_description: Simple proxy resolver implementation - * @include: gio/gio.h - * @see_also: g_socket_client_set_proxy_resolver() + * GSimpleProxyResolver: * - * #GSimpleProxyResolver is a simple #GProxyResolver implementation + * `GSimpleProxyResolver` is a simple [iface@Gio.ProxyResolver] implementation * that handles a single default proxy, multiple URI-scheme-specific * proxies, and a list of hosts that proxies should not be used for. * - * #GSimpleProxyResolver is never the default proxy resolver, but it + * `GSimpleProxyResolver` is never the default proxy resolver, but it * can be used as the base class for another proxy resolver * implementation, or it can be created and used manually, such as - * with g_socket_client_set_proxy_resolver(). + * with [method@Gio.SocketClient.set_proxy_resolver]. * * Since: 2.36 */ @@ -417,7 +414,7 @@ g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass *resolver_class) object_class->finalize = g_simple_proxy_resolver_finalize; /** - * GSimpleProxyResolver:default-proxy: (nullable) + * GSimpleProxyResolver:default-proxy: * * The default proxy URI that will be used for any URI that doesn't * match #GSimpleProxyResolver:ignore-hosts, and doesn't match any @@ -428,9 +425,7 @@ g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass *resolver_class) * to all three of the socks5, socks4a, and socks4 proxy types. */ g_object_class_install_property (object_class, PROP_DEFAULT_PROXY, - g_param_spec_string ("default-proxy", - P_("Default proxy"), - P_("The default proxy URI"), + g_param_spec_string ("default-proxy", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -474,9 +469,7 @@ g_simple_proxy_resolver_class_init (GSimpleProxyResolverClass *resolver_class) * commonly used by other applications. */ g_object_class_install_property (object_class, PROP_IGNORE_HOSTS, - g_param_spec_boxed ("ignore-hosts", - P_("Ignore hosts"), - P_("Hosts that will not use the proxy"), + g_param_spec_boxed ("ignore-hosts", NULL, NULL, G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -503,7 +496,7 @@ g_simple_proxy_resolver_iface_init (GProxyResolverInterface *iface) * #GSimpleProxyResolver:ignore-hosts for more details on how the * arguments are interpreted. * - * Returns: (transfer full) a new #GSimpleProxyResolver + * Returns: (transfer full): a new #GSimpleProxyResolver * * Since: 2.36 */ diff --git a/gio/gsimpleproxyresolver.h b/gio/gsimpleproxyresolver.h index 2e5f4b2..113b491 100644 --- a/gio/gsimpleproxyresolver.h +++ b/gio/gsimpleproxyresolver.h @@ -36,11 +36,6 @@ G_BEGIN_DECLS #define G_IS_SIMPLE_PROXY_RESOLVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SIMPLE_PROXY_RESOLVER)) #define G_SIMPLE_PROXY_RESOLVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SIMPLE_PROXY_RESOLVER, GSimpleProxyResolverClass)) -/** - * GSimpleProxyResolver: - * - * A #GProxyResolver implementation for using a fixed set of proxies. - **/ typedef struct _GSimpleProxyResolver GSimpleProxyResolver; typedef struct _GSimpleProxyResolverPrivate GSimpleProxyResolverPrivate; typedef struct _GSimpleProxyResolverClass GSimpleProxyResolverClass; diff --git a/gio/gsocket.c b/gio/gsocket.c index a4b57d9..c2ddade 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -83,46 +83,44 @@ #endif /** - * SECTION:gsocket - * @short_description: Low-level socket object - * @include: gio/gio.h - * @see_also: #GInitable, [][gio-gnetworking.h] + * GSocket: * - * A #GSocket is a low-level networking primitive. It is a more or less + * A `GSocket` is a low-level networking primitive. It is a more or less * direct mapping of the BSD socket API in a portable GObject based API. * It supports both the UNIX socket implementations and winsock2 on Windows. * - * #GSocket is the platform independent base upon which the higher level + * `GSocket` is the platform independent base upon which the higher level * network primitives are based. Applications are not typically meant to - * use it directly, but rather through classes like #GSocketClient, - * #GSocketService and #GSocketConnection. However there may be cases where - * direct use of #GSocket is useful. + * use it directly, but rather through classes like [class@Gio.SocketClient], + * [class@Gio.SocketService] and [class@Gio.SocketConnection]. However there may + * be cases where direct use of `GSocket` is useful. * - * #GSocket implements the #GInitable interface, so if it is manually constructed - * by e.g. g_object_new() you must call g_initable_init() and check the - * results before using the object. This is done automatically in - * g_socket_new() and g_socket_new_from_fd(), so these functions can return - * %NULL. + * `GSocket` implements the [iface@Gio.Initable] interface, so if it is manually + * constructed by e.g. [ctor@GObject.Object.new] you must call + * [method@Gio.Initable.init] and check the results before using the object. + * This is done automatically in [ctor@Gio.Socket.new] and + * [ctor@Gio.Socket.new_from_fd], so these functions can return `NULL`. * * Sockets operate in two general modes, blocking or non-blocking. When * in blocking mode all operations (which don’t take an explicit blocking * parameter) block until the requested operation * is finished or there is an error. In non-blocking mode all calls that - * would block return immediately with a %G_IO_ERROR_WOULD_BLOCK error. - * To know when a call would successfully run you can call g_socket_condition_check(), - * or g_socket_condition_wait(). You can also use g_socket_create_source() and - * attach it to a #GMainContext to get callbacks when I/O is possible. + * would block return immediately with a `G_IO_ERROR_WOULD_BLOCK` error. + * To know when a call would successfully run you can call + * [method@Gio.Socket.condition_check], or [method@Gio.Socket.condition_wait]. + * You can also use [method@Gio.Socket.create_source] and attach it to a + * [type@GLib.MainContext] to get callbacks when I/O is possible. * Note that all sockets are always set to non blocking mode in the system, and - * blocking mode is emulated in GSocket. + * blocking mode is emulated in `GSocket`. * * When working in non-blocking mode applications should always be able to - * handle getting a %G_IO_ERROR_WOULD_BLOCK error even when some other + * handle getting a `G_IO_ERROR_WOULD_BLOCK` error even when some other * function said that I/O was possible. This can easily happen in case * of a race condition in the application, but it can also happen for other * reasons. For instance, on Windows a socket is always seen as writable - * until a write returns %G_IO_ERROR_WOULD_BLOCK. + * until a write returns `G_IO_ERROR_WOULD_BLOCK`. * - * #GSockets can be either connection oriented or datagram based. + * `GSocket`s can be either connection oriented or datagram based. * For connection oriented types you must first establish a connection by * either connecting to an address or accepting a connection from another * address. For connectionless socket types the target/source address is @@ -130,16 +128,34 @@ * * All socket file descriptors are set to be close-on-exec. * - * Note that creating a #GSocket causes the signal %SIGPIPE to be + * Note that creating a `GSocket` causes the signal `SIGPIPE` to be * ignored for the remainder of the program. If you are writing a - * command-line utility that uses #GSocket, you may need to take into + * command-line utility that uses `GSocket`, you may need to take into * account the fact that your program will not automatically be killed - * if it tries to write to %stdout after it has been closed. + * if it tries to write to `stdout` after it has been closed. * - * Like most other APIs in GLib, #GSocket is not inherently thread safe. To use - * a #GSocket concurrently from multiple threads, you must implement your own + * Like most other APIs in GLib, `GSocket` is not inherently thread safe. To use + * a `GSocket` concurrently from multiple threads, you must implement your own * locking. * + * ## Nagle’s algorithm + * + * Since GLib 2.80, `GSocket` will automatically set the `TCP_NODELAY` option on + * all `G_SOCKET_TYPE_STREAM` sockets. This disables + * [Nagle’s algorithm](https://en.wikipedia.org/wiki/Nagle%27s_algorithm) as it + * typically does more harm than good on modern networks. + * + * If your application needs Nagle’s algorithm enabled, call + * [method@Gio.Socket.set_option] after constructing a `GSocket` to enable it: + * ```c + * socket = g_socket_new (…, G_SOCKET_TYPE_STREAM, …); + * if (socket != NULL) + * { + * g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, FALSE, &local_error); + * // handle error if needed + * } + * ``` + * * Since: 2.22 */ @@ -751,6 +767,8 @@ g_socket_constructed (GObject *object) /* See note about SIGPIPE below. */ g_socket_set_option (socket, SOL_SOCKET, SO_NOSIGPIPE, TRUE, NULL); #endif + if (socket->priv->type == G_SOCKET_TYPE_STREAM) + g_socket_set_option (socket, IPPROTO_TCP, TCP_NODELAY, TRUE, NULL); } } @@ -954,40 +972,60 @@ g_socket_class_init (GSocketClass *klass) gobject_class->set_property = g_socket_set_property; gobject_class->get_property = g_socket_get_property; + /** + * GSocket:family: + * + * The socket’s address family. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_FAMILY, - g_param_spec_enum ("family", - P_("Socket family"), - P_("The sockets address family"), + g_param_spec_enum ("family", NULL, NULL, G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:type: + * + * The socket’s type. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_TYPE, - g_param_spec_enum ("type", - P_("Socket type"), - P_("The sockets type"), + g_param_spec_enum ("type", NULL, NULL, G_TYPE_SOCKET_TYPE, G_SOCKET_TYPE_STREAM, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:protocol: + * + * The ID of the protocol to use, or `-1` for unknown. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PROTOCOL, - g_param_spec_enum ("protocol", - P_("Socket protocol"), - P_("The id of the protocol to use, or -1 for unknown"), + g_param_spec_enum ("protocol", NULL, NULL, G_TYPE_SOCKET_PROTOCOL, G_SOCKET_PROTOCOL_UNKNOWN, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:fd: + * + * The socket’s file descriptor. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_FD, - g_param_spec_int ("fd", - P_("File descriptor"), - P_("The sockets file descriptor"), + g_param_spec_int ("fd", NULL, NULL, G_MININT, G_MAXINT, -1, @@ -995,44 +1033,69 @@ g_socket_class_init (GSocketClass *klass) G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:blocking: + * + * Whether I/O on this socket is blocking. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_BLOCKING, - g_param_spec_boolean ("blocking", - P_("blocking"), - P_("Whether or not I/O on this socket is blocking"), + g_param_spec_boolean ("blocking", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:listen-backlog: + * + * The number of outstanding connections in the listen queue. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG, - g_param_spec_int ("listen-backlog", - P_("Listen backlog"), - P_("Outstanding connections in the listen queue"), + g_param_spec_int ("listen-backlog", NULL, NULL, 0, SOMAXCONN, 10, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:keepalive: + * + * Whether to keep the connection alive by sending periodic pings. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_KEEPALIVE, - g_param_spec_boolean ("keepalive", - P_("Keep connection alive"), - P_("Keep connection alive by sending periodic pings"), + g_param_spec_boolean ("keepalive", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:local-address: + * + * The local address the socket is bound to. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS, - g_param_spec_object ("local-address", - P_("Local address"), - P_("The local address the socket is bound to"), + g_param_spec_object ("local-address", NULL, NULL, G_TYPE_SOCKET_ADDRESS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); + /** + * GSocket:remote-address: + * + * The remote address the socket is connected to. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_REMOTE_ADDRESS, - g_param_spec_object ("remote-address", - P_("Remote address"), - P_("The remote address the socket is connected to"), + g_param_spec_object ("remote-address", NULL, NULL, G_TYPE_SOCKET_ADDRESS, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -1045,9 +1108,7 @@ g_socket_class_init (GSocketClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_TIMEOUT, - g_param_spec_uint ("timeout", - P_("Timeout"), - P_("The timeout in seconds on socket I/O"), + g_param_spec_uint ("timeout", NULL, NULL, 0, G_MAXUINT, 0, @@ -1062,9 +1123,7 @@ g_socket_class_init (GSocketClass *klass) * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_BROADCAST, - g_param_spec_boolean ("broadcast", - P_("Broadcast"), - P_("Whether to allow sending to broadcast addresses"), + g_param_spec_boolean ("broadcast", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -1077,9 +1136,7 @@ g_socket_class_init (GSocketClass *klass) * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_TTL, - g_param_spec_uint ("ttl", - P_("TTL"), - P_("Time-to-live of outgoing unicast packets"), + g_param_spec_uint ("ttl", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -1092,9 +1149,7 @@ g_socket_class_init (GSocketClass *klass) * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_MULTICAST_LOOPBACK, - g_param_spec_boolean ("multicast-loopback", - P_("Multicast loopback"), - P_("Whether outgoing multicast packets loop back to the local host"), + g_param_spec_boolean ("multicast-loopback", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -1107,9 +1162,7 @@ g_socket_class_init (GSocketClass *klass) * Since: 2.32 */ g_object_class_install_property (gobject_class, PROP_MULTICAST_TTL, - g_param_spec_uint ("multicast-ttl", - P_("Multicast TTL"), - P_("Time-to-live of outgoing multicast packets"), + g_param_spec_uint ("multicast-ttl", NULL, NULL, 0, G_MAXUINT, 1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -3179,8 +3232,8 @@ g_socket_get_available_bytes (GSocket *socket) #else if (socket->priv->type == G_SOCKET_TYPE_DATAGRAM) { - if (G_UNLIKELY (g_once_init_enter (&buf))) - g_once_init_leave (&buf, g_malloc (bufsize)); + if (G_UNLIKELY (g_once_init_enter_pointer (&buf))) + g_once_init_leave_pointer (&buf, g_malloc (bufsize)); /* On datagram sockets, FIONREAD ioctl is not reliable because many * systems add internal header size to the reported size, making it @@ -3313,6 +3366,69 @@ g_socket_receive_with_timeout (GSocket *socket, } /** + * g_socket_receive_bytes: + * @socket: a #GSocket + * @size: the number of bytes you want to read from the socket + * @timeout_us: the timeout to wait for, in microseconds, or `-1` to block + * indefinitely + * @cancellable: (nullable): a %GCancellable, or `NULL` + * @error: return location for a #GError, or `NULL` + * + * Receives data (up to @size bytes) from a socket. + * + * This function is a variant of [method@Gio.Socket.receive] which returns a + * [struct@GLib.Bytes] rather than a plain buffer. + * + * Pass `-1` to @timeout_us to block indefinitely until data is received (or + * the connection is closed, or there is an error). Pass `0` to use the default + * timeout from [property@Gio.Socket:timeout], or pass a positive number to wait + * for that many microseconds for data before returning `G_IO_ERROR_TIMED_OUT`. + * + * Returns: (transfer full): a bytes buffer containing the + * received bytes, or `NULL` on error + * Since: 2.80 + */ +GBytes * +g_socket_receive_bytes (GSocket *socket, + gsize size, + gint64 timeout_us, + GCancellable *cancellable, + GError **error) +{ + guint8 *data; + gssize res; + GBytes *buf; + + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + data = g_new0 (guint8, size); + res = g_socket_receive_with_timeout (socket, data, size, timeout_us, cancellable, error); + if (res < 0) + { + g_free (data); + return NULL; + } + + if ((gsize) res == size) + { + buf = g_bytes_new_take (g_steal_pointer (&data), (gsize) res); + } + else + { + GBytes *sub_buf; + + buf = g_bytes_new_take (g_steal_pointer (&data), size); + sub_buf = g_bytes_new_from_bytes (buf, 0, (gsize) res); + g_bytes_unref (buf); + buf = g_steal_pointer (&sub_buf); + } + + return g_steal_pointer (&buf); +} + +/** * g_socket_receive: * @socket: a #GSocket * @buffer: (array length=size) (element-type guint8) (out caller-allocates): @@ -3394,6 +3510,85 @@ g_socket_receive_with_blocking (GSocket *socket, } /** + * g_socket_receive_bytes_from: + * @socket: a #GSocket + * @address: (out) (optional): return location for a #GSocketAddress + * @size: the number of bytes you want to read from the socket + * @timeout_us: the timeout to wait for, in microseconds, or `-1` to block + * indefinitely + * @cancellable: (nullable): a #GCancellable, or `NULL` + * @error: return location for a #GError, or `NULL` + * + * Receive data (up to @size bytes) from a socket. + * + * This function is a variant of [method@Gio.Socket.receive_from] which returns + * a [struct@GLib.Bytes] rather than a plain buffer. + * + * If @address is non-%NULL then @address will be set equal to the + * source address of the received packet. + * + * The @address is owned by the caller. + * + * Pass `-1` to @timeout_us to block indefinitely until data is received (or + * the connection is closed, or there is an error). Pass `0` to use the default + * timeout from [property@Gio.Socket:timeout], or pass a positive number to wait + * for that many microseconds for data before returning `G_IO_ERROR_TIMED_OUT`. + * + * Returns: (transfer full): a bytes buffer containing the + * received bytes, or `NULL` on error + * Since: 2.80 + */ +GBytes * +g_socket_receive_bytes_from (GSocket *socket, + GSocketAddress **address, + gsize size, + gint64 timeout_us, + GCancellable *cancellable, + GError **error) +{ + GInputVector v; + gssize res; + GBytes *buf; + + g_return_val_if_fail (G_IS_SOCKET (socket), NULL); + g_return_val_if_fail (address == NULL || *address == NULL, NULL); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + v.buffer = g_new0 (guint8, size); + v.size = size; + + res = g_socket_receive_message_with_timeout (socket, + address, + &v, 1, + NULL, 0, NULL, + timeout_us, + cancellable, + error); + if (res < 0) + { + g_free (v.buffer); + return NULL; + } + + if ((gsize) res == size) + { + buf = g_bytes_new_take (g_steal_pointer (&v.buffer), (gsize) res); + } + else + { + GBytes *sub_buf; + + buf = g_bytes_new_take (g_steal_pointer (&v.buffer), size); + sub_buf = g_bytes_new_from_bytes (buf, 0, (gsize) res); + g_bytes_unref (buf); + buf = g_steal_pointer (&sub_buf); + } + + return g_steal_pointer (&buf); +} + +/** * g_socket_receive_from: * @socket: a #GSocket * @address: (out) (optional): a pointer to a #GSocketAddress @@ -4062,7 +4257,7 @@ socket_source_dispatch (GSource *source, #endif timeout = g_source_get_ready_time (source); - if (timeout >= 0 && timeout < g_source_get_time (source) && + if (timeout >= 0 && timeout <= g_source_get_time (source) && !g_socket_is_closed (socket_source->socket)) { socket->priv->timed_out = TRUE; diff --git a/gio/gsocket.h b/gio/gsocket.h index 0f0624b..341e23e 100644 --- a/gio/gsocket.h +++ b/gio/gsocket.h @@ -210,6 +210,12 @@ gssize g_socket_receive (GSocket gsize size, GCancellable *cancellable, GError **error); +GIO_AVAILABLE_IN_2_80 +GBytes * g_socket_receive_bytes (GSocket *socket, + gsize size, + gint64 timeout_us, + GCancellable *cancellable, + GError **error); GIO_AVAILABLE_IN_ALL gssize g_socket_receive_from (GSocket *socket, GSocketAddress **address, @@ -217,6 +223,13 @@ gssize g_socket_receive_from (GSocket gsize size, GCancellable *cancellable, GError **error); +GIO_AVAILABLE_IN_2_80 +GBytes * g_socket_receive_bytes_from (GSocket *socket, + GSocketAddress **address, + gsize size, + gint64 timeout_us, + GCancellable *cancellable, + GError **error); GIO_AVAILABLE_IN_ALL gssize g_socket_send (GSocket *socket, const gchar *buffer, diff --git a/gio/gsocketaddress.c b/gio/gsocketaddress.c index 994037c..09cb9ab 100644 --- a/gio/gsocketaddress.c +++ b/gio/gsocketaddress.c @@ -45,21 +45,12 @@ /** - * SECTION:gsocketaddress - * @short_description: Abstract base class representing endpoints - * for socket communication - * @include: gio/gio.h - * - * #GSocketAddress is the equivalent of struct sockaddr in the BSD - * sockets API. This is an abstract class; use #GInetSocketAddress - * for internet sockets, or #GUnixSocketAddress for UNIX domain sockets. - */ - -/** * GSocketAddress: * - * A socket endpoint address, corresponding to struct sockaddr - * or one of its subtypes. + * `GSocketAddress` is the equivalent of + * [`struct sockaddr`](man:sockaddr(3type)) and its subtypes in the BSD sockets + * API. This is an abstract class; use [class@Gio.InetSocketAddress] for + * internet sockets, or [class@Gio.UnixSocketAddress] for UNIX domain sockets. */ enum @@ -118,10 +109,15 @@ g_socket_address_class_init (GSocketAddressClass *klass) gobject_class->get_property = g_socket_address_get_property; + /** + * GSocketAddress:family: + * + * The family of the socket address. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_FAMILY, - g_param_spec_enum ("family", - P_("Address family"), - P_("The family of the socket address"), + g_param_spec_enum ("family", NULL, NULL, G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, G_PARAM_READABLE | diff --git a/gio/gsocketaddressenumerator.c b/gio/gsocketaddressenumerator.c index 5a0e937..8b99d50 100644 --- a/gio/gsocketaddressenumerator.c +++ b/gio/gsocketaddressenumerator.c @@ -25,23 +25,22 @@ #include "gtask.h" /** - * SECTION:gsocketaddressenumerator - * @short_description: Enumerator for socket addresses - * @include: gio/gio.h + * GSocketAddressEnumerator: * - * #GSocketAddressEnumerator is an enumerator type for #GSocketAddress - * instances. It is returned by enumeration functions such as - * g_socket_connectable_enumerate(), which returns a #GSocketAddressEnumerator - * to list each #GSocketAddress which could be used to connect to that - * #GSocketConnectable. + * `GSocketAddressEnumerator` is an enumerator type for + * [class@Gio.SocketAddress] instances. It is returned by enumeration functions + * such as [method@Gio.SocketConnectable.enumerate], which returns a + * `GSocketAddressEnumerator` to list each [class@Gio.SocketAddress] which could + * be used to connect to that [iface@Gio.SocketConnectable]. * * Enumeration is typically a blocking operation, so the asynchronous methods - * g_socket_address_enumerator_next_async() and - * g_socket_address_enumerator_next_finish() should be used where possible. + * [method@Gio.SocketAddressEnumerator.next_async] and + * [method@Gio.SocketAddressEnumerator.next_finish] should be used where + * possible. * - * Each #GSocketAddressEnumerator can only be enumerated once. Once - * g_socket_address_enumerator_next() has returned %NULL, further - * enumeration with that #GSocketAddressEnumerator is not possible, and it can + * Each `GSocketAddressEnumerator` can only be enumerated once. Once + * [method@Gio.SocketAddressEnumerator.next] has returned `NULL`, further + * enumeration with that `GSocketAddressEnumerator` is not possible, and it can * be unreffed. */ diff --git a/gio/gsocketaddressenumerator.h b/gio/gsocketaddressenumerator.h index ceee6a3..b3ff71c 100644 --- a/gio/gsocketaddressenumerator.h +++ b/gio/gsocketaddressenumerator.h @@ -36,12 +36,6 @@ G_BEGIN_DECLS #define G_IS_SOCKET_ADDRESS_ENUMERATOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_SOCKET_ADDRESS_ENUMERATOR)) #define G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_SOCKET_ADDRESS_ENUMERATOR, GSocketAddressEnumeratorClass)) -/** - * GSocketAddressEnumerator: - * - * Enumerator type for objects that contain or generate - * #GSocketAddress instances. - */ typedef struct _GSocketAddressEnumeratorClass GSocketAddressEnumeratorClass; struct _GSocketAddressEnumerator diff --git a/gio/gsocketclient.c b/gio/gsocketclient.c index 6eb4126..1127e45 100644 --- a/gio/gsocketclient.c +++ b/gio/gsocketclient.c @@ -60,27 +60,26 @@ /* As recommended by RFC 8305 this is the time it waits * on a connection before starting another concurrent attempt. + * + * See https://datatracker.ietf.org/doc/html/rfc8305#section-8 */ -#define HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS 250 +#define HAPPY_EYEBALLS_CONNECTION_ATTEMPT_DELAY_MS 250 /** - * SECTION:gsocketclient - * @short_description: Helper for connecting to a network service - * @include: gio/gio.h - * @see_also: #GSocketConnection, #GSocketListener + * GSocketClient: * - * #GSocketClient is a lightweight high-level utility class for connecting to + * `GSocketClient` is a lightweight high-level utility class for connecting to * a network host using a connection oriented socket type. * - * You create a #GSocketClient object, set any options you want, and then - * call a sync or async connect operation, which returns a #GSocketConnection - * subclass on success. + * You create a `GSocketClient` object, set any options you want, and then + * call a sync or async connect operation, which returns a + * [class@Gio.SocketConnection] subclass on success. * - * The type of the #GSocketConnection object returned depends on the type of - * the underlying socket that is in use. For instance, for a TCP/IP connection - * it will be a #GTcpConnection. + * The type of the [class@Gio.SocketConnection] object returned depends on the + * type of the underlying socket that is in use. For instance, for a TCP/IP + * connection it will be a [class@Gio.TcpConnection]. * - * As #GSocketClient is a lightweight object, you don't need to cache it. You + * As `GSocketClient` is a lightweight object, you don't need to cache it. You * can just create a new one any time you need one. * * Since: 2.22 @@ -869,67 +868,102 @@ g_socket_client_class_init (GSocketClientClass *class) G_TYPE_FROM_CLASS (class), _g_cclosure_marshal_VOID__ENUM_OBJECT_OBJECTv); + /** + * GSocketClient:family: + * + * The address family to use for socket construction. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_FAMILY, - g_param_spec_enum ("family", - P_("Socket family"), - P_("The sockets address family to use for socket construction"), + g_param_spec_enum ("family", NULL, NULL, G_TYPE_SOCKET_FAMILY, G_SOCKET_FAMILY_INVALID, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:type: + * + * The type to use for socket construction. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_TYPE, - g_param_spec_enum ("type", - P_("Socket type"), - P_("The sockets type to use for socket construction"), + g_param_spec_enum ("type", NULL, NULL, G_TYPE_SOCKET_TYPE, G_SOCKET_TYPE_STREAM, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:protocol: + * + * The protocol to use for socket construction, or `0` for default. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PROTOCOL, - g_param_spec_enum ("protocol", - P_("Socket protocol"), - P_("The protocol to use for socket construction, or 0 for default"), + g_param_spec_enum ("protocol", NULL, NULL, G_TYPE_SOCKET_PROTOCOL, G_SOCKET_PROTOCOL_DEFAULT, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:local-address: + * + * The local address constructed sockets will be bound to. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_LOCAL_ADDRESS, - g_param_spec_object ("local-address", - P_("Local address"), - P_("The local address constructed sockets will be bound to"), + g_param_spec_object ("local-address", NULL, NULL, G_TYPE_SOCKET_ADDRESS, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:timeout: + * + * The I/O timeout for sockets, in seconds, or `0` for none. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_TIMEOUT, - g_param_spec_uint ("timeout", - P_("Socket timeout"), - P_("The I/O timeout for sockets, or 0 for none"), + g_param_spec_uint ("timeout", NULL, NULL, 0, G_MAXUINT, 0, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:enable-proxy: + * + * Enable proxy support. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_ENABLE_PROXY, - g_param_spec_boolean ("enable-proxy", - P_("Enable proxy"), - P_("Enable proxy support"), + g_param_spec_boolean ("enable-proxy", NULL, NULL, TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GSocketClient:tls: + * + * Whether to create TLS connections. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_TLS, - g_param_spec_boolean ("tls", - P_("TLS"), - P_("Whether to create TLS connections"), + g_param_spec_boolean ("tls", NULL, NULL, FALSE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | @@ -958,9 +992,7 @@ g_socket_client_class_init (GSocketClientClass *class) * Deprecated: 2.72: Do not attempt to ignore validation errors. */ g_object_class_install_property (gobject_class, PROP_TLS_VALIDATION_FLAGS, - g_param_spec_flags ("tls-validation-flags", - P_("TLS validation flags"), - P_("TLS validation flags to use"), + g_param_spec_flags ("tls-validation-flags", NULL, NULL, G_TYPE_TLS_CERTIFICATE_FLAGS, G_TLS_CERTIFICATE_VALIDATE_ALL, G_PARAM_CONSTRUCT | @@ -976,9 +1008,7 @@ g_socket_client_class_init (GSocketClientClass *class) * Since: 2.36 */ g_object_class_install_property (gobject_class, PROP_PROXY_RESOLVER, - g_param_spec_object ("proxy-resolver", - P_("Proxy resolver"), - P_("The proxy resolver to use"), + g_param_spec_object ("proxy-resolver", NULL, NULL, G_TYPE_PROXY_RESOLVER, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | @@ -1473,7 +1503,10 @@ typedef struct GSList *successful_connections; SocketClientErrorInfo *error_info; - gboolean enumerated_at_least_once; + /* Number of times g_socket_address_enumerator_next_async() has successfully + * returned an address. */ + guint n_addresses_enumerated; + gboolean enumeration_completed; gboolean connection_in_progress; gboolean completed; @@ -1508,7 +1541,8 @@ typedef struct GIOStream *connection; GProxyAddress *proxy_addr; GSocketClientAsyncConnectData *data; /* unowned */ - GSource *timeout_source; + GSource *delay_timeout_source; /* (owned) */ + gboolean delay_reached; GCancellable *cancellable; GCancellable *task_cancellable; /* (owned); this is equal to g_task_get_cancellable (ConnectionAttempt.data->task), but with a longer lifetime */ gulong cancelled_id; @@ -1544,10 +1578,10 @@ connection_attempt_unref (gpointer pointer) attempt->cancelled_id = 0; g_clear_object (&attempt->cancellable); g_clear_object (&attempt->proxy_addr); - if (attempt->timeout_source) + if (attempt->delay_timeout_source) { - g_source_destroy (attempt->timeout_source); - g_source_unref (attempt->timeout_source); + g_source_destroy (attempt->delay_timeout_source); + g_source_unref (attempt->delay_timeout_source); } g_free (attempt); } @@ -1556,8 +1590,12 @@ connection_attempt_unref (gpointer pointer) static void connection_attempt_remove (ConnectionAttempt *attempt) { - attempt->data->connection_attempts = g_slist_remove (attempt->data->connection_attempts, attempt); - connection_attempt_unref (attempt); + GSList *attempt_link = g_slist_find (attempt->data->connection_attempts, attempt); + if (attempt_link != NULL) + { + attempt->data->connection_attempts = g_slist_delete_link (attempt->data->connection_attempts, attempt_link); + connection_attempt_unref (attempt); + } } static void @@ -1632,7 +1670,7 @@ enumerator_next_async (GSocketClientAsyncConnectData *data, if (add_task_ref) g_object_ref (data->task); - if (!data->enumerated_at_least_once) + if (data->n_addresses_enumerated == 0) g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVING, data->connectable, NULL); g_debug ("GSocketClient: Starting new address enumeration"); g_socket_address_enumerator_next_async (data->enumerator, @@ -1696,6 +1734,10 @@ G_GNUC_BEGIN_IGNORE_DEPRECATIONS data->client->priv->tls_validation_flags); G_GNUC_END_IGNORE_DEPRECATIONS g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_TLS_HANDSHAKING, data->connectable, G_IO_STREAM (tlsconn)); + + /* This operation will time out if the underlying #GSocket times out on + * any part of the TLS handshake. It does not have a higher-level + * timeout. */ g_tls_connection_handshake_async (G_TLS_CONNECTION (tlsconn), G_PRIORITY_DEFAULT, g_task_get_cancellable (data->task), @@ -1768,6 +1810,8 @@ task_completed_or_cancelled (GSocketClientAsyncConnectData *data) return FALSE; } +/* Returns %TRUE if it’s popped a connection of data->successful_connections and + * successfully started the next ongoing async operation for that connection. */ static gboolean try_next_successful_connection (GSocketClientAsyncConnectData *data) { @@ -1821,6 +1865,12 @@ try_next_successful_connection (GSocketClientAsyncConnectData *data) g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_PROXY_NEGOTIATING, data->connectable, attempt->connection); g_debug ("GSocketClient: Starting proxy connection"); + + /* FIXME: The #GProxy implementations do not have well-defined timeout + * behaviour, so this operation may theoretically never complete or time + * out. In practice, all #GProxy implementations use a #GSocket and a + * default timeout on that will eventually be hit. But there is no + * higher-level timeout. */ g_proxy_connect_async (proxy, connection, proxy_addr, @@ -1853,13 +1903,15 @@ try_next_connection_or_finish (GSocketClientAsyncConnectData *data, if (data->connection_in_progress) return; - /* Keep trying successful connections until one works, each iteration pops one */ + /* Try to pop and make progress on the next successful_connection. */ while (data->successful_connections) { if (try_next_successful_connection (data)) return; } + /* If there are no more successful_connections which we can make progress on, + * try the next address enumeration. */ if (!data->enumeration_completed) { enumerator_next_async (data, FALSE); @@ -1880,14 +1932,15 @@ g_socket_client_connected_callback (GObject *source, if (task_completed_or_cancelled (data) || g_cancellable_is_cancelled (attempt->cancellable)) { g_object_unref (data->task); + connection_attempt_remove (attempt); connection_attempt_unref (attempt); return; } - if (attempt->timeout_source) + if (attempt->delay_timeout_source) { - g_source_destroy (attempt->timeout_source); - g_clear_pointer (&attempt->timeout_source, g_source_unref); + g_source_destroy (attempt->delay_timeout_source); + g_clear_pointer (&attempt->delay_timeout_source, g_source_unref); } if (!g_socket_connection_connect_finish (G_SOCKET_CONNECTION (source), @@ -1930,17 +1983,20 @@ g_socket_client_connected_callback (GObject *source, } static gboolean -on_connection_attempt_timeout (gpointer data) +on_connection_attempt_delay_reached (gpointer data) { ConnectionAttempt *attempt = data; + g_assert (!attempt->delay_reached); + attempt->delay_reached = TRUE; + if (!attempt->data->enumeration_completed) { - g_debug ("GSocketClient: Timeout reached, trying another enumeration"); + g_debug ("GSocketClient: Connection attempt delay reached, trying another enumeration"); enumerator_next_async (attempt->data, TRUE); } - g_clear_pointer (&attempt->timeout_source, g_source_unref); + g_clear_pointer (&attempt->delay_timeout_source, g_source_unref); return G_SOURCE_REMOVE; } @@ -1987,8 +2043,8 @@ g_socket_client_enumerator_callback (GObject *object, If this fails and nothing is in progress then we will complete task here. */ - if ((data->enumerated_at_least_once && !data->connection_attempts && !data->connection_in_progress) || - !data->enumerated_at_least_once) + if ((data->n_addresses_enumerated > 0 && !data->connection_attempts && !data->connection_in_progress) || + data->n_addresses_enumerated == 0) { g_debug ("GSocketClient: Address enumeration failed: %s", data->error_info->tmp_error ? data->error_info->tmp_error->message : NULL); @@ -2003,12 +2059,11 @@ g_socket_client_enumerator_callback (GObject *object, } g_debug ("GSocketClient: Address enumeration succeeded"); - if (!data->enumerated_at_least_once) - { - g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVED, - data->connectable, NULL); - data->enumerated_at_least_once = TRUE; - } + if (data->n_addresses_enumerated == 0) + g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_RESOLVED, + data->connectable, NULL); + + data->n_addresses_enumerated++; socket = create_socket (data->client, address, &data->error_info->tmp_error); if (socket == NULL) @@ -2025,13 +2080,16 @@ g_socket_client_enumerator_callback (GObject *object, attempt->address = address; attempt->cancellable = g_cancellable_new (); attempt->connection = (GIOStream *)g_socket_connection_factory_create_connection (socket); - attempt->timeout_source = g_timeout_source_new (HAPPY_EYEBALLS_CONNECTION_ATTEMPT_TIMEOUT_MS); + attempt->delay_timeout_source = g_timeout_source_new (HAPPY_EYEBALLS_CONNECTION_ATTEMPT_DELAY_MS); + + g_debug ("%s: starting connection attempt %p for GSocketClientAsyncConnectData %p", + G_STRFUNC, attempt, data); if (G_IS_PROXY_ADDRESS (address) && data->client->priv->enable_proxy) attempt->proxy_addr = g_object_ref (G_PROXY_ADDRESS (address)); - g_source_set_callback (attempt->timeout_source, on_connection_attempt_timeout, attempt, NULL); - g_source_attach (attempt->timeout_source, g_task_get_context (data->task)); + g_source_set_callback (attempt->delay_timeout_source, on_connection_attempt_delay_reached, attempt, NULL); + g_source_attach (attempt->delay_timeout_source, g_task_get_context (data->task)); data->connection_attempts = g_slist_append (data->connection_attempts, connection_attempt_ref (attempt)); if (g_task_get_cancellable (data->task)) @@ -2045,6 +2103,10 @@ g_socket_client_enumerator_callback (GObject *object, g_socket_connection_set_cached_remote_address ((GSocketConnection *)attempt->connection, address); g_debug ("GSocketClient: Starting TCP connection attempt"); g_socket_client_emit_event (data->client, G_SOCKET_CLIENT_CONNECTING, data->connectable, attempt->connection); + + /* If client->priv->timeout is set, this async operation will time out after + * then. Otherwise it will continue until the kernel timeouts for a + * non-blocking connect() call (if any) are hit. */ g_socket_connection_connect_async (G_SOCKET_CONNECTION (attempt->connection), address, attempt->cancellable, @@ -2123,7 +2185,7 @@ g_socket_client_connect_async (GSocketClient *client, - Each connection is independent and kept in a ConnectionAttempt object. - They each hold a ref on the main task and have their own cancellable. - Multiple attempts may happen in parallel as per Happy Eyeballs. - - Upon failure or timeouts more connection attempts are made. + - Upon failure or attempt delays being reached more connection attempts are made. - If no connections succeed the task errors. - Upon success they are kept in a list of successful connections. @@ -2152,6 +2214,10 @@ g_socket_client_connect_async (GSocketClient *client, g_object_ref (data->enumeration_cancellable), g_object_unref); } + g_debug ("%s: starting new g_socket_client_connect_async() with GTask %p " + "and GSocketClientAsyncConnectData %p", + G_STRFUNC, data->task, data); + enumerator_next_async (data, FALSE); } diff --git a/gio/gsocketconnectable.c b/gio/gsocketconnectable.c index 1efde65..728992b 100644 --- a/gio/gsocketconnectable.c +++ b/gio/gsocketconnectable.c @@ -24,17 +24,15 @@ /** - * SECTION:gsocketconnectable - * @short_description: Interface for potential socket endpoints - * @include: gio/gio.h + * GSocketConnectable: * * Objects that describe one or more potential socket endpoints - * implement #GSocketConnectable. Callers can then use - * g_socket_connectable_enumerate() to get a #GSocketAddressEnumerator - * to try out each socket address in turn until one succeeds, as shown - * in the sample code below. + * implement `GSocketConnectable`. Callers can then use + * [method@Gio.SocketConnectable.enumerate] to get a + * [class@Gio.SocketAddressEnumerator] to try out each socket address in turn + * until one succeeds, as shown in the sample code below. * - * |[ + * ```c * MyConnectionType * * connect_to_host (const char *hostname, * guint16 port, @@ -84,7 +82,7 @@ * return NULL; * } * } - * ]| + * ``` */ diff --git a/gio/gsocketconnectable.h b/gio/gsocketconnectable.h index ed2cad9..bedef56 100644 --- a/gio/gsocketconnectable.h +++ b/gio/gsocketconnectable.h @@ -34,11 +34,6 @@ G_BEGIN_DECLS #define G_IS_SOCKET_CONNECTABLE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_SOCKET_CONNECTABLE)) #define G_SOCKET_CONNECTABLE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), G_TYPE_SOCKET_CONNECTABLE, GSocketConnectableIface)) -/** - * GSocketConnectable: - * - * Interface for objects that contain or generate a #GSocketAddress. - */ typedef struct _GSocketConnectableIface GSocketConnectableIface; /** diff --git a/gio/gsocketconnection.c b/gio/gsocketconnection.c index 67e8f3d..c535438 100644 --- a/gio/gsocketconnection.c +++ b/gio/gsocketconnection.c @@ -40,27 +40,24 @@ /** - * SECTION:gsocketconnection - * @short_description: A socket connection - * @include: gio/gio.h - * @see_also: #GIOStream, #GSocketClient, #GSocketListener + * GSocketConnection: * - * #GSocketConnection is a #GIOStream for a connected socket. They - * can be created either by #GSocketClient when connecting to a host, - * or by #GSocketListener when accepting a new client. + * `GSocketConnection` is a [class@Gio.IOStream] for a connected socket. They + * can be created either by [class@Gio.SocketClient] when connecting to a host, + * or by [class@Gio.SocketListener] when accepting a new client. * - * The type of the #GSocketConnection object returned from these calls + * The type of the `GSocketConnection` object returned from these calls * depends on the type of the underlying socket that is in use. For - * instance, for a TCP/IP connection it will be a #GTcpConnection. + * instance, for a TCP/IP connection it will be a [class@Gio.TcpConnection]. * * Choosing what type of object to construct is done with the socket - * connection factory, and it is possible for 3rd parties to register + * connection factory, and it is possible for third parties to register * custom socket connection types for specific combination of socket - * family/type/protocol using g_socket_connection_factory_register_type(). + * family/type/protocol using [func@Gio.SocketConnection.factory_register_type]. * - * To close a #GSocketConnection, use g_io_stream_close(). Closing both - * substreams of the #GIOStream separately will not close the underlying - * #GSocket. + * To close a `GSocketConnection`, use [method@Gio.IOStream.close]. Closing both + * substreams of the [class@Gio.IOStream] separately will not close the + * underlying [class@Gio.Socket]. * * Since: 2.22 */ @@ -180,6 +177,10 @@ static gboolean g_socket_connection_connect_callback (GSocket *socket, * This clears the #GSocket:blocking flag on @connection's underlying * socket if it is currently set. * + * If #GSocket:timeout is set, the operation will time out and return + * %G_IO_ERROR_TIMED_OUT after that period. Otherwise, it will continue + * indefinitely until operating system timeouts (if any) are hit. + * * Use g_socket_connection_connect_finish() to retrieve the result. * * Since: 2.32 @@ -448,11 +449,16 @@ g_socket_connection_class_init (GSocketConnectionClass *klass) stream_class->close_async = g_socket_connection_close_async; stream_class->close_finish = g_socket_connection_close_finish; + /** + * GSocketConnection:socket: + * + * The underlying [class@Gio.Socket]. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_SOCKET, - g_param_spec_object ("socket", - P_("Socket"), - P_("The underlying GSocket"), + g_param_spec_object ("socket", NULL, NULL, G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | diff --git a/gio/gsocketcontrolmessage.c b/gio/gsocketcontrolmessage.c index 398e04e..d79bd74 100644 --- a/gio/gsocketcontrolmessage.c +++ b/gio/gsocketcontrolmessage.c @@ -15,32 +15,28 @@ */ /** - * SECTION:gsocketcontrolmessage - * @title: GSocketControlMessage - * @short_description: A GSocket control message - * @include: gio/gio.h - * @see_also: #GSocket. + * GSocketControlMessage: * - * A #GSocketControlMessage is a special-purpose utility message that - * can be sent to or received from a #GSocket. These types of - * messages are often called "ancillary data". + * A `GSocketControlMessage` is a special-purpose utility message that + * can be sent to or received from a [class@Gio.Socket]. These types of + * messages are often called ‘ancillary data’. * * The message can represent some sort of special instruction to or * information from the socket or can represent a special kind of * transfer to the peer (for example, sending a file descriptor over * a UNIX socket). * - * These messages are sent with g_socket_send_message() and received - * with g_socket_receive_message(). + * These messages are sent with [method@Gio.Socket.send_message] and received + * with [method@Gio.Socket.receive_message]. * * To extend the set of control message that can be sent, subclass this - * class and override the get_size, get_level, get_type and serialize + * class and override the `get_size`, `get_level`, `get_type` and `serialize` * methods. * * To extend the set of control messages that can be received, subclass - * this class and implement the deserialize method. Also, make sure your - * class is registered with the GType typesystem before calling - * g_socket_receive_message() to read such a message. + * this class and implement the `deserialize` method. Also, make sure your + * class is registered with the [type@GObject.Type] type system before calling + * [method@Gio.Socket.receive_message] to read such a message. * * Since: 2.22 */ diff --git a/gio/gsocketinputstream.c b/gio/gsocketinputstream.c index 5307fcd..7a15f51 100644 --- a/gio/gsocketinputstream.c +++ b/gio/gsocketinputstream.c @@ -191,9 +191,7 @@ g_socket_input_stream_class_init (GSocketInputStreamClass *klass) ginputstream_class->read_fn = g_socket_input_stream_read; g_object_class_install_property (gobject_class, PROP_SOCKET, - g_param_spec_object ("socket", - P_("socket"), - P_("The socket that this stream wraps"), + g_param_spec_object ("socket", NULL, NULL, G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c index 392f9ec..8a296a5 100644 --- a/gio/gsocketlistener.c +++ b/gio/gsocketlistener.c @@ -42,26 +42,23 @@ /** - * SECTION:gsocketlistener - * @title: GSocketListener - * @short_description: Helper for accepting network client connections - * @include: gio/gio.h - * @see_also: #GThreadedSocketService, #GSocketService. + * GSocketListener: * - * A #GSocketListener is an object that keeps track of a set + * A `GSocketListener` is an object that keeps track of a set * of server sockets and helps you accept sockets from any of the * socket, either sync or async. * - * Add addresses and ports to listen on using g_socket_listener_add_address() - * and g_socket_listener_add_inet_port(). These will be listened on until - * g_socket_listener_close() is called. Dropping your final reference to the - * #GSocketListener will not cause g_socket_listener_close() to be called - * implicitly, as some references to the #GSocketListener may be held + * Add addresses and ports to listen on using + * [method@Gio.SocketListener.add_address] and + * [method@Gio.SocketListener.add_inet_port]. These will be listened on until + * [method@Gio.SocketListener.close] is called. Dropping your final reference to + * the `GSocketListener` will not cause [method@Gio.SocketListener.close] to be + * called implicitly, as some references to the `GSocketListener` may be held * internally. * - * If you want to implement a network server, also look at #GSocketService - * and #GThreadedSocketService which are subclasses of #GSocketListener - * that make this even easier. + * If you want to implement a network server, also look at + * [class@Gio.SocketService] and [class@Gio.ThreadedSocketService] which are + * subclasses of `GSocketListener` that make this even easier. * * Since: 2.22 */ @@ -157,10 +154,16 @@ g_socket_listener_class_init (GSocketListenerClass *klass) gobject_class->finalize = g_socket_listener_finalize; gobject_class->set_property = g_socket_listener_set_property; gobject_class->get_property = g_socket_listener_get_property; + + /** + * GSocketListener:listen-backlog: + * + * The number of outstanding connections in the listen queue. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_LISTEN_BACKLOG, - g_param_spec_int ("listen-backlog", - P_("Listen backlog"), - P_("outstanding connections in the listen queue"), + g_param_spec_int ("listen-backlog", NULL, NULL, 0, 2000, 10, diff --git a/gio/gsocketoutputstream.c b/gio/gsocketoutputstream.c index d380c52..a5b4c35 100644 --- a/gio/gsocketoutputstream.c +++ b/gio/gsocketoutputstream.c @@ -247,9 +247,7 @@ g_socket_output_stream_class_init (GSocketOutputStreamClass *klass) goutputstream_class->writev_fn = g_socket_output_stream_writev; g_object_class_install_property (gobject_class, PROP_SOCKET, - g_param_spec_object ("socket", - P_("socket"), - P_("The socket that this stream wraps"), + g_param_spec_object ("socket", NULL, NULL, G_TYPE_SOCKET, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gsocketservice.c b/gio/gsocketservice.c index 42e18d0..324e6ef 100644 --- a/gio/gsocketservice.c +++ b/gio/gsocketservice.c @@ -23,37 +23,33 @@ */ /** - * SECTION:gsocketservice - * @title: GSocketService - * @short_description: Make it easy to implement a network service - * @include: gio/gio.h - * @see_also: #GThreadedSocketService, #GSocketListener. + * GSocketService: * - * A #GSocketService is an object that represents a service that + * A `GSocketService` is an object that represents a service that * is provided to the network or over local sockets. When a new - * connection is made to the service the #GSocketService::incoming + * connection is made to the service the [signal@Gio.SocketService::incoming] * signal is emitted. * - * A #GSocketService is a subclass of #GSocketListener and you need + * A `GSocketService` is a subclass of [class@Gio.SocketListener] and you need * to add the addresses you want to accept connections on with the - * #GSocketListener APIs. + * [class@Gio.SocketListener] APIs. * * There are two options for implementing a network service based on - * #GSocketService. The first is to create the service using - * g_socket_service_new() and to connect to the #GSocketService::incoming - * signal. The second is to subclass #GSocketService and override the - * default signal handler implementation. + * `GSocketService`. The first is to create the service using + * [ctor@Gio.SocketService.new] and to connect to the + * [signal@Gio.SocketService::incoming] signal. The second is to subclass + * `GSocketService` and override the default signal handler implementation. * * In either case, the handler must immediately return, or else it * will block additional incoming connections from being serviced. * If you are interested in writing connection handlers that contain - * blocking code then see #GThreadedSocketService. + * blocking code then see [class@Gio.ThreadedSocketService]. * * The socket service runs on the main loop of the - * [thread-default context][g-main-context-push-thread-default-context] - * of the thread it is created in, and is not - * threadsafe in general. However, the calls to start and stop the - * service are thread-safe so these can be used from threads that + * thread-default context (see + * [method@GLib.MainContext.push_thread_default]) of the thread it is + * created in, and is not threadsafe in general. However, the calls to start and + * stop the service are thread-safe so these can be used from threads that * handle incoming clients. * * Since: 2.22 @@ -364,9 +360,7 @@ g_socket_service_class_init (GSocketServiceClass *class) * Since: 2.46 */ g_object_class_install_property (gobject_class, PROP_ACTIVE, - g_param_spec_boolean ("active", - P_("Active"), - P_("Whether the service is currently accepting connections"), + g_param_spec_boolean ("active", NULL, NULL, TRUE, G_PARAM_CONSTRUCT | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gsocks5proxy.c b/gio/gsocks5proxy.c index 6f25672..71ac107 100644 --- a/gio/gsocks5proxy.c +++ b/gio/gsocks5proxy.c @@ -724,10 +724,10 @@ nego_reply_read_cb (GObject *source, if (read == 0) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection to SOCKSv5 proxy server lost"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection to SOCKSv5 proxy server lost"); g_object_unref (task); return; } @@ -837,10 +837,10 @@ auth_reply_read_cb (GObject *source, if (read == 0) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection to SOCKSv5 proxy server lost"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection to SOCKSv5 proxy server lost"); g_object_unref (task); return; } @@ -949,10 +949,10 @@ connect_reply_read_cb (GObject *source, if (read == 0) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection to SOCKSv5 proxy server lost"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection to SOCKSv5 proxy server lost"); g_object_unref (task); return; } @@ -1019,10 +1019,10 @@ connect_addr_len_read_cb (GObject *source, if (read == 0) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection to SOCKSv5 proxy server lost"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection to SOCKSv5 proxy server lost"); g_object_unref (task); return; } @@ -1055,10 +1055,10 @@ connect_addr_read_cb (GObject *source, if (read == 0) { - g_task_return_new_error (task, - G_IO_ERROR, - G_IO_ERROR_CONNECTION_CLOSED, - "Connection to SOCKSv5 proxy server lost"); + g_task_return_new_error_literal (task, + G_IO_ERROR, + G_IO_ERROR_CONNECTION_CLOSED, + "Connection to SOCKSv5 proxy server lost"); g_object_unref (task); return; } diff --git a/gio/gsrvtarget.c b/gio/gsrvtarget.c index cecd4eb..f5f17ef 100644 --- a/gio/gsrvtarget.c +++ b/gio/gsrvtarget.c @@ -31,24 +31,24 @@ /** - * SECTION:gsrvtarget - * @short_description: DNS SRV record target - * @include: gio/gio.h + * GSrvTarget: + * + * A single target host/port that a network service is running on. * * SRV (service) records are used by some network protocols to provide * service-specific aliasing and load-balancing. For example, XMPP * (Jabber) uses SRV records to locate the XMPP server for a domain; - * rather than connecting directly to "example.com" or assuming a - * specific server hostname like "xmpp.example.com", an XMPP client - * would look up the "xmpp-client" SRV record for "example.com", and + * rather than connecting directly to ‘example.com’ or assuming a + * specific server hostname like ‘xmpp.example.com’, an XMPP client + * would look up the `xmpp-client` SRV record for ‘example.com’, and * then connect to whatever host was pointed to by that record. * - * You can use g_resolver_lookup_service() or - * g_resolver_lookup_service_async() to find the #GSrvTargets + * You can use [method@Gio.Resolver.lookup_service] or + * [method@Gio.Resolver.lookup_service_async] to find the `GSrvTarget`s * for a given service. However, if you are simply planning to connect - * to the remote service, you can use #GNetworkService's - * #GSocketConnectable interface and not need to worry about - * #GSrvTarget at all. + * to the remote service, you can use [class@Gio.NetworkService]’s + * [iface@Gio.SocketConnectable] interface and not need to worry about + * `GSrvTarget` at all. */ struct _GSrvTarget { @@ -59,12 +59,6 @@ struct _GSrvTarget { guint16 weight; }; -/** - * GSrvTarget: - * - * A single target host/port that a network service is running on. - */ - G_DEFINE_BOXED_TYPE (GSrvTarget, g_srv_target, g_srv_target_copy, g_srv_target_free) diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c index c4747a1..6af94db 100644 --- a/gio/gsubprocess.c +++ b/gio/gsubprocess.c @@ -17,18 +17,14 @@ */ /** - * SECTION:gsubprocess - * @title: GSubprocess - * @short_description: Child processes - * @include: gio/gio.h - * @see_also: #GSubprocessLauncher + * GSubprocess: * - * #GSubprocess allows the creation of and interaction with child + * `GSubprocess` allows the creation of and interaction with child * processes. * * Processes can be communicated with using standard GIO-style APIs (ie: - * #GInputStream, #GOutputStream). There are GIO-style APIs to wait for - * process termination (ie: cancellable and with an asynchronous + * [class@Gio.InputStream], [class@Gio.OutputStream]). There are GIO-style APIs + * to wait for process termination (ie: cancellable and with an asynchronous * variant). * * There is an API to force a process to terminate, as well as a @@ -36,50 +32,50 @@ * * One major advantage that GIO brings over the core GLib library is * comprehensive API for asynchronous I/O, such - * g_output_stream_splice_async(). This makes GSubprocess + * [method@Gio.OutputStream.splice_async]. This makes `GSubprocess` * significantly more powerful and flexible than equivalent APIs in * some other languages such as the `subprocess.py` - * included with Python. For example, using #GSubprocess one could + * included with Python. For example, using `GSubprocess` one could * create two child processes, reading standard output from the first, * processing it, and writing to the input stream of the second, all * without blocking the main loop. * - * A powerful g_subprocess_communicate() API is provided similar to the + * A powerful [method@Gio.Subprocess.communicate] API is provided similar to the * `communicate()` method of `subprocess.py`. This enables very easy * interaction with a subprocess that has been opened with pipes. * - * #GSubprocess defaults to tight control over the file descriptors open - * in the child process, avoiding dangling-fd issues that are caused by - * a simple fork()/exec(). The only open file descriptors in the + * `GSubprocess` defaults to tight control over the file descriptors open + * in the child process, avoiding dangling-FD issues that are caused by + * a simple `fork()`/`exec()`. The only open file descriptors in the * spawned process are ones that were explicitly specified by the - * #GSubprocess API (unless %G_SUBPROCESS_FLAGS_INHERIT_FDS was + * `GSubprocess` API (unless `G_SUBPROCESS_FLAGS_INHERIT_FDS` was * specified). * - * #GSubprocess will quickly reap all child processes as they exit, - * avoiding "zombie processes" remaining around for long periods of - * time. g_subprocess_wait() can be used to wait for this to happen, + * `GSubprocess` will quickly reap all child processes as they exit, + * avoiding ‘zombie processes’ remaining around for long periods of + * time. [method@Gio.Subprocess.wait] can be used to wait for this to happen, * but it will happen even without the call being explicitly made. * - * As a matter of principle, #GSubprocess has no API that accepts + * As a matter of principle, `GSubprocess` has no API that accepts * shell-style space-separated strings. It will, however, match the - * typical shell behaviour of searching the PATH for executables that do + * typical shell behaviour of searching the `PATH` for executables that do * not contain a directory separator in their name. By default, the `PATH` * of the current process is used. You can specify - * %G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP to use the `PATH` of the + * `G_SUBPROCESS_FLAGS_SEARCH_PATH_FROM_ENVP` to use the `PATH` of the * launcher environment instead. * - * #GSubprocess attempts to have a very simple API for most uses (ie: + * `GSubprocess` attempts to have a very simple API for most uses (ie: * spawning a subprocess with arguments and support for most typical - * kinds of input and output redirection). See g_subprocess_new(). The - * #GSubprocessLauncher API is provided for more complicated cases + * kinds of input and output redirection). See [ctor@Gio.Subprocess.new]. The + * [class@Gio.SubprocessLauncher] API is provided for more complicated cases * (advanced types of redirection, environment variable manipulation, * change of working directory, child setup functions, etc). * - * A typical use of #GSubprocess will involve calling - * g_subprocess_new(), followed by g_subprocess_wait_async() or - * g_subprocess_wait(). After the process exits, the status can be - * checked using functions such as g_subprocess_get_if_exited() (which - * are similar to the familiar WIFEXITED-style POSIX macros). + * A typical use of `GSubprocess` will involve calling + * [ctor@Gio.Subprocess.new], followed by [method@Gio.Subprocess.wait_async] or + * [method@Gio.Subprocess.wait]. After the process exits, the status can be + * checked using functions such as [method@Gio.Subprocess.get_if_exited] (which + * are similar to the familiar `WIFEXITED`-style POSIX macros). * * Since: 2.40 **/ @@ -500,12 +496,27 @@ g_subprocess_class_init (GSubprocessClass *class) gobject_class->finalize = g_subprocess_finalize; gobject_class->set_property = g_subprocess_set_property; + /** + * GSubprocess:flags: + * + * Subprocess flags. + * + * Since: 2.40 + */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", P_("Flags"), P_("Subprocess flags"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GSubprocess:argv: + * + * Argument vector. + * + * Since: 2.40 + */ g_object_class_install_property (gobject_class, PROP_ARGV, - g_param_spec_boxed ("argv", P_("Arguments"), P_("Argument vector"), + g_param_spec_boxed ("argv", NULL, NULL, G_TYPE_STRV, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gsubprocesslauncher.c b/gio/gsubprocesslauncher.c index 759ddf0..d5ec01e 100644 --- a/gio/gsubprocesslauncher.c +++ b/gio/gsubprocesslauncher.c @@ -17,16 +17,13 @@ */ /** - * SECTION:gsubprocesslauncher - * @title: GSubprocess Launcher - * @short_description: Environment options for launching a child process - * @include: gio/gio.h + * GSubprocessLauncher: * * This class contains a set of options for launching child processes, * such as where its standard input and output will be directed, the * argument list, the environment, and more. * - * While the #GSubprocess class has high level functions covering + * While the [class@Gio.Subprocess] class has high level functions covering * popular cases, use of this class allows access to more advanced * options. It can also be used to launch multiple subprocesses with * a similar configuration. @@ -179,8 +176,15 @@ g_subprocess_launcher_class_init (GSubprocessLauncherClass *class) gobject_class->set_property = g_subprocess_launcher_set_property; gobject_class->dispose = g_subprocess_launcher_dispose; + /** + * GSubprocessLauncher:flags: + * + * [flags@Gio.SubprocessFlags] for launched processes. + * + * Since: 2.40 + */ g_object_class_install_property (gobject_class, 1, - g_param_spec_flags ("flags", "Flags", "GSubprocessFlags for launched processes", + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_SUBPROCESS_FLAGS, 0, G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY)); } @@ -403,7 +407,7 @@ assign_fd (gint *fd_ptr, gint fd) /** * g_subprocess_launcher_set_stdin_file_path: * @self: a #GSubprocessLauncher - * @path: (type filename) (nullable: a filename or %NULL + * @path: (type filename) (nullable): a filename or %NULL * * Sets the file path to use as the stdin for spawned processes. * diff --git a/gio/gtask.c b/gio/gtask.c index 1272700..dd5730b 100644 --- a/gio/gtask.c +++ b/gio/gtask.c @@ -33,520 +33,518 @@ #include /** - * SECTION:gtask - * @short_description: Cancellable synchronous or asynchronous task - * and result - * @include: gio/gio.h - * @see_also: #GAsyncResult + * GTask: * - * A #GTask represents and manages a cancellable "task". + * A `GTask` represents and manages a cancellable ‘task’. * * ## Asynchronous operations * - * The most common usage of #GTask is as a #GAsyncResult, to + * The most common usage of `GTask` is as a [iface@Gio.AsyncResult], to * manage data during an asynchronous operation. You call - * g_task_new() in the "start" method, followed by - * g_task_set_task_data() and the like if you need to keep some + * [ctor@Gio.Task.new] in the ‘start’ method, followed by + * [method@Gio.Task.set_task_data] and the like if you need to keep some * additional data associated with the task, and then pass the * task object around through your asynchronous operation. * Eventually, you will call a method such as - * g_task_return_pointer() or g_task_return_error(), which will - * save the value you give it and then invoke the task's callback - * function in the - * [thread-default main context][g-main-context-push-thread-default] + * [method@Gio.Task.return_pointer] or [method@Gio.Task.return_error], which + * will save the value you give it and then invoke the task’s callback + * function in the thread-default main context (see + * [method@GLib.MainContext.push_thread_default]) * where it was created (waiting until the next iteration of the main - * loop first, if necessary). The caller will pass the #GTask back to - * the operation's finish function (as a #GAsyncResult), and you can - * use g_task_propagate_pointer() or the like to extract the + * loop first, if necessary). The caller will pass the `GTask` back to + * the operation’s finish function (as a [iface@Gio.AsyncResult]), and you can + * use [method@Gio.Task.propagate_pointer] or the like to extract the * return value. * - * Using #GTask requires the thread-default #GMainContext from when the - * #GTask was constructed to be running at least until the task has completed - * and its data has been freed. + * Using `GTask` requires the thread-default [struct@GLib.MainContext] from when + * the `GTask` was constructed to be running at least until the task has + * completed and its data has been freed. * - * If a #GTask has been constructed and its callback set, it is an error to + * If a `GTask` has been constructed and its callback set, it is an error to * not call `g_task_return_*()` on it. GLib will warn at runtime if this happens * (since 2.76). * - * Here is an example for using GTask as a GAsyncResult: - * |[ - * typedef struct { - * CakeFrostingType frosting; - * char *message; - * } DecorationData; - * - * static void - * decoration_data_free (DecorationData *decoration) + * Here is an example for using `GTask` as a [iface@Gio.AsyncResult]: + * ```c + * typedef struct { + * CakeFrostingType frosting; + * char *message; + * } DecorationData; + * + * static void + * decoration_data_free (DecorationData *decoration) + * { + * g_free (decoration->message); + * g_slice_free (DecorationData, decoration); + * } + * + * static void + * baked_cb (Cake *cake, + * gpointer user_data) + * { + * GTask *task = user_data; + * DecorationData *decoration = g_task_get_task_data (task); + * GError *error = NULL; + * + * if (cake == NULL) * { - * g_free (decoration->message); - * g_slice_free (DecorationData, decoration); + * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, + * "Go to the supermarket"); + * g_object_unref (task); + * return; * } * - * static void - * baked_cb (Cake *cake, - * gpointer user_data) + * if (!cake_decorate (cake, decoration->frosting, decoration->message, &error)) * { - * GTask *task = user_data; - * DecorationData *decoration = g_task_get_task_data (task); - * GError *error = NULL; - * - * if (cake == NULL) - * { - * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, - * "Go to the supermarket"); - * g_object_unref (task); - * return; - * } - * - * if (!cake_decorate (cake, decoration->frosting, decoration->message, &error)) - * { - * g_object_unref (cake); - * // g_task_return_error() takes ownership of error - * g_task_return_error (task, error); - * g_object_unref (task); - * return; - * } - * - * g_task_return_pointer (task, cake, g_object_unref); + * g_object_unref (cake); + * // g_task_return_error() takes ownership of error + * g_task_return_error (task, error); * g_object_unref (task); + * return; * } * - * void - * baker_bake_cake_async (Baker *self, - * guint radius, - * CakeFlavor flavor, - * CakeFrostingType frosting, - * const char *message, - * GCancellable *cancellable, - * GAsyncReadyCallback callback, - * gpointer user_data) + * g_task_return_pointer (task, cake, g_object_unref); + * g_object_unref (task); + * } + * + * void + * baker_bake_cake_async (Baker *self, + * guint radius, + * CakeFlavor flavor, + * CakeFrostingType frosting, + * const char *message, + * GCancellable *cancellable, + * GAsyncReadyCallback callback, + * gpointer user_data) + * { + * GTask *task; + * DecorationData *decoration; + * Cake *cake; + * + * task = g_task_new (self, cancellable, callback, user_data); + * if (radius < 3) * { - * GTask *task; - * DecorationData *decoration; - * Cake *cake; - * - * task = g_task_new (self, cancellable, callback, user_data); - * if (radius < 3) - * { - * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_TOO_SMALL, - * "%ucm radius cakes are silly", - * radius); - * g_object_unref (task); - * return; - * } - * - * cake = _baker_get_cached_cake (self, radius, flavor, frosting, message); - * if (cake != NULL) - * { - * // _baker_get_cached_cake() returns a reffed cake - * g_task_return_pointer (task, cake, g_object_unref); - * g_object_unref (task); - * return; - * } - * - * decoration = g_slice_new (DecorationData); - * decoration->frosting = frosting; - * decoration->message = g_strdup (message); - * g_task_set_task_data (task, decoration, (GDestroyNotify) decoration_data_free); - * - * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); + * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_TOO_SMALL, + * "%ucm radius cakes are silly", + * radius); + * g_object_unref (task); + * return; * } * - * Cake * - * baker_bake_cake_finish (Baker *self, - * GAsyncResult *result, - * GError **error) + * cake = _baker_get_cached_cake (self, radius, flavor, frosting, message); + * if (cake != NULL) * { - * g_return_val_if_fail (g_task_is_valid (result, self), NULL); - * - * return g_task_propagate_pointer (G_TASK (result), error); + * // _baker_get_cached_cake() returns a reffed cake + * g_task_return_pointer (task, cake, g_object_unref); + * g_object_unref (task); + * return; * } - * ]| + * + * decoration = g_slice_new (DecorationData); + * decoration->frosting = frosting; + * decoration->message = g_strdup (message); + * g_task_set_task_data (task, decoration, (GDestroyNotify) decoration_data_free); + * + * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); + * } + * + * Cake * + * baker_bake_cake_finish (Baker *self, + * GAsyncResult *result, + * GError **error) + * { + * g_return_val_if_fail (g_task_is_valid (result, self), NULL); + * + * return g_task_propagate_pointer (G_TASK (result), error); + * } + * ``` * * ## Chained asynchronous operations * - * #GTask also tries to simplify asynchronous operations that + * `GTask` also tries to simplify asynchronous operations that * internally chain together several smaller asynchronous - * operations. g_task_get_cancellable(), g_task_get_context(), - * and g_task_get_priority() allow you to get back the task's - * #GCancellable, #GMainContext, and [I/O priority][io-priority] - * when starting a new subtask, so you don't have to keep track - * of them yourself. g_task_attach_source() simplifies the case + * operations. [method@Gio.Task.get_cancellable], [method@Gio.Task.get_context], + * and [method@Gio.Task.get_priority] allow you to get back the task’s + * [class@Gio.Cancellable], [struct@GLib.MainContext], and + * [I/O priority](iface.AsyncResult.html#io-priority) + * when starting a new subtask, so you don’t have to keep track + * of them yourself. [method@Gio.Task.attach_source] simplifies the case * of waiting for a source to fire (automatically using the correct - * #GMainContext and priority). + * [struct@GLib.MainContext] and priority). * * Here is an example for chained asynchronous operations: - * |[ - * typedef struct { - * Cake *cake; - * CakeFrostingType frosting; - * char *message; - * } BakingData; - * - * static void - * decoration_data_free (BakingData *bd) + * ```c + * typedef struct { + * Cake *cake; + * CakeFrostingType frosting; + * char *message; + * } BakingData; + * + * static void + * decoration_data_free (BakingData *bd) + * { + * if (bd->cake) + * g_object_unref (bd->cake); + * g_free (bd->message); + * g_slice_free (BakingData, bd); + * } + * + * static void + * decorated_cb (Cake *cake, + * GAsyncResult *result, + * gpointer user_data) + * { + * GTask *task = user_data; + * GError *error = NULL; + * + * if (!cake_decorate_finish (cake, result, &error)) * { - * if (bd->cake) - * g_object_unref (bd->cake); - * g_free (bd->message); - * g_slice_free (BakingData, bd); + * g_object_unref (cake); + * g_task_return_error (task, error); + * g_object_unref (task); + * return; * } * - * static void - * decorated_cb (Cake *cake, - * GAsyncResult *result, - * gpointer user_data) + * // baking_data_free() will drop its ref on the cake, so we have to + * // take another here to give to the caller. + * g_task_return_pointer (task, g_object_ref (cake), g_object_unref); + * g_object_unref (task); + * } + * + * static gboolean + * decorator_ready (gpointer user_data) + * { + * GTask *task = user_data; + * BakingData *bd = g_task_get_task_data (task); + * + * cake_decorate_async (bd->cake, bd->frosting, bd->message, + * g_task_get_cancellable (task), + * decorated_cb, task); + * + * return G_SOURCE_REMOVE; + * } + * + * static void + * baked_cb (Cake *cake, + * gpointer user_data) + * { + * GTask *task = user_data; + * BakingData *bd = g_task_get_task_data (task); + * GError *error = NULL; + * + * if (cake == NULL) * { - * GTask *task = user_data; - * GError *error = NULL; - * - * if (!cake_decorate_finish (cake, result, &error)) - * { - * g_object_unref (cake); - * g_task_return_error (task, error); - * g_object_unref (task); - * return; - * } - * - * // baking_data_free() will drop its ref on the cake, so we have to - * // take another here to give to the caller. - * g_task_return_pointer (task, g_object_ref (cake), g_object_unref); + * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, + * "Go to the supermarket"); * g_object_unref (task); + * return; * } * - * static gboolean - * decorator_ready (gpointer user_data) - * { - * GTask *task = user_data; - * BakingData *bd = g_task_get_task_data (task); - * - * cake_decorate_async (bd->cake, bd->frosting, bd->message, - * g_task_get_cancellable (task), - * decorated_cb, task); + * bd->cake = cake; * - * return G_SOURCE_REMOVE; - * } - * - * static void - * baked_cb (Cake *cake, - * gpointer user_data) + * // Bail out now if the user has already cancelled + * if (g_task_return_error_if_cancelled (task)) * { - * GTask *task = user_data; - * BakingData *bd = g_task_get_task_data (task); - * GError *error = NULL; - * - * if (cake == NULL) - * { - * g_task_return_new_error (task, BAKER_ERROR, BAKER_ERROR_NO_FLOUR, - * "Go to the supermarket"); - * g_object_unref (task); - * return; - * } - * - * bd->cake = cake; - * - * // Bail out now if the user has already cancelled - * if (g_task_return_error_if_cancelled (task)) - * { - * g_object_unref (task); - * return; - * } - * - * if (cake_decorator_available (cake)) - * decorator_ready (task); - * else - * { - * GSource *source; - * - * source = cake_decorator_wait_source_new (cake); - * // Attach @source to @task's GMainContext and have it call - * // decorator_ready() when it is ready. - * g_task_attach_source (task, source, decorator_ready); - * g_source_unref (source); - * } - * } - * - * void - * baker_bake_cake_async (Baker *self, - * guint radius, - * CakeFlavor flavor, - * CakeFrostingType frosting, - * const char *message, - * gint priority, - * GCancellable *cancellable, - * GAsyncReadyCallback callback, - * gpointer user_data) - * { - * GTask *task; - * BakingData *bd; - * - * task = g_task_new (self, cancellable, callback, user_data); - * g_task_set_priority (task, priority); - * - * bd = g_slice_new0 (BakingData); - * bd->frosting = frosting; - * bd->message = g_strdup (message); - * g_task_set_task_data (task, bd, (GDestroyNotify) baking_data_free); - * - * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); + * g_object_unref (task); + * return; * } * - * Cake * - * baker_bake_cake_finish (Baker *self, - * GAsyncResult *result, - * GError **error) + * if (cake_decorator_available (cake)) + * decorator_ready (task); + * else * { - * g_return_val_if_fail (g_task_is_valid (result, self), NULL); + * GSource *source; * - * return g_task_propagate_pointer (G_TASK (result), error); + * source = cake_decorator_wait_source_new (cake); + * // Attach @source to @task’s GMainContext and have it call + * // decorator_ready() when it is ready. + * g_task_attach_source (task, source, decorator_ready); + * g_source_unref (source); * } - * ]| + * } + * + * void + * baker_bake_cake_async (Baker *self, + * guint radius, + * CakeFlavor flavor, + * CakeFrostingType frosting, + * const char *message, + * gint priority, + * GCancellable *cancellable, + * GAsyncReadyCallback callback, + * gpointer user_data) + * { + * GTask *task; + * BakingData *bd; + * + * task = g_task_new (self, cancellable, callback, user_data); + * g_task_set_priority (task, priority); + * + * bd = g_slice_new0 (BakingData); + * bd->frosting = frosting; + * bd->message = g_strdup (message); + * g_task_set_task_data (task, bd, (GDestroyNotify) baking_data_free); + * + * _baker_begin_cake (self, radius, flavor, cancellable, baked_cb, task); + * } + * + * Cake * + * baker_bake_cake_finish (Baker *self, + * GAsyncResult *result, + * GError **error) + * { + * g_return_val_if_fail (g_task_is_valid (result, self), NULL); + * + * return g_task_propagate_pointer (G_TASK (result), error); + * } + * ``` * * ## Asynchronous operations from synchronous ones * - * You can use g_task_run_in_thread() to turn a synchronous + * You can use [method@Gio.Task.run_in_thread] to turn a synchronous * operation into an asynchronous one, by running it in a thread. - * When it completes, the result will be dispatched to the - * [thread-default main context][g-main-context-push-thread-default] - * where the #GTask was created. + * When it completes, the result will be dispatched to the thread-default main + * context (see [method@GLib.MainContext.push_thread_default]) where the `GTask` + * was created. * * Running a task in a thread: - * |[ - * typedef struct { - * guint radius; - * CakeFlavor flavor; - * CakeFrostingType frosting; - * char *message; - * } CakeData; - * - * static void - * cake_data_free (CakeData *cake_data) - * { - * g_free (cake_data->message); - * g_slice_free (CakeData, cake_data); - * } - * - * static void - * bake_cake_thread (GTask *task, - * gpointer source_object, - * gpointer task_data, - * GCancellable *cancellable) - * { - * Baker *self = source_object; - * CakeData *cake_data = task_data; - * Cake *cake; - * GError *error = NULL; - * - * cake = bake_cake (baker, cake_data->radius, cake_data->flavor, - * cake_data->frosting, cake_data->message, - * cancellable, &error); - * if (cake) - * g_task_return_pointer (task, cake, g_object_unref); - * else - * g_task_return_error (task, error); - * } - * - * void - * baker_bake_cake_async (Baker *self, - * guint radius, - * CakeFlavor flavor, - * CakeFrostingType frosting, - * const char *message, - * GCancellable *cancellable, - * GAsyncReadyCallback callback, - * gpointer user_data) - * { - * CakeData *cake_data; - * GTask *task; - * - * cake_data = g_slice_new (CakeData); - * cake_data->radius = radius; - * cake_data->flavor = flavor; - * cake_data->frosting = frosting; - * cake_data->message = g_strdup (message); - * task = g_task_new (self, cancellable, callback, user_data); - * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); - * g_task_run_in_thread (task, bake_cake_thread); - * g_object_unref (task); - * } - * - * Cake * - * baker_bake_cake_finish (Baker *self, - * GAsyncResult *result, - * GError **error) - * { - * g_return_val_if_fail (g_task_is_valid (result, self), NULL); - * - * return g_task_propagate_pointer (G_TASK (result), error); - * } - * ]| + * ```c + * typedef struct { + * guint radius; + * CakeFlavor flavor; + * CakeFrostingType frosting; + * char *message; + * } CakeData; + * + * static void + * cake_data_free (CakeData *cake_data) + * { + * g_free (cake_data->message); + * g_slice_free (CakeData, cake_data); + * } + * + * static void + * bake_cake_thread (GTask *task, + * gpointer source_object, + * gpointer task_data, + * GCancellable *cancellable) + * { + * Baker *self = source_object; + * CakeData *cake_data = task_data; + * Cake *cake; + * GError *error = NULL; + * + * cake = bake_cake (baker, cake_data->radius, cake_data->flavor, + * cake_data->frosting, cake_data->message, + * cancellable, &error); + * if (cake) + * g_task_return_pointer (task, cake, g_object_unref); + * else + * g_task_return_error (task, error); + * } + * + * void + * baker_bake_cake_async (Baker *self, + * guint radius, + * CakeFlavor flavor, + * CakeFrostingType frosting, + * const char *message, + * GCancellable *cancellable, + * GAsyncReadyCallback callback, + * gpointer user_data) + * { + * CakeData *cake_data; + * GTask *task; + * + * cake_data = g_slice_new (CakeData); + * cake_data->radius = radius; + * cake_data->flavor = flavor; + * cake_data->frosting = frosting; + * cake_data->message = g_strdup (message); + * task = g_task_new (self, cancellable, callback, user_data); + * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); + * g_task_run_in_thread (task, bake_cake_thread); + * g_object_unref (task); + * } + * + * Cake * + * baker_bake_cake_finish (Baker *self, + * GAsyncResult *result, + * GError **error) + * { + * g_return_val_if_fail (g_task_is_valid (result, self), NULL); + * + * return g_task_propagate_pointer (G_TASK (result), error); + * } + * ``` * * ## Adding cancellability to uncancellable tasks * - * Finally, g_task_run_in_thread() and g_task_run_in_thread_sync() - * can be used to turn an uncancellable operation into a - * cancellable one. If you call g_task_set_return_on_cancel(), - * passing %TRUE, then if the task's #GCancellable is cancelled, - * it will return control back to the caller immediately, while - * allowing the task thread to continue running in the background - * (and simply discarding its result when it finally does finish). + * Finally, [method@Gio.Task.run_in_thread] and + * [method@Gio.Task.run_in_thread_sync] can be used to turn an uncancellable + * operation into a cancellable one. If you call + * [method@Gio.Task.set_return_on_cancel], passing `TRUE`, then if the task’s + * [class@Gio.Cancellable] is cancelled, it will return control back to the + * caller immediately, while allowing the task thread to continue running in the + * background (and simply discarding its result when it finally does finish). * Provided that the task thread is careful about how it uses * locks and other externally-visible resources, this allows you - * to make "GLib-friendly" asynchronous and cancellable + * to make ‘GLib-friendly’ asynchronous and cancellable * synchronous variants of blocking APIs. * * Cancelling a task: - * |[ - * static void - * bake_cake_thread (GTask *task, - * gpointer source_object, - * gpointer task_data, - * GCancellable *cancellable) + * ```c + * static void + * bake_cake_thread (GTask *task, + * gpointer source_object, + * gpointer task_data, + * GCancellable *cancellable) + * { + * Baker *self = source_object; + * CakeData *cake_data = task_data; + * Cake *cake; + * GError *error = NULL; + * + * cake = bake_cake (baker, cake_data->radius, cake_data->flavor, + * cake_data->frosting, cake_data->message, + * &error); + * if (error) * { - * Baker *self = source_object; - * CakeData *cake_data = task_data; - * Cake *cake; - * GError *error = NULL; - * - * cake = bake_cake (baker, cake_data->radius, cake_data->flavor, - * cake_data->frosting, cake_data->message, - * &error); - * if (error) - * { - * g_task_return_error (task, error); - * return; - * } - * - * // If the task has already been cancelled, then we don't want to add - * // the cake to the cake cache. Likewise, we don't want to have the - * // task get cancelled in the middle of updating the cache. - * // g_task_set_return_on_cancel() will return %TRUE here if it managed - * // to disable return-on-cancel, or %FALSE if the task was cancelled - * // before it could. - * if (g_task_set_return_on_cancel (task, FALSE)) - * { - * // If the caller cancels at this point, their - * // GAsyncReadyCallback won't be invoked until we return, - * // so we don't have to worry that this code will run at - * // the same time as that code does. But if there were - * // other functions that might look at the cake cache, - * // then we'd probably need a GMutex here as well. - * baker_add_cake_to_cache (baker, cake); - * g_task_return_pointer (task, cake, g_object_unref); - * } + * g_task_return_error (task, error); + * return; * } * - * void - * baker_bake_cake_async (Baker *self, - * guint radius, - * CakeFlavor flavor, - * CakeFrostingType frosting, - * const char *message, - * GCancellable *cancellable, - * GAsyncReadyCallback callback, - * gpointer user_data) + * // If the task has already been cancelled, then we don’t want to add + * // the cake to the cake cache. Likewise, we don’t want to have the + * // task get cancelled in the middle of updating the cache. + * // g_task_set_return_on_cancel() will return %TRUE here if it managed + * // to disable return-on-cancel, or %FALSE if the task was cancelled + * // before it could. + * if (g_task_set_return_on_cancel (task, FALSE)) * { - * CakeData *cake_data; - * GTask *task; - * - * cake_data = g_slice_new (CakeData); - * - * ... - * - * task = g_task_new (self, cancellable, callback, user_data); - * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); - * g_task_set_return_on_cancel (task, TRUE); - * g_task_run_in_thread (task, bake_cake_thread); - * } - * - * Cake * - * baker_bake_cake_sync (Baker *self, - * guint radius, - * CakeFlavor flavor, - * CakeFrostingType frosting, - * const char *message, - * GCancellable *cancellable, - * GError **error) - * { - * CakeData *cake_data; - * GTask *task; - * Cake *cake; - * - * cake_data = g_slice_new (CakeData); - * - * ... - * - * task = g_task_new (self, cancellable, NULL, NULL); - * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); - * g_task_set_return_on_cancel (task, TRUE); - * g_task_run_in_thread_sync (task, bake_cake_thread); - * - * cake = g_task_propagate_pointer (task, error); - * g_object_unref (task); - * return cake; + * // If the caller cancels at this point, their + * // GAsyncReadyCallback won’t be invoked until we return, + * // so we don’t have to worry that this code will run at + * // the same time as that code does. But if there were + * // other functions that might look at the cake cache, + * // then we’d probably need a GMutex here as well. + * baker_add_cake_to_cache (baker, cake); + * g_task_return_pointer (task, cake, g_object_unref); * } - * ]| - * - * ## Porting from GSimpleAsyncResult + * } + * + * void + * baker_bake_cake_async (Baker *self, + * guint radius, + * CakeFlavor flavor, + * CakeFrostingType frosting, + * const char *message, + * GCancellable *cancellable, + * GAsyncReadyCallback callback, + * gpointer user_data) + * { + * CakeData *cake_data; + * GTask *task; + * + * cake_data = g_slice_new (CakeData); + * + * ... + * + * task = g_task_new (self, cancellable, callback, user_data); + * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); + * g_task_set_return_on_cancel (task, TRUE); + * g_task_run_in_thread (task, bake_cake_thread); + * } + * + * Cake * + * baker_bake_cake_sync (Baker *self, + * guint radius, + * CakeFlavor flavor, + * CakeFrostingType frosting, + * const char *message, + * GCancellable *cancellable, + * GError **error) + * { + * CakeData *cake_data; + * GTask *task; + * Cake *cake; + * + * cake_data = g_slice_new (CakeData); + * + * ... + * + * task = g_task_new (self, cancellable, NULL, NULL); + * g_task_set_task_data (task, cake_data, (GDestroyNotify) cake_data_free); + * g_task_set_return_on_cancel (task, TRUE); + * g_task_run_in_thread_sync (task, bake_cake_thread); + * + * cake = g_task_propagate_pointer (task, error); + * g_object_unref (task); + * return cake; + * } + * ``` + * + * ## Porting from [class@Gio.SimpleAsyncResult] * - * #GTask's API attempts to be simpler than #GSimpleAsyncResult's + * `GTask`’s API attempts to be simpler than [class@Gio.SimpleAsyncResult]’s * in several ways: - * - You can save task-specific data with g_task_set_task_data(), and - * retrieve it later with g_task_get_task_data(). This replaces the - * abuse of g_simple_async_result_set_op_res_gpointer() for the same - * purpose with #GSimpleAsyncResult. - * - In addition to the task data, #GTask also keeps track of the - * [priority][io-priority], #GCancellable, and - * #GMainContext associated with the task, so tasks that consist of - * a chain of simpler asynchronous operations will have easy access + * + * - You can save task-specific data with [method@Gio.Task.set_task_data], and + * retrieve it later with [method@Gio.Task.get_task_data]. This replaces the + * abuse of [method@Gio.SimpleAsyncResult.set_op_res_gpointer] for the same + * purpose with [class@Gio.SimpleAsyncResult]. + * - In addition to the task data, `GTask` also keeps track of the + * [priority](iface.AsyncResult.html#io-priority), [class@Gio.Cancellable], + * and [struct@GLib.MainContext] associated with the task, so tasks that + * consist of a chain of simpler asynchronous operations will have easy access * to those values when starting each sub-task. - * - g_task_return_error_if_cancelled() provides simplified + * - [method@Gio.Task.return_error_if_cancelled] provides simplified * handling for cancellation. In addition, cancellation - * overrides any other #GTask return value by default, like - * #GSimpleAsyncResult does when - * g_simple_async_result_set_check_cancellable() is called. - * (You can use g_task_set_check_cancellable() to turn off that - * behavior.) On the other hand, g_task_run_in_thread() + * overrides any other `GTask` return value by default, like + * [class@Gio.SimpleAsyncResult] does when + * [method@Gio.SimpleAsyncResult.set_check_cancellable] is called. + * (You can use [method@Gio.Task.set_check_cancellable] to turn off that + * behavior.) On the other hand, [method@Gio.Task.run_in_thread] * guarantees that it will always run your - * `task_func`, even if the task's #GCancellable + * `task_func`, even if the task’s [class@Gio.Cancellable] * is already cancelled before the task gets a chance to run; * you can start your `task_func` with a - * g_task_return_error_if_cancelled() check if you need the + * [method@Gio.Task.return_error_if_cancelled] check if you need the * old behavior. - * - The "return" methods (eg, g_task_return_pointer()) - * automatically cause the task to be "completed" as well, and - * there is no need to worry about the "complete" vs "complete - * in idle" distinction. (#GTask automatically figures out - * whether the task's callback can be invoked directly, or - * if it needs to be sent to another #GMainContext, or delayed - * until the next iteration of the current #GMainContext.) - * - The "finish" functions for #GTask based operations are generally - * much simpler than #GSimpleAsyncResult ones, normally consisting - * of only a single call to g_task_propagate_pointer() or the like. - * Since g_task_propagate_pointer() "steals" the return value from - * the #GTask, it is not necessary to juggle pointers around to + * - The ‘return’ methods (eg, [method@Gio.Task.return_pointer]) + * automatically cause the task to be ‘completed’ as well, and + * there is no need to worry about the ‘complete’ vs ‘complete in idle’ + * distinction. (`GTask` automatically figures out + * whether the task’s callback can be invoked directly, or + * if it needs to be sent to another [struct@GLib.MainContext], or delayed + * until the next iteration of the current [struct@GLib.MainContext].) + * - The ‘finish’ functions for `GTask` based operations are generally + * much simpler than [class@Gio.SimpleAsyncResult] ones, normally consisting + * of only a single call to [method@Gio.Task.propagate_pointer] or the like. + * Since [method@Gio.Task.propagate_pointer] ‘steals’ the return value from + * the `GTask`, it is not necessary to juggle pointers around to * prevent it from being freed twice. - * - With #GSimpleAsyncResult, it was common to call - * g_simple_async_result_propagate_error() from the + * - With [class@Gio.SimpleAsyncResult], it was common to call + * [method@Gio.SimpleAsyncResult.propagate_error] from the * `_finish()` wrapper function, and have * virtual method implementations only deal with successful * returns. This behavior is deprecated, because it makes it - * difficult for a subclass to chain to a parent class's async + * difficult for a subclass to chain to a parent class’s async * methods. Instead, the wrapper function should just be a * simple wrapper, and the virtual method should call an * appropriate `g_task_propagate_` function. * Note that wrapper methods can now use - * g_async_result_legacy_propagate_error() to do old-style - * #GSimpleAsyncResult error-returning behavior, and - * g_async_result_is_tagged() to check if a result is tagged as + * [method@Gio.AsyncResult.legacy_propagate_error] to do old-style + * [class@Gio.SimpleAsyncResult] error-returning behavior, and + * [method@Gio.AsyncResult.is_tagged] to check if a result is tagged as * having come from the `_async()` wrapper - * function (for "short-circuit" results, such as when passing - * 0 to g_input_stream_read_async()). + * function (for ‘short-circuit’ results, such as when passing + * `0` to [method@Gio.InputStream.read_async]). * * ## Thread-safety considerations * * Due to some infelicities in the API design, there is a - * thread-safety concern that users of GTask have to be aware of: + * thread-safety concern that users of `GTask` have to be aware of: * * If the `main` thread drops its last reference to the source object * or the task data before the task is finalized, then the finalizers @@ -556,19 +554,11 @@ * can lead to hard-to-debug crashes. Possible workarounds include: * * - Clear task data in a signal handler for `notify::completed` - * * - Keep iterating a main context in the main thread and defer * dropping the reference to the source object to that main * context when the task is finalized */ -/** - * GTask: - * - * The opaque object representing a synchronous or asynchronous task - * and its result. - */ - struct _GTask { GObject parent_instance; @@ -962,7 +952,7 @@ g_task_set_task_data (GTask *task, /** * g_task_set_priority: * @task: the #GTask - * @priority: the [priority][io-priority] of the request + * @priority: the [priority](iface.AsyncResult.html#io-priority) of the request * * Sets @task's priority. If you do not call this, it will default to * %G_PRIORITY_DEFAULT. @@ -1787,8 +1777,9 @@ g_task_run_in_thread_sync (GTask *task, * * A utility function for dealing with async operations where you need * to wait for a #GSource to trigger. Attaches @source to @task's - * #GMainContext with @task's [priority][io-priority], and sets @source's - * callback to @callback, with @task as the callback's `user_data`. + * #GMainContext with @task's [priority](iface.AsyncResult.html#io-priority), + * and sets @source's callback to @callback, with @task as the callback's + * `user_data`. * * It will set the @source’s name to the task’s name (as set with * g_task_set_name()), if one has been set on the task and the source doesn’t @@ -2040,7 +2031,8 @@ g_task_propagate_boolean (GTask *task, * Call g_error_copy() on the error if you need to keep a local copy * as well. * - * See also g_task_return_new_error(). + * See also [method@Gio.Task.return_new_error], + * [method@Gio.Task.return_new_error_literal]. * * Since: 2.36 */ @@ -2058,6 +2050,54 @@ g_task_return_error (GTask *task, } /** + * g_task_return_prefixed_error: + * @task: a #GTask. + * @error: (transfer full): the #GError result of a task function. + * @format: a string with format characters. + * @...: a list of values to insert into @format. + * + * Sets @task's result to @error (which @task assumes ownership of), with + * the message prefixed according to @format, and completes the task + * (see g_task_return_pointer() for more discussion of exactly what this + * means). + * + * Note that since the task takes ownership of @error, and since the + * task may be completed before returning from g_task_return_prefixed_error(), + * you cannot assume that @error is still valid after calling this. + * Call g_error_copy() on the error if you need to keep a local copy + * as well. + * + * See also g_task_return_error(), g_prefix_error(). + * + * Since: 2.80 + */ +void +g_task_return_prefixed_error (GTask *task, + GError *error, + const char *format, + ...) +{ + char *prefix; + va_list ap; + + g_return_if_fail (G_IS_TASK (task)); + g_return_if_fail (!task->ever_returned); + g_return_if_fail (error != NULL); + + task->error = error; + + va_start (ap, format); + prefix = g_strdup_vprintf (format, ap); + va_end (ap); + + g_prefix_error_literal (&task->error, prefix); + + g_free (prefix); + + g_task_return (task, G_TASK_RETURN_ERROR); +} + +/** * g_task_return_new_error: * @task: a #GTask. * @domain: a #GQuark. @@ -2092,6 +2132,32 @@ g_task_return_new_error (GTask *task, } /** + * g_task_return_new_error_literal: + * @task: a #GTask. + * @domain: a #GQuark. + * @code: an error code. + * @message: an error message + * + * Sets @task’s result to a new [type@GLib.Error] created from @domain, @code, + * @message and completes the task. + * + * See [method@Gio.Task.return_pointer] for more discussion of exactly what + * ‘completing the task’ means. + * + * See also [method@Gio.Task.return_new_error]. + * + * Since: 2.80 + */ +void +g_task_return_new_error_literal (GTask *task, + GQuark domain, + gint code, + const char *message) +{ + g_task_return_error (task, g_error_new_literal (domain, code, message)); +} + +/** * g_task_return_error_if_cancelled: * @task: a #GTask * @@ -2400,9 +2466,7 @@ g_task_class_init (GTaskClass *klass) * Since: 2.44 */ g_object_class_install_property (gobject_class, PROP_COMPLETED, - g_param_spec_boolean ("completed", - P_("Task completed"), - P_("Whether the task has completed yet"), + g_param_spec_boolean ("completed", NULL, NULL, FALSE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); if (G_UNLIKELY (task_pool_max_counter == 0)) diff --git a/gio/gtask.h b/gio/gtask.h index 6d7fa82..9fabddc 100644 --- a/gio/gtask.h +++ b/gio/gtask.h @@ -163,12 +163,24 @@ void g_task_return_int (GTask *task, GIO_AVAILABLE_IN_2_36 void g_task_return_error (GTask *task, GError *error); +GIO_AVAILABLE_IN_2_80 +void g_task_return_prefixed_error (GTask *task, + GError *error, + const char *format, + ...) G_GNUC_PRINTF (3, 4); + GIO_AVAILABLE_IN_2_36 void g_task_return_new_error (GTask *task, GQuark domain, gint code, const char *format, ...) G_GNUC_PRINTF (4, 5); + +GIO_AVAILABLE_IN_2_80 +void g_task_return_new_error_literal (GTask *task, + GQuark domain, + gint code, + const char *message); GIO_AVAILABLE_IN_2_64 void g_task_return_value (GTask *task, GValue *result); diff --git a/gio/gtcpconnection.c b/gio/gtcpconnection.c index e0865d8..07747d1 100644 --- a/gio/gtcpconnection.c +++ b/gio/gtcpconnection.c @@ -13,13 +13,9 @@ */ /** - * SECTION:gtcpconnection - * @title: GTcpConnection - * @short_description: A TCP GSocketConnection - * @include: gio/gio.h - * @see_also: #GSocketConnection. + * GTcpConnection: * - * This is the subclass of #GSocketConnection that is created + * This is the subclass of [class@Gio.SocketConnection] that is created * for TCP/IP sockets. * * Since: 2.22 @@ -132,10 +128,15 @@ g_tcp_connection_class_init (GTcpConnectionClass *class) stream_class->close_fn = g_tcp_connection_close; stream_class->close_async = g_tcp_connection_close_async; + /** + * GTcpConnection:graceful-disconnect: + * + * Whether [method@Gio.IOStream.close] does a graceful disconnect. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_GRACEFUL_DISCONNECT, - g_param_spec_boolean ("graceful-disconnect", - P_("Graceful Disconnect"), - P_("Whether or not close does a graceful disconnect"), + g_param_spec_boolean ("graceful-disconnect", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gtcpwrapperconnection.c b/gio/gtcpwrapperconnection.c index 686aa42..b174e2b 100644 --- a/gio/gtcpwrapperconnection.c +++ b/gio/gtcpwrapperconnection.c @@ -21,29 +21,18 @@ */ /** - * SECTION:gtcpwrapperconnection - * @title: GTcpWrapperConnection - * @short_description: Wrapper for non-GSocketConnection-based, - * GSocket-based GIOStreams - * @include: gio/gio.h - * @see_also: #GSocketConnection. + * GTcpWrapperConnection: * - * A #GTcpWrapperConnection can be used to wrap a #GIOStream that is - * based on a #GSocket, but which is not actually a - * #GSocketConnection. This is used by #GSocketClient so that it can - * always return a #GSocketConnection, even when the connection it has - * actually created is not directly a #GSocketConnection. + * A `GTcpWrapperConnection` can be used to wrap a [class@Gio.IOStream] that is + * based on a [class@Gio.Socket], but which is not actually a + * [class@Gio.SocketConnection]. This is used by [class@Gio.SocketClient] so + * that it can always return a [class@Gio.SocketConnection], even when the + * connection it has actually created is not directly a + * [class@Gio.SocketConnection]. * * Since: 2.28 */ -/** - * GTcpWrapperConnection: - * - * #GTcpWrapperConnection is an opaque data structure and can only be accessed - * using the following functions. - **/ - #include "config.h" #include "gtcpwrapperconnection.h" @@ -142,11 +131,16 @@ g_tcp_wrapper_connection_class_init (GTcpWrapperConnectionClass *klass) stream_class->get_input_stream = g_tcp_wrapper_connection_get_input_stream; stream_class->get_output_stream = g_tcp_wrapper_connection_get_output_stream; + /** + * GTcpWrapperConnection:base-io-stream: + * + * The wrapped [class@Gio.IOStream]. + * + * Since: 2.28 + */ g_object_class_install_property (gobject_class, PROP_BASE_IO_STREAM, - g_param_spec_object ("base-io-stream", - P_("Base IO Stream"), - P_("The wrapped GIOStream"), + g_param_spec_object ("base-io-stream", NULL, NULL, G_TYPE_IO_STREAM, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | diff --git a/gio/gtestdbus.c b/gio/gtestdbus.c index d75b439..29727e2 100644 --- a/gio/gtestdbus.c +++ b/gio/gtestdbus.c @@ -121,25 +121,22 @@ _g_object_unref_and_wait_weak_notify (gpointer object) static void _g_test_watcher_add_pid (GPid pid) { - static gsize started = 0; - HANDLE job; + HANDLE job = NULL; - if (g_once_init_enter (&started)) + if (g_once_init_enter (&job)) { JOBOBJECT_EXTENDED_LIMIT_INFORMATION info; - job = CreateJobObjectW (NULL, NULL); + HANDLE tmp = CreateJobObjectW (NULL, NULL); memset (&info, 0, sizeof (info)); info.BasicLimitInformation.LimitFlags = 0x2000 /* JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE */; - if (!SetInformationJobObject(job, JobObjectExtendedLimitInformation, &info, sizeof (info))) - g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError())); + if (!SetInformationJobObject (tmp, JobObjectExtendedLimitInformation, &info, sizeof (info))) + g_warning ("Can't enable JOB_OBJECT_LIMIT_KILL_ON_JOB_CLOSE: %s", g_win32_error_message (GetLastError())); - g_once_init_leave (&started,(gsize)job); + g_once_init_leave_pointer (&job, tmp); } - job = (HANDLE)started; - if (!AssignProcessToJobObject(job, pid)) g_warning ("Can't assign process to job: %s", g_win32_error_message (GetLastError())); } @@ -336,25 +333,23 @@ _g_test_watcher_remove_pid (GPid pid) /* GTestDBus object implementation */ /** - * SECTION:gtestdbus - * @short_description: D-Bus testing helper - * @include: gio/gio.h + * GTestDBus: * - * A helper class for testing code which uses D-Bus without touching the user's + * A helper class for testing code which uses D-Bus without touching the user’s * session bus. * - * Note that #GTestDBus modifies the user’s environment, calling setenv(). - * This is not thread-safe, so all #GTestDBus calls should be completed before - * threads are spawned, or should have appropriate locking to ensure no access - * conflicts to environment variables shared between #GTestDBus and other - * threads. + * Note that `GTestDBus` modifies the user’s environment, calling + * [`setenv()`](man:setenv(3)). This is not thread-safe, so all `GTestDBus` + * calls should be completed before threads are spawned, or should have + * appropriate locking to ensure no access conflicts to environment variables + * shared between `GTestDBus` and other threads. * - * ## Creating unit tests using GTestDBus + * ## Creating unit tests using `GTestDBus` * * Testing of D-Bus services can be tricky because normally we only ever run * D-Bus services over an existing instance of the D-Bus daemon thus we - * usually don't activate D-Bus services that are not yet installed into the - * target system. The #GTestDBus object makes this easier for us by taking care + * usually don’t activate D-Bus services that are not yet installed into the + * target system. The `GTestDBus` object makes this easier for us by taking care * of the lower level tasks such as running a private D-Bus daemon and looking * up uninstalled services in customizable locations, typically in your source * code tree. @@ -367,20 +362,24 @@ _g_test_watcher_remove_pid (GPid pid) * uninstalled service executable in your source tree. Using autotools we would * achieve this by adding a file such as `my-server.service.in` in the services * directory and have it processed by configure. - * |[ - * [D-BUS Service] - * Name=org.gtk.GDBus.Examples.ObjectManager - * Exec=@abs_top_builddir@/gio/tests/gdbus-example-objectmanager-server - * ]| + * + * ``` + * [D-BUS Service] + * Name=org.gtk.GDBus.Examples.ObjectManager + * Exec=@abs_top_builddir@/gio/tests/gdbus-example-objectmanager-server + * ``` + * * You will also need to indicate this service directory in your test * fixtures, so you will need to pass the path while compiling your * test cases. Typically this is done with autotools with an added * preprocessor flag specified to compile your tests such as: - * |[ - * -DTEST_SERVICES=\""$(abs_top_builddir)/tests/services"\" - * ]| - * Once you have a service definition file which is local to your source tree, - * you can proceed to set up a GTest fixture using the #GTestDBus scaffolding. + * + * ``` + * -DTEST_SERVICES=\""$(abs_top_builddir)/tests/services"\" + * ``` + * + * Once you have a service definition file which is local to your source tree, + * you can proceed to set up a GTest fixture using the `GTestDBus` scaffolding. * * An example of a test fixture for D-Bus services can be found * here: @@ -389,42 +388,39 @@ _g_test_watcher_remove_pid (GPid pid) * Note that these examples only deal with isolating the D-Bus aspect of your * service. To successfully run isolated unit tests on your service you may need * some additional modifications to your test case fixture. For example; if your - * service uses GSettings and installs a schema then it is important that your test service - * not load the schema in the ordinary installed location (chances are that your service - * and schema files are not yet installed, or worse; there is an older version of the - * schema file sitting in the install location). + * service uses [class@Gio.Settings] and installs a schema then it is important + * that your test service not load the schema in the ordinary installed location + * (chances are that your service and schema files are not yet installed, or + * worse; there is an older version of the schema file sitting in the install + * location). * * Most of the time we can work around these obstacles using the * environment. Since the environment is inherited by the D-Bus daemon - * created by #GTestDBus and then in turn inherited by any services the + * created by `GTestDBus` and then in turn inherited by any services the * D-Bus daemon activates, using the setup routine for your fixture is * a practical place to help sandbox your runtime environment. For the * rather typical GSettings case we can work around this by setting * `GSETTINGS_SCHEMA_DIR` to the in tree directory holding your schemas - * in the above fixture_setup() routine. + * in the above `fixture_setup()` routine. + * + * The GSettings schemas need to be locally pre-compiled for this to work. This + * can be achieved by compiling the schemas locally as a step before running + * test cases, an autotools setup might do the following in the directory + * holding schemas: * - * The GSettings schemas need to be locally pre-compiled for this to work. This can be achieved - * by compiling the schemas locally as a step before running test cases, an autotools setup might - * do the following in the directory holding schemas: - * |[ + * ``` * all-am: * $(GLIB_COMPILE_SCHEMAS) . * * CLEANFILES += gschemas.compiled - * ]| + * ``` + * + * Since: 2.34 */ typedef struct _GTestDBusClass GTestDBusClass; typedef struct _GTestDBusPrivate GTestDBusPrivate; -/** - * GTestDBus: - * - * The #GTestDBus structure contains only private data and - * should only be accessed using the provided API. - * - * Since: 2.34 - */ struct _GTestDBus { GObject parent; @@ -537,9 +533,7 @@ g_test_dbus_class_init (GTestDBusClass *klass) * Since: 2.34 */ g_object_class_install_property (object_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("D-Bus session flags"), - P_("Flags specifying the behaviour of the D-Bus session"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_TEST_DBUS_FLAGS, G_TEST_DBUS_NONE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gthemedicon.c b/gio/gthemedicon.c index 8551bd2..1d6aacd 100644 --- a/gio/gthemedicon.c +++ b/gio/gthemedicon.c @@ -31,16 +31,15 @@ /** - * SECTION:gthemedicon - * @short_description: Icon theming support - * @include: gio/gio.h - * @see_also: #GIcon, #GLoadableIcon + * GThemedIcon: * - * #GThemedIcon is an implementation of #GIcon that supports icon themes. - * #GThemedIcon contains a list of all of the icons present in an icon - * theme, so that icons can be looked up quickly. #GThemedIcon does + * `GThemedIcon` is an implementation of [iface@Gio.Icon] that supports icon + * themes. + * + * `GThemedIcon` contains a list of all of the icons present in an icon + * theme, so that icons can be looked up quickly. `GThemedIcon` does * not provide actual pixmaps for icons, just the icon names. - * Ideally something like gtk_icon_theme_choose_icon() should be used to + * Ideally something like [method@Gtk.IconTheme.choose_icon] should be used to * resolve the list of names so that fallback icons work nicely with * themes that inherit other themes. **/ @@ -180,9 +179,7 @@ g_themed_icon_class_init (GThemedIconClass *klass) * The icon name. */ g_object_class_install_property (gobject_class, PROP_NAME, - g_param_spec_string ("name", - P_("name"), - P_("The name of the icon"), + g_param_spec_string ("name", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); @@ -192,9 +189,7 @@ g_themed_icon_class_init (GThemedIconClass *klass) * A %NULL-terminated array of icon names. */ g_object_class_install_property (gobject_class, PROP_NAMES, - g_param_spec_boxed ("names", - P_("names"), - P_("An array containing the icon names"), + g_param_spec_boxed ("names", NULL, NULL, G_TYPE_STRV, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); @@ -218,9 +213,7 @@ g_themed_icon_class_init (GThemedIconClass *klass) * ]| */ g_object_class_install_property (gobject_class, PROP_USE_DEFAULT_FALLBACKS, - g_param_spec_boolean ("use-default-fallbacks", - P_("use default fallbacks"), - P_("Whether to use default fallbacks found by shortening the name at “-” characters. Ignores names after the first if multiple names are given."), + g_param_spec_boolean ("use-default-fallbacks", NULL, NULL, FALSE, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_BLURB | G_PARAM_STATIC_NICK)); } diff --git a/gio/gthemedicon.h b/gio/gthemedicon.h index 5ac36ce..432896d 100644 --- a/gio/gthemedicon.h +++ b/gio/gthemedicon.h @@ -38,11 +38,6 @@ G_BEGIN_DECLS #define G_IS_THEMED_ICON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_THEMED_ICON)) #define G_THEMED_ICON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_THEMED_ICON, GThemedIconClass)) -/** - * GThemedIcon: - * - * An implementation of #GIcon for themed icons. - **/ typedef struct _GThemedIconClass GThemedIconClass; GIO_AVAILABLE_IN_ALL diff --git a/gio/gthreadedresolver.c b/gio/gthreadedresolver.c index c7a5675..f75c934 100644 --- a/gio/gthreadedresolver.c +++ b/gio/gthreadedresolver.c @@ -1104,7 +1104,7 @@ g_resolver_records_from_res_query (const gchar *rrname, #elif defined(G_OS_WIN32) static GVariant * -parse_dns_srv (DNS_RECORD *rec) +parse_dns_srv (DNS_RECORDA *rec) { return g_variant_new ("(qqqs)", (guint16)rec->Data.SRV.wPriority, @@ -1114,7 +1114,7 @@ parse_dns_srv (DNS_RECORD *rec) } static GVariant * -parse_dns_soa (DNS_RECORD *rec) +parse_dns_soa (DNS_RECORDA *rec) { return g_variant_new ("(ssuuuuu)", rec->Data.SOA.pNamePrimaryServer, @@ -1127,13 +1127,13 @@ parse_dns_soa (DNS_RECORD *rec) } static GVariant * -parse_dns_ns (DNS_RECORD *rec) +parse_dns_ns (DNS_RECORDA *rec) { return g_variant_new ("(s)", rec->Data.NS.pNameHost); } static GVariant * -parse_dns_mx (DNS_RECORD *rec) +parse_dns_mx (DNS_RECORDA *rec) { return g_variant_new ("(qs)", (guint16)rec->Data.MX.wPreference, @@ -1141,7 +1141,7 @@ parse_dns_mx (DNS_RECORD *rec) } static GVariant * -parse_dns_txt (DNS_RECORD *rec) +parse_dns_txt (DNS_RECORDA *rec) { GVariant *record; GPtrArray *array; @@ -1179,10 +1179,10 @@ static GList * g_resolver_records_from_DnsQuery (const gchar *rrname, WORD dnstype, DNS_STATUS status, - DNS_RECORD *results, + DNS_RECORDA *results, GError **error) { - DNS_RECORD *rec; + DNS_RECORDA *rec; gpointer record; GList *records; @@ -1342,11 +1342,18 @@ do_lookup_records (const gchar *rrname, #else DNS_STATUS status; - DNS_RECORD *results = NULL; + DNS_RECORDA *results = NULL; WORD dnstype; + /* Work around differences in Windows SDK and mingw-w64 headers */ +#ifdef _MSC_VER + typedef DNS_RECORDW * PDNS_RECORD_UTF8_; +#else + typedef DNS_RECORDA * PDNS_RECORD_UTF8_; +#endif + dnstype = g_resolver_record_type_to_dnstype (record_type); - status = DnsQuery_A (rrname, dnstype, DNS_QUERY_STANDARD, NULL, &results, NULL); + status = DnsQuery_UTF8 (rrname, dnstype, DNS_QUERY_STANDARD, NULL, (PDNS_RECORD_UTF8_*)&results, NULL); records = g_resolver_records_from_DnsQuery (rrname, dnstype, status, results, error); if (results != NULL) DnsRecordListFree (results, DnsFreeRecordList); @@ -1441,8 +1448,10 @@ timeout_cb (gpointer user_data) g_mutex_unlock (&data->lock); if (should_return) - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, - _("Socket I/O timed out")); + { + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_TIMED_OUT, + _("Socket I/O timed out")); + } /* Signal completion of the task. */ g_mutex_lock (&data->lock); diff --git a/gio/gthreadedresolver.h b/gio/gthreadedresolver.h index 099df5b..b5556d1 100644 --- a/gio/gthreadedresolver.h +++ b/gio/gthreadedresolver.h @@ -41,6 +41,7 @@ G_DECLARE_FINAL_TYPE (GThreadedResolver, g_threaded_resolver, G, THREADED_RESOLV /* Used for a private test API */ #ifdef G_OS_UNIX +/*< private >*/ GIO_AVAILABLE_IN_ALL GList *g_resolver_records_from_res_query (const gchar *rrname, gint rrtype, @@ -48,6 +49,7 @@ GList *g_resolver_records_from_res_query (const gchar *rrname, gssize len, gint herr, GError **error); +/*< private >*/ GIO_AVAILABLE_IN_ALL gint g_resolver_record_type_to_rrtype (GResolverRecordType type); #endif diff --git a/gio/gthreadedsocketservice.c b/gio/gthreadedsocketservice.c index 63dc2a8..42e4fd2 100644 --- a/gio/gthreadedsocketservice.c +++ b/gio/gthreadedsocketservice.c @@ -23,27 +23,26 @@ */ /** - * SECTION:gthreadedsocketservice - * @title: GThreadedSocketService - * @short_description: A threaded GSocketService - * @include: gio/gio.h - * @see_also: #GSocketService. + * GThreadedSocketService: * - * A #GThreadedSocketService is a simple subclass of #GSocketService + * A `GThreadedSocketService` is a simple subclass of [class@Gio.SocketService] * that handles incoming connections by creating a worker thread and * dispatching the connection to it by emitting the - * #GThreadedSocketService::run signal in the new thread. + * [signal@Gio.ThreadedSocketService::run signal] in the new thread. * - * The signal handler may perform blocking IO and need not return + * The signal handler may perform blocking I/O and need not return * until the connection is closed. * * The service is implemented using a thread pool, so there is a * limited amount of threads available to serve incoming requests. - * The service automatically stops the #GSocketService from accepting + * The service automatically stops the [class@Gio.SocketService] from accepting * new connections when all threads are busy. * - * As with #GSocketService, you may connect to #GThreadedSocketService::run, - * or subclass and override the default handler. + * As with [class@Gio.SocketService], you may connect to + * [signal@Gio.ThreadedSocketService::run], or subclass and override the default + * handler. + * + * Since: 2.22 */ #include "config.h" @@ -248,10 +247,15 @@ g_threaded_socket_service_class_init (GThreadedSocketServiceClass *class) G_TYPE_FROM_CLASS (class), _g_cclosure_marshal_BOOLEAN__OBJECT_OBJECTv); + /** + * GThreadedSocketService:max-threads: + * + * The maximum number of threads handling clients for this service. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_MAX_THREADS, - g_param_spec_int ("max-threads", - P_("Max threads"), - P_("The max number of threads handling clients for this service"), + g_param_spec_int ("max-threads", NULL, NULL, -1, G_MAXINT, 10, diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c index 227dd77..43bdbd4 100644 --- a/gio/gtlsbackend.c +++ b/gio/gtlsbackend.c @@ -29,53 +29,6 @@ #include "giomodule-priv.h" /** - * SECTION:gtls - * @title: TLS Overview - * @short_description: TLS (aka SSL) support for GSocketConnection - * @include: gio/gio.h - * - * #GTlsConnection and related classes provide TLS (Transport Layer - * Security, previously known as SSL, Secure Sockets Layer) support for - * gio-based network streams. - * - * #GDtlsConnection and related classes provide DTLS (Datagram TLS) support for - * GIO-based network sockets, using the #GDatagramBased interface. The TLS and - * DTLS APIs are almost identical, except TLS is stream-based and DTLS is - * datagram-based. They share certificate and backend infrastructure. - * - * In the simplest case, for a client TLS connection, you can just set the - * #GSocketClient:tls flag on a #GSocketClient, and then any - * connections created by that client will have TLS negotiated - * automatically, using appropriate default settings, and rejecting - * any invalid or self-signed certificates (unless you change that - * default by setting the #GSocketClient:tls-validation-flags - * property). The returned object will be a #GTcpWrapperConnection, - * which wraps the underlying #GTlsClientConnection. - * - * For greater control, you can create your own #GTlsClientConnection, - * wrapping a #GSocketConnection (or an arbitrary #GIOStream with - * pollable input and output streams) and then connect to its signals, - * such as #GTlsConnection::accept-certificate, before starting the - * handshake. - * - * Server-side TLS is similar, using #GTlsServerConnection. At the - * moment, there is no support for automatically wrapping server-side - * connections in the way #GSocketClient does for client-side - * connections. - */ - -/** - * SECTION:gtlsbackend - * @title: GTlsBackend - * @short_description: TLS backend implementation - * @include: gio/gio.h - * - * TLS (Transport Layer Security, aka SSL) and DTLS backend. - * - * Since: 2.28 - */ - -/** * GTlsBackend: * * TLS (Transport Layer Security, aka SSL) and DTLS backend. This is an @@ -110,7 +63,7 @@ static GTlsBackend *tls_backend_default_singleton = NULL; /* (owned) (atomic) * GTlsBackend * g_tls_backend_get_default (void) { - if (g_once_init_enter (&tls_backend_default_singleton)) + if (g_once_init_enter_pointer (&tls_backend_default_singleton)) { GTlsBackend *singleton; @@ -118,7 +71,7 @@ g_tls_backend_get_default (void) "GIO_USE_TLS", NULL); - g_once_init_leave (&tls_backend_default_singleton, singleton); + g_once_init_leave_pointer (&tls_backend_default_singleton, singleton); } return tls_backend_default_singleton; diff --git a/gio/gtlscertificate.c b/gio/gtlscertificate.c index 4862bc9..8720506 100644 --- a/gio/gtlscertificate.c +++ b/gio/gtlscertificate.c @@ -29,25 +29,13 @@ #include "glibintl.h" /** - * SECTION:gtlscertificate - * @title: GTlsCertificate - * @short_description: TLS certificate - * @include: gio/gio.h - * @see_also: #GTlsConnection + * GTlsCertificate: * * A certificate used for TLS authentication and encryption. * This can represent either a certificate only (eg, the certificate * received by a client from a server), or the combination of * a certificate and a private key (which is needed when acting as a - * #GTlsServerConnection). - * - * Since: 2.28 - */ - -/** - * GTlsCertificate: - * - * Abstract base class for TLS certificate types. + * [iface@Gio.TlsServerConnection]). * * Since: 2.28 */ @@ -147,9 +135,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.72 */ g_object_class_install_property (gobject_class, PROP_PKCS12_DATA, - g_param_spec_boxed ("pkcs12-data", - P_("PKCS #12 data"), - P_("The PKCS #12 data used for construction"), + g_param_spec_boxed ("pkcs12-data", NULL, NULL, G_TYPE_BYTE_ARRAY, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -163,9 +149,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.72 */ g_object_class_install_property (gobject_class, PROP_PASSWORD, - g_param_spec_string ("password", - P_("Password"), - P_("Password used when constructing from bytes"), + g_param_spec_string ("password", NULL, NULL, NULL, G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -180,9 +164,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_CERTIFICATE, - g_param_spec_boxed ("certificate", - P_("Certificate"), - P_("The DER representation of the certificate"), + g_param_spec_boxed ("certificate", NULL, NULL, G_TYPE_BYTE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -197,9 +179,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_CERTIFICATE_PEM, - g_param_spec_string ("certificate-pem", - P_("Certificate (PEM)"), - P_("The PEM representation of the certificate"), + g_param_spec_string ("certificate-pem", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -228,9 +208,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY, - g_param_spec_boxed ("private-key", - P_("Private key"), - P_("The DER representation of the certificate’s private key"), + g_param_spec_boxed ("private-key", NULL, NULL, G_TYPE_BYTE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -260,9 +238,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY_PEM, - g_param_spec_string ("private-key-pem", - P_("Private key (PEM)"), - P_("The PEM representation of the certificate’s private key"), + g_param_spec_string ("private-key-pem", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -290,9 +266,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_ISSUER, - g_param_spec_object ("issuer", - P_("Issuer"), - P_("The certificate for the issuing entity"), + g_param_spec_object ("issuer", NULL, NULL, G_TYPE_TLS_CERTIFICATE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -310,9 +284,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.68 */ g_object_class_install_property (gobject_class, PROP_PKCS11_URI, - g_param_spec_string ("pkcs11-uri", - P_("PKCS #11 URI"), - P_("The PKCS #11 URI"), + g_param_spec_string ("pkcs11-uri", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -327,9 +299,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.68 */ g_object_class_install_property (gobject_class, PROP_PRIVATE_KEY_PKCS11_URI, - g_param_spec_string ("private-key-pkcs11-uri", - P_("PKCS #11 URI"), - P_("The PKCS #11 URI for a private key"), + g_param_spec_string ("private-key-pkcs11-uri", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -344,9 +314,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_NOT_VALID_BEFORE, - g_param_spec_boxed ("not-valid-before", - P_("Not Valid Before"), - P_("Cert should not be considered valid before this time."), + g_param_spec_boxed ("not-valid-before", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -360,9 +328,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_NOT_VALID_AFTER, - g_param_spec_boxed ("not-valid-after", - P_("Not Valid after"), - P_("Cert should not be considered valid after this time."), + g_param_spec_boxed ("not-valid-after", NULL, NULL, G_TYPE_DATE_TIME, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -376,9 +342,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_SUBJECT_NAME, - g_param_spec_string ("subject-name", - P_("Subject Name"), - P_("The subject name from the certificate."), + g_param_spec_string ("subject-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -391,9 +355,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_ISSUER_NAME, - g_param_spec_string ("issuer-name", - P_("Issuer Name"), - P_("The issuer from the certificate."), + g_param_spec_string ("issuer-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -407,9 +369,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_DNS_NAMES, - g_param_spec_boxed ("dns-names", - P_("DNS Names"), - P_("DNS Names listed on the cert."), + g_param_spec_boxed ("dns-names", NULL, NULL, G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -423,9 +383,7 @@ g_tls_certificate_class_init (GTlsCertificateClass *class) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_IP_ADDRESSES, - g_param_spec_boxed ("ip-addresses", - P_("IP Addresses"), - P_("IP Addresses listed on the cert."), + g_param_spec_boxed ("ip-addresses", NULL, NULL, G_TYPE_PTR_ARRAY, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gtlsclientconnection.c b/gio/gtlsclientconnection.c index d64106e..2b511f3 100644 --- a/gio/gtlsclientconnection.c +++ b/gio/gtlsclientconnection.c @@ -31,19 +31,10 @@ #include "glibintl.h" /** - * SECTION:gtlsclientconnection - * @short_description: TLS client-side connection - * @include: gio/gio.h - * - * #GTlsClientConnection is the client-side subclass of - * #GTlsConnection, representing a client-side TLS connection. - */ - -/** * GTlsClientConnection: * - * Abstract base class for the backend-specific client connection - * type. + * `GTlsClientConnection` is the client-side subclass of + * [class@Gio.TlsConnection], representing a client-side TLS connection. * * Since: 2.28 */ @@ -78,9 +69,7 @@ g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) * Deprecated: 2.72: Do not attempt to ignore validation errors. */ g_object_interface_install_property (iface, - g_param_spec_flags ("validation-flags", - P_("Validation flags"), - P_("What certificate validation to perform"), + g_param_spec_flags ("validation-flags", NULL, NULL, G_TYPE_TLS_CERTIFICATE_FLAGS, G_TLS_CERTIFICATE_VALIDATE_ALL, G_PARAM_READWRITE | @@ -109,9 +98,7 @@ g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) * Since: 2.28 */ g_object_interface_install_property (iface, - g_param_spec_object ("server-identity", - P_("Server identity"), - P_("GSocketConnectable identifying the server"), + g_param_spec_object ("server-identity", NULL, NULL, G_TYPE_SOCKET_CONNECTABLE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -128,9 +115,7 @@ g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) * Deprecated: 2.56: SSL 3.0 is insecure. */ g_object_interface_install_property (iface, - g_param_spec_boolean ("use-ssl3", - P_("Use fallback"), - P_("Use fallback version of SSL/TLS rather than most recent version"), + g_param_spec_boolean ("use-ssl3", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -151,9 +136,7 @@ g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) * Since: 2.28 */ g_object_interface_install_property (iface, - g_param_spec_pointer ("accepted-cas", - P_("Accepted CAs"), - P_("Distinguished names of the CAs the server accepts certificates from"), + g_param_spec_pointer ("accepted-cas", NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); } diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c index 95b4bc8..2e3f273 100644 --- a/gio/gtlsconnection.c +++ b/gio/gtlsconnection.c @@ -34,25 +34,15 @@ #include "gmarshal-internal.h" /** - * SECTION:gtlsconnection - * @short_description: TLS connection type - * @include: gio/gio.h - * - * #GTlsConnection is the base TLS connection class type, which wraps - * a #GIOStream and provides TLS encryption on top of it. Its - * subclasses, #GTlsClientConnection and #GTlsServerConnection, - * implement client-side and server-side TLS, respectively. - * - * For DTLS (Datagram TLS) support, see #GDtlsConnection. - * - * Since: 2.28 - */ - -/** * GTlsConnection: * - * Abstract base class for the backend-specific #GTlsClientConnection - * and #GTlsServerConnection types. + * `GTlsConnection` is the base TLS connection class type, which wraps + * a [class@Gio.IOStream] and provides TLS encryption on top of it. Its + * subclasses, [iface@Gio.TlsClientConnection] and + * [iface@Gio.TlsServerConnection], implement client-side and server-side TLS, + * respectively. + * + * For DTLS (Datagram TLS) support, see [iface@Gio.DtlsConnection]. * * Since: 2.28 */ @@ -113,9 +103,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_BASE_IO_STREAM, - g_param_spec_object ("base-io-stream", - P_("Base IOStream"), - P_("The GIOStream that the connection wraps"), + g_param_spec_object ("base-io-stream", NULL, NULL, G_TYPE_IO_STREAM, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -130,9 +118,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Deprecated: 2.30: Use GTlsConnection:database instead */ g_object_class_install_property (gobject_class, PROP_USE_SYSTEM_CERTDB, - g_param_spec_boolean ("use-system-certdb", - P_("Use system certificate database"), - P_("Whether to verify peer certificates against the system certificate database"), + g_param_spec_boolean ("use-system-certdb", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -161,9 +147,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.30 */ g_object_class_install_property (gobject_class, PROP_DATABASE, - g_param_spec_object ("database", - P_("Database"), - P_("Certificate database to use for looking up or verifying certificates"), + g_param_spec_object ("database", NULL, NULL, G_TYPE_TLS_DATABASE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -177,9 +161,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.30 */ g_object_class_install_property (gobject_class, PROP_INTERACTION, - g_param_spec_object ("interaction", - P_("Interaction"), - P_("Optional object for user interaction"), + g_param_spec_object ("interaction", NULL, NULL, G_TYPE_TLS_INTERACTION, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -192,9 +174,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_REQUIRE_CLOSE_NOTIFY, - g_param_spec_boolean ("require-close-notify", - P_("Require close notify"), - P_("Whether to require proper TLS close notification"), + g_param_spec_boolean ("require-close-notify", NULL, NULL, TRUE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | @@ -210,9 +190,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Deprecated: 2.60: The rehandshake mode is ignored. */ g_object_class_install_property (gobject_class, PROP_REHANDSHAKE_MODE, - g_param_spec_enum ("rehandshake-mode", - P_("Rehandshake mode"), - P_("When to allow rehandshaking"), + g_param_spec_enum ("rehandshake-mode", NULL, NULL, G_TYPE_TLS_REHANDSHAKE_MODE, G_TLS_REHANDSHAKE_SAFELY, G_PARAM_READWRITE | @@ -228,9 +206,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_CERTIFICATE, - g_param_spec_object ("certificate", - P_("Certificate"), - P_("The connection’s certificate"), + g_param_spec_object ("certificate", NULL, NULL, G_TYPE_TLS_CERTIFICATE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -247,9 +223,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_PEER_CERTIFICATE, - g_param_spec_object ("peer-certificate", - P_("Peer Certificate"), - P_("The connection’s peer’s certificate"), + g_param_spec_object ("peer-certificate", NULL, NULL, G_TYPE_TLS_CERTIFICATE, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -274,9 +248,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.28 */ g_object_class_install_property (gobject_class, PROP_PEER_CERTIFICATE_ERRORS, - g_param_spec_flags ("peer-certificate-errors", - P_("Peer Certificate Errors"), - P_("Errors found with the peer’s certificate"), + g_param_spec_flags ("peer-certificate-errors", NULL, NULL, G_TYPE_TLS_CERTIFICATE_FLAGS, 0, G_PARAM_READABLE | @@ -291,9 +263,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.60 */ g_object_class_install_property (gobject_class, PROP_ADVERTISED_PROTOCOLS, - g_param_spec_boxed ("advertised-protocols", - P_("Advertised Protocols"), - P_("Application-layer protocols available on this connection"), + g_param_spec_boxed ("advertised-protocols", NULL, NULL, G_TYPE_STRV, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -306,9 +276,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.60 */ g_object_class_install_property (gobject_class, PROP_NEGOTIATED_PROTOCOL, - g_param_spec_string ("negotiated-protocol", - P_("Negotiated Protocol"), - P_("Application-layer protocol negotiated for this connection"), + g_param_spec_string ("negotiated-protocol", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); @@ -321,9 +289,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_PROTOCOL_VERSION, - g_param_spec_enum ("protocol-version", - P_("Protocol Version"), - P_("TLS protocol version negotiated for this connection"), + g_param_spec_enum ("protocol-version", NULL, NULL, G_TYPE_TLS_PROTOCOL_VERSION, G_TLS_PROTOCOL_VERSION_UNKNOWN, G_PARAM_READABLE | @@ -337,9 +303,7 @@ g_tls_connection_class_init (GTlsConnectionClass *klass) * Since: 2.70 */ g_object_class_install_property (gobject_class, PROP_CIPHERSUITE_NAME, - g_param_spec_string ("ciphersuite-name", - P_("Ciphersuite Name"), - P_("Name of ciphersuite negotiated for this connection"), + g_param_spec_string ("ciphersuite-name", NULL, NULL, NULL, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gtlsdatabase.c b/gio/gtlsdatabase.c index 4966aad..d55d0fe 100644 --- a/gio/gtlsdatabase.c +++ b/gio/gtlsdatabase.c @@ -33,27 +33,17 @@ #include "gtlsinteraction.h" /** - * SECTION:gtlsdatabase - * @short_description: TLS database type - * @include: gio/gio.h + * GTlsDatabase: * - * #GTlsDatabase is used to look up certificates and other information + * `GTlsDatabase` is used to look up certificates and other information * from a certificate or key store. It is an abstract base class which * TLS library specific subtypes override. * - * A #GTlsDatabase may be accessed from multiple threads by the TLS backend. + * A `GTlsDatabase` may be accessed from multiple threads by the TLS backend. * All implementations are required to be fully thread-safe. * * Most common client applications will not directly interact with - * #GTlsDatabase. It is used internally by #GTlsConnection. - * - * Since: 2.30 - */ - -/** - * GTlsDatabase: - * - * Abstract base class for the backend-specific database types. + * `GTlsDatabase`. It is used internally by [class@Gio.TlsConnection]. * * Since: 2.30 */ diff --git a/gio/gtlsfiledatabase.c b/gio/gtlsfiledatabase.c index e32faf9..fe67131 100644 --- a/gio/gtlsfiledatabase.c +++ b/gio/gtlsfiledatabase.c @@ -30,25 +30,15 @@ #include "glibintl.h" /** - * SECTION:gtlsfiledatabase - * @short_description: TLS file based database type - * @include: gio/gio.h + * GTlsFileDatabase: * - * #GTlsFileDatabase is implemented by #GTlsDatabase objects which load - * their certificate information from a file. It is an interface which + * `GTlsFileDatabase` is implemented by [class@Gio.TlsDatabase] objects which + * load their certificate information from a file. It is an interface which * TLS library specific subtypes implement. * * Since: 2.30 */ -/** - * GTlsFileDatabase: - * - * Implemented by a #GTlsDatabase which allows you to load certificates - * from a file. - * - * Since: 2.30 - */ G_DEFINE_INTERFACE (GTlsFileDatabase, g_tls_file_database, G_TYPE_TLS_DATABASE) static void @@ -65,9 +55,7 @@ g_tls_file_database_default_init (GTlsFileDatabaseInterface *iface) * Since: 2.30 */ g_object_interface_install_property (iface, - g_param_spec_string ("anchors", - P_("Anchors"), - P_("The certificate authority anchor file"), + g_param_spec_string ("anchors", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | diff --git a/gio/gtlsinteraction.c b/gio/gtlsinteraction.c index 9b15fcc..acafd4f 100644 --- a/gio/gtlsinteraction.c +++ b/gio/gtlsinteraction.c @@ -36,37 +36,28 @@ /** - * SECTION:gtlsinteraction - * @short_description: Interaction with the user during TLS operations. - * @include: gio/gio.h + * GTlsInteraction: * - * #GTlsInteraction provides a mechanism for the TLS connection and database + * `GTlsInteraction` provides a mechanism for the TLS connection and database * code to interact with the user. It can be used to ask the user for passwords. * - * To use a #GTlsInteraction with a TLS connection use - * g_tls_connection_set_interaction(). + * To use a `GTlsInteraction` with a TLS connection use + * [method@Gio.TlsConnection.set_interaction]. * * Callers should instantiate a derived class that implements the various * interaction methods to show the required dialogs. * * Callers should use the 'invoke' functions like - * g_tls_interaction_invoke_ask_password() to run interaction methods. These - * functions make sure that the interaction is invoked in the main loop + * [method@Gio.TlsInteraction.invoke_ask_password] to run interaction methods. + * These functions make sure that the interaction is invoked in the main loop * and not in the current thread, if the current thread is not running the * main loop. * - * Derived classes can choose to implement whichever interactions methods they'd + * Derived classes can choose to implement whichever interactions methods they’d * like to support by overriding those virtual methods in their class * initialization function. Any interactions not implemented will return - * %G_TLS_INTERACTION_UNHANDLED. If a derived class implements an async method, + * `G_TLS_INTERACTION_UNHANDLED`. If a derived class implements an async method, * it must also implement the corresponding finish method. - */ - -/** - * GTlsInteraction: - * - * An object representing interaction that the TLS connection and database - * might have with the user. * * Since: 2.30 */ diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c index 586d761..ff1fb26 100644 --- a/gio/gtlspassword.c +++ b/gio/gtlspassword.c @@ -30,15 +30,6 @@ #include /** - * SECTION:gtlspassword - * @title: GTlsPassword - * @short_description: TLS Passwords for prompting - * @include: gio/gio.h - * - * Holds a password used in TLS. - */ - -/** * GTlsPassword: * * An abstract interface representing a password used in TLS. Often used in @@ -196,27 +187,42 @@ g_tls_password_class_init (GTlsPasswordClass *klass) gobject_class->set_property = g_tls_password_set_property; gobject_class->finalize = g_tls_password_finalize; + /** + * GTlsPassword:flags: + * + * Flags about the password. + * + * Since: 2.30 + */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("Flags"), - P_("Flags about the password"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_TLS_PASSWORD_FLAGS, G_TLS_PASSWORD_NONE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GTlsPassword:description: + * + * Description of what the password is for. + * + * Since: 2.30 + */ g_object_class_install_property (gobject_class, PROP_DESCRIPTION, - g_param_spec_string ("description", - P_("Description"), - P_("Description of what the password is for"), + g_param_spec_string ("description", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + /** + * GTlsPassword:warning: + * + * Warning about the password. + * + * Since: 2.30 + */ g_object_class_install_property (gobject_class, PROP_WARNING, - g_param_spec_string ("warning", - P_("Warning"), - P_("Warning about the password"), + g_param_spec_string ("warning", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -245,7 +251,7 @@ g_tls_password_new (GTlsPasswordFlags flags, /** * g_tls_password_get_value: (virtual get_value) * @password: a #GTlsPassword object - * @length: (optional): location to place the length of the password. + * @length: (optional) (out caller-allocates): location to place the length of the password. * * Get the password value. If @length is not %NULL then it will be * filled in with the length of the password value. (Note that the @@ -300,7 +306,7 @@ g_tls_password_set_value (GTlsPassword *password, } /** - * g_tls_password_set_value_full: + * g_tls_password_set_value_full: (virtual set_value) * @password: a #GTlsPassword object * @value: (array length=length): the value for the password * @length: the length of the password, or -1 @@ -316,7 +322,6 @@ g_tls_password_set_value (GTlsPassword *password, * calculated automatically. (Note that the terminating nul is not * considered part of the password in this case.) * - * Virtual: set_value * Since: 2.30 */ void diff --git a/gio/gtlsserverconnection.c b/gio/gtlsserverconnection.c index dc9db62..f68542b 100644 --- a/gio/gtlsserverconnection.c +++ b/gio/gtlsserverconnection.c @@ -30,12 +30,10 @@ #include "glibintl.h" /** - * SECTION:gtlsserverconnection - * @short_description: TLS server-side connection - * @include: gio/gio.h + * GTlsServerConnection: * - * #GTlsServerConnection is the server-side subclass of #GTlsConnection, - * representing a server-side TLS connection. + * `GTlsServerConnection` is the server-side subclass of + * [class@Gio.TlsConnection], representing a server-side TLS connection. * * Since: 2.28 */ @@ -55,9 +53,7 @@ g_tls_server_connection_default_init (GTlsServerConnectionInterface *iface) * Since: 2.28 */ g_object_interface_install_property (iface, - g_param_spec_enum ("authentication-mode", - P_("Authentication Mode"), - P_("The client authentication mode"), + g_param_spec_enum ("authentication-mode", NULL, NULL, G_TYPE_TLS_AUTHENTICATION_MODE, G_TLS_AUTHENTICATION_NONE, G_PARAM_READWRITE | diff --git a/gio/gtlsserverconnection.h b/gio/gtlsserverconnection.h index f84c25b..7c4e283 100644 --- a/gio/gtlsserverconnection.h +++ b/gio/gtlsserverconnection.h @@ -34,14 +34,6 @@ G_BEGIN_DECLS #define G_IS_TLS_SERVER_CONNECTION(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), G_TYPE_TLS_SERVER_CONNECTION)) #define G_TLS_SERVER_CONNECTION_GET_INTERFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), G_TYPE_TLS_SERVER_CONNECTION, GTlsServerConnectionInterface)) -/** - * GTlsServerConnection: - * - * TLS server-side connection. This is the server-side implementation - * of a #GTlsConnection. - * - * Since: 2.28 - */ typedef struct _GTlsServerConnectionInterface GTlsServerConnectionInterface; /** diff --git a/gio/gtrashportal.c b/gio/gtrashportal.c index 0e1d109..82c1356 100644 --- a/gio/gtrashportal.c +++ b/gio/gtrashportal.c @@ -48,7 +48,7 @@ ensure_trash_portal (void) { static GXdpTrash *trash = NULL; - if (g_once_init_enter (&trash)) + if (g_once_init_enter_pointer (&trash)) { GDBusConnection *connection = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); GXdpTrash *proxy = NULL; @@ -62,7 +62,7 @@ ensure_trash_portal (void) g_object_unref (connection); } - g_once_init_leave (&trash, proxy); + g_once_init_leave_pointer (&trash, proxy); } return trash; diff --git a/gio/gunixconnection.c b/gio/gunixconnection.c index 9367366..94a92e3 100644 --- a/gio/gunixconnection.c +++ b/gio/gunixconnection.c @@ -31,19 +31,15 @@ #endif /** - * SECTION:gunixconnection - * @title: GUnixConnection - * @short_description: A UNIX domain GSocketConnection - * @include: gio/gunixconnection.h - * @see_also: #GSocketConnection. + * GUnixConnection: * - * This is the subclass of #GSocketConnection that is created + * This is the subclass of [class@Gio.SocketConnection] that is created * for UNIX domain sockets. * * It contains functions to do some of the UNIX socket specific * functionality like passing file descriptors. * - * Since GLib 2.72, #GUnixConnection is available on all platforms. It requires + * Since GLib 2.72, `GUnixConnection` is available on all platforms. It requires * underlying system support (such as Windows 10 with `AF_UNIX`) at run time. * * Before GLib 2.72, `` belonged to the UNIX-specific GIO @@ -53,13 +49,6 @@ * Since: 2.22 */ -/** - * GUnixConnection: - * - * #GUnixConnection is an opaque data structure and can only be accessed - * using the following functions. - **/ - G_DEFINE_TYPE_WITH_CODE (GUnixConnection, g_unix_connection, G_TYPE_SOCKET_CONNECTION, g_socket_connection_factory_register_type (g_define_type_id, diff --git a/gio/gunixcredentialsmessage.c b/gio/gunixcredentialsmessage.c index 212c4b0..f56665c 100644 --- a/gio/gunixcredentialsmessage.c +++ b/gio/gunixcredentialsmessage.c @@ -16,31 +16,29 @@ */ /** - * SECTION:gunixcredentialsmessage - * @title: GUnixCredentialsMessage - * @short_description: A GSocketControlMessage containing credentials - * @include: gio/gunixcredentialsmessage.h - * @see_also: #GUnixConnection, #GSocketControlMessage + * GUnixCredentialsMessage: * - * This #GSocketControlMessage contains a #GCredentials instance. It - * may be sent using g_socket_send_message() and received using - * g_socket_receive_message() over UNIX sockets (ie: sockets in the - * %G_SOCKET_FAMILY_UNIX family). + * This [class@Gio.SocketControlMessage] contains a [class@Gio.Credentials] + * instance. It may be sent using [method@Gio.Socket.send_message] and received + * using [method@Gio.Socket.receive_message] over UNIX sockets (ie: sockets in + * the `G_SOCKET_FAMILY_UNIX` family). * * For an easier way to send and receive credentials over * stream-oriented UNIX sockets, see - * g_unix_connection_send_credentials() and - * g_unix_connection_receive_credentials(). To receive credentials of + * [method@Gio.UnixConnection.send_credentials] and + * [method@Gio.UnixConnection.receive_credentials]. To receive credentials of * a foreign process connected to a socket, use - * g_socket_get_credentials(). + * [method@Gio.Socket.get_credentials]. * - * Since GLib 2.72, #GUnixCredentialMessage is available on all platforms. It + * Since GLib 2.72, `GUnixCredentialMessage` is available on all platforms. It * requires underlying system support (such as Windows 10 with `AF_UNIX`) at run * time. * * Before GLib 2.72, `` belonged to the UNIX-specific * GIO interfaces, thus you had to use the `gio-unix-2.0.pc` pkg-config file * when using it. This is no longer necessary since GLib 2.72. + * + * Since: 2.26 */ #include "config.h" @@ -266,9 +264,7 @@ g_unix_credentials_message_class_init (GUnixCredentialsMessageClass *class) */ g_object_class_install_property (gobject_class, PROP_CREDENTIALS, - g_param_spec_object ("credentials", - P_("Credentials"), - P_("The credentials stored in the message"), + g_param_spec_object ("credentials", NULL, NULL, G_TYPE_CREDENTIALS, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gunixcredentialsmessage.h b/gio/gunixcredentialsmessage.h index cd42d25..8f63bd2 100644 --- a/gio/gunixcredentialsmessage.h +++ b/gio/gunixcredentialsmessage.h @@ -58,14 +58,6 @@ struct _GUnixCredentialsMessageClass void (*_g_reserved2) (void); }; -/** - * GUnixCredentialsMessage: - * - * The #GUnixCredentialsMessage structure contains only private data - * and should only be accessed using the provided API. - * - * Since: 2.26 - */ struct _GUnixCredentialsMessage { GSocketControlMessage parent_instance; diff --git a/gio/gunixfdlist.c b/gio/gunixfdlist.c index e061714..f17bb8d 100644 --- a/gio/gunixfdlist.c +++ b/gio/gunixfdlist.c @@ -15,18 +15,15 @@ */ /** - * SECTION:gunixfdlist - * @title: GUnixFDList - * @short_description: An object containing a set of UNIX file descriptors - * @include: gio/gunixfdlist.h - * @see_also: #GUnixFDMessage + * GUnixFDList: * - * A #GUnixFDList contains a list of file descriptors. It owns the file + * A `GUnixFDList` contains a list of file descriptors. It owns the file * descriptors that it contains, closing them when finalized. * - * It may be wrapped in a #GUnixFDMessage and sent over a #GSocket in - * the %G_SOCKET_FAMILY_UNIX family by using g_socket_send_message() - * and received using g_socket_receive_message(). + * It may be wrapped in a [class@Gio.UnixFDMessage] and sent over a + * [class@Gio.Socket] in the `G_SOCKET_FAMILY_UNIX` family by using + * [method@Gio.Socket.send_message] and received using + * [method@Gio.Socket.receive_message]. * * Before 2.74, `` belonged to the UNIX-specific GIO * interfaces, thus you had to use the `gio-unix-2.0.pc` pkg-config file when @@ -35,13 +32,6 @@ * Since 2.74, the API is available for Windows. */ -/** - * GUnixFDList: - * - * #GUnixFDList is an opaque data structure and can only be accessed - * using the following functions. - **/ - #include "config.h" #include diff --git a/gio/gunixfdmessage.c b/gio/gunixfdmessage.c index 889a0c9..2d11a35 100644 --- a/gio/gunixfdmessage.c +++ b/gio/gunixfdmessage.c @@ -15,34 +15,23 @@ */ /** - * SECTION:gunixfdmessage - * @title: GUnixFDMessage - * @short_description: A GSocketControlMessage containing a GUnixFDList - * @include: gio/gunixfdmessage.h - * @see_also: #GUnixConnection, #GUnixFDList, #GSocketControlMessage + * GUnixFDMessage: * - * This #GSocketControlMessage contains a #GUnixFDList. - * It may be sent using g_socket_send_message() and received using - * g_socket_receive_message() over UNIX sockets (ie: sockets in the - * %G_SOCKET_FAMILY_UNIX family). The file descriptors are copied + * This [class@Gio.SocketControlMessage] contains a [class@Gio.UnixFDList]. + * It may be sent using [method@Gio.Socket.send_message] and received using + * [method@Gio.Socket.receive_message] over UNIX sockets (ie: sockets in the + * `G_SOCKET_FAMILY_UNIX` family). The file descriptors are copied * between processes by the kernel. * * For an easier way to send and receive file descriptors over - * stream-oriented UNIX sockets, see g_unix_connection_send_fd() and - * g_unix_connection_receive_fd(). + * stream-oriented UNIX sockets, see [method@Gio.UnixConnection.send_fd] and + * [method@Gio.UnixConnection.receive_fd]. * * Note that `` belongs to the UNIX-specific GIO * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config * file when using it. */ -/** - * GUnixFDMessage: - * - * #GUnixFDMessage is an opaque data structure and can only be accessed - * using the following functions. - **/ - #include "config.h" #include @@ -224,9 +213,15 @@ g_unix_fd_message_class_init (GUnixFDMessageClass *class) object_class->set_property = g_unix_fd_message_set_property; object_class->get_property = g_unix_fd_message_get_property; + /** + * GUnixFDMessage:fd-list: + * + * The [class@Gio.UnixFDList] object to send with the message. + * + * Since: 2.22 + */ g_object_class_install_property (object_class, 1, - g_param_spec_object ("fd-list", "file descriptor list", - "The GUnixFDList object to send with the message", + g_param_spec_object ("fd-list", NULL, NULL, G_TYPE_UNIX_FD_LIST, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); } diff --git a/gio/gunixinputstream.c b/gio/gunixinputstream.c index 2180ce8..1ace44a 100644 --- a/gio/gunixinputstream.c +++ b/gio/gunixinputstream.c @@ -39,14 +39,11 @@ /** - * SECTION:gunixinputstream - * @short_description: Streaming input operations for UNIX file descriptors - * @include: gio/gunixinputstream.h - * @see_also: #GInputStream + * GUnixInputStream: * - * #GUnixInputStream implements #GInputStream for reading from a UNIX + * `GUnixInputStream` implements [class@Gio.InputStream] for reading from a UNIX * file descriptor, including asynchronous operations. (If the file - * descriptor refers to a socket or pipe, this will use poll() to do + * descriptor refers to a socket or pipe, this will use `poll()` to do * asynchronous I/O. If it refers to a regular file, it will fall back * to doing asynchronous I/O in another thread.) * @@ -136,9 +133,7 @@ g_unix_input_stream_class_init (GUnixInputStreamClass *klass) */ g_object_class_install_property (gobject_class, PROP_FD, - g_param_spec_int ("fd", - P_("File descriptor"), - P_("The file descriptor to read from"), + g_param_spec_int ("fd", NULL, NULL, G_MININT, G_MAXINT, -1, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); @@ -151,9 +146,7 @@ g_unix_input_stream_class_init (GUnixInputStreamClass *klass) */ g_object_class_install_property (gobject_class, PROP_CLOSE_FD, - g_param_spec_boolean ("close-fd", - P_("Close file descriptor"), - P_("Whether to close the file descriptor when the stream is closed"), + g_param_spec_boolean ("close-fd", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } diff --git a/gio/gunixinputstream.h b/gio/gunixinputstream.h index 78b2cbb..0c2af4f 100644 --- a/gio/gunixinputstream.h +++ b/gio/gunixinputstream.h @@ -34,11 +34,6 @@ G_BEGIN_DECLS #define G_IS_UNIX_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_INPUT_STREAM)) #define G_UNIX_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_UNIX_INPUT_STREAM, GUnixInputStreamClass)) -/** - * GUnixInputStream: - * - * Implements #GInputStream for reading from selectable unix file descriptors - **/ typedef struct _GUnixInputStream GUnixInputStream; typedef struct _GUnixInputStreamClass GUnixInputStreamClass; typedef struct _GUnixInputStreamPrivate GUnixInputStreamPrivate; diff --git a/gio/gunixmount.c b/gio/gunixmount.c index 7055d8e..ec6c573 100644 --- a/gio/gunixmount.c +++ b/gio/gunixmount.c @@ -262,7 +262,7 @@ eject_unmount_done (GObject *source, { if (!g_subprocess_get_successful (subprocess)) /* ...but bad exit code */ - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "%s", stderr_str); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, stderr_str); else /* ...and successful exit code */ g_task_return_boolean (task, TRUE); diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c index 1cfd25d..626f349 100644 --- a/gio/gunixmounts.c +++ b/gio/gunixmounts.c @@ -88,18 +88,6 @@ static const char *_resolve_dev_root (void); #endif /** - * SECTION:gunixmounts - * @include: gio/gunixmounts.h - * @short_description: UNIX mounts - * - * Routines for managing mounted UNIX mount points and paths. - * - * Note that `` belongs to the UNIX-specific GIO - * interfaces, thus you have to use the `gio-unix-2.0.pc` pkg-config - * file when using it. - */ - -/** * GUnixMountType: * @G_UNIX_MOUNT_TYPE_UNKNOWN: Unknown UNIX mount type. * @G_UNIX_MOUNT_TYPE_FLOPPY: Floppy disk UNIX mount type. diff --git a/gio/gunixoutputstream.c b/gio/gunixoutputstream.c index 8a71c31..e0782ca 100644 --- a/gio/gunixoutputstream.c +++ b/gio/gunixoutputstream.c @@ -41,14 +41,11 @@ /** - * SECTION:gunixoutputstream - * @short_description: Streaming output operations for UNIX file descriptors - * @include: gio/gunixoutputstream.h - * @see_also: #GOutputStream + * GUnixOutputStream: * - * #GUnixOutputStream implements #GOutputStream for writing to a UNIX + * `GUnixOutputStream` implements [class@Gio.OutputStream] for writing to a UNIX * file descriptor, including asynchronous operations. (If the file - * descriptor refers to a socket or pipe, this will use poll() to do + * descriptor refers to a socket or pipe, this will use `poll()` to do * asynchronous I/O. If it refers to a regular file, it will fall back * to doing asynchronous I/O in another thread.) * @@ -135,9 +132,7 @@ g_unix_output_stream_class_init (GUnixOutputStreamClass *klass) */ g_object_class_install_property (gobject_class, PROP_FD, - g_param_spec_int ("fd", - P_("File descriptor"), - P_("The file descriptor to write to"), + g_param_spec_int ("fd", NULL, NULL, G_MININT, G_MAXINT, -1, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); @@ -150,9 +145,7 @@ g_unix_output_stream_class_init (GUnixOutputStreamClass *klass) */ g_object_class_install_property (gobject_class, PROP_CLOSE_FD, - g_param_spec_boolean ("close-fd", - P_("Close file descriptor"), - P_("Whether to close the file descriptor when the stream is closed"), + g_param_spec_boolean ("close-fd", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); } diff --git a/gio/gunixoutputstream.h b/gio/gunixoutputstream.h index 37aa225..55e33f6 100644 --- a/gio/gunixoutputstream.h +++ b/gio/gunixoutputstream.h @@ -34,11 +34,6 @@ G_BEGIN_DECLS #define G_IS_UNIX_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_UNIX_OUTPUT_STREAM)) #define G_UNIX_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_UNIX_OUTPUT_STREAM, GUnixOutputStreamClass)) -/** - * GUnixOutputStream: - * - * Implements #GOutputStream for outputting to selectable unix file descriptors - **/ typedef struct _GUnixOutputStream GUnixOutputStream; typedef struct _GUnixOutputStreamClass GUnixOutputStreamClass; typedef struct _GUnixOutputStreamPrivate GUnixOutputStreamPrivate; diff --git a/gio/gunixsocketaddress.c b/gio/gunixsocketaddress.c index 3ccb2cb..3d1a26e 100644 --- a/gio/gunixsocketaddress.c +++ b/gio/gunixsocketaddress.c @@ -35,22 +35,21 @@ #endif /** - * SECTION:gunixsocketaddress - * @short_description: UNIX GSocketAddress - * @include: gio/gunixsocketaddress.h + * GUnixSocketAddress: * - * Support for UNIX-domain (also known as local) sockets. + * Support for UNIX-domain (also known as local) sockets, corresponding to + * `struct sockaddr_un`. * * UNIX domain sockets are generally visible in the filesystem. * However, some systems support abstract socket names which are not * visible in the filesystem and not affected by the filesystem * permissions, visibility, etc. Currently this is only supported * under Linux. If you attempt to use abstract sockets on other - * systems, function calls may return %G_IO_ERROR_NOT_SUPPORTED - * errors. You can use g_unix_socket_address_abstract_names_supported() + * systems, function calls may return `G_IO_ERROR_NOT_SUPPORTED` + * errors. You can use [func@Gio.UnixSocketAddress.abstract_names_supported] * to see if abstract names are supported. * - * Since GLib 2.72, #GUnixSocketAddress is available on all platforms. It + * Since GLib 2.72, `GUnixSocketAddress` is available on all platforms. It * requires underlying system support (such as Windows 10 with `AF_UNIX`) at * run time. * @@ -59,13 +58,6 @@ * when using it. This is no longer necessary since GLib 2.72. */ -/** - * GUnixSocketAddress: - * - * A UNIX-domain (local) socket address, corresponding to a - * struct sockaddr_un. - */ - enum { PROP_0, @@ -275,23 +267,35 @@ g_unix_socket_address_class_init (GUnixSocketAddressClass *klass) gsocketaddress_class->to_native = g_unix_socket_address_to_native; gsocketaddress_class->get_native_size = g_unix_socket_address_get_native_size; + /** + * GUnixSocketAddress:path: + * + * Unix socket path. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PATH, - g_param_spec_string ("path", - P_("Path"), - P_("UNIX socket path"), + g_param_spec_string ("path", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GUnixSocketAddress:path-as-array: + * + * Unix socket path, as a byte array. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_PATH_AS_ARRAY, - g_param_spec_boxed ("path-as-array", - P_("Path array"), - P_("UNIX socket path, as byte array"), + g_param_spec_boxed ("path-as-array", NULL, NULL, G_TYPE_BYTE_ARRAY, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + /** * GUnixSocketAddress:abstract: * @@ -302,17 +306,21 @@ g_unix_socket_address_class_init (GUnixSocketAddressClass *klass) * abstract addresses. */ g_object_class_install_property (gobject_class, PROP_ABSTRACT, - g_param_spec_boolean ("abstract", - P_("Abstract"), - P_("Whether or not this is an abstract address"), + g_param_spec_boolean ("abstract", NULL, NULL, FALSE, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GUnixSocketAddress:address-type: + * + * The type of Unix socket address. + * + * Since: 2.22 + */ g_object_class_install_property (gobject_class, PROP_ADDRESS_TYPE, - g_param_spec_enum ("address-type", - P_("Address type"), - P_("The type of UNIX socket address"), + g_param_spec_enum ("address-type", NULL, NULL, G_TYPE_UNIX_SOCKET_ADDRESS_TYPE, G_UNIX_SOCKET_ADDRESS_PATH, G_PARAM_READWRITE | diff --git a/gio/gunixvolume.c b/gio/gunixvolume.c index a0f00ff..6737457 100644 --- a/gio/gunixvolume.c +++ b/gio/gunixvolume.c @@ -287,7 +287,7 @@ eject_mount_done (GObject *source, { if (!g_subprocess_get_successful (subprocess)) /* ...but bad exit code */ - g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "%s", stderr_str); + g_task_return_new_error_literal (task, G_IO_ERROR, G_IO_ERROR_FAILED, stderr_str); else { /* ...and successful exit code */ diff --git a/gio/gvfs.c b/gio/gvfs.c index f73dcfe..1ff566b 100644 --- a/gio/gvfs.c +++ b/gio/gvfs.c @@ -31,12 +31,9 @@ /** - * SECTION:gvfs - * @short_description: Virtual File System - * @include: gio/gio.h + * GVfs: * * Entry point for using GIO functionality. - * */ static GRWLock additional_schemes_lock; @@ -355,7 +352,7 @@ g_vfs_get_default (void) if (GLIB_PRIVATE_CALL (g_check_setuid) ()) return g_vfs_get_local (); - if (g_once_init_enter (&vfs_default_singleton)) + if (g_once_init_enter_pointer (&vfs_default_singleton)) { GVfs *singleton; @@ -363,7 +360,7 @@ g_vfs_get_default (void) "GIO_USE_VFS", (GIOModuleVerifyFunc) g_vfs_is_active); - g_once_init_leave (&vfs_default_singleton, singleton); + g_once_init_leave_pointer (&vfs_default_singleton, singleton); } return vfs_default_singleton; @@ -379,12 +376,12 @@ g_vfs_get_default (void) GVfs * g_vfs_get_local (void) { - static gsize vfs = 0; + static GVfs *vfs = 0; - if (g_once_init_enter (&vfs)) - g_once_init_leave (&vfs, (gsize)_g_local_vfs_new ()); + if (g_once_init_enter_pointer (&vfs)) + g_once_init_leave_pointer (&vfs, _g_local_vfs_new ()); - return G_VFS (vfs); + return vfs; } /** diff --git a/gio/gvfs.h b/gio/gvfs.h index cbe9792..0fdce36 100644 --- a/gio/gvfs.h +++ b/gio/gvfs.h @@ -68,11 +68,6 @@ typedef GFile * (* GVfsFileLookupFunc) (GVfs *vfs, */ #define G_VFS_EXTENSION_POINT_NAME "gio-vfs" -/** - * GVfs: - * - * Virtual File System object. - **/ typedef struct _GVfsClass GVfsClass; struct _GVfs diff --git a/gio/gvolume.c b/gio/gvolume.c index ba94b17..6b809a6 100644 --- a/gio/gvolume.c +++ b/gio/gvolume.c @@ -32,51 +32,49 @@ /** - * SECTION:gvolume - * @short_description: Volume management - * @include: gio/gio.h + * GVolume: * - * The #GVolume interface represents user-visible objects that can be - * mounted. Note, when porting from GnomeVFS, #GVolume is the moral - * equivalent of #GnomeVFSDrive. - * - * Mounting a #GVolume instance is an asynchronous operation. For more - * information about asynchronous operations, see #GAsyncResult and - * #GTask. To mount a #GVolume, first call g_volume_mount() with (at - * least) the #GVolume instance, optionally a #GMountOperation object - * and a #GAsyncReadyCallback. - * - * Typically, one will only want to pass %NULL for the - * #GMountOperation if automounting all volumes when a desktop session - * starts since it's not desirable to put up a lot of dialogs asking + * The `GVolume` interface represents user-visible objects that can be + * mounted. Note, when [porting from GnomeVFS](migrating-gnome-vfs.html), + * `GVolume` is the moral equivalent of `GnomeVFSDrive`. + * + * Mounting a `GVolume` instance is an asynchronous operation. For more + * information about asynchronous operations, see [iface@Gio.AsyncResult] and + * [class@Gio.Task]. To mount a `GVolume`, first call [method@Gio.Volume.mount] + * with (at least) the `GVolume` instance, optionally a + * [class@Gio.MountOperation] object and a [type@Gio.AsyncReadyCallback]. + * + * Typically, one will only want to pass `NULL` for the + * [class@Gio.MountOperation] if automounting all volumes when a desktop session + * starts since it’s not desirable to put up a lot of dialogs asking * for credentials. * * The callback will be fired when the operation has resolved (either - * with success or failure), and a #GAsyncResult instance will be + * with success or failure), and a [iface@Gio.AsyncResult] instance will be * passed to the callback. That callback should then call - * g_volume_mount_finish() with the #GVolume instance and the - * #GAsyncResult data to see if the operation was completed - * successfully. If an @error is present when g_volume_mount_finish() - * is called, then it will be filled with any error information. + * [method@Gio.Volume.mount_finish] with the `GVolume` instance and the + * [iface@Gio.AsyncResult] data to see if the operation was completed + * successfully. If a [type@GLib.Error] is present when + * [method@Gio.Volume.mount_finish] is called, then it will be filled with any + * error information. * - * ## Volume Identifiers # {#volume-identifier} + * ## Volume Identifiers * * It is sometimes necessary to directly access the underlying * operating system object behind a volume (e.g. for passing a volume - * to an application via the commandline). For this purpose, GIO - * allows to obtain an 'identifier' for the volume. There can be + * to an application via the command line). For this purpose, GIO + * allows to obtain an ‘identifier’ for the volume. There can be * different kinds of identifiers, such as Hal UDIs, filesystem labels, * traditional Unix devices (e.g. `/dev/sda2`), UUIDs. GIO uses predefined * strings as names for the different kinds of identifiers: - * %G_VOLUME_IDENTIFIER_KIND_UUID, %G_VOLUME_IDENTIFIER_KIND_LABEL, etc. - * Use g_volume_get_identifier() to obtain an identifier for a volume. + * `G_VOLUME_IDENTIFIER_KIND_UUID`, `G_VOLUME_IDENTIFIER_KIND_LABEL`, etc. + * Use [method@Gio.Volume.get_identifier] to obtain an identifier for a volume. * - * - * Note that %G_VOLUME_IDENTIFIER_KIND_HAL_UDI will only be available - * when the gvfs hal volume monitor is in use. Other volume monitors - * will generally be able to provide the %G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE + * Note that `G_VOLUME_IDENTIFIER_KIND_HAL_UDI` will only be available + * when the GVFS hal volume monitor is in use. Other volume monitors + * will generally be able to provide the `G_VOLUME_IDENTIFIER_KIND_UNIX_DEVICE` * identifier, which can be used to obtain a hal device by means of - * libhal_manager_find_device_string_match(). + * `libhal_manager_find_device_string_match()`. */ typedef GVolumeIface GVolumeInterface; @@ -330,7 +328,7 @@ g_volume_should_automount (GVolume *volume) /** - * g_volume_mount: + * g_volume_mount: (virtual mount_fn) * @volume: a #GVolume * @flags: flags affecting the operation * @mount_operation: (nullable): a #GMountOperation or %NULL to avoid user interaction @@ -341,8 +339,6 @@ g_volume_should_automount (GVolume *volume) * Mounts a volume. This is an asynchronous operation, and is * finished by calling g_volume_mount_finish() with the @volume * and #GAsyncResult returned in the @callback. - * - * Virtual: mount_fn */ void g_volume_mount (GVolume *volume, @@ -565,7 +561,7 @@ g_volume_eject_with_operation_finish (GVolume *volume, * @kind: the kind of identifier to return * * Gets the identifier of the given kind for @volume. - * See the [introduction][volume-identifier] for more + * See the [introduction](#volume-identifiers) for more * information about volume identifiers. * * Returns: (nullable) (transfer full): a newly allocated string containing the @@ -593,7 +589,7 @@ g_volume_get_identifier (GVolume *volume, * g_volume_enumerate_identifiers: * @volume: a #GVolume * - * Gets the kinds of [identifiers][volume-identifier] that @volume has. + * Gets the kinds of [identifiers](#volume-identifiers) that @volume has. * Use g_volume_get_identifier() to obtain the identifiers themselves. * * Returns: (array zero-terminated=1) (transfer full): a %NULL-terminated array diff --git a/gio/gvolume.h b/gio/gvolume.h index 2d6e14e..7b5a81a 100644 --- a/gio/gvolume.h +++ b/gio/gvolume.h @@ -109,10 +109,10 @@ G_BEGIN_DECLS * @mount_finish: Finishes a mount operation. * @eject: Ejects a given #GVolume. * @eject_finish: Finishes an eject operation. - * @get_identifier: Returns the [identifier][volume-identifier] of the given kind, or %NULL if + * @get_identifier: Returns the [identifier](#volume-identifiers) of the given kind, or %NULL if * the #GVolume doesn't have one. * @enumerate_identifiers: Returns an array strings listing the kinds - * of [identifiers][volume-identifier] which the #GVolume has. + * of [identifiers](#volume-identifiers) which the #GVolume has. * @should_automount: Returns %TRUE if the #GVolume should be automatically mounted. * @get_activation_root: Returns the activation root for the #GVolume if it is known in advance or %NULL if * it is not known. diff --git a/gio/gvolumemonitor.c b/gio/gvolumemonitor.c index cc4f3e4..ed7288b 100644 --- a/gio/gvolumemonitor.c +++ b/gio/gvolumemonitor.c @@ -32,19 +32,16 @@ /** - * SECTION:gvolumemonitor - * @short_description: Volume Monitor - * @include: gio/gio.h - * @see_also: #GFileMonitor + * GVolumeMonitor: * - * #GVolumeMonitor is for listing the user interesting devices and volumes + * `GVolumeMonitor` is for listing the user interesting devices and volumes * on the computer. In other words, what a file selector or file manager - * would show in a sidebar. + * would show in a sidebar. * - * #GVolumeMonitor is not - * [thread-default-context aware][g-main-context-push-thread-default], - * and so should not be used other than from the main thread, with no - * thread-default-context active. + * `GVolumeMonitor` is not + * thread-default-context aware (see + * [method@GLib.MainContext.push_thread_default]), and so should not be used + * other than from the main thread, with no thread-default-context active. * * In order to receive updates about volumes and mounts monitored through GVFS, * a main loop must be running. diff --git a/gio/gvolumemonitor.h b/gio/gvolumemonitor.h index 11bd331..7ef917a 100644 --- a/gio/gvolumemonitor.h +++ b/gio/gvolumemonitor.h @@ -49,11 +49,6 @@ G_BEGIN_DECLS */ #define G_VOLUME_MONITOR_EXTENSION_POINT_NAME "gio-volume-monitor" -/** - * GVolumeMonitor: - * - * A Volume Monitor that watches for volume events. - **/ typedef struct _GVolumeMonitorClass GVolumeMonitorClass; struct _GVolumeMonitor diff --git a/gio/gwin32appinfo.c b/gio/gwin32appinfo.c index 49e76ca..f177878 100644 --- a/gio/gwin32appinfo.c +++ b/gio/gwin32appinfo.c @@ -4034,9 +4034,9 @@ gio_win32_appinfo_init (gboolean do_wait) /* Trigger initial tree build. Fake data pointer. */ g_thread_pool_push (gio_win32_appinfo_threadpool, (gpointer) keys_updated, NULL); /* Increment the DLL refcount */ - GetModuleHandleExA (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, - (const char *) gio_win32_appinfo_init, - &gio_dll_extra); + GetModuleHandleEx (GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS | GET_MODULE_HANDLE_EX_FLAG_PIN, + (LPCWSTR) gio_win32_appinfo_init, + &gio_dll_extra); /* gio DLL cannot be unloaded now */ g_once_init_leave (&initialized, TRUE); @@ -4253,7 +4253,7 @@ g_win32_app_info_get_name (GAppInfo *appinfo) else if (info->app && info->app->canonical_name_u8) return info->app->canonical_name_u8; else - return P_("Unnamed"); + return _("Unnamed"); } static const char * @@ -5213,11 +5213,11 @@ g_win32_app_info_launch_internal (GWin32AppInfo *info, { if (info->app->is_uwp || info->handler == NULL) g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - P_("The app ‘%s’ in the application object has no verbs"), + _("The app ‘%s’ in the application object has no verbs"), g_win32_appinfo_application_get_some_name (info->app)); else if (info->handler->verbs->len == 0) g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, - P_("The app ‘%s’ and the handler ‘%s’ in the application object have no verbs"), + _("The app ‘%s’ and the handler ‘%s’ in the application object have no verbs"), g_win32_appinfo_application_get_some_name (info->app), info->handler->handler_id_folded); diff --git a/gio/gwin32inputstream.c b/gio/gwin32inputstream.c index 685d6f2..afb362a 100644 --- a/gio/gwin32inputstream.c +++ b/gio/gwin32inputstream.c @@ -36,12 +36,9 @@ #include "glibintl.h" /** - * SECTION:gwin32inputstream - * @short_description: Streaming input operations for Windows file handles - * @include: gio/gwin32inputstream.h - * @see_also: #GInputStream + * GWin32InputStream: * - * #GWin32InputStream implements #GInputStream for reading from a + * `GWin32InputStream` implements [class@Gio.InputStream] for reading from a * Windows file handle. * * Note that `` belongs to the Windows-specific GIO @@ -261,9 +258,7 @@ g_win32_input_stream_class_init (GWin32InputStreamClass *klass) * Since: 2.26 */ props[PROP_HANDLE] = - g_param_spec_pointer ("handle", - P_("File handle"), - P_("The file handle to read from"), + g_param_spec_pointer ("handle", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -277,9 +272,7 @@ g_win32_input_stream_class_init (GWin32InputStreamClass *klass) * Since: 2.26 */ props[PROP_CLOSE_HANDLE] = - g_param_spec_boolean ("close-handle", - P_("Close file handle"), - P_("Whether to close the file handle when the stream is closed"), + g_param_spec_boolean ("close-handle", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gwin32inputstream.h b/gio/gwin32inputstream.h index 8dde9e8..53c7d78 100644 --- a/gio/gwin32inputstream.h +++ b/gio/gwin32inputstream.h @@ -35,11 +35,6 @@ G_BEGIN_DECLS #define G_IS_WIN32_INPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_INPUT_STREAM)) #define G_WIN32_INPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_INPUT_STREAM, GWin32InputStreamClass)) -/** - * GWin32InputStream: - * - * Implements #GInputStream for reading from selectable Windows file handles - **/ typedef struct _GWin32InputStream GWin32InputStream; typedef struct _GWin32InputStreamClass GWin32InputStreamClass; typedef struct _GWin32InputStreamPrivate GWin32InputStreamPrivate; diff --git a/gio/gwin32outputstream.c b/gio/gwin32outputstream.c index b88f05c..fdf1e98 100644 --- a/gio/gwin32outputstream.c +++ b/gio/gwin32outputstream.c @@ -37,12 +37,9 @@ #include "glibintl.h" /** - * SECTION:gwin32outputstream - * @short_description: Streaming output operations for Windows file handles - * @include: gio/gwin32outputstream.h - * @see_also: #GOutputStream + * GWin32OutputStream: * - * #GWin32OutputStream implements #GOutputStream for writing to a + * `GWin32OutputStream` implements [class@Gio.OutputStream] for writing to a * Windows file handle. * * Note that `` belongs to the Windows-specific GIO @@ -248,9 +245,7 @@ g_win32_output_stream_class_init (GWin32OutputStreamClass *klass) * Since: 2.26 */ props[PROP_HANDLE] = - g_param_spec_pointer ("handle", - P_("File handle"), - P_("The file handle to write to"), + g_param_spec_pointer ("handle", NULL, NULL, G_PARAM_READABLE | G_PARAM_WRITABLE | G_PARAM_CONSTRUCT_ONLY | @@ -264,9 +259,7 @@ g_win32_output_stream_class_init (GWin32OutputStreamClass *klass) * Since: 2.26 */ props[PROP_CLOSE_HANDLE] = - g_param_spec_boolean ("close-handle", - P_("Close file handle"), - P_("Whether to close the file handle when the stream is closed"), + g_param_spec_boolean ("close-handle", NULL, NULL, TRUE, G_PARAM_READABLE | G_PARAM_WRITABLE | diff --git a/gio/gwin32outputstream.h b/gio/gwin32outputstream.h index d64fdc1..35942ca 100644 --- a/gio/gwin32outputstream.h +++ b/gio/gwin32outputstream.h @@ -35,11 +35,6 @@ G_BEGIN_DECLS #define G_IS_WIN32_OUTPUT_STREAM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_WIN32_OUTPUT_STREAM)) #define G_WIN32_OUTPUT_STREAM_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_WIN32_OUTPUT_STREAM, GWin32OutputStreamClass)) -/** - * GWin32OutputStream: - * - * Implements #GOutputStream for outputting to Windows file handles - **/ typedef struct _GWin32OutputStream GWin32OutputStream; typedef struct _GWin32OutputStreamClass GWin32OutputStreamClass; typedef struct _GWin32OutputStreamPrivate GWin32OutputStreamPrivate; diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c index df20db1..bd83b38 100644 --- a/gio/gwin32registrykey.c +++ b/gio/gwin32registrykey.c @@ -347,23 +347,21 @@ G_DEFINE_BOXED_TYPE (GWin32RegistryValueIter, g_win32_registry_value_iter, g_win32_registry_value_iter_free) /** - * SECTION:gwin32registrykey - * @title: GWin32RegistryKey - * @short_description: W32 registry access helper - * @include: gio/win32/gwin32registrykey.h + * GWin32RegistryKey: * - * #GWin32RegistryKey represents a single Windows Registry key. + * `GWin32RegistryKey` represents a single Windows Registry key. * - * #GWin32RegistryKey is used by a number of helper functions that read + * `GWin32RegistryKey` is used by a number of helper functions that read * Windows Registry. All keys are opened with read-only access, and at * the moment there is no API for writing into registry keys or creating * new ones. * - * #GWin32RegistryKey implements the #GInitable interface, so if it is manually - * constructed by e.g. g_object_new() you must call g_initable_init() and check - * the results before using the object. This is done automatically - * in g_win32_registry_key_new() and g_win32_registry_key_get_child(), so these - * functions can return %NULL. + * `GWin32RegistryKey` implements the [iface@Gio.Initable] interface, so if it + * is manually constructed by e.g. [ctor@GObject.Object.new] you must call + * [method@Gio.Initable.init] and check the results before using the object. + * This is done automatically in [ctor@Gio.Win32RegistryKey.new] and + * [method@Gio.Win32RegistryKey.get_child], so these functions can return + * `NULL`. * * To increase efficiency, a UTF-16 variant is available for all functions * that deal with key or value names in the registry. Use these to perform @@ -372,17 +370,17 @@ G_DEFINE_BOXED_TYPE (GWin32RegistryValueIter, g_win32_registry_value_iter, * of UTF-16 functions avoids the overhead of converting names to UTF-8 and * back. * - * All functions operate in current user's context (it is not possible to - * access registry tree of a different user). + * All functions operate in the current user’s context (it is not possible to + * access the registry tree of a different user). * - * Key paths must use '\\' as a separator, '/' is not supported. Key names - * must not include '\\', because it's used as a separator. Value names - * can include '\\'. + * Key paths must use `\\` as a separator, `/` is not supported. Key names + * must not include `\\`, because it’s used as a separator. Value names + * can include `\\`. * * Key and value names are not case sensitive. * - * Full key name (excluding the pre-defined ancestor's name) can't exceed - * 255 UTF-16 characters, give or take. Value name can't exceed 16383 UTF-16 + * A full key name (excluding the pre-defined ancestor’s name) can’t exceed + * 255 UTF-16 characters, give or take. A value name can’t exceed 16383 UTF-16 * characters. Tree depth is limited to 512 levels. **/ @@ -1747,7 +1745,7 @@ static void _g_win32_registry_key_reread (GWin32RegistryKey *key, GWin32RegistryKeyPrivate *buf) { - if (g_once_init_enter (&nt_query_key)) + if (g_once_init_enter_pointer (&nt_query_key)) { NtQueryKeyFunc func; HMODULE ntdll = GetModuleHandleW (L"ntdll.dll"); @@ -1757,7 +1755,7 @@ _g_win32_registry_key_reread (GWin32RegistryKey *key, else func = NULL; - g_once_init_leave (&nt_query_key, func); + g_once_init_leave_pointer (&nt_query_key, func); } /* Assume that predefined keys never get renamed. Also, their handles probably @@ -1875,7 +1873,7 @@ g_win32_registry_get_os_dirs_w (void) { static gunichar2 **mui_os_dirs = NULL; - if (g_once_init_enter (&mui_os_dirs)) + if (g_once_init_enter_pointer (&mui_os_dirs)) { gunichar2 **new_mui_os_dirs; gunichar2 *system32 = NULL; @@ -1915,7 +1913,7 @@ g_win32_registry_get_os_dirs_w (void) new_mui_os_dirs[array_index++] = NULL; - g_once_init_leave (&mui_os_dirs, new_mui_os_dirs); + g_once_init_leave_pointer (&mui_os_dirs, new_mui_os_dirs); } return (const gunichar2 * const *) mui_os_dirs; @@ -1936,7 +1934,7 @@ g_win32_registry_get_os_dirs (void) { static gchar **mui_os_dirs = NULL; - if (g_once_init_enter (&mui_os_dirs)) + if (g_once_init_enter_pointer (&mui_os_dirs)) { gchar **new_mui_os_dirs; gsize array_index; @@ -1960,7 +1958,7 @@ g_win32_registry_get_os_dirs (void) g_critical ("Failed to convert to a system directory #%zu to UTF-8", array_index); } - g_once_init_leave (&mui_os_dirs, new_mui_os_dirs); + g_once_init_leave_pointer (&mui_os_dirs, new_mui_os_dirs); } return (const gchar * const *) mui_os_dirs; @@ -2504,7 +2502,7 @@ g_win32_registry_key_watch (GWin32RegistryKey *key, return FALSE; } - if (g_once_init_enter (&nt_notify_change_multiple_keys)) + if (g_once_init_enter_pointer (&nt_notify_change_multiple_keys)) { NtNotifyChangeMultipleKeysFunc func; HMODULE ntdll = GetModuleHandleW (L"ntdll.dll"); @@ -2514,7 +2512,7 @@ g_win32_registry_key_watch (GWin32RegistryKey *key, else func = NULL; - g_once_init_leave (&nt_notify_change_multiple_keys, func); + g_once_init_leave_pointer (&nt_notify_change_multiple_keys, func); } if (nt_notify_change_multiple_keys== NULL) @@ -2697,9 +2695,7 @@ g_win32_registry_key_class_init (GWin32RegistryKeyClass *klass) */ g_object_class_install_property (gobject_class, PROP_PATH, - g_param_spec_string ("path", - "Path", - "Path to the key in the registry", + g_param_spec_string ("path", NULL, NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -2714,9 +2710,7 @@ g_win32_registry_key_class_init (GWin32RegistryKeyClass *klass) */ g_object_class_install_property (gobject_class, PROP_PATH_UTF16, - g_param_spec_pointer ("path-utf16", - "Path (UTF-16)", - "Path to the key in the registry, in UTF-16", + g_param_spec_pointer ("path-utf16", NULL, NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gwin32sid.c b/gio/gwin32sid.c index 5bab405..ddc888b 100644 --- a/gio/gwin32sid.c +++ b/gio/gwin32sid.c @@ -192,20 +192,20 @@ _g_win32_process_get_access_token_sid (DWORD process_id, gchar * _g_win32_sid_to_string (SID *sid, GError **error) { - gchar *tmp, *ret; + wchar_t *tmp = NULL; + char *ret; g_return_val_if_fail (sid != NULL, NULL); g_return_val_if_fail (error == NULL || *error == NULL, NULL); - if (!ConvertSidToStringSidA (sid, &tmp)) + if (!ConvertSidToStringSid (sid, &tmp)) { g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (GetLastError ()), "Failed to ConvertSidToString"); - return NULL; } - ret = g_strdup (tmp); + ret = g_utf16_to_utf8 (tmp, -1, NULL, NULL, NULL); LocalFree (tmp); return ret; } diff --git a/gio/gzlibcompressor.c b/gio/gzlibcompressor.c index a1c018a..00bde8f 100644 --- a/gio/gzlibcompressor.c +++ b/gio/gzlibcompressor.c @@ -43,21 +43,14 @@ enum { }; /** - * SECTION:gzlibcompressor - * @short_description: Zlib compressor - * @include: gio/gio.h + * GZlibCompressor: * - * #GZlibCompressor is an implementation of #GConverter that + * `GZlibCompressor` is an implementation of [iface@Gio.Converter] that * compresses data using zlib. */ static void g_zlib_compressor_iface_init (GConverterIface *iface); -/** - * GZlibCompressor: - * - * Zlib decompression - */ struct _GZlibCompressor { GObject parent_instance; @@ -228,20 +221,32 @@ g_zlib_compressor_class_init (GZlibCompressorClass *klass) gobject_class->get_property = g_zlib_compressor_get_property; gobject_class->set_property = g_zlib_compressor_set_property; + /** + * GZlibCompressor:format: + * + * The format of the compressed data. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_FORMAT, - g_param_spec_enum ("format", - P_("compression format"), - P_("The format of the compressed data"), + g_param_spec_enum ("format", NULL, NULL, G_TYPE_ZLIB_COMPRESSOR_FORMAT, G_ZLIB_COMPRESSOR_FORMAT_ZLIB, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); + + /** + * GZlibCompressor:level: + * + * The level of compression from `0` (no compression) to `9` (most + * compression). `-1` for the default level. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_LEVEL, - g_param_spec_int ("level", - P_("compression level"), - P_("The level of compression from 0 (no compression) to 9 (most compression), -1 for the default level"), + g_param_spec_int ("level", NULL, NULL, -1, 9, -1, G_PARAM_READWRITE | @@ -259,9 +264,7 @@ g_zlib_compressor_class_init (GZlibCompressorClass *klass) */ g_object_class_install_property (gobject_class, PROP_FILE_INFO, - g_param_spec_object ("file-info", - P_("file info"), - P_("File info"), + g_param_spec_object ("file-info", NULL, NULL, G_TYPE_FILE_INFO, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/gzlibdecompressor.c b/gio/gzlibdecompressor.c index f704509..dbe126d 100644 --- a/gio/gzlibdecompressor.c +++ b/gio/gzlibdecompressor.c @@ -42,11 +42,9 @@ enum { }; /** - * SECTION:gzlibdecompressor - * @short_description: Zlib decompressor - * @include: gio/gio.h + * GZlibDecompressor: * - * #GZlibDecompressor is an implementation of #GConverter that + * `GZlibDecompressor` is an implementation of [iface@Gio.Converter] that * decompresses data compressed with zlib. */ @@ -58,11 +56,6 @@ typedef struct { GFileInfo *file_info; } HeaderData; -/** - * GZlibDecompressor: - * - * Zlib decompression - */ struct _GZlibDecompressor { GObject parent_instance; @@ -222,11 +215,16 @@ g_zlib_decompressor_class_init (GZlibDecompressorClass *klass) gobject_class->get_property = g_zlib_decompressor_get_property; gobject_class->set_property = g_zlib_decompressor_set_property; + /** + * GZlibDecompressor:format: + * + * The format of the compressed data. + * + * Since: 2.24 + */ g_object_class_install_property (gobject_class, PROP_FORMAT, - g_param_spec_enum ("format", - P_("compression format"), - P_("The format of the compressed data"), + g_param_spec_enum ("format", NULL, NULL, G_TYPE_ZLIB_COMPRESSOR_FORMAT, G_ZLIB_COMPRESSOR_FORMAT_ZLIB, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -244,9 +242,7 @@ g_zlib_decompressor_class_init (GZlibDecompressorClass *klass) */ g_object_class_install_property (gobject_class, PROP_FILE_INFO, - g_param_spec_object ("file-info", - P_("file info"), - P_("File info"), + g_param_spec_object ("file-info", NULL, NULL, G_TYPE_FILE_INFO, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS)); diff --git a/gio/inotify/inotify-kernel.c b/gio/inotify/inotify-kernel.c index 7733d39..f950a21 100644 --- a/gio/inotify/inotify-kernel.c +++ b/gio/inotify/inotify-kernel.c @@ -416,8 +416,8 @@ ik_source_new (gboolean (* callback) (ik_event_t *event)) gboolean _ik_startup (gboolean (*cb)(ik_event_t *event)) { - if (g_once_init_enter (&inotify_source)) - g_once_init_leave (&inotify_source, ik_source_new (cb)); + if (g_once_init_enter_pointer (&inotify_source)) + g_once_init_leave_pointer (&inotify_source, ik_source_new (cb)); return inotify_source->fd >= 0; } diff --git a/gio/meson.build b/gio/meson.build index f9fdf6e..9b3c5ba 100644 --- a/gio/meson.build +++ b/gio/meson.build @@ -242,6 +242,7 @@ xdp_dbus_generated = custom_target('xdp-dbus', 'org.freedesktop.portal.Trash.xml'], output : ['xdp-dbus.h', 'xdp-dbus.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-prefix', 'org.freedesktop.portal.', '--output-directory', '@OUTDIR@', @@ -254,6 +255,7 @@ gdbus_daemon_generated = custom_target('gdbus-daemon-generated', input : ['dbus-daemon.xml'], output : ['gdbus-daemon-generated.h', 'gdbus-daemon-generated.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-prefix', 'org.', '--output-directory', '@OUTDIR@', @@ -472,7 +474,7 @@ else install_headers(gio_win32_include_headers, subdir : 'gio-win32-2.0/gio') endif -gio_sources = files( +gio_base_sources = files( 'gappinfo.c', 'gasynchelper.c', 'gasyncinitable.c', @@ -603,6 +605,8 @@ gio_sources = files( 'gliststore.c', ) +gio_sources = gio_base_sources + if glib_build_shared gio_sources += files ('../glib/gtrace.c') endif @@ -879,10 +883,8 @@ libgio_dep = declare_dependency(link_with : libgio, pkg.generate(libgio, requires : ['glib-2.0', 'gobject-2.0'], variables : [ - 'datadir=' + '${prefix}' / get_option('datadir'), 'schemasdir=' + '${datadir}' / schemas_subdir, 'dtdsdir=' + '${datadir}' / dtds_subdir, - 'bindir=' + '${prefix}' / get_option('bindir'), 'giomoduledir=' + pkgconfig_giomodulesdir, 'gio=' + '${bindir}' / 'gio', 'gio_querymodules=' + pkgconfig_multiarch_bindir / 'gio-querymodules', @@ -983,7 +985,7 @@ gio_tool_sources = [ 'gio-tool-tree.c', ] -executable('gio', gio_tool_sources, +gio_tool = executable('gio', gio_tool_sources, install : true, install_tag : 'bin', c_args : gio_c_args, @@ -1084,20 +1086,11 @@ endif if multiarch_bindir != get_option('bindir') foreach exe : ['gio-querymodules', 'glib-compile-schemas'] - if meson.version().version_compare('>=0.61.0') - install_symlink( - exe, - install_dir : get_option('bindir'), - pointing_to : get_option('prefix') / multiarch_bindir / exe, - ) - else - warning( - 'Please use Meson >= 0.61.0 or create a symlink @1@ -> @2@ in packaging'.format( - get_option('prefix') / get_option('bindir') / exe, - get_option('prefix') / multiarch_bindir / exe, - ) - ) - endif + install_symlink( + exe, + install_dir : get_option('bindir'), + pointing_to : get_option('prefix') / multiarch_bindir / exe, + ) endforeach endif diff --git a/gio/tests/appinfo.c b/gio/tests/appinfo.c index 625b828..6a2ae69 100644 --- a/gio/tests/appinfo.c +++ b/gio/tests/appinfo.c @@ -384,6 +384,21 @@ test_associations (void) gboolean result; GList *list; gchar *cmdline; + gchar *update_desktop_database = NULL, *update_mime_database = NULL; + + update_desktop_database = g_find_program_in_path ("update-desktop-database"); + update_mime_database = g_find_program_in_path ("update-mime-database"); + + if (update_desktop_database == NULL || update_mime_database == NULL) + { + g_test_skip ("update-desktop-database and update-mime-database are needed to change file associations"); + g_free (update_desktop_database); + g_free (update_mime_database); + return; + } + + g_free (update_desktop_database); + g_free (update_mime_database); cmdline = g_strconcat (g_test_get_dir (G_TEST_BUILT), "/appinfo-test --option", NULL); appinfo = g_app_info_create_from_commandline (cmdline, diff --git a/gio/tests/application-command-line.c b/gio/tests/application-command-line.c index 185d49f..6104cb6 100644 --- a/gio/tests/application-command-line.c +++ b/gio/tests/application-command-line.c @@ -76,6 +76,15 @@ test_basic_properties (void) g_object_get (cl, "is-remote", &is_remote, NULL); g_assert_false (is_remote); + /* exit status */ + g_assert_cmpint (g_application_command_line_get_exit_status (cl), ==, 0); + g_application_command_line_set_exit_status (cl, 1); + g_assert_cmpint (g_application_command_line_get_exit_status (cl), ==, 1); + + g_application_command_line_done (cl); + g_application_command_line_set_exit_status (cl, 2); + g_assert_cmpint (g_application_command_line_get_exit_status (cl), ==, 1); + g_clear_object (&cl); } diff --git a/gio/tests/apps.c b/gio/tests/apps.c index 191edd4..d656b6c 100644 --- a/gio/tests/apps.c +++ b/gio/tests/apps.c @@ -33,8 +33,28 @@ main (int argc, char **argv) { setlocale (LC_ALL, ""); - if (argv[1] == NULL) - ; + if (argv[1] == NULL || g_str_equal (argv[1], "--help")) + g_print ("Usage:\n" + " apps --help\n" + " apps COMMAND [COMMAND_OPTIONS]\n" + "\n" + "COMMANDS:\n" + " list\n" + " search [--should-show-only] TEXT_TO_SEARCH\n" + " implementations INTERFACE_NAME\n" + " show-info DESKTOP_FILE\n" + " default-for-type MIME_TYPE\n" + " recommended-for-type MIME_TYPE\n" + " all-for-type MIME_TYPE\n" + " fallback-for-type MIME_TYPE\n" + " should-show DESKTOP_FILE\n" + " monitor\n" + "\n" + "Examples:\n" + " apps search --should-show-only ter\n" + " apps show-info org.gnome.Nautilus.desktop\n" + " apps default-for-type image/png\n" + "\n"); else if (g_str_equal (argv[1], "list")) { GList *all, *i; @@ -47,13 +67,31 @@ main (int argc, char **argv) else if (g_str_equal (argv[1], "search")) { gchar ***results; + gboolean should_show_only; gint i, j; - results = g_desktop_app_info_search (argv[2]); + should_show_only = argc > 3 && g_str_equal (argv[2], "--should-show-only"); + results = g_desktop_app_info_search (argv[ should_show_only ? 3 : 2 ]); for (i = 0; results[i]; i++) { for (j = 0; results[i][j]; j++) - g_print ("%s%s", j ? " " : "", results[i][j]); + { + if (should_show_only) + { + GDesktopAppInfo *info; + gboolean should_show; + + info = g_desktop_app_info_new (results[i][j]); + if (info) + { + should_show = g_app_info_should_show (G_APP_INFO (info)); + g_object_unref (info); + if (!should_show) + continue; + } + } + g_print ("%s%s", j ? " " : "", results[i][j]); + } g_print ("\n"); g_strfreev (results[i]); } diff --git a/gio/tests/codegen.py b/gio/tests/codegen.py index bb570f1..0681bb4 100644 --- a/gio/tests/codegen.py +++ b/gio/tests/codegen.py @@ -117,6 +117,7 @@ class TestCodegen(unittest.TestCase): env = os.environ.copy() env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" print("Environment:", env) # We want to ensure consistent line endings... diff --git a/gio/tests/contenttype.c b/gio/tests/contenttype.c index 7fd97f4..8784374 100644 --- a/gio/tests/contenttype.c +++ b/gio/tests/contenttype.c @@ -361,6 +361,57 @@ test_tree (void) } static void +test_tree_invalid_encoding (void) +{ + gchar *path; + gchar *name; + GFile *tmpdir; + GFile *file; + gchar **types; + GError *error = NULL; + + g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/3168"); + +#if defined(__APPLE__) || defined(G_OS_WIN32) + g_test_skip ("The OSX & Windows backends do not implement g_content_type_guess_for_tree()"); + return; +#endif + + path = g_dir_make_tmp ("gio-test-tree-invalid-encoding-XXXXXX", &error); + g_assert_no_error (error); + tmpdir = g_file_new_for_path (path); + g_free (path); + + name = g_strdup_printf ("\260"); + file = g_file_get_child (tmpdir, name); + g_free (name); + + g_file_replace_contents (file, "", 0, NULL, FALSE, 0, NULL, NULL, &error); + if (g_error_matches (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT)) + { + g_test_skip ("Unable to create testing file with non-ASCII characters."); + + g_object_unref (tmpdir); + g_object_unref (file); + g_clear_error (&error); + + return; + } + g_assert_no_error (error); + + types = g_content_type_guess_for_tree (tmpdir); + g_strfreev (types); + + g_file_delete (file, NULL, &error); + g_assert_no_error (error); + g_object_unref (file); + + g_file_delete (tmpdir, NULL, &error); + g_assert_no_error (error); + g_object_unref (tmpdir); +} + +static void test_type_is_a_special_case (void) { gboolean res; @@ -442,6 +493,8 @@ main (int argc, char *argv[]) g_test_add_func ("/contenttype/icon", test_icon); g_test_add_func ("/contenttype/symbolic-icon", test_symbolic_icon); g_test_add_func ("/contenttype/tree", test_tree); + g_test_add_func ("/contenttype/tree_invalid_encoding", + test_tree_invalid_encoding); g_test_add_func ("/contenttype/test_type_is_a_special_case", test_type_is_a_special_case); diff --git a/gio/tests/cxx.cpp b/gio/tests/cxx.cpp index 630eeab..7aba351 100644 --- a/gio/tests/cxx.cpp +++ b/gio/tests/cxx.cpp @@ -59,7 +59,7 @@ int main (int argc, char **argv) { #if G_CXX_STD_CHECK_VERSION (11) - g_test_init (&argc, &argv, NULL); + g_test_init (&argc, &argv, nullptr); #else g_test_init (&argc, &argv, static_cast(NULL)); #endif diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c index 594ec94..bd28f94 100644 --- a/gio/tests/desktop-app-info.c +++ b/gio/tests/desktop-app-info.c @@ -881,26 +881,24 @@ test_search (void) assert_search ("frobni", "frobnicator.desktop\n", TRUE, FALSE, NULL, NULL); /* Obvious multi-word search */ - assert_search ("gno hel", "yelp.desktop\n", TRUE, TRUE, NULL, NULL); + assert_search ("doc hel", "yelp.desktop\n", TRUE, TRUE, NULL, NULL); /* Repeated search terms should do nothing... */ - assert_search ("files file fil fi f", "nautilus.desktop\n" - "gedit.desktop\n", TRUE, TRUE, NULL, NULL); + assert_search ("files file fil fi f", "nautilus.desktop\n", TRUE, TRUE, NULL, NULL); /* "con" will match "connect" and "contacts" on name with prefix match in - * first group, then match "Dconf Editor" and "Desktop Icons" with substring - * match in next group. + * first group, then second group is a Keyword prefix match for "configuration" in dconf-editor.desktop + * and third group is a substring match for "Desktop Icons" in Name of nautilus-classic.desktop. */ assert_search ("con", "gnome-contacts.desktop nautilus-connect-server.desktop\n" - "dconf-editor.desktop nautilus-classic.desktop\n", TRUE, TRUE, NULL, NULL); + "dconf-editor.desktop\n" + "nautilus-classic.desktop\n", TRUE, TRUE, NULL, NULL); /* "gnome" will match "eye of gnome" from the user's directory, plus - * matching "GNOME Clocks" X-GNOME-FullName. It's only a comment on - * yelp and gnome-contacts, though. + * matching "GNOME Clocks" X-GNOME-FullName. */ assert_search ("gnome", "eog.desktop\n" - "org.gnome.clocks.desktop\n" - "yelp.desktop gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL); + "org.gnome.clocks.desktop\n", TRUE, TRUE, NULL, NULL); /* eog has exec name 'false' in usr only */ assert_search ("false", "eog.desktop\n", TRUE, FALSE, NULL, NULL); @@ -912,9 +910,9 @@ test_search (void) assert_search ("nonsearchable", "", TRUE, FALSE, NULL, NULL); /* "gnome con" will match only gnome contacts; via the name for - * "contacts" and the comment for "gnome" + * "contacts" and keywords for "friend" */ - assert_search ("gnome con", "gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL); + assert_search ("friend con", "gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL); /* make sure we get the correct kde4- prefix on the application IDs * from subdirectories @@ -937,8 +935,7 @@ test_search (void) /* make sure localised searching works properly */ assert_search ("foliumi", "nautilus.desktop\n" - "kde4-konqbrowser.desktop\n" - "eog.desktop\n", TRUE, FALSE, "en_US.UTF-8", "eo"); + "kde4-konqbrowser.desktop\n", TRUE, FALSE, "en_US.UTF-8", "eo"); /* the user's eog.desktop has no translations... */ assert_search ("foliumi", "nautilus.desktop\n" "kde4-konqbrowser.desktop\n", TRUE, TRUE, "en_US.UTF-8", "eo"); diff --git a/gio/tests/error.c b/gio/tests/error.c index dc79a4d..702c9c6 100644 --- a/gio/tests/error.c +++ b/gio/tests/error.c @@ -557,7 +557,7 @@ test_error_from_errno (void) #ifdef EDESTADDRREQ g_assert_cmpuint (g_io_error_from_errno (EDESTADDRREQ), ==, - G_IO_ERROR_FAILED); + G_IO_ERROR_DESTINATION_UNSET); #endif #ifdef EPROTOTYPE diff --git a/gio/tests/file.c b/gio/tests/file.c index 310981b..d32d955 100644 --- a/gio/tests/file.c +++ b/gio/tests/file.c @@ -2451,12 +2451,15 @@ test_copy_preserve_mode (void) { 0600, 0600, TRUE, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS }, /* The same behaviour should hold if the destination file is not being * overwritten because it doesn’t already exist: */ + { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_ALL_METADATA }, { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA }, { 0600, 0600, FALSE, G_FILE_COPY_NOFOLLOW_SYMLINKS }, /* Anything with %G_FILE_COPY_TARGET_DEFAULT_PERMS should use the current * umask for the destination file: */ { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA }, { 0600, 0666 & ~current_umask, TRUE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS }, + { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_ALL_METADATA }, + { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME }, { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA }, { 0600, 0666 & ~current_umask, FALSE, G_FILE_COPY_TARGET_DEFAULT_PERMS | G_FILE_COPY_NOFOLLOW_SYMLINKS }, }; @@ -3375,6 +3378,9 @@ test_build_attribute_list_for_copy (void) G_FILE_COPY_TARGET_DEFAULT_PERMS, G_FILE_COPY_ALL_METADATA, G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_PERMS, + G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME, + G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME | G_FILE_COPY_TARGET_DEFAULT_PERMS, + G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME, }; gsize i; char *attrs; @@ -3416,8 +3422,16 @@ test_build_attribute_list_for_copy (void) } #endif #ifdef HAVE_UTIMES - g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); - g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ",")); + if (flags & G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME) + { + g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); + g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ",")); + } + else + { + g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); + g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ",")); + } if (flags & G_FILE_COPY_ALL_METADATA) { g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ",")); @@ -3430,8 +3444,16 @@ test_build_attribute_list_for_copy (void) } #endif #ifdef HAVE_UTIMENSAT - g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); - g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ",")); + if (flags & G_FILE_COPY_TARGET_DEFAULT_MODIFIED_TIME) + { + g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); + g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ",")); + } + else + { + g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ",")); + g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_NSEC ",")); + } if (flags & G_FILE_COPY_ALL_METADATA) { g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ",")); @@ -3936,35 +3958,42 @@ test_enumerator_cancellation (void) } static void -test_from_uri_ignores_fragment (void) +test_path_from_uri_helper (const gchar *uri, + const gchar *expected_path) { GFile *file; gchar *path; - file = g_file_new_for_uri ("file:///tmp/foo#bar"); - path = g_file_get_path (file); + gchar *expected_platform_path; + + expected_platform_path = g_strdup (expected_path); #ifdef G_OS_WIN32 - g_assert_cmpstr (path, ==, "\\tmp\\foo"); -#else - g_assert_cmpstr (path, ==, "/tmp/foo"); + for (gchar *p = expected_platform_path; *p; p++) + { + if (*p == '/') + *p = '\\'; + } #endif + + file = g_file_new_for_uri (uri); + path = g_file_get_path (file); + g_assert_cmpstr (path, ==, expected_platform_path); g_free (path); g_object_unref (file); + g_free (expected_platform_path); +} + +static void +test_from_uri_ignores_fragment (void) +{ + test_path_from_uri_helper ("file:///tmp/foo#bar", "/tmp/foo"); + test_path_from_uri_helper ("file:///tmp/foo#bar?baz", "/tmp/foo"); } static void test_from_uri_ignores_query_string (void) { - GFile *file; - gchar *path; - file = g_file_new_for_uri ("file:///tmp/foo?bar"); - path = g_file_get_path (file); -#ifdef G_OS_WIN32 - g_assert_cmpstr (path, ==, "\\tmp\\foo"); -#else - g_assert_cmpstr (path, ==, "/tmp/foo"); -#endif - g_free (path); - g_object_unref (file); + test_path_from_uri_helper ("file:///tmp/foo?bar", "/tmp/foo"); + test_path_from_uri_helper ("file:///tmp/foo?bar#baz", "/tmp/foo"); } int diff --git a/gio/tests/gapplication.c b/gio/tests/gapplication.c index b0584eb..29c6989 100644 --- a/gio/tests/gapplication.c +++ b/gio/tests/gapplication.c @@ -832,6 +832,47 @@ test_help (void) g_test_trap_assert_stdout ("*Application options*"); } +static gint +command_line_done_callback (GApplication *app, + GApplicationCommandLine *command_line, + gpointer user_data) +{ + gboolean *called = user_data; + + *called = TRUE; + + g_application_command_line_set_exit_status (command_line, 42); + g_application_command_line_done (command_line); + + return 0; +} + +/* Test whether 'command-line' handler return value is ignored + * after g_application_command_line_done() + */ +static void +test_command_line_done (void) +{ + char *binpath = g_test_build_filename (G_TEST_BUILT, "unimportant", NULL); + const gchar *const argv[] = { binpath, "arg", NULL }; + GApplication *app; + gboolean called = FALSE; + int status; + gulong command_line_id; + + app = g_application_new ("org.gtk.TestApplication", G_APPLICATION_HANDLES_COMMAND_LINE); + command_line_id = g_signal_connect (app, "command-line", G_CALLBACK (command_line_done_callback), &called); + + status = g_application_run (app, G_N_ELEMENTS (argv) - 1, (gchar **) argv); + + g_signal_handler_disconnect (app, command_line_id); + g_object_unref (app); + g_free (binpath); + + g_assert_true (called); + g_assert_cmpint (status, ==, 42); +} + static void test_busy (void) { @@ -1242,8 +1283,7 @@ dbus_startup_reply_cb (GObject *source_object, reply = g_dbus_connection_send_message_with_reply_finish (connection, result, &local_error); g_assert_no_error (local_error); - /* Nothing to check on the reply for now. */ - g_clear_object (&reply); + g_object_set_data_full (G_OBJECT (app), "dbus-command-line-reply", g_steal_pointer (&reply), g_object_unref); /* Release the app in an idle callback, so there’s time to process other * pending sources first. */ @@ -1563,6 +1603,80 @@ test_dbus_command_line (void) g_clear_object (&bus); } +static gint +dbus_command_line_done_cb (GApplication *app, + GApplicationCommandLine *command_line, + gpointer user_data) +{ + guint *n_command_lines = user_data; + + *n_command_lines = *n_command_lines + 1; + + if (*n_command_lines == 1) + return 0; + + g_object_set_data_full (G_OBJECT (app), "command-line", g_object_ref (command_line), g_object_unref); + + g_application_command_line_set_exit_status (command_line, 42); + g_application_command_line_done (command_line); + + return 1; /* ignored - after g_application_command_line_done () */ +} + +static void +test_dbus_command_line_done (void) +{ + GTestDBus *bus = NULL; + GVariantBuilder builder; + GDBusMessage *message = NULL; + GDBusMessage *reply = NULL; + GApplication *app = NULL; + guint n_command_lines = 0; + gint exit_status; + + g_test_summary ("Test that GDBusCommandLine.done() works"); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aay")); + g_variant_builder_add (&builder, "^ay", "test-program"); + g_variant_builder_add (&builder, "^ay", "/path/to/something"); + + message = g_dbus_message_new_method_call ("org.gtk.TestApplication.CommandLine", + "/org/gtk/TestApplication/CommandLine", + "org.gtk.Application", + "CommandLine"); + g_dbus_message_set_body (message, g_variant_new ("(oaaya{sv})", + "/my/org/gtk/private/CommandLine", + &builder, NULL)); + + bus = g_test_dbus_new (G_TEST_DBUS_NONE); + g_test_dbus_up (bus); + + app = g_application_new ("org.gtk.TestApplication.CommandLine", G_APPLICATION_HANDLES_COMMAND_LINE); + g_signal_connect (app, "activate", G_CALLBACK (dbus_activate_noop_cb), NULL); + g_signal_connect (app, "command-line", G_CALLBACK (dbus_command_line_done_cb), &n_command_lines); + g_signal_connect (app, "startup", G_CALLBACK (dbus_startup_cb), message); + + g_application_hold (app); + exit_status = g_application_run (app, 0, NULL); + + g_assert_cmpuint (n_command_lines, ==, 2); + g_assert_cmpint (exit_status, ==, 0); + + reply = g_object_get_data (G_OBJECT (app), "dbus-command-line-reply"); + g_variant_get (g_dbus_message_get_body (reply), "(i)", &exit_status); + g_assert_cmpint (exit_status, ==, 42); + + g_signal_handlers_disconnect_by_func (app, G_CALLBACK (dbus_activate_noop_cb), NULL); + g_signal_handlers_disconnect_by_func (app, G_CALLBACK (dbus_command_line_done_cb), &n_command_lines); + g_signal_handlers_disconnect_by_func (app, G_CALLBACK (dbus_startup_cb), message); + + g_clear_object (&app); + g_clear_object (&message); + + g_test_dbus_down (bus); + g_clear_object (&bus); +} + static void dbus_activate_action_cb (GSimpleAction *action, GVariant *parameter, @@ -1710,6 +1824,7 @@ main (int argc, char **argv) /* g_test_add_func ("/gapplication/remote-command-line", test_remote_command_line); */ g_test_add_func ("/gapplication/resource-path", test_resource_path); g_test_add_func ("/gapplication/test-help", test_help); + g_test_add_func ("/gapplication/command-line-done", test_command_line_done); g_test_add_func ("/gapplication/test-busy", test_busy); g_test_add_func ("/gapplication/test-handle-local-options1", test_handle_local_options_success); g_test_add_func ("/gapplication/test-handle-local-options2", test_handle_local_options_failure); @@ -1720,6 +1835,7 @@ main (int argc, char **argv) g_test_add_func ("/gapplication/dbus/activate", test_dbus_activate); g_test_add_func ("/gapplication/dbus/open", test_dbus_open); g_test_add_func ("/gapplication/dbus/command-line", test_dbus_command_line); + g_test_add_func ("/gapplication/dbus/command-line-done", test_dbus_command_line_done); g_test_add_func ("/gapplication/dbus/activate-action", test_dbus_activate_action); return g_test_run (); diff --git a/gio/tests/gdbus-connection.c b/gio/tests/gdbus-connection.c index 05b1f12..1be1a2f 100644 --- a/gio/tests/gdbus-connection.c +++ b/gio/tests/gdbus-connection.c @@ -742,6 +742,7 @@ test_match_rule (GDBusConnection *connection, GDBusSignalFlags flags, gchar *arg0_rule, gchar *arg0, + const gchar *signal_type, gboolean should_match) { guint subscription_ids[2]; @@ -766,7 +767,7 @@ test_match_rule (GDBusConnection *connection, g_dbus_connection_emit_signal (connection, NULL, "/", "org.gtk.ExampleInterface", - "Foo", g_variant_new ("(s)", arg0), + "Foo", g_variant_new (signal_type, arg0), &error); g_assert_no_error (error); @@ -793,22 +794,28 @@ test_connection_signal_match_rules (void) session_bus_up (); con = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", FALSE); - - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", FALSE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", FALSE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", FALSE); - - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", FALSE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", TRUE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", FALSE); - test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "foo", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_NONE, "foo", "bar", "(s)", FALSE); + + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "", "(s)", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org", "(s)", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk.Example", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_NAMESPACE, "org.gtk", "org.gtk+", "(s)", FALSE); + + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "", "(s)", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/", "(s)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(s)", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(s)", FALSE); + + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/", "/", "(o)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk/Example", "(o)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/", "/org/gtk/Example", "(o)", TRUE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk/Example", "/org/gtk", "(o)", FALSE); + test_match_rule (con, G_DBUS_SIGNAL_FLAGS_MATCH_ARG0_PATH, "/org/gtk+", "/org/gtk", "(o)", FALSE); g_object_unref (con); session_bus_down (); @@ -1209,6 +1216,70 @@ test_connection_serials (void) /* ---------------------------------------------------------------------------------------------------- */ static void +get_connection_cb_expect_cancel (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *c; + GError *error; + + error = NULL; + c = g_bus_get_finish (res, &error); + + /* unref here to avoid timeouts when the test fails */ + if (c) + g_object_unref (c); + + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert_null (c); + + g_error_free (error); +} + +static void +get_connection_cb_expect_success (GObject *source_object, + GAsyncResult *res, + gpointer user_data) +{ + GDBusConnection *c; + GError *error; + + error = NULL; + c = g_bus_get_finish (res, &error); + g_assert_no_error (error); + g_assert_nonnull (c); + + g_main_loop_quit (loop); + + g_object_unref (c); +} + +static void +test_connection_cancel (void) +{ + GCancellable *cancellable, *cancellable2; + + g_test_summary ("Test that cancelling one of two racing g_bus_get() calls does not cancel the other one"); + + session_bus_up (); + + cancellable = g_cancellable_new (); + cancellable2 = g_cancellable_new (); + + g_bus_get (G_BUS_TYPE_SESSION, cancellable, get_connection_cb_expect_cancel, NULL); + g_bus_get (G_BUS_TYPE_SESSION, cancellable2, get_connection_cb_expect_success, NULL); + g_cancellable_cancel (cancellable); + g_main_loop_run (loop); + + g_object_unref (cancellable); + g_object_unref (cancellable2); + + session_bus_down (); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +static void test_connection_basic (void) { GDBusConnection *connection; @@ -1294,6 +1365,7 @@ main (int argc, g_test_add_func ("/gdbus/connection/signal-match-rules", test_connection_signal_match_rules); g_test_add_func ("/gdbus/connection/filter", test_connection_filter); g_test_add_func ("/gdbus/connection/serials", test_connection_serials); + g_test_add_func ("/gdbus/connection/cancel", test_connection_cancel); ret = g_test_run(); g_main_loop_unref (loop); diff --git a/gio/tests/gdbus-object-manager-example/meson.build b/gio/tests/gdbus-object-manager-example/meson.build index df09992..83b4fc0 100644 --- a/gio/tests/gdbus-object-manager-example/meson.build +++ b/gio/tests/gdbus-object-manager-example/meson.build @@ -20,7 +20,10 @@ gdbus_example_objectmanager_generated = custom_target('objectmanager-gen', '--generate-docbook', 'objectmanager-gen', '--symbol-decorator', 'GDBUS_OBJECT_MANAGER_EXAMPLE_AVAILABLE_IN_ALL', '--symbol-decorator-header', 'gdbus-example-objectmanager-visibility.h', - '@INPUT@']) + '@INPUT@'], + depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, +) gdbus_example_objectmanager_rst_gen = custom_target('objectmanager-rst-gen', input: gdbus_example_objectmanager_xml, @@ -36,6 +39,8 @@ gdbus_example_objectmanager_rst_gen = custom_target('objectmanager-rst-gen', '--output-directory', '@OUTDIR@', '@INPUT@', ], + depend_files: gdbus_codegen_built_files, + depends: gdbus_codegen_built_targets, ) extra_c_args = [] diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c index ab36eae..ac5f720 100644 --- a/gio/tests/gdbus-proxy.c +++ b/gio/tests/gdbus-proxy.c @@ -780,12 +780,6 @@ kill_test_service (GDBusConnection *connection) while (!name_disappeared) g_main_context_iteration (NULL, TRUE); - /* GDBusConnection doesn't guarantee that different subscriptions to the - * same signal will get their callbacks scheduled in any particular order, - * so make sure they have all happened */ - while (g_main_context_iteration (NULL, FALSE)) - continue; - g_bus_unwatch_name (watch_id); #else g_warning ("Can't kill com.example.TestService"); diff --git a/gio/tests/gdbus-subscribe.c b/gio/tests/gdbus-subscribe.c deleted file mode 100644 index 4cba4f5..0000000 --- a/gio/tests/gdbus-subscribe.c +++ /dev/null @@ -1,1342 +0,0 @@ -/* - * Copyright 2024 Collabora Ltd. - * SPDX-License-Identifier: LGPL-2.1-or-later - */ - -#include - -#include "gdbus-tests.h" - -/* From the D-Bus Specification */ -#define DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER 1 - -#define DBUS_SERVICE_DBUS "org.freedesktop.DBus" -#define DBUS_PATH_DBUS "/org/freedesktop/DBus" -#define DBUS_INTERFACE_DBUS DBUS_SERVICE_DBUS -#define NAME_OWNER_CHANGED "NameOwnerChanged" - -/* A signal that each connection emits to indicate that it has finished - * emitting other signals */ -#define FINISHED_PATH "/org/gtk/Test/Finished" -#define FINISHED_INTERFACE "org.gtk.Test.Finished" -#define FINISHED_SIGNAL "Finished" - -/* A signal emitted during testing */ -#define EXAMPLE_PATH "/org/gtk/GDBus/ExampleInterface" -#define EXAMPLE_INTERFACE "org.gtk.GDBus.ExampleInterface" -#define FOO_SIGNAL "Foo" - -#define ALREADY_OWNED_NAME "org.gtk.Test.AlreadyOwned" -#define OWNED_LATER_NAME "org.gtk.Test.OwnedLater" - -/* Log @s in a debug message. */ -static inline const char * -nonnull (const char *s, - const char *if_null) -{ - return (s == NULL) ? if_null : s; -} - -typedef enum -{ - TEST_CONN_NONE, - TEST_CONN_FIRST, - /* A connection that subscribes to signals */ - TEST_CONN_SUBSCRIBER = TEST_CONN_FIRST, - /* A mockup of a legitimate service */ - TEST_CONN_SERVICE, - /* A mockup of a second legitimate service */ - TEST_CONN_SERVICE2, - /* A connection that tries to trick @subscriber into processing its signals - * as if they came from @service */ - TEST_CONN_ATTACKER, - NUM_TEST_CONNS -} TestConn; - -static const char * const test_conn_descriptions[NUM_TEST_CONNS] = -{ - "(unused)", - "subscriber", - "service", - "service 2", - "attacker" -}; - -typedef enum -{ - SUBSCRIPTION_MODE_CONN, - SUBSCRIPTION_MODE_PROXY, - SUBSCRIPTION_MODE_PARALLEL -} SubscriptionMode; - -typedef struct -{ - GDBusProxy *received_by_proxy; - TestConn sender; - char *path; - char *iface; - char *member; - GVariant *parameters; - char *arg0; - guint32 step; -} ReceivedMessage; - -static void -received_message_free (ReceivedMessage *self) -{ - - g_clear_object (&self->received_by_proxy); - g_free (self->path); - g_free (self->iface); - g_free (self->member); - g_clear_pointer (&self->parameters, g_variant_unref); - g_free (self->arg0); - g_free (self); -} - -typedef struct -{ - TestConn sender; - TestConn unicast_to; - const char *path; - const char *iface; - const char *member; - const char *arg0; - const char *args; - guint received_by_conn; - guint received_by_proxy; -} TestEmitSignal; - -typedef struct -{ - const char *string_sender; - TestConn unique_sender; - const char *path; - const char *iface; - const char *member; - const char *arg0; - GDBusSignalFlags flags; - gboolean unsubscribe_immediately; -} TestSubscribe; - -typedef struct -{ - const char *name; - TestConn owner; - guint received_by_conn; - guint received_by_proxy; -} TestOwnName; - -typedef enum -{ - TEST_ACTION_NONE = 0, - TEST_ACTION_SUBSCRIBE, - TEST_ACTION_EMIT_SIGNAL, - TEST_ACTION_OWN_NAME, -} TestAction; - -typedef struct -{ - TestAction action; - union { - TestEmitSignal signal; - TestSubscribe subscribe; - TestOwnName own_name; - guint unsubscribe_undo_step; - } u; -} TestStep; - -/* Arbitrary, extend as necessary to accommodate the longest test */ -#define MAX_TEST_STEPS 10 - -typedef struct -{ - const char *description; - TestStep steps[MAX_TEST_STEPS]; -} TestPlan; - -static const TestPlan plan_simple = -{ - .description = "A broadcast is only received after subscribing to it", - .steps = { - { - /* We don't receive a signal if we haven't subscribed yet */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* Now it works */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - /* The proxy can't be used in this case, because it needs - * a bus name to subscribe to */ - .received_by_proxy = 0 - }, - }, - }, -}; - -static const TestPlan plan_broadcast_from_anyone = -{ - .description = "A subscription with NULL sender accepts broadcast and unicast", - .steps = { - { - /* Subscriber wants to receive signals from anyone */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* First service sends a broadcast */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 0 - }, - }, - { - /* Second service also sends a broadcast */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE2, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 0 - }, - }, - { - /* First service sends a unicast signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .unicast_to = TEST_CONN_SUBSCRIBER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 0 - }, - }, - { - /* Second service also sends a unicast signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE2, - .unicast_to = TEST_CONN_SUBSCRIBER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 0 - }, - }, - }, -}; - -static const TestPlan plan_match_twice = -{ - .description = "A message matching more than one subscription is received " - "once per subscription", - .steps = { - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .unique_sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .path = EXAMPLE_PATH, - }, - }, - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .iface = EXAMPLE_INTERFACE, - }, - }, - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .unique_sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 4, - /* Only the first and last work with GDBusProxy */ - .received_by_proxy = 2 - }, - }, - }, -}; - -static const TestPlan plan_limit_by_unique_name = -{ - .description = "A subscription via a unique name only accepts messages " - "sent by that same unique name", - .steps = { - { - /* Subscriber wants to receive signals from service */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .unique_sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* Attacker wants to trick subscriber into thinking that service - * sent a signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* Attacker tries harder, by sending a signal unicast directly to - * the subscriber */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .unicast_to = TEST_CONN_SUBSCRIBER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* When the real service sends a signal, it should still get through */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 1 - }, - }, - }, -}; - -static const TestPlan plan_nonexistent_unique_name = -{ - .description = "A subscription via a unique name that doesn't exist " - "accepts no messages", - .steps = { - { - /* Subscriber wants to receive signals from service */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - /* This relies on the implementation detail that the dbus-daemon - * (and presumably other bus implementations) never actually generates - * a unique name in this format */ - .string_sender = ":0.this.had.better.not.exist", - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* Attacker wants to trick subscriber into thinking that service - * sent a signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* Attacker tries harder, by sending a signal unicast directly to - * the subscriber */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .unicast_to = TEST_CONN_SUBSCRIBER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - }, -}; - -static const TestPlan plan_limit_by_well_known_name = -{ - .description = "A subscription via a well-known name only accepts messages " - "sent by the owner of that well-known name", - .steps = { - { - /* Service already owns one name */ - .action = TEST_ACTION_OWN_NAME, - .u.own_name = { - .name = ALREADY_OWNED_NAME, - .owner = TEST_CONN_SERVICE - }, - }, - { - /* Subscriber wants to receive signals from service */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .string_sender = ALREADY_OWNED_NAME, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* Subscriber wants to receive signals from service by another name */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .string_sender = OWNED_LATER_NAME, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - }, - }, - { - /* Attacker wants to trick subscriber into thinking that service - * sent a signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* Attacker tries harder, by sending a signal unicast directly to - * the subscriber */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .unicast_to = TEST_CONN_SUBSCRIBER, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* When the service sends a signal with the name it already owns, - * it should get through */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 1, - .received_by_proxy = 1 - }, - }, - { - /* Service claims another name */ - .action = TEST_ACTION_OWN_NAME, - .u.own_name = { - .name = OWNED_LATER_NAME, - .owner = TEST_CONN_SERVICE - }, - }, - { - /* Now the subscriber gets this signal twice, once for each - * subscription; and similarly each of the two proxies gets this - * signal twice */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 2, - .received_by_proxy = 2 - }, - }, - }, -}; - -static const TestPlan plan_unsubscribe_immediately = -{ - .description = "Unsubscribing before GetNameOwner can return doesn't result in a crash", - .steps = { - { - /* Service already owns one name */ - .action = TEST_ACTION_OWN_NAME, - .u.own_name = { - .name = ALREADY_OWNED_NAME, - .owner = TEST_CONN_SERVICE - }, - }, - { - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .string_sender = ALREADY_OWNED_NAME, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .unsubscribe_immediately = TRUE - }, - }, - { - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_SERVICE, - .path = EXAMPLE_PATH, - .iface = EXAMPLE_INTERFACE, - .member = FOO_SIGNAL, - .received_by_conn = 0, - /* The proxy can't unsubscribe, except by destroying the proxy - * completely, which we don't currently implement in this test */ - .received_by_proxy = 1 - }, - }, - }, -}; - -static const TestPlan plan_limit_to_message_bus = -{ - .description = "A subscription to the message bus only accepts messages " - "from the message bus", - .steps = { - { - /* Subscriber wants to receive signals from the message bus itself */ - .action = TEST_ACTION_SUBSCRIBE, - .u.subscribe = { - .string_sender = DBUS_SERVICE_DBUS, - .path = DBUS_PATH_DBUS, - .iface = DBUS_INTERFACE_DBUS, - }, - }, - { - /* Attacker wants to trick subscriber into thinking that the message - * bus sent a signal */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .sender = TEST_CONN_ATTACKER, - .path = DBUS_PATH_DBUS, - .iface = DBUS_INTERFACE_DBUS, - .member = NAME_OWNER_CHANGED, - .arg0 = "would I lie to you?", - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* Attacker tries harder, by sending a signal unicast directly to - * the subscriber, and using more realistic arguments */ - .action = TEST_ACTION_EMIT_SIGNAL, - .u.signal = { - .unicast_to = TEST_CONN_SUBSCRIBER, - .sender = TEST_CONN_ATTACKER, - .path = DBUS_PATH_DBUS, - .iface = DBUS_INTERFACE_DBUS, - .member = NAME_OWNER_CHANGED, - .args = "('com.example.Name', '', ':1.12')", - .received_by_conn = 0, - .received_by_proxy = 0 - }, - }, - { - /* When the message bus sends a signal (in this case triggered by - * owning a name), it should still get through */ - .action = TEST_ACTION_OWN_NAME, - .u.own_name = { - .name = OWNED_LATER_NAME, - .owner = TEST_CONN_SERVICE, - .received_by_conn = 1, - .received_by_proxy = 1 - }, - }, - }, -}; - -typedef struct -{ - const TestPlan *plan; - SubscriptionMode mode; - GError *error; - /* (element-type ReceivedMessage) */ - GPtrArray *received; - /* conns[TEST_CONN_NONE] is unused and remains NULL */ - GDBusConnection *conns[NUM_TEST_CONNS]; - /* Proxies on conns[TEST_CONN_SUBSCRIBER] */ - GPtrArray *proxies; - /* unique_names[TEST_CONN_NONE] is unused and remains NULL */ - const char *unique_names[NUM_TEST_CONNS]; - /* finished[TEST_CONN_NONE] is unused and remains FALSE */ - gboolean finished[NUM_TEST_CONNS]; - /* Remains 0 for any step that is not a subscription */ - guint subscriptions[MAX_TEST_STEPS]; - /* Number of times the signal from step n was received */ - guint received_by_conn[MAX_TEST_STEPS]; - /* Number of times the signal from step n was received */ - guint received_by_proxy[MAX_TEST_STEPS]; - guint finished_subscription; -} Fixture; - -/* Wait for asynchronous messages from @conn to have been processed - * by the message bus, as a sequence point so that we can make - * "happens before" and "happens after" assertions relative to this. - * The easiest way to achieve this is to call a message bus method that has - * no arguments and wait for it to return: because the message bus processes - * messages in-order, anything we sent before this must have been processed - * by the time this call arrives. */ -static void -connection_wait_for_bus (GDBusConnection *conn) -{ - GError *error = NULL; - GVariant *call_result; - - call_result = g_dbus_connection_call_sync (conn, - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "GetId", - NULL, /* arguments */ - NULL, /* result type */ - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &error); - g_assert_no_error (error); - g_assert_nonnull (call_result); - g_variant_unref (call_result); -} - -/* - * Called when the subscriber receives a message from any connection - * announcing that it has emitted all the signals that it plans to emit. - */ -static void -subscriber_finished_cb (GDBusConnection *conn, - const char *sender_name, - const char *path, - const char *iface, - const char *member, - GVariant *parameters, - void *user_data) -{ - Fixture *f = user_data; - GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; - guint i; - - g_assert_true (conn == subscriber); - - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - { - if (g_str_equal (sender_name, f->unique_names[i])) - { - g_assert_false (f->finished[i]); - f->finished[i] = TRUE; - - g_test_message ("Received Finished signal from %s %s", - test_conn_descriptions[i], sender_name); - return; - } - } - - g_error ("Received Finished signal from unknown sender %s", sender_name); -} - -/* - * Called when we receive a signal, either via the GDBusProxy (proxy != NULL) - * or via the GDBusConnection (proxy == NULL). - */ -static void -fixture_received_signal (Fixture *f, - GDBusProxy *proxy, - const char *sender_name, - const char *path, - const char *iface, - const char *member, - GVariant *parameters) -{ - guint i; - ReceivedMessage *received; - - /* Ignore the Finished signal if it matches a wildcard subscription */ - if (g_str_equal (member, FINISHED_SIGNAL)) - return; - - received = g_new0 (ReceivedMessage, 1); - - if (proxy != NULL) - received->received_by_proxy = g_object_ref (proxy); - else - received->received_by_proxy = NULL; - - received->path = g_strdup (path); - received->iface = g_strdup (iface); - received->member = g_strdup (member); - received->parameters = g_variant_ref (parameters); - - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - { - if (g_str_equal (sender_name, f->unique_names[i])) - { - received->sender = i; - g_assert_false (f->finished[i]); - break; - } - } - - if (g_str_equal (sender_name, DBUS_SERVICE_DBUS)) - { - g_test_message ("Signal received from message bus %s", - sender_name); - } - else - { - g_test_message ("Signal received from %s %s", - test_conn_descriptions[received->sender], - sender_name); - g_assert_cmpint (received->sender, !=, TEST_CONN_NONE); - } - - g_test_message ("Signal received from %s %s via %s", - test_conn_descriptions[received->sender], - sender_name, - proxy != NULL ? "proxy" : "connection"); - g_test_message ("\tPath: %s", path); - g_test_message ("\tInterface: %s", iface); - g_test_message ("\tMember: %s", member); - - if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(su)"))) - { - g_variant_get (parameters, "(su)", &received->arg0, &received->step); - g_test_message ("\tString argument 0: %s", received->arg0); - g_test_message ("\tSent in step: %u", received->step); - } - else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(uu)"))) - { - g_variant_get (parameters, "(uu)", NULL, &received->step); - g_test_message ("\tArgument 0: (not a string)"); - g_test_message ("\tSent in step: %u", received->step); - } - else if (g_variant_is_of_type (parameters, G_VARIANT_TYPE ("(sss)"))) - { - const char *name; - const char *old_owner; - const char *new_owner; - - /* The only signal of this signature that we legitimately receive - * during this test is NameOwnerChanged, so just assert that it - * is from the message bus and can be matched to a plausible step. - * (This is less thorough than the above, and will not work if we - * add a test scenario where a name's ownership is repeatedly - * changed while watching NameOwnerChanged - so don't do that.) */ - g_assert_cmpstr (sender_name, ==, DBUS_SERVICE_DBUS); - g_assert_cmpstr (path, ==, DBUS_PATH_DBUS); - g_assert_cmpstr (iface, ==, DBUS_INTERFACE_DBUS); - g_assert_cmpstr (member, ==, NAME_OWNER_CHANGED); - - g_variant_get (parameters, "(&s&s&s)", &name, &old_owner, &new_owner); - - for (i = 0; i < G_N_ELEMENTS (f->plan->steps); i++) - { - const TestStep *step = &f->plan->steps[i]; - - if (step->action == TEST_ACTION_OWN_NAME) - { - const TestOwnName *own_name = &step->u.own_name; - - if (g_str_equal (name, own_name->name) - && g_str_equal (new_owner, f->unique_names[own_name->owner]) - && own_name->received_by_conn > 0) - { - received->step = i; - break; - } - } - - if (i >= G_N_ELEMENTS (f->plan->steps)) - g_error ("Could not match message to a test step"); - } - } - else - { - g_error ("Unexpected message received"); - } - - g_ptr_array_add (f->received, g_steal_pointer (&received)); -} - -static void -proxy_signal_cb (GDBusProxy *proxy, - const char *sender_name, - const char *member, - GVariant *parameters, - void *user_data) -{ - Fixture *f = user_data; - - fixture_received_signal (f, proxy, sender_name, - g_dbus_proxy_get_object_path (proxy), - g_dbus_proxy_get_interface_name (proxy), - member, parameters); -} - -static void -subscribed_signal_cb (GDBusConnection *conn, - const char *sender_name, - const char *path, - const char *iface, - const char *member, - GVariant *parameters, - void *user_data) -{ - Fixture *f = user_data; - GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; - - g_assert_true (conn == subscriber); - - fixture_received_signal (f, NULL, sender_name, path, iface, member, parameters); -} - -static void -fixture_subscribe (Fixture *f, - const TestSubscribe *subscribe, - guint step_number) -{ - GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; - const char *sender; - - if (subscribe->string_sender != NULL) - { - sender = subscribe->string_sender; - g_test_message ("\tSender: %s", sender); - } - else if (subscribe->unique_sender != TEST_CONN_NONE) - { - sender = f->unique_names[subscribe->unique_sender]; - g_test_message ("\tSender: %s %s", - test_conn_descriptions[subscribe->unique_sender], - sender); - } - else - { - sender = NULL; - g_test_message ("\tSender: (any)"); - } - - g_test_message ("\tPath: %s", nonnull (subscribe->path, "(any)")); - g_test_message ("\tInterface: %s", - nonnull (subscribe->iface, "(any)")); - g_test_message ("\tMember: %s", - nonnull (subscribe->member, "(any)")); - g_test_message ("\tString argument 0: %s", - nonnull (subscribe->arg0, "(any)")); - g_test_message ("\tFlags: %x", subscribe->flags); - - if (f->mode != SUBSCRIPTION_MODE_PROXY) - { - /* CONN or PARALLEL */ - guint id; - - g_test_message ("\tSubscribing via connection"); - id = g_dbus_connection_signal_subscribe (subscriber, - sender, - subscribe->iface, - subscribe->member, - subscribe->path, - subscribe->arg0, - subscribe->flags, - subscribed_signal_cb, - f, NULL); - - g_assert_cmpuint (id, !=, 0); - - if (subscribe->unsubscribe_immediately) - { - g_test_message ("\tImmediately unsubscribing"); - g_dbus_connection_signal_unsubscribe (subscriber, id); - } - else - { - f->subscriptions[step_number] = id; - } - } - - if (f->mode != SUBSCRIPTION_MODE_CONN) - { - /* PROXY or PARALLEL */ - - if (sender == NULL) - { - g_test_message ("\tCannot subscribe via proxy: no bus name"); - } - else if (subscribe->path == NULL) - { - g_test_message ("\tCannot subscribe via proxy: no path"); - } - else if (subscribe->iface == NULL) - { - g_test_message ("\tCannot subscribe via proxy: no interface"); - } - else - { - GDBusProxy *proxy; - - g_test_message ("\tSubscribing via proxy"); - proxy = g_dbus_proxy_new_sync (subscriber, - (G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES - | G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START), - NULL, /* GDBusInterfaceInfo */ - sender, - subscribe->path, - subscribe->iface, - NULL, /* GCancellable */ - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (proxy); - g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal_cb), f); - g_ptr_array_add (f->proxies, g_steal_pointer (&proxy)); - } - } - - /* As in setup(), we need to wait for AddMatch to happen. */ - g_test_message ("Waiting for AddMatch to be processed"); - connection_wait_for_bus (subscriber); -} - -static void -fixture_emit_signal (Fixture *f, - const TestEmitSignal *signal, - guint step_number) -{ - GVariant *body; - const char *destination; - gboolean ok; - - g_test_message ("\tSender: %s", - test_conn_descriptions[signal->sender]); - - if (signal->unicast_to != TEST_CONN_NONE) - { - destination = f->unique_names[signal->unicast_to]; - g_test_message ("\tDestination: %s %s", - test_conn_descriptions[signal->unicast_to], - destination); - } - else - { - destination = NULL; - g_test_message ("\tDestination: (broadcast)"); - } - - g_assert_nonnull (signal->path); - g_test_message ("\tPath: %s", signal->path); - g_assert_nonnull (signal->iface); - g_test_message ("\tInterface: %s", signal->iface); - g_assert_nonnull (signal->member); - g_test_message ("\tMember: %s", signal->member); - - /* If arg0 is non-NULL, put it in the message's argument 0. - * Otherwise put something that will not match any arg0. - * Either way, put the sequence number in argument 1 so we can - * correlate sent messages with received messages later. */ - if (signal->args != NULL) - { - /* floating */ - body = g_variant_new_parsed (signal->args); - g_assert_nonnull (body); - } - else if (signal->arg0 != NULL) - { - g_test_message ("\tString argument 0: %s", signal->arg0); - body = g_variant_new ("(su)", signal->arg0, (guint32) step_number); - } - else - { - g_test_message ("\tArgument 0: (not a string)"); - body = g_variant_new ("(uu)", (guint32) 0, (guint32) step_number); - } - - ok = g_dbus_connection_emit_signal (f->conns[signal->sender], - destination, - signal->path, - signal->iface, - signal->member, - /* steals floating reference */ - g_steal_pointer (&body), - &f->error); - g_assert_no_error (f->error); - g_assert_true (ok); - - /* Emitting the signal is asynchronous, so if we want subsequent steps - * to be guaranteed to happen after the signal from the message bus's - * perspective, we have to do a round-trip to the message bus to sync up. */ - g_test_message ("Waiting for signal to reach message bus"); - connection_wait_for_bus (f->conns[signal->sender]); -} - -static void -fixture_own_name (Fixture *f, - const TestOwnName *own_name) -{ - GVariant *call_result; - guint32 flags; - guint32 result_code; - - g_test_message ("\tName: %s", own_name->name); - g_test_message ("\tOwner: %s", - test_conn_descriptions[own_name->owner]); - - /* For simplicity, we do this via a direct bus call rather than - * using g_bus_own_name_on_connection(). The flags in - * GBusNameOwnerFlags are numerically equal to those in the - * D-Bus wire protocol. */ - flags = G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE; - call_result = g_dbus_connection_call_sync (f->conns[own_name->owner], - DBUS_SERVICE_DBUS, - DBUS_PATH_DBUS, - DBUS_INTERFACE_DBUS, - "RequestName", - g_variant_new ("(su)", - own_name->name, - flags), - G_VARIANT_TYPE ("(u)"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (call_result); - g_variant_get (call_result, "(u)", &result_code); - g_assert_cmpuint (result_code, ==, DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER); - g_variant_unref (call_result); -} - -static void -fixture_run_plan (Fixture *f, - const TestPlan *plan, - SubscriptionMode mode) -{ - guint i; - - G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->subscriptions)); - G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_conn)); - G_STATIC_ASSERT (G_N_ELEMENTS (plan->steps) == G_N_ELEMENTS (f->received_by_proxy)); - - f->mode = mode; - f->plan = plan; - - g_test_summary (plan->description); - - for (i = 0; i < G_N_ELEMENTS (plan->steps); i++) - { - const TestStep *step = &plan->steps[i]; - - switch (step->action) - { - case TEST_ACTION_SUBSCRIBE: - g_test_message ("Step %u: adding subscription", i); - fixture_subscribe (f, &step->u.subscribe, i); - break; - - case TEST_ACTION_EMIT_SIGNAL: - g_test_message ("Step %u: emitting signal", i); - fixture_emit_signal (f, &step->u.signal, i); - break; - - case TEST_ACTION_OWN_NAME: - g_test_message ("Step %u: claiming bus name", i); - fixture_own_name (f, &step->u.own_name); - break; - - case TEST_ACTION_NONE: - /* Padding to fill the rest of the array, do nothing */ - break; - - default: - g_return_if_reached (); - } - } - - /* Now that we have done everything we wanted to do, emit Finished - * from each connection. */ - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - { - gboolean ok; - - ok = g_dbus_connection_emit_signal (f->conns[i], - NULL, - FINISHED_PATH, - FINISHED_INTERFACE, - FINISHED_SIGNAL, - NULL, - &f->error); - g_assert_no_error (f->error); - g_assert_true (ok); - } - - /* Wait until we have seen the Finished signal from each sender */ - while (TRUE) - { - gboolean all_finished = TRUE; - - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - all_finished = all_finished && f->finished[i]; - - if (all_finished) - break; - - g_main_context_iteration (NULL, TRUE); - } - - /* Assert that the correct things happened before each Finished signal */ - for (i = 0; i < f->received->len; i++) - { - const ReceivedMessage *received = g_ptr_array_index (f->received, i); - - g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_conn)); - g_assert_cmpuint (received->step, <, G_N_ELEMENTS (f->received_by_proxy)); - - if (received->received_by_proxy != NULL) - f->received_by_proxy[received->step] += 1; - else - f->received_by_conn[received->step] += 1; - } - - for (i = 0; i < G_N_ELEMENTS (plan->steps); i++) - { - const TestStep *step = &plan->steps[i]; - - if (step->action == TEST_ACTION_EMIT_SIGNAL) - { - const TestEmitSignal *signal = &plan->steps[i].u.signal; - - if (mode != SUBSCRIPTION_MODE_PROXY) - { - g_test_message ("Signal from step %u was received %u times by " - "GDBusConnection, expected %u", - i, f->received_by_conn[i], signal->received_by_conn); - g_assert_cmpuint (f->received_by_conn[i], ==, signal->received_by_conn); - } - else - { - g_assert_cmpuint (f->received_by_conn[i], ==, 0); - } - - if (mode != SUBSCRIPTION_MODE_CONN) - { - g_test_message ("Signal from step %u was received %u times by " - "GDBusProxy, expected %u", - i, f->received_by_proxy[i], signal->received_by_proxy); - g_assert_cmpuint (f->received_by_proxy[i], ==, signal->received_by_proxy); - } - else - { - g_assert_cmpuint (f->received_by_proxy[i], ==, 0); - } - } - else if (step->action == TEST_ACTION_OWN_NAME) - { - const TestOwnName *own_name = &plan->steps[i].u.own_name; - - if (mode != SUBSCRIPTION_MODE_PROXY) - { - g_test_message ("NameOwnerChanged from step %u was received %u " - "times by GDBusConnection, expected %u", - i, f->received_by_conn[i], own_name->received_by_conn); - g_assert_cmpuint (f->received_by_conn[i], ==, own_name->received_by_conn); - } - else - { - g_assert_cmpuint (f->received_by_conn[i], ==, 0); - } - - if (mode != SUBSCRIPTION_MODE_CONN) - { - g_test_message ("NameOwnerChanged from step %u was received %u " - "times by GDBusProxy, expected %u", - i, f->received_by_proxy[i], own_name->received_by_proxy); - g_assert_cmpuint (f->received_by_proxy[i], ==, own_name->received_by_proxy); - } - else - { - g_assert_cmpuint (f->received_by_proxy[i], ==, 0); - } - } - } -} - -static void -setup (Fixture *f, - G_GNUC_UNUSED const void *context) -{ - GDBusConnection *subscriber; - guint i; - - session_bus_up (); - - f->proxies = g_ptr_array_new_full (MAX_TEST_STEPS, g_object_unref); - f->received = g_ptr_array_new_full (MAX_TEST_STEPS, - (GDestroyNotify) received_message_free); - - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - { - f->conns[i] = _g_bus_get_priv (G_BUS_TYPE_SESSION, NULL, &f->error); - g_assert_no_error (f->error); - g_assert_nonnull (f->conns[i]); - - f->unique_names[i] = g_dbus_connection_get_unique_name (f->conns[i]); - g_assert_nonnull (f->unique_names[i]); - g_test_message ("%s is %s", - test_conn_descriptions[i], - f->unique_names[i]); - } - - subscriber = f->conns[TEST_CONN_SUBSCRIBER]; - - /* Used to wait for all connections to finish sending whatever they - * wanted to send */ - f->finished_subscription = g_dbus_connection_signal_subscribe (subscriber, - NULL, - FINISHED_INTERFACE, - FINISHED_SIGNAL, - FINISHED_PATH, - NULL, - G_DBUS_SIGNAL_FLAGS_NONE, - subscriber_finished_cb, - f, NULL); - /* AddMatch is sent asynchronously, so we don't know how - * soon it will be processed. Before emitting signals, we - * need to wait for the message bus to get as far as processing - * AddMatch. */ - g_test_message ("Waiting for AddMatch to be processed"); - connection_wait_for_bus (subscriber); -} - -static void -test_conn_subscribe (Fixture *f, - const void *context) -{ - fixture_run_plan (f, context, SUBSCRIPTION_MODE_CONN); -} - -static void -test_proxy_subscribe (Fixture *f, - const void *context) -{ - fixture_run_plan (f, context, SUBSCRIPTION_MODE_PROXY); -} - -static void -test_parallel_subscribe (Fixture *f, - const void *context) -{ - fixture_run_plan (f, context, SUBSCRIPTION_MODE_PARALLEL); -} - -static void -teardown (Fixture *f, - G_GNUC_UNUSED const void *context) -{ - GDBusConnection *subscriber = f->conns[TEST_CONN_SUBSCRIBER]; - guint i; - - g_ptr_array_unref (f->proxies); - - if (f->finished_subscription != 0) - g_dbus_connection_signal_unsubscribe (subscriber, f->finished_subscription); - - for (i = 0; i < G_N_ELEMENTS (f->subscriptions); i++) - { - if (f->subscriptions[i] != 0) - g_dbus_connection_signal_unsubscribe (subscriber, f->subscriptions[i]); - } - - g_ptr_array_unref (f->received); - - for (i = TEST_CONN_FIRST; i < G_N_ELEMENTS (f->conns); i++) - g_clear_object (&f->conns[i]); - - g_clear_error (&f->error); - - session_bus_down (); -} - -int -main (int argc, - char *argv[]) -{ - g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); - - g_test_dbus_unset (); - -#define ADD_SUBSCRIBE_TEST(name) \ - do { \ - g_test_add ("/gdbus/subscribe/conn/" #name, \ - Fixture, &plan_ ## name, \ - setup, test_conn_subscribe, teardown); \ - g_test_add ("/gdbus/subscribe/proxy/" #name, \ - Fixture, &plan_ ## name, \ - setup, test_proxy_subscribe, teardown); \ - g_test_add ("/gdbus/subscribe/parallel/" #name, \ - Fixture, &plan_ ## name, \ - setup, test_parallel_subscribe, teardown); \ - } while (0) - - ADD_SUBSCRIBE_TEST (simple); - ADD_SUBSCRIBE_TEST (broadcast_from_anyone); - ADD_SUBSCRIBE_TEST (match_twice); - ADD_SUBSCRIBE_TEST (limit_by_unique_name); - ADD_SUBSCRIBE_TEST (nonexistent_unique_name); - ADD_SUBSCRIBE_TEST (limit_by_well_known_name); - ADD_SUBSCRIBE_TEST (limit_to_message_bus); - ADD_SUBSCRIBE_TEST (unsubscribe_immediately); - - return g_test_run(); -} diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c index 31de7f1..9c84ea6 100644 --- a/gio/tests/gdbus-test-codegen.c +++ b/gio/tests/gdbus-test-codegen.c @@ -1395,8 +1395,8 @@ check_proxies_in_thread (gpointer user_data) "/bar", NULL, /* GCancellable* */ &error); - check_bar_proxy (bar_proxy, thread_loop); g_assert_no_error (error); + check_bar_proxy (bar_proxy, thread_loop); g_object_unref (bar_proxy); error = NULL; @@ -1406,8 +1406,8 @@ check_proxies_in_thread (gpointer user_data) "/bat", NULL, /* GCancellable* */ &error); - check_bat_proxy (bat_proxy, thread_loop); g_assert_no_error (error); + check_bat_proxy (bat_proxy, thread_loop); g_object_unref (bat_proxy); error = NULL; @@ -1417,8 +1417,8 @@ check_proxies_in_thread (gpointer user_data) "/authorize", NULL, /* GCancellable* */ &error); - check_authorize_proxy (authorize_proxy, thread_loop); g_assert_no_error (error); + check_authorize_proxy (authorize_proxy, thread_loop); g_object_unref (authorize_proxy); error = NULL; diff --git a/gio/tests/gio-tool.py b/gio/tests/gio-tool.py new file mode 100644 index 0000000..1a030df --- /dev/null +++ b/gio/tests/gio-tool.py @@ -0,0 +1,138 @@ +#!/usr/bin/python3 +# -*- coding: utf-8 -*- +# +# Copyright © 2018, 2019 Endless Mobile, Inc. +# Copyright © 2023 Philip Withnall +# +# SPDX-License-Identifier: LGPL-2.1-or-later +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, +# MA 02110-1301 USA + +"""Integration tests for the gio utility.""" + +import collections +import os +import shutil +import subprocess +import sys +import tempfile +import unittest + +import taptestrunner + + +Result = collections.namedtuple("Result", ("info", "out", "err")) + + +class TestGioTool(unittest.TestCase): + """Integration test for running the gio tool. + + This can be run when installed or uninstalled. When uninstalled, it + requires G_TEST_BUILDDIR and G_TEST_SRCDIR to be set. + + The idea with this test harness is to test the gio utility, its + handling of command line arguments, its exit statuses, and its actual + effects on the file system. + """ + + # Track the cwd, we want to back out to that to clean up our tempdir + cwd = "" + + def setUp(self): + self.timeout_seconds = 6 # seconds per test + self.tmpdir = tempfile.TemporaryDirectory() + self.cwd = os.getcwd() + os.chdir(self.tmpdir.name) + print("tmpdir:", self.tmpdir.name) + + ext = "" + if os.name == "nt": + ext = ".exe" + + if "G_TEST_BUILDDIR" in os.environ: + self.__gio = os.path.join( + os.environ["G_TEST_BUILDDIR"], + "..", + "gio" + ext, + ) + else: + self.__gio = shutil.which("gio" + ext) + print("gio:", self.__gio) + + def tearDown(self): + os.chdir(self.cwd) + self.tmpdir.cleanup() + + def runGio(self, *args): + argv = [self.__gio] + argv.extend(args) + print("Running:", argv) + + env = os.environ.copy() + env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" + print("Environment:", env) + + # We want to ensure consistent line endings... + info = subprocess.run( + argv, + timeout=self.timeout_seconds, + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + env=env, + universal_newlines=True, + ) + info.check_returncode() + out = info.stdout.strip() + err = info.stderr.strip() + + result = Result(info, out, err) + + print("Output:", result.out) + return result + + def test_help(self): + """Test the --help argument and help subcommand.""" + result = self.runGio("--help") + result2 = self.runGio("help") + + self.assertEqual(result.out, result2.out) + self.assertEqual(result.err, result2.err) + + self.assertIn("Usage:\n gio COMMAND", result.out) + self.assertIn("List the contents of locations", result.out) + + def test_no_args(self): + """Test running with no arguments at all.""" + with self.assertRaises(subprocess.CalledProcessError): + self.runGio() + + def test_info_non_default_attributes(self): + """Test running `gio info --attributes` with a non-default list.""" + with tempfile.NamedTemporaryFile(dir=self.tmpdir.name) as tmpfile: + result = self.runGio( + "info", "--attributes=standard::content-type", tmpfile.name + ) + if sys.platform == "darwin": + self.assertIn("standard::content-type: public.text", result.out) + else: + self.assertIn( + "standard::content-type: application/x-zerosize", result.out + ) + + +if __name__ == "__main__": + unittest.main(testRunner=taptestrunner.TAPTestRunner()) diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index aa30140..6995fee 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -1163,9 +1163,9 @@ test_object_set_property (GObject *object, static GType test_enum_get_type (void) { - static gsize define_type_id = 0; + static GType define_type_id = 0; - if (g_once_init_enter (&define_type_id)) + if (g_once_init_enter_pointer (&define_type_id)) { static const GEnumValue values[] = { { TEST_ENUM_FOO, "TEST_ENUM_FOO", "foo" }, @@ -1176,7 +1176,7 @@ test_enum_get_type (void) }; GType type_id = g_enum_register_static ("TestEnum", values); - g_once_init_leave (&define_type_id, type_id); + g_once_init_leave_pointer (&define_type_id, type_id); } return define_type_id; @@ -1185,9 +1185,9 @@ test_enum_get_type (void) static GType test_flags_get_type (void) { - static gsize define_type_id = 0; + static GType define_type_id = 0; - if (g_once_init_enter (&define_type_id)) + if (g_once_init_enter_pointer (&define_type_id)) { static const GFlagsValue values[] = { { TEST_FLAGS_NONE, "TEST_FLAGS_NONE", "none" }, @@ -1198,7 +1198,7 @@ test_flags_get_type (void) }; GType type_id = g_flags_register_static ("TestFlags", values); - g_once_init_leave (&define_type_id, type_id); + g_once_init_leave_pointer (&define_type_id, type_id); } return define_type_id; diff --git a/gio/tests/memory-monitor-portal.py.in b/gio/tests/memory-monitor-portal.py.in index 748cee8..7fdf3c7 100755 --- a/gio/tests/memory-monitor-portal.py.in +++ b/gio/tests/memory-monitor-portal.py.in @@ -73,7 +73,7 @@ try: raise # subprocess.Popen(['gdbus', 'monitor', '--session', '--dest', 'org.freedesktop.portal.Desktop']) - os.environ['GTK_USE_PORTAL'] = "1" + os.environ['GIO_USE_PORTALS'] = "1" self.memory_monitor = Gio.MemoryMonitor.dup_default() assert("GMemoryMonitorPortal" in str(self.memory_monitor)) self.memory_monitor.connect("low-memory-warning", self.portal_memory_warning_cb) diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 298f9b4..fd4c46f 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -51,7 +51,8 @@ gio_tests = { 'application-command-line': {}, 'appmonitor' : { # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 - 'can_fail' : host_system == 'darwin', + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system in ['darwin', 'gnu'], }, 'async-close-output-stream' : {}, 'async-splice-output-stream' : {}, @@ -63,7 +64,12 @@ gio_tests = { # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 / https://gitlab.gnome.org/GNOME/glib/-/issues/1251 'can_fail' : host_system == 'darwin', }, - 'converter-stream' : {}, + 'converter-stream' : { + # musl: charset tests fail due to missing collation support in musl libc + # From https://wiki.musl-libc.org/roadmap#Open_future_goals + # "LC_COLLATE support for collation orders other than simple codepoint order" + 'can_fail' : linux_libc == 'musl', + }, 'credentials' : {}, 'data-input-stream' : {}, 'data-output-stream' : {}, @@ -81,7 +87,8 @@ gio_tests = { 'g-file' : {}, 'g-file-info' : { # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3070 - 'can_fail' : host_system == 'darwin' or host_system == 'windows' and cc.get_id() != 'gcc', + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system in ['darwin', 'gnu'] or host_system == 'windows' and cc.get_id() != 'gcc', }, 'g-icon' : {}, 'gdbus-addresses' : {}, @@ -90,7 +97,8 @@ gio_tests = { 'dependencies' : [libgdbus_example_objectmanager_dep], 'install_rpath' : installed_tests_execdir, # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 - 'can_fail' : host_system in ['darwin', 'windows'], + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system in ['darwin', 'windows', 'gnu'], }, 'inet-address' : {}, 'io-stream' : {}, @@ -118,7 +126,8 @@ gio_tests = { 'sleepy-stream' : {}, 'socket' : { # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 - 'can_fail' : host_system == 'darwin', + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system in ['darwin', 'gnu'], }, 'socket-listener' : {}, 'socket-service' : {}, @@ -137,7 +146,8 @@ gio_tests = { 'gdbus-address-get-session' : { 'extra_programs': host_system != 'windows' ? ['dbus-launch'] : [], # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 - 'can_fail' : host_system == 'darwin', + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system in ['darwin', 'gnu'], }, 'win32-appinfo' : {}, } @@ -176,6 +186,10 @@ python_tests = { 'suite': ['gdbus-codegen', 'slow'], 'timeout': 90, }, + 'gio-tool.py' : { + 'depends' : gio_tool, + 'can_fail' : host_system == 'windows', + }, } test_env = environment() @@ -232,7 +246,10 @@ endif # Test programs buildable on UNIX only if host_machine.system() != 'windows' gio_tests += { - 'file' : {}, + 'file' : { + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', + }, 'gdbus-peer-object-manager' : {}, 'gdbus-sasl' : {}, 'live-g-file' : {}, @@ -277,7 +294,10 @@ if host_machine.system() != 'windows' }, 'resolver-parsing' : {'dependencies' : [network_libs]}, 'socket-address' : {}, - 'stream-rw_all' : {}, + 'stream-rw_all' : { + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', + }, 'unix-mounts' : {}, 'unix-streams' : {}, 'g-file-info-filesystem-readonly' : {}, @@ -324,6 +344,8 @@ if host_machine.system() != 'windows' 'install' : false, 'depends' : gio_launch_desktop, 'extra_programs' : ['apps', 'appinfo-test'], + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', }, } endif @@ -360,6 +382,7 @@ if host_machine.system() != 'windows' output : ['gdbus-test-codegen-generated.h', 'gdbus-test-codegen-generated.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-prefix', 'org.project.', '--output-directory', '@OUTDIR@', @@ -376,6 +399,7 @@ if host_machine.system() != 'windows' output : ['gdbus-test-codegen-generated-min-required-2-64.h', 'gdbus-test-codegen-generated-min-required-2-64.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--glib-min-required', '2.64', '--interface-prefix', 'org.project.', @@ -392,6 +416,7 @@ if host_machine.system() != 'windows' input : ['test-codegen.xml'], output : ['gdbus-test-codegen-generated-interface-info.h'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-info-header', annotate_args, @@ -401,6 +426,7 @@ if host_machine.system() != 'windows' input : ['test-codegen.xml'], output : ['gdbus-test-codegen-generated-interface-info.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-info-body', annotate_args, @@ -454,6 +480,8 @@ if host_machine.system() != 'windows' 'gdbus-proxy-threads' : { 'extra_sources' : extra_sources, 'dependencies' : [dbus1_dep], + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', }, 'gdbus-proxy-unique-name' : { 'extra_sources' : extra_sources, @@ -463,10 +491,6 @@ if host_machine.system() != 'windows' 'extra_sources' : extra_sources, 'extra_programs': extra_programs, }, - 'gdbus-subscribe' : { - 'extra_sources' : extra_sources, - 'extra_programs': extra_programs, - }, 'gdbus-test-codegen' : { 'extra_sources' : [extra_sources, gdbus_test_codegen_generated, gdbus_test_codegen_generated_interface_info], 'c_args' : ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_32'], @@ -517,6 +541,7 @@ if host_machine.system() != 'windows' output : ['fake-document-portal-generated.h', 'fake-document-portal-generated.c'], depend_files : gdbus_codegen_built_files, + depends : gdbus_codegen_built_targets, command : [python, gdbus_codegen, '--interface-prefix', 'org.freedesktop.portal.', '--output-directory', '@OUTDIR@', @@ -560,6 +585,8 @@ if host_machine.system() != 'windows' '-DTEST_LOCALE_PATH="@0@"'.format(test_mo_dir)], 'install' : false, 'depends' : glib_compile_schemas, + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', }, } endif @@ -797,8 +824,12 @@ if not meson.is_cross_build() output : ['gresource-big-test.txt'], command : [python, '@INPUT0@', '@OUTPUT@']) + # referenced by test.gresource.xml + test_generated_txt = fs.copyfile('test1.txt', 'test-generated.txt') + test_gresource = custom_target('test.gresource', input : 'test.gresource.xml', + depends : test_generated_txt, output : 'test.gresource', command : [glib_compile_resources, compiler_type, @@ -876,12 +907,6 @@ if not meson.is_cross_build() '--manual-register', '@INPUT@']) - # referenced by test.gresource.xml - test_generated_txt = configure_file(input : 'test1.txt', - output : 'test-generated.txt', - copy : true, - ) - resources_extra_sources = [ test_gresource, test_resources_c, @@ -909,7 +934,9 @@ if not meson.is_cross_build() ld = find_program('ld', required : false) - if build_machine.system() == 'linux' and objcopy.found() and objcopy_supports_add_symbol and ld.found() + if build_machine.system() == 'linux' and \ + objcopy.found() and objcopy_supports_add_symbol and ld.found() and \ + build_machine.cpu_family() not in ['mips', 'mips64'] test_gresource_binary = custom_target('test5.gresource', input : 'test5.gresource.xml', output : 'test5.gresource', @@ -971,6 +998,8 @@ if not meson.is_cross_build() 'resources' : { 'extra_sources' : resources_extra_sources, 'depends' : resource_plugin, + # FIXME: musl: https://gitlab.gnome.org/GNOME/glib/-/issues/3160 + 'can_fail' : linux_libc == 'musl', }, } endif @@ -1061,6 +1090,7 @@ endforeach foreach test_name, extra_args : python_tests depends = [extra_args.get('depends', [])] suite = ['gio', 'no-valgrind'] + extra_args.get('suite', []) + timeout = extra_args.get('timeout', test_timeout) if extra_args.get('can_fail', false) suite += 'failing' @@ -1077,7 +1107,7 @@ foreach test_name, extra_args : python_tests depends: depends, args: ['-B', files(test_name)], env: test_env, - timeout: extra_args.get('timeout'), + timeout: timeout, suite: suite, ) diff --git a/gio/tests/portal-support-env-var.c b/gio/tests/portal-support-env-var.c index b1d3fd3..50982bd 100644 --- a/gio/tests/portal-support-env-var.c +++ b/gio/tests/portal-support-env-var.c @@ -37,7 +37,7 @@ main (int argc, char **argv) { g_test_init (&argc, &argv, NULL); - g_setenv ("GTK_USE_PORTAL", "1", TRUE); + g_setenv ("GIO_USE_PORTALS", "1", TRUE); g_test_add_func ("/portal-support/env-var", test_portal_support_env_var); diff --git a/gio/tests/power-profile-monitor-portal.py.in b/gio/tests/power-profile-monitor-portal.py.in index 09e9a45..d094ada 100755 --- a/gio/tests/power-profile-monitor-portal.py.in +++ b/gio/tests/power-profile-monitor-portal.py.in @@ -79,7 +79,7 @@ try: raise # subprocess.Popen(['gdbus', 'monitor', '--session', '--dest', 'org.freedesktop.portal.Desktop']) - os.environ['GTK_USE_PORTAL'] = "1" + os.environ['GIO_USE_PORTALS'] = "1" self.power_profile_monitor = Gio.PowerProfileMonitor.dup_default() assert("GPowerProfileMonitorPortal" in str(self.power_profile_monitor)) self.power_profile_monitor.connect("notify::power-saver-enabled", self.power_saver_enabled_cb) diff --git a/gio/tests/proxy-test.c b/gio/tests/proxy-test.c index e040c63..ca3f4b3 100644 --- a/gio/tests/proxy-test.c +++ b/gio/tests/proxy-test.c @@ -797,9 +797,9 @@ g_fake_resolver_lookup_by_name_async (GResolver *resolver, } else { - g_task_return_new_error (task, - G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, - "Not found"); + g_task_return_new_error_literal (task, + G_RESOLVER_ERROR, G_RESOLVER_ERROR_NOT_FOUND, + "Not found"); } g_object_unref (task); } diff --git a/gio/tests/socket.c b/gio/tests/socket.c index c1c1bcf..5747c20 100644 --- a/gio/tests/socket.c +++ b/gio/tests/socket.c @@ -43,14 +43,25 @@ static gboolean ipv6_supported; typedef struct { - GSocket *server; - GSocket *client; + GSocket *server; /* (owned) (not nullable) */ + GSocket *client; /* (owned) (nullable) */ GSocketFamily family; - GThread *thread; - GMainLoop *loop; - GCancellable *cancellable; /* to shut down dgram echo server thread */ + GThread *thread; /* (owned) (not nullable) */ + GMainLoop *loop; /* (owned) (nullable) */ + GCancellable *cancellable; /* to shut down dgram echo server thread; (owned) (nullable) */ } IPTestData; +static void +ip_test_data_free (IPTestData *data) +{ + g_clear_object (&data->server); + g_clear_object (&data->client); + g_clear_pointer (&data->loop, g_main_loop_unref); + g_clear_object (&data->cancellable); + + g_slice_free (IPTestData, data); +} + static gpointer echo_server_dgram_thread (gpointer user_data) { @@ -130,7 +141,7 @@ create_server_full (GSocketFamily family, GSocketAddress *addr; GInetAddress *iaddr; - data = g_slice_new (IPTestData); + data = g_slice_new0 (IPTestData); data->family = family; data->server = server = g_socket_new (family, @@ -144,7 +155,7 @@ create_server_full (GSocketFamily family, g_assert_cmpint (g_socket_get_socket_type (server), ==, socket_type); g_assert_cmpint (g_socket_get_protocol (server), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (server))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (server))); #endif g_socket_set_blocking (server, TRUE); @@ -198,8 +209,7 @@ create_server_full (GSocketFamily family, return data; error: - g_clear_object (&data->server); - g_slice_free (IPTestData, data); + ip_test_data_free (data); return NULL; } @@ -310,7 +320,7 @@ test_ip_async_connected (GSocket *client, */ g_assert_cmpint (cond, ==, G_IO_OUT); - g_assert (g_socket_is_connected (client)); + g_assert_true (g_socket_is_connected (client)); /* This adds 1 second to "make check", so let's just only do it once. */ if (data->family == G_SOCKET_FAMILY_IPV4) @@ -396,7 +406,7 @@ test_ip_async (GSocketFamily family) data->loop = g_main_loop_new (NULL, TRUE); g_main_loop_run (data->loop); - g_main_loop_unref (data->loop); + g_clear_pointer (&data->loop, g_main_loop_unref); g_socket_shutdown (client, FALSE, TRUE, &error); g_assert_no_error (error); @@ -426,10 +436,7 @@ test_ip_async (GSocketFamily family) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); - g_object_unref (client); - - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static void @@ -483,14 +490,14 @@ test_ip_sync (GSocketFamily family) g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM); g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); #endif g_socket_set_blocking (client, TRUE); g_socket_set_timeout (client, 1); g_socket_connect (client, addr, NULL, &error); g_assert_no_error (error); - g_assert (g_socket_is_connected (client)); + g_assert_true (g_socket_is_connected (client)); g_object_unref (addr); /* This adds 1 second to "make check", so let's just only do it once. */ @@ -567,10 +574,9 @@ test_ip_sync (GSocketFamily family) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); g_object_unref (client); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static void @@ -611,6 +617,7 @@ test_ip_sync_dgram (GSocketFamily family) } dest_addr = g_socket_get_local_address (data->server, &error); + g_assert_no_error (error); client = g_socket_new (family, G_SOCKET_TYPE_DATAGRAM, @@ -622,7 +629,7 @@ test_ip_sync_dgram (GSocketFamily family) g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_DATAGRAM); g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); #endif g_socket_set_blocking (client, TRUE); @@ -711,7 +718,7 @@ test_ip_sync_dgram (GSocketFamily family) g_assert_no_error (error); /* v[0].size + v[1].size + v[2].size + v[3].size + v[4].size + v[5].size */ g_assert_cmpint (len, ==, 17); - g_assert (memcmp (testbuf2, buf, 17) == 0); + g_assert_cmpmem (testbuf2, 17, buf, 17); memset (buf, 0, sizeof (buf)); len = g_socket_receive_from (client, NULL, buf, sizeof (buf), NULL, &error); @@ -777,7 +784,7 @@ test_ip_sync_dgram (GSocketFamily family) len = g_socket_send_messages (client, m, G_N_ELEMENTS (m), 0, NULL, &error); /* This error code may vary between platforms and over time; it is not guaranteed API: */ #ifndef G_OS_WIN32 - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DESTINATION_UNSET); #else g_assert_error (error, G_IO_ERROR, G_IO_ERROR_NOT_CONNECTED); #endif @@ -801,12 +808,10 @@ test_ip_sync_dgram (GSocketFamily family) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); - g_object_unref (data->cancellable); g_object_unref (client); g_object_unref (dest_addr); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static void @@ -862,7 +867,7 @@ test_ip_sync_dgram_timeouts (GSocketFamily family) g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_DATAGRAM); g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); #endif #ifdef G_OS_WIN32 @@ -1007,7 +1012,7 @@ test_close_graceful (void) g_assert_cmpint (g_socket_get_socket_type (client), ==, G_SOCKET_TYPE_STREAM); g_assert_cmpint (g_socket_get_protocol (client), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); #endif g_socket_set_blocking (client, TRUE); @@ -1015,7 +1020,7 @@ test_close_graceful (void) g_socket_connect (client, addr, NULL, &error); g_assert_no_error (error); - g_assert (g_socket_is_connected (client)); + g_assert_true (g_socket_is_connected (client)); g_object_unref (addr); server = g_thread_join (data->thread); @@ -1046,10 +1051,9 @@ test_close_graceful (void) g_assert_no_error (error); g_object_unref (server); - g_object_unref (data->server); g_object_unref (client); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } #if defined (IPPROTO_IPV6) && defined (IPV6_V6ONLY) @@ -1123,7 +1127,7 @@ test_ipv6_v4mapped (void) g_socket_connect (client, v4addr, NULL, &error); g_assert_no_error (error); - g_assert (g_socket_is_connected (client)); + g_assert_true (g_socket_is_connected (client)); g_thread_join (data->thread); @@ -1132,11 +1136,10 @@ test_ipv6_v4mapped (void) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); g_object_unref (client); g_object_unref (v4addr); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } #endif @@ -1198,10 +1201,9 @@ test_timed_wait (void) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); g_object_unref (client); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static int @@ -1265,7 +1267,7 @@ test_fd_reuse (void) g_socket_connect (client, addr, NULL, &error); g_assert_no_error (error); - g_assert (g_socket_is_connected (client)); + g_assert_true (g_socket_is_connected (client)); g_object_unref (addr); /* we have to dup otherwise the fd gets closed twice on unref */ @@ -1277,7 +1279,7 @@ test_fd_reuse (void) g_assert_cmpint (g_socket_get_socket_type (client2), ==, g_socket_get_socket_type (client)); g_assert_cmpint (g_socket_get_protocol (client2), ==, G_SOCKET_PROTOCOL_TCP); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (client))); #endif len = g_socket_send (client2, testbuf, strlen (testbuf) + 1, NULL, &error); @@ -1310,11 +1312,10 @@ test_fd_reuse (void) g_assert_cmpint (g_socket_get_fd (client2), ==, -1); g_assert_cmpint (g_socket_get_fd (data->server), ==, -1); - g_object_unref (data->server); g_object_unref (client); g_object_unref (client2); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static void @@ -1334,12 +1335,12 @@ test_sockaddr (void) sin6.sin6_flowinfo = 1729; saddr = g_socket_address_new_from_native (&sin6, sizeof (sin6)); - g_assert (G_IS_INET_SOCKET_ADDRESS (saddr)); + g_assert_true (G_IS_INET_SOCKET_ADDRESS (saddr)); isaddr = G_INET_SOCKET_ADDRESS (saddr); iaddr = g_inet_socket_address_get_address (isaddr); g_assert_cmpint (g_inet_address_get_family (iaddr), ==, G_SOCKET_FAMILY_IPV6); - g_assert (g_inet_address_get_is_loopback (iaddr)); + g_assert_true (g_inet_address_get_is_loopback (iaddr)); g_assert_cmpint (g_inet_socket_address_get_port (isaddr), ==, 42); g_assert_cmpint (g_inet_socket_address_get_scope_id (isaddr), ==, 17); @@ -1348,7 +1349,7 @@ test_sockaddr (void) g_socket_address_to_native (saddr, &gsin6, sizeof (gsin6), &error); g_assert_no_error (error); - g_assert (memcmp (&sin6.sin6_addr, &gsin6.sin6_addr, sizeof (struct in6_addr)) == 0); + g_assert_cmpmem (&sin6.sin6_addr, sizeof (struct in6_addr), &gsin6.sin6_addr, sizeof (struct in6_addr)); g_assert_cmpint (sin6.sin6_port, ==, gsin6.sin6_port); g_assert_cmpint (sin6.sin6_scope_id, ==, gsin6.sin6_scope_id); g_assert_cmpint (sin6.sin6_flowinfo, ==, gsin6.sin6_flowinfo); @@ -1399,7 +1400,7 @@ test_unix_from_fd (void) g_assert_cmpint (g_socket_get_socket_type (s), ==, G_SOCKET_TYPE_STREAM); g_assert_cmpint (g_socket_get_protocol (s), ==, G_SOCKET_PROTOCOL_DEFAULT); #ifdef G_OS_WIN32 - g_assert (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (s))); + g_assert_true (GLIB_PRIVATE_CALL (g_win32_handle_is_socket) ((HANDLE)(gintptr) g_socket_get_fd (s))); #endif g_object_unref (s); } @@ -1428,7 +1429,7 @@ test_unix_connection (void) s = g_socket_new_from_fd (fd, &error); g_assert_no_error (error); c = g_socket_connection_factory_create_connection (s); - g_assert (G_IS_UNIX_CONNECTION (c)); + g_assert_true (G_IS_UNIX_CONNECTION (c)); g_object_unref (c); g_object_unref (s); } @@ -1443,9 +1444,9 @@ create_connection_for_fd (int fd) socket = g_socket_new_from_fd (fd, &err); g_assert_no_error (err); - g_assert (G_IS_SOCKET (socket)); + g_assert_true (G_IS_SOCKET (socket)); connection = g_socket_connection_factory_create_connection (socket); - g_assert (G_IS_UNIX_CONNECTION (connection)); + g_assert_true (G_IS_UNIX_CONNECTION (connection)); g_object_unref (socket); return connection; } @@ -1525,7 +1526,7 @@ test_unix_connection_ancillary_data (void) g_assert_cmpstr (buffer, ==, TEST_DATA); waitpid (pid, &status, 0); - g_assert (WIFEXITED (status)); + g_assert_true (WIFEXITED (status)); g_assert_cmpint (WEXITSTATUS (status), ==, 0); } @@ -1612,8 +1613,8 @@ test_source_postmortem (void) /* Test that, after a socket is closed, its source callback should be called * exactly once. */ g_main_context_iteration (context, FALSE); - g_assert (callback_visited); - g_assert (!g_main_context_pending (context)); + g_assert_true (callback_visited); + g_assert_false (g_main_context_pending (context)); g_main_context_unref (context); } @@ -1713,14 +1714,14 @@ test_get_available (gconstpointer user_data) G_SOCKET_PROTOCOL_DEFAULT, &err); g_assert_no_error (err); - g_assert (G_IS_SOCKET (listener)); + g_assert_true (G_IS_SOCKET (listener)); client = g_socket_new (G_SOCKET_FAMILY_IPV4, socket_type, G_SOCKET_PROTOCOL_DEFAULT, &err); g_assert_no_error (err); - g_assert (G_IS_SOCKET (client)); + g_assert_true (G_IS_SOCKET (client)); if (socket_type == G_SOCKET_TYPE_STREAM) { @@ -1918,14 +1919,14 @@ test_read_write (gconstpointer user_data) G_SOCKET_PROTOCOL_DEFAULT, &err); g_assert_no_error (err); - g_assert (G_IS_SOCKET (listener)); + g_assert_true (G_IS_SOCKET (listener)); client = g_socket_new (G_SOCKET_FAMILY_IPV4, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &err); g_assert_no_error (err); - g_assert (G_IS_SOCKET (client)); + g_assert_true (G_IS_SOCKET (client)); addr = g_inet_address_new_any (G_SOCKET_FAMILY_IPV4); saddr = g_inet_socket_address_new (addr, 0); @@ -2071,10 +2072,9 @@ test_credentials_tcp_client (void) g_socket_close (data->server, &error); g_assert_no_error (error); - g_object_unref (data->server); g_object_unref (client); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } static void @@ -2144,10 +2144,8 @@ beach: g_clear_object (&iaddr); g_clear_pointer (&data->thread, g_thread_join); - g_clear_object (&data->server); - g_clear_object (&data->client); - g_slice_free (IPTestData, data); + ip_test_data_free (data); } } @@ -2201,6 +2199,7 @@ _g_win32_socketpair (gint domain, SOCKET client = INVALID_SOCKET; SOCKET server = INVALID_SOCKET; gchar *path = NULL; + wchar_t *path_utf16 = NULL; int tmpfd, rv = -1; u_long arg, br; @@ -2230,7 +2229,11 @@ _g_win32_socketpair (gint domain, if (listener == INVALID_SOCKET) goto out; - if (DeleteFile (path) == 0) + path_utf16 = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); + if (!path_utf16) + goto out; + + if (DeleteFile (path_utf16) == 0) { if (GetLastError () != ERROR_FILE_NOT_FOUND) goto out; @@ -2285,7 +2288,10 @@ _g_win32_socketpair (gint domain, if (server != INVALID_SOCKET) closesocket (server); - DeleteFile (path); + if (path_utf16) + DeleteFile (path_utf16); + + g_free (path_utf16); g_free (path); return rv; } @@ -2337,6 +2343,205 @@ test_credentials_unix_socketpair (void) } #endif +static void +test_receive_bytes (void) +{ + const GSocketFamily family = G_SOCKET_FAMILY_IPV4; + IPTestData *data; + GError *error = NULL; + GSocket *client; + GSocketAddress *addr; + gssize len; + GBytes *bytes = NULL; + gint64 time_start; + GCancellable *cancellable = NULL; + + g_test_summary ("Test basic functionality of g_socket_receive_bytes()"); + + data = create_server (family, echo_server_thread, FALSE, &error); + if (error != NULL) + { + g_test_skip_printf ("Failed to create server: %s", error->message); + g_clear_error (&error); + return; + } + + addr = g_socket_get_local_address (data->server, &error); + g_assert_no_error (error); + + client = g_socket_new (family, + G_SOCKET_TYPE_STREAM, + G_SOCKET_PROTOCOL_DEFAULT, + &error); + g_assert_no_error (error); + + g_socket_set_blocking (client, TRUE); + g_socket_set_timeout (client, 10); + + g_socket_connect (client, addr, NULL, &error); + g_assert_no_error (error); + g_object_unref (addr); + + /* Send something. */ + len = g_socket_send (client, "hello", strlen ("hello"), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (len, ==, strlen ("hello")); + + /* And receive it back again. */ + bytes = g_socket_receive_bytes (client, 5, -1, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + g_assert_cmpuint (g_bytes_get_size (bytes), ==, 5); + g_assert_cmpmem (g_bytes_get_data (bytes, NULL), 5, "hello", 5); + g_bytes_unref (bytes); + + /* Try again with a receive buffer which is bigger than the sent bytes, to + * test sub-buffer handling. */ + len = g_socket_send (client, "hello", strlen ("hello"), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (len, ==, strlen ("hello")); + + /* And receive it back again. */ + bytes = g_socket_receive_bytes (client, 500, -1, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + g_assert_cmpuint (g_bytes_get_size (bytes), ==, 5); + g_assert_cmpmem (g_bytes_get_data (bytes, NULL), 5, "hello", 5); + g_bytes_unref (bytes); + + /* Try receiving when there’s nothing to receive, with a timeout. This should + * be the per-operation timeout, not the socket’s overall timeout */ + time_start = g_get_real_time (); + bytes = g_socket_receive_bytes (client, 500, 10, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT); + g_assert_null (bytes); + g_assert_cmpint (g_get_real_time () - time_start, <, g_socket_get_timeout (client) * G_USEC_PER_SEC); + g_clear_error (&error); + + /* And try receiving when already cancelled. */ + cancellable = g_cancellable_new (); + g_cancellable_cancel (cancellable); + bytes = g_socket_receive_bytes (client, 500, -1, cancellable, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert_null (bytes); + g_clear_error (&error); + g_clear_object (&cancellable); + + /* Tidy up. */ + g_socket_close (client, &error); + g_assert_no_error (error); + + g_cancellable_cancel (data->cancellable); + g_thread_join (data->thread); + + g_socket_close (data->server, &error); + g_assert_no_error (error); + + g_object_unref (client); + + ip_test_data_free (data); +} + +static void +test_receive_bytes_from (void) +{ + const GSocketFamily family = G_SOCKET_FAMILY_IPV4; + IPTestData *data; + GError *error = NULL; + GSocket *client; + GSocketAddress *dest_addr = NULL, *sender_addr = NULL; + gssize len; + GBytes *bytes = NULL; + gint64 time_start; + GCancellable *cancellable = NULL; + + g_test_summary ("Test basic functionality of g_socket_receive_bytes_from()"); + + data = create_server_full (family, G_SOCKET_TYPE_DATAGRAM, + echo_server_dgram_thread, FALSE, &error); + if (error != NULL) + { + g_test_skip_printf ("Failed to create server: %s", error->message); + g_clear_error (&error); + return; + } + + dest_addr = g_socket_get_local_address (data->server, &error); + g_assert_no_error (error); + + client = g_socket_new (family, + G_SOCKET_TYPE_DATAGRAM, + G_SOCKET_PROTOCOL_DEFAULT, + &error); + g_assert_no_error (error); + + g_socket_set_blocking (client, TRUE); + g_socket_set_timeout (client, 10); + + /* Send something. */ + len = g_socket_send_to (client, dest_addr, "hello", strlen ("hello"), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (len, ==, strlen ("hello")); + + /* And receive it back again. */ + bytes = g_socket_receive_bytes_from (client, &sender_addr, 5, -1, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + g_assert_cmpuint (g_bytes_get_size (bytes), ==, 5); + g_assert_cmpmem (g_bytes_get_data (bytes, NULL), 5, "hello", 5); + g_assert_nonnull (sender_addr); + g_clear_object (&sender_addr); + g_bytes_unref (bytes); + + /* Try again with a receive buffer which is bigger than the sent bytes, to + * test sub-buffer handling. */ + len = g_socket_send_to (client, dest_addr, "hello", strlen ("hello"), NULL, &error); + g_assert_no_error (error); + g_assert_cmpint (len, ==, strlen ("hello")); + + /* And receive it back again. */ + bytes = g_socket_receive_bytes_from (client, NULL, 500, -1, NULL, &error); + g_assert_no_error (error); + g_assert_nonnull (bytes); + g_assert_cmpuint (g_bytes_get_size (bytes), ==, 5); + g_assert_cmpmem (g_bytes_get_data (bytes, NULL), 5, "hello", 5); + g_bytes_unref (bytes); + + /* Try receiving when there’s nothing to receive, with a timeout. This should + * be the per-operation timeout, not the socket’s overall timeout */ + time_start = g_get_real_time (); + bytes = g_socket_receive_bytes_from (client, &sender_addr, 500, 10, NULL, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT); + g_assert_null (bytes); + g_assert_null (sender_addr); + g_assert_cmpint (g_get_real_time () - time_start, <, g_socket_get_timeout (client) * G_USEC_PER_SEC); + g_clear_error (&error); + + /* And try receiving when already cancelled. */ + cancellable = g_cancellable_new (); + g_cancellable_cancel (cancellable); + bytes = g_socket_receive_bytes_from (client, &sender_addr, 500, -1, cancellable, &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED); + g_assert_null (bytes); + g_assert_null (sender_addr); + g_clear_error (&error); + g_clear_object (&cancellable); + + /* Tidy up. */ + g_socket_close (client, &error); + g_assert_no_error (error); + + g_cancellable_cancel (data->cancellable); + g_thread_join (data->thread); + + g_socket_close (data->server, &error); + g_assert_no_error (error); + + g_object_unref (client); + + ip_test_data_free (data); +} + int main (int argc, char *argv[]) @@ -2403,6 +2608,8 @@ main (int argc, g_test_add_func ("/socket/credentials/tcp_server", test_credentials_tcp_server); g_test_add_func ("/socket/credentials/unix_socketpair", test_credentials_unix_socketpair); #endif + g_test_add_func ("/socket/receive_bytes", test_receive_bytes); + g_test_add_func ("/socket/receive_bytes_from", test_receive_bytes_from); return g_test_run(); } diff --git a/gio/tests/stream-rw_all.c b/gio/tests/stream-rw_all.c index 7d8ceb2..4d90355 100644 --- a/gio/tests/stream-rw_all.c +++ b/gio/tests/stream-rw_all.c @@ -44,7 +44,7 @@ static void wait_for_read (gboolean success, gsize read) { - g_assert (!got_read_done); + g_assert_false (got_read_done); expected_read_success = success; expected_read = read; @@ -76,7 +76,7 @@ static void wait_for_write (gboolean success, gsize written) { - g_assert (!got_write_done); + g_assert_false (got_write_done); expected_write_success = success; expected_written = written; @@ -110,7 +110,7 @@ test_write_all_async_memory (void) g_output_stream_write_all_async (ms, "0123456789", 10, 0, NULL, write_done, NULL); wait_for_write (FALSE, 0); - g_assert (!memcmp (b, "012345678901234567890123", 24)); + g_assert_cmpint (memcmp (b, "012345678901234567890123", 24), ==, 0); g_object_unref (ms); } @@ -126,16 +126,16 @@ test_read_all_async_memory (void) g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL); wait_for_read (TRUE, 10); - g_assert (!memcmp (buf, "0123456789", 10)); + g_assert_cmpint (memcmp (buf, "0123456789", 10), ==, 0); g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL); wait_for_read (TRUE, 10); - g_assert (!memcmp (buf, "ABCDEFGHIJ", 10)); + g_assert_cmpint (memcmp (buf, "ABCDEFGHIJ", 10), ==, 0); /* partial read... */ g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL); wait_for_read (TRUE, 4); - g_assert (!memcmp (buf, "!@#$", 4)); + g_assert_cmpint (memcmp (buf, "!@#$", 4), ==, 0); /* EOF */ g_input_stream_read_all_async (ms, buf, 10, 0, NULL, read_done, NULL); @@ -146,6 +146,7 @@ test_read_all_async_memory (void) #ifdef G_OS_UNIX #include +#include #include #include #include @@ -165,13 +166,12 @@ test_read_write_all_async_pipe (void) { gint sv[2]; - gint s; - s = socketpair (AF_UNIX, SOCK_STREAM, 0, sv); - g_assert (s == 0); + g_unix_open_pipe (sv, O_CLOEXEC | O_NONBLOCK, &error); + g_assert_no_error (error); - out = g_unix_output_stream_new (sv[0], TRUE); - in = g_unix_input_stream_new (sv[1], TRUE); + out = g_unix_output_stream_new (sv[1], TRUE); + in = g_unix_input_stream_new (sv[0], TRUE); } /* Try to fill up the buffer */ @@ -180,7 +180,7 @@ test_read_write_all_async_pipe (void) { s = g_output_stream_write (out, wbuf, sizeof wbuf, NULL, &error); g_assert_no_error (error); - g_assert (s > 0); + g_assert_cmpint (s, >, 0); in_flight += s; } @@ -189,7 +189,7 @@ test_read_write_all_async_pipe (void) g_output_stream_write_all_async (out, "0123456789", 10, 0, cancellable, write_done, NULL); while (g_main_context_iteration (NULL, FALSE)) ; - g_assert (!got_write_done); + g_assert_false (got_write_done); /* Cancel that to make sure it works */ g_cancellable_cancel (cancellable); @@ -200,7 +200,7 @@ test_read_write_all_async_pipe (void) g_output_stream_write_all_async (out, "0123456789", 10, 0, NULL, write_done, NULL); while (g_main_context_iteration (NULL, FALSE)) ; - g_assert (!got_write_done); + g_assert_false (got_write_done); /* Now drain as much as we originally put in the buffer to make it * block -- this will unblock the writer. @@ -209,7 +209,7 @@ test_read_write_all_async_pipe (void) { s = g_input_stream_read (in, rbuf, MIN (sizeof wbuf, in_flight), NULL, &error); g_assert_no_error (error); - g_assert (s > 0); + g_assert_cmpint (s, >, 0); in_flight -= s; } @@ -221,7 +221,7 @@ test_read_write_all_async_pipe (void) /* The write is surely finished by now */ wait_for_write (TRUE, 10); /* ...but the read will not yet be satisfied */ - g_assert (!got_read_done); + g_assert_false (got_read_done); /* Feed the read more than it asked for; this really should not block * since the buffer is so small... diff --git a/gio/tests/task.c b/gio/tests/task.c index 8dfc0e9..a7f2312 100644 --- a/gio/tests/task.c +++ b/gio/tests/task.c @@ -129,12 +129,19 @@ test_basic (void) /* test_error */ +typedef struct { + GQuark expected_domain; + int expected_code; + char *expected_message; + gssize int_result; +} TaskErrorResult; + static void error_callback (GObject *object, GAsyncResult *result, gpointer user_data) { - gssize *result_out = user_data; + TaskErrorResult *result_inout = user_data; GError *error = NULL; g_assert (object == NULL); @@ -143,13 +150,12 @@ error_callback (GObject *object, g_assert (g_task_had_error (G_TASK (result))); g_assert_false (g_task_get_completed (G_TASK (result))); - *result_out = g_task_propagate_int (G_TASK (result), &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_FAILED); + result_inout->int_result = g_task_propagate_int (G_TASK (result), &error); + g_assert_error (error, result_inout->expected_domain, result_inout->expected_code); + g_assert_cmpstr (error->message, ==, result_inout->expected_message); g_error_free (error); g_assert (g_task_had_error (G_TASK (result))); - - g_main_loop_quit (loop); } static gboolean @@ -159,7 +165,7 @@ error_return (gpointer user_data) g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, - "Failed"); + "Failed %p", task); g_object_unref (task); return FALSE; @@ -177,15 +183,17 @@ static void test_error (void) { GTask *task; - gssize result; + TaskErrorResult result; gboolean first_task_data_destroyed = FALSE; gboolean second_task_data_destroyed = FALSE; - gboolean notification_emitted = FALSE; task = g_task_new (NULL, NULL, error_callback, &result); + result = (TaskErrorResult){ + .expected_domain = G_IO_ERROR, + .expected_code = G_IO_ERROR_FAILED, + .expected_message = g_strdup_printf ("Failed %p", task), + }; g_object_add_weak_pointer (G_OBJECT (task), (gpointer *)&task); - g_signal_connect (task, "notify::completed", - (GCallback) completed_cb, ¬ification_emitted); g_assert (first_task_data_destroyed == FALSE); g_task_set_task_data (task, &first_task_data_destroyed, error_destroy_notify); @@ -197,12 +205,59 @@ test_error (void) g_assert (second_task_data_destroyed == FALSE); g_idle_add (error_return, task); - g_main_loop_run (loop); + wait_for_completed_notification (task); - g_assert_cmpint (result, ==, -1); + g_assert_cmpint (result.int_result, ==, -1); g_assert (second_task_data_destroyed == TRUE); - g_assert_true (notification_emitted); g_assert (task == NULL); + g_free (result.expected_message); +} + +static void +test_error_literal (void) +{ + GTask *task; + TaskErrorResult result; + + task = g_task_new (NULL, NULL, error_callback, &result); + result = (TaskErrorResult){ + .expected_domain = G_IO_ERROR, + .expected_code = G_IO_ERROR_FAILED, + .expected_message = "Literal Failure", + }; + + g_task_return_new_error_literal (task, + result.expected_domain, + result.expected_code, + "Literal Failure"); + + wait_for_completed_notification (task); + g_assert_cmpint (result.int_result, ==, -1); + + g_assert_finalize_object (task); +} + +static void +test_error_literal_from_variable (void) +{ + GTask *task; + TaskErrorResult result; + + task = g_task_new (NULL, NULL, error_callback, &result); + result = (TaskErrorResult){ + .expected_domain = G_IO_ERROR, + .expected_code = G_IO_ERROR_FAILED, + .expected_message = "Literal Failure", + }; + + g_task_return_new_error_literal (task, + result.expected_domain, + result.expected_code, + result.expected_message); + + wait_for_completed_notification (task); + g_assert_cmpint (result.int_result, ==, -1); + g_assert_finalize_object (task); } /* test_return_from_same_iteration: calling g_task_return_* from the @@ -2112,6 +2167,28 @@ test_return_value (void) g_assert_null (object); } +static void +test_return_prefixed_error (void) +{ + GTask *task; + GError *original_error = NULL; + GError *error = NULL; + + g_set_error (&original_error, G_IO_ERROR, G_IO_ERROR_UNKNOWN, "oh no!"); + + task = g_task_new (NULL, NULL, NULL, NULL); + g_task_return_prefixed_error (task, original_error, "task %s: ", "failed"); + + wait_for_completed_notification (task); + + g_assert_null (g_task_propagate_pointer (task, &error)); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_UNKNOWN); + g_assert_cmpstr (error->message, ==, "task failed: oh no!"); + + g_assert_finalize_object (task); + g_clear_error (&error); +} + /* test_object_keepalive: GTask takes a ref on its source object */ static GObject *keepalive_object; @@ -2502,6 +2579,8 @@ main (int argc, char **argv) g_test_add_func ("/gtask/basic", test_basic); g_test_add_func ("/gtask/error", test_error); + g_test_add_func ("/gtask/error-literal", test_error_literal); + g_test_add_func ("/gtask/error-literal-from-variable", test_error_literal_from_variable); g_test_add_func ("/gtask/return-from-same-iteration", test_return_from_same_iteration); g_test_add_func ("/gtask/return-from-toplevel", test_return_from_toplevel); g_test_add_func ("/gtask/return-from-anon-thread", test_return_from_anon_thread); @@ -2525,6 +2604,7 @@ main (int argc, char **argv) g_test_add_func ("/gtask/return-on-cancel-atomic", test_return_on_cancel_atomic); g_test_add_func ("/gtask/return-pointer", test_return_pointer); g_test_add_func ("/gtask/return-value", test_return_value); + g_test_add_func ("/gtask/return-prefixed-error", test_return_prefixed_error); g_test_add_func ("/gtask/object-keepalive", test_object_keepalive); g_test_add_func ("/gtask/legacy-error", test_legacy_error); g_test_add_func ("/gtask/return/in-idle/error-first", test_return_in_idle_error_first); diff --git a/gio/tests/tls-interaction.c b/gio/tests/tls-interaction.c index c0c58b5..a64181e 100644 --- a/gio/tests/tls-interaction.c +++ b/gio/tests/tls-interaction.c @@ -149,7 +149,7 @@ test_interaction_ask_password_async_failure (GTlsInteraction *interaction, task = g_task_new (self, cancellable, callback, user_data); - g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message"); + g_task_return_new_error_literal (task, G_FILE_ERROR, G_FILE_ERROR_ACCES, "The message"); g_object_unref (task); } @@ -348,7 +348,7 @@ test_interaction_request_certificate_async_failure (GTlsInteraction *interact task = g_task_new (self, cancellable, callback, user_data); - g_task_return_new_error (task, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message"); + g_task_return_new_error_literal (task, G_FILE_ERROR, G_FILE_ERROR_NOENT, "Another message"); g_object_unref (task); } diff --git a/gio/tests/win32-streams.c b/gio/tests/win32-streams.c index aea660d..222498a 100644 --- a/gio/tests/win32-streams.c +++ b/gio/tests/win32-streams.c @@ -340,17 +340,21 @@ test_pipe_io_overlap (void) PipeIOOverlapReader rs, rc; HANDLE server, client; gchar name[256]; + wchar_t *name_utf16; g_snprintf (name, sizeof (name), "\\\\.\\pipe\\gtest-io-overlap-%u", (guint) GetCurrentProcessId ()); - server = CreateNamedPipe (name, + name_utf16 = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL); + g_assert_nonnull (name_utf16); + + server = CreateNamedPipe (name_utf16, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0, 0, 0, NULL); g_assert (server != INVALID_HANDLE_VALUE); - client = CreateFile (name, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); + client = CreateFile (name_utf16, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, 0, NULL); g_assert (client != INVALID_HANDLE_VALUE); out_server = g_win32_output_stream_new (server, TRUE); @@ -372,6 +376,8 @@ test_pipe_io_overlap (void) g_object_unref (rc.in); g_object_unref (out_server); g_object_unref (out_client); + + g_free (name_utf16); } static gpointer @@ -419,18 +425,22 @@ test_pipe_io_concurrent (void) PipeIOOverlapReader rc1, rc2; HANDLE server, client; gchar name[256], c; + wchar_t *name_utf16; g_snprintf (name, sizeof (name), "\\\\.\\pipe\\gtest-io-concurrent-%u", (guint) GetCurrentProcessId ()); - server = CreateNamedPipe (name, + name_utf16 = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL); + g_assert_nonnull (name_utf16); + + server = CreateNamedPipe (name_utf16, PIPE_ACCESS_DUPLEX | FILE_FLAG_OVERLAPPED, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0, 0, 0, NULL); g_assert (server != INVALID_HANDLE_VALUE); g_assert (_pipe (writer_pipe, 10, _O_BINARY) == 0); - client = CreateFile (name, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); + client = CreateFile (name_utf16, GENERIC_WRITE | GENERIC_READ, 0, NULL, OPEN_EXISTING, FILE_FLAG_OVERLAPPED, NULL); g_assert (client != INVALID_HANDLE_VALUE); rc1.in = g_win32_input_stream_new (client, TRUE); @@ -467,6 +477,8 @@ test_pipe_io_concurrent (void) close (writer_pipe[0]); close (writer_pipe[1]); + + g_free (name_utf16); } static void @@ -491,17 +503,21 @@ test_pipe_io_cancel (void) GOutputStream *out; HANDLE in_handle, out_handle; gchar name[256]; + wchar_t *name_utf16; g_snprintf (name, sizeof (name), "\\\\.\\pipe\\gtest-io-cancel-%u", (guint) GetCurrentProcessId ()); - in_handle = CreateNamedPipe (name, + name_utf16 = g_utf8_to_utf16 (name, -1, NULL, NULL, NULL); + g_assert_nonnull (name_utf16); + + in_handle = CreateNamedPipe (name_utf16, PIPE_ACCESS_INBOUND | FILE_FLAG_OVERLAPPED, PIPE_READMODE_BYTE | PIPE_WAIT, 1, 0, 0, 0, NULL); g_assert (in_handle != INVALID_HANDLE_VALUE); - out_handle = CreateFile (name, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); + out_handle = CreateFile (name_utf16, GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL); g_assert (out_handle != INVALID_HANDLE_VALUE); in = g_win32_input_stream_new (in_handle, TRUE); @@ -521,6 +537,8 @@ test_pipe_io_cancel (void) g_object_unref (reader_cancel); g_object_unref (in); g_object_unref (out); + + g_free (name_utf16); } int diff --git a/girepository/cmph-bdz-test.c b/girepository/cmph-bdz-test.c new file mode 100644 index 0000000..aec4f79 --- /dev/null +++ b/girepository/cmph-bdz-test.c @@ -0,0 +1,156 @@ +/* GObject introspection: Test cmph hashing + * + * Copyright (C) 2010 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "cmph.h" + +static cmph_t * +build (void) +{ + cmph_config_t *config; + cmph_io_adapter_t *io; + char **strings; + cmph_t *c; + guint32 size; + + strings = g_strsplit ("foo,bar,baz", ",", -1); + + io = cmph_io_vector_adapter (strings, g_strv_length (strings)); + config = cmph_config_new (io); + cmph_config_set_algo (config, CMPH_BDZ); + + c = cmph_new (config); + size = cmph_size (c); + g_assert_cmpuint (size, ==, g_strv_length (strings)); + + cmph_config_destroy (config); + cmph_io_vector_adapter_destroy (io); + g_strfreev (strings); + + return c; +} + +static void +assert_hashes_unique (guint n_hashes, + guint32* hashes) +{ + guint i; + + for (i = 0; i < n_hashes; i++) + { + guint j = 0; + for (j = 0; j < n_hashes; j++) + { + if (j != i) + g_assert_cmpuint (hashes[i], !=, hashes[j]); + } + } +} + +static void +test_search (void) +{ + cmph_t *c = build(); + guint i; + guint32 hash; + guint32 hashes[3]; + guint32 size; + + size = cmph_size (c); + + i = 0; + hash = cmph_search (c, "foo", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + hash = cmph_search (c, "bar", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + hash = cmph_search (c, "baz", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + assert_hashes_unique (G_N_ELEMENTS (hashes), &hashes[0]); + + cmph_destroy (c); +} + +static void +test_search_packed (void) +{ + cmph_t *c = build(); + guint32 bufsize; + guint i; + guint32 hash; + guint32 hashes[3]; + guint32 size; + guint8 *buf; + + bufsize = cmph_packed_size (c); + buf = g_malloc (bufsize); + cmph_pack (c, buf); + + size = cmph_size (c); + + cmph_destroy (c); + c = NULL; + + i = 0; + hash = cmph_search_packed (buf, "foo", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + hash = cmph_search_packed (buf, "bar", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + hash = cmph_search_packed (buf, "baz", 3); + g_assert_cmpuint (hash, >=, 0); + g_assert_cmpuint (hash, <, size); + hashes[i++] = hash; + + assert_hashes_unique (G_N_ELEMENTS (hashes), &hashes[0]); + + g_free (buf); +} + +int +main(int argc, char **argv) +{ + gint ret; + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/cmph-bdz/search", test_search); + g_test_add_func ("/cmph-bdz/search-packed", test_search_packed); + + ret = g_test_run (); + + return ret; +} + diff --git a/girepository/cmph/README-CMPH-IMPORT.txt b/girepository/cmph/README-CMPH-IMPORT.txt new file mode 100644 index 0000000..a1c23c2 --- /dev/null +++ b/girepository/cmph/README-CMPH-IMPORT.txt @@ -0,0 +1,5 @@ +This import of CMPH was made from revision bfdcc3a3a18dfb9 of +git://cmph.git.sourceforge.net/gitroot/cmph/cmph + +Only the following files were taken, and everything else deleted: +COPYING src/*.[ch] diff --git a/girepository/cmph/bdz.c b/girepository/cmph/bdz.c new file mode 100644 index 0000000..e70f118 --- /dev/null +++ b/girepository/cmph/bdz.c @@ -0,0 +1,721 @@ +#include "bdz.h" +#include "cmph_structs.h" +#include "bdz_structs.h" +#include "hash.h" +#include "bitbool.h" + +#include +#include +#include +#include +#include +#include +//#define DEBUG +#include "debug.h" +#define UNASSIGNED 3U +#define NULL_EDGE 0xffffffff + +//cmph_uint32 ngrafos = 0; +//cmph_uint32 ngrafos_aciclicos = 0; +// table used for looking up the number of assigned vertices a 8-bit integer +const cmph_uint8 bdz_lookup_table[] = +{ +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +4, 4, 4, 3, 4, 4, 4, 3, 4, 4, 4, 3, 3, 3, 3, 2, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +3, 3, 3, 2, 3, 3, 3, 2, 3, 3, 3, 2, 2, 2, 2, 1, +2, 2, 2, 1, 2, 2, 2, 1, 2, 2, 2, 1, 1, 1, 1, 0 +}; + +typedef struct +{ + cmph_uint32 vertices[3]; + cmph_uint32 next_edges[3]; +}bdz_edge_t; + +typedef cmph_uint32 * bdz_queue_t; + +static void bdz_alloc_queue(bdz_queue_t * queuep, cmph_uint32 nedges) +{ + (*queuep)=malloc(nedges*sizeof(cmph_uint32)); +}; +static void bdz_free_queue(bdz_queue_t * queue) +{ + free(*queue); +}; + +typedef struct +{ + cmph_uint32 nedges; + bdz_edge_t * edges; + cmph_uint32 * first_edge; + cmph_uint8 * vert_degree; +}bdz_graph3_t; + + +static void bdz_alloc_graph3(bdz_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + graph3->edges=malloc(nedges*sizeof(bdz_edge_t)); + graph3->first_edge=malloc(nvertices*sizeof(cmph_uint32)); + graph3->vert_degree=malloc((size_t)nvertices); +}; +static void bdz_init_graph3(bdz_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + memset(graph3->first_edge,0xff,nvertices*sizeof(cmph_uint32)); + memset(graph3->vert_degree,0,(size_t)nvertices); + graph3->nedges=0; +}; +static void bdz_free_graph3(bdz_graph3_t *graph3) +{ + free(graph3->edges); + free(graph3->first_edge); + free(graph3->vert_degree); +}; + +static void bdz_partial_free_graph3(bdz_graph3_t *graph3) +{ + free(graph3->first_edge); + free(graph3->vert_degree); + graph3->first_edge = NULL; + graph3->vert_degree = NULL; +}; + +static void bdz_add_edge(bdz_graph3_t * graph3, cmph_uint32 v0, cmph_uint32 v1, cmph_uint32 v2) +{ + graph3->edges[graph3->nedges].vertices[0]=v0; + graph3->edges[graph3->nedges].vertices[1]=v1; + graph3->edges[graph3->nedges].vertices[2]=v2; + graph3->edges[graph3->nedges].next_edges[0]=graph3->first_edge[v0]; + graph3->edges[graph3->nedges].next_edges[1]=graph3->first_edge[v1]; + graph3->edges[graph3->nedges].next_edges[2]=graph3->first_edge[v2]; + graph3->first_edge[v0]=graph3->first_edge[v1]=graph3->first_edge[v2]=graph3->nedges; + graph3->vert_degree[v0]++; + graph3->vert_degree[v1]++; + graph3->vert_degree[v2]++; + graph3->nedges++; +}; + +static void bdz_dump_graph(bdz_graph3_t* graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + cmph_uint32 i; + for(i=0;iedges[i].vertices[0], + graph3->edges[i].vertices[1],graph3->edges[i].vertices[2]); + printf(" nexts %d %d %d",graph3->edges[i].next_edges[0], + graph3->edges[i].next_edges[1],graph3->edges[i].next_edges[2]); + }; + + for(i=0;ifirst_edge[i]); + + }; +}; + +static void bdz_remove_edge(bdz_graph3_t * graph3, cmph_uint32 curr_edge) +{ + cmph_uint32 i,j=0,vert,edge1,edge2; + for(i=0;i<3;i++){ + vert=graph3->edges[curr_edge].vertices[i]; + edge1=graph3->first_edge[vert]; + edge2=NULL_EDGE; + while(edge1!=curr_edge&&edge1!=NULL_EDGE){ + edge2=edge1; + if(graph3->edges[edge1].vertices[0]==vert){ + j=0; + } else if(graph3->edges[edge1].vertices[1]==vert){ + j=1; + } else + j=2; + edge1=graph3->edges[edge1].next_edges[j]; + }; + if(edge1==NULL_EDGE){ + printf("\nerror remove edge %d dump graph",curr_edge); + bdz_dump_graph(graph3,graph3->nedges,graph3->nedges+graph3->nedges/4); + exit(-1); + }; + + if(edge2!=NULL_EDGE){ + graph3->edges[edge2].next_edges[j] = + graph3->edges[edge1].next_edges[i]; + } else + graph3->first_edge[vert]= + graph3->edges[edge1].next_edges[i]; + graph3->vert_degree[vert]--; + }; + +}; + +static int bdz_generate_queue(cmph_uint32 nedges, cmph_uint32 nvertices, bdz_queue_t queue, bdz_graph3_t* graph3) +{ + cmph_uint32 i,v0,v1,v2; + cmph_uint32 queue_head=0,queue_tail=0; + cmph_uint32 curr_edge; + cmph_uint32 tmp_edge; + cmph_uint8 * marked_edge =malloc((size_t)(nedges >> 3) + 1); + memset(marked_edge, 0, (size_t)(nedges >> 3) + 1); + + for(i=0;iedges[i].vertices[0]; + v1=graph3->edges[i].vertices[1]; + v2=graph3->edges[i].vertices[2]; + if(graph3->vert_degree[v0]==1 || + graph3->vert_degree[v1]==1 || + graph3->vert_degree[v2]==1){ + if(!GETBIT(marked_edge,i)) { + queue[queue_head++]=i; + SETBIT(marked_edge,i); + } + }; + }; + while(queue_tail!=queue_head){ + curr_edge=queue[queue_tail++]; + bdz_remove_edge(graph3,curr_edge); + v0=graph3->edges[curr_edge].vertices[0]; + v1=graph3->edges[curr_edge].vertices[1]; + v2=graph3->edges[curr_edge].vertices[2]; + if(graph3->vert_degree[v0]==1 ) { + tmp_edge=graph3->first_edge[v0]; + if(!GETBIT(marked_edge,tmp_edge)) { + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + + }; + if(graph3->vert_degree[v1]==1) { + tmp_edge=graph3->first_edge[v1]; + if(!GETBIT(marked_edge,tmp_edge)){ + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + + }; + if(graph3->vert_degree[v2]==1){ + tmp_edge=graph3->first_edge[v2]; + if(!GETBIT(marked_edge,tmp_edge)){ + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + }; + }; + free(marked_edge); + return (int)(queue_head-nedges);/* returns 0 if successful otherwies return negative number*/ +}; + +static int bdz_mapping(cmph_config_t *mph, bdz_graph3_t* graph3, bdz_queue_t queue); +static void assigning(bdz_config_data_t *bdz, bdz_graph3_t* graph3, bdz_queue_t queue); +static void ranking(bdz_config_data_t *bdz); +static cmph_uint32 rank(cmph_uint32 b, cmph_uint32 * ranktable, cmph_uint8 * g, cmph_uint32 vertex); + +bdz_config_data_t *bdz_config_new(void) +{ + bdz_config_data_t *bdz; + bdz = (bdz_config_data_t *)malloc(sizeof(bdz_config_data_t)); + assert(bdz); + memset(bdz, 0, sizeof(bdz_config_data_t)); + bdz->hashfunc = CMPH_HASH_JENKINS; + bdz->g = NULL; + bdz->hl = NULL; + bdz->k = 0; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$ + bdz->b = 7; // number of bits of k + bdz->ranktablesize = 0; //number of entries in ranktable, $n/k +1$ + bdz->ranktable = NULL; // rank table + return bdz; +} + +void bdz_config_destroy(cmph_config_t *mph) +{ + bdz_config_data_t *data = (bdz_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void bdz_config_set_b(cmph_config_t *mph, cmph_uint32 b) +{ + bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data; + if (b <= 2 || b > 10) b = 7; // validating restrictions over parameter b. + bdz->b = (cmph_uint8)b; + DEBUGP("b: %u\n", b); + +} + +void bdz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 1) break; //bdz only uses one linear hash function + bdz->hashfunc = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *bdz_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + bdz_data_t *bdzf = NULL; + cmph_uint32 iterations; + bdz_queue_t edges; + bdz_graph3_t graph3; + bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data; + #ifdef CMPH_TIMING + double construction_time_begin = 0.0; + double construction_time = 0.0; + ELAPSED_TIME_IN_SECONDS(&construction_time_begin); + #endif + + + if (c == 0) c = 1.23; // validating restrictions over parameter c. + DEBUGP("c: %f\n", c); + bdz->m = mph->key_source->nkeys; + bdz->r = (cmph_uint32)ceil((c * mph->key_source->nkeys)/3); + if ((bdz->r % 2) == 0) bdz->r+=1; + bdz->n = 3*bdz->r; + + bdz->k = (1U << bdz->b); + DEBUGP("b: %u -- k: %u\n", bdz->b, bdz->k); + + bdz->ranktablesize = (cmph_uint32)ceil(bdz->n/(double)bdz->k); + DEBUGP("ranktablesize: %u\n", bdz->ranktablesize); + + + bdz_alloc_graph3(&graph3, bdz->m, bdz->n); + bdz_alloc_queue(&edges,bdz->m); + DEBUGP("Created hypergraph\n"); + + DEBUGP("m (edges): %u n (vertices): %u r: %u c: %f \n", bdz->m, bdz->n, bdz->r, c); + + // Mapping step + iterations = 1000; + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n); + } + while(1) + { + int ok; + DEBUGP("linear hash function \n"); + bdz->hl = hash_state_new(bdz->hashfunc, 15); + + ok = bdz_mapping(mph, &graph3, edges); + //ok = 0; + if (!ok) + { + --iterations; + hash_state_destroy(bdz->hl); + bdz->hl = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "acyclic graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + + if (iterations == 0) + { + bdz_free_queue(&edges); + bdz_free_graph3(&graph3); + return NULL; + } + bdz_partial_free_graph3(&graph3); + // Assigning step + if (mph->verbosity) + { + fprintf(stderr, "Entering assigning step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n); + } + assigning(bdz, &graph3, edges); + + bdz_free_queue(&edges); + bdz_free_graph3(&graph3); + if (mph->verbosity) + { + fprintf(stderr, "Entering ranking step for mph creation of %u keys with graph sized %u\n", bdz->m, bdz->n); + } + ranking(bdz); + #ifdef CMPH_TIMING + ELAPSED_TIME_IN_SECONDS(&construction_time); + #endif + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + bdzf = (bdz_data_t *)malloc(sizeof(bdz_data_t)); + bdzf->g = bdz->g; + bdz->g = NULL; //transfer memory ownership + bdzf->hl = bdz->hl; + bdz->hl = NULL; //transfer memory ownership + bdzf->ranktable = bdz->ranktable; + bdz->ranktable = NULL; //transfer memory ownership + bdzf->ranktablesize = bdz->ranktablesize; + bdzf->k = bdz->k; + bdzf->b = bdz->b; + bdzf->n = bdz->n; + bdzf->m = bdz->m; + bdzf->r = bdz->r; + mphf->data = bdzf; + mphf->size = bdz->m; + + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + + + #ifdef CMPH_TIMING + register cmph_uint32 space_usage = bdz_packed_size(mphf)*8; + register cmph_uint32 keys_per_bucket = 1; + construction_time = construction_time - construction_time_begin; + fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", bdz->m, bdz->m/(double)bdz->n, keys_per_bucket, construction_time, space_usage/(double)bdz->m); + #endif + + return mphf; +} + + +static int bdz_mapping(cmph_config_t *mph, bdz_graph3_t* graph3, bdz_queue_t queue) +{ + cmph_uint32 e; + int cycles = 0; + cmph_uint32 hl[3]; + bdz_config_data_t *bdz = (bdz_config_data_t *)mph->data; + bdz_init_graph3(graph3, bdz->m, bdz->n); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint32 h0, h1, h2; + cmph_uint32 keylen; + char *key = NULL; + mph->key_source->read(mph->key_source->data, &key, &keylen); + hash_vector(bdz->hl, key, keylen,hl); + h0 = hl[0] % bdz->r; + h1 = hl[1] % bdz->r + bdz->r; + h2 = hl[2] % bdz->r + (bdz->r << 1); + mph->key_source->dispose(mph->key_source->data, key, keylen); + bdz_add_edge(graph3,h0,h1,h2); + } + cycles = bdz_generate_queue(bdz->m, bdz->n, queue, graph3); + return (cycles == 0); +} + +static void assigning(bdz_config_data_t *bdz, bdz_graph3_t* graph3, bdz_queue_t queue) +{ + cmph_uint32 i; + cmph_uint32 nedges=graph3->nedges; + cmph_uint32 curr_edge; + cmph_uint32 v0,v1,v2; + cmph_uint8 * marked_vertices =malloc((size_t)(bdz->n >> 3) + 1); + cmph_uint32 sizeg = (cmph_uint32)ceil(bdz->n/4.0); + bdz->g = (cmph_uint8 *)calloc((size_t)(sizeg), sizeof(cmph_uint8)); + memset(marked_vertices, 0, (size_t)(bdz->n >> 3) + 1); + memset(bdz->g, 0xff, (size_t)(sizeg)); + + for(i=nedges-1;i+1>0;i--){ + curr_edge=queue[i]; + v0=graph3->edges[curr_edge].vertices[0]; + v1=graph3->edges[curr_edge].vertices[1]; + v2=graph3->edges[curr_edge].vertices[2]; + DEBUGP("B:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz->g, v0), GETVALUE(bdz->g, v1), GETVALUE(bdz->g, v2)); + if(!GETBIT(marked_vertices, v0)){ + if(!GETBIT(marked_vertices,v1)) + { + SETVALUE1(bdz->g, v1, UNASSIGNED); + SETBIT(marked_vertices, v1); + } + if(!GETBIT(marked_vertices,v2)) + { + SETVALUE1(bdz->g, v2, UNASSIGNED); + SETBIT(marked_vertices, v2); + } + SETVALUE1(bdz->g, v0, (6-(GETVALUE(bdz->g, v1) + GETVALUE(bdz->g,v2)))%3); + SETBIT(marked_vertices, v0); + } else if(!GETBIT(marked_vertices, v1)) { + if(!GETBIT(marked_vertices, v2)) + { + SETVALUE1(bdz->g, v2, UNASSIGNED); + SETBIT(marked_vertices, v2); + } + SETVALUE1(bdz->g, v1, (7-(GETVALUE(bdz->g, v0)+GETVALUE(bdz->g, v2)))%3); + SETBIT(marked_vertices, v1); + }else { + SETVALUE1(bdz->g, v2, (8-(GETVALUE(bdz->g,v0)+GETVALUE(bdz->g, v1)))%3); + SETBIT(marked_vertices, v2); + } + DEBUGP("A:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz->g, v0), GETVALUE(bdz->g, v1), GETVALUE(bdz->g, v2)); + }; + free(marked_vertices); +} + + +static void ranking(bdz_config_data_t *bdz) +{ + cmph_uint32 i, j, offset = 0U, count = 0U, size = (bdz->k >> 2U), nbytes_total = (cmph_uint32)ceil(bdz->n/4.0), nbytes; + bdz->ranktable = (cmph_uint32 *)calloc((size_t)bdz->ranktablesize, sizeof(cmph_uint32)); + // ranktable computation + bdz->ranktable[0] = 0; + i = 1; + while(1) + { + if(i == bdz->ranktablesize) break; + nbytes = size < nbytes_total? size : nbytes_total; + for(j = 0; j < nbytes; j++) + { + count += bdz_lookup_table[*(bdz->g + offset + j)]; + } + bdz->ranktable[i] = count; + offset += nbytes; + nbytes_total -= size; + i++; + } +} + + +int bdz_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + bdz_data_t *data = (bdz_data_t *)mphf->data; + cmph_uint32 sizeg; +#ifdef DEBUG + cmph_uint32 i; +#endif + __cmph_dump(mphf, fd); + + hash_state_dump(data->hl, &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->r), sizeof(cmph_uint32), (size_t)1, fd); + + sizeg = (cmph_uint32)ceil(data->n/4.0); + nbytes = fwrite(data->g, sizeof(cmph_uint8)*sizeg, (size_t)1, fd); + + nbytes = fwrite(&(data->k), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->b), sizeof(cmph_uint8), (size_t)1, fd); + nbytes = fwrite(&(data->ranktablesize), sizeof(cmph_uint32), (size_t)1, fd); + + nbytes = fwrite(data->ranktable, sizeof(cmph_uint32)*(data->ranktablesize), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", GETVALUE(data->g, i)); + fprintf(stderr, "\n"); + #endif + return 1; +} + +void bdz_load(FILE *f, cmph_t *mphf) +{ + char *buf = NULL; + cmph_uint32 buflen, sizeg; + register size_t nbytes; + bdz_data_t *bdz = (bdz_data_t *)malloc(sizeof(bdz_data_t)); +#ifdef DEBUG + cmph_uint32 i = 0; +#endif + + DEBUGP("Loading bdz mphf\n"); + mphf->data = bdz; + + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + bdz->hl = hash_state_load(buf, buflen); + free(buf); + + + DEBUGP("Reading m and n\n"); + nbytes = fread(&(bdz->n), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bdz->m), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bdz->r), sizeof(cmph_uint32), (size_t)1, f); + sizeg = (cmph_uint32)ceil(bdz->n/4.0); + bdz->g = (cmph_uint8 *)calloc((size_t)(sizeg), sizeof(cmph_uint8)); + nbytes = fread(bdz->g, sizeg*sizeof(cmph_uint8), (size_t)1, f); + + nbytes = fread(&(bdz->k), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bdz->b), sizeof(cmph_uint8), (size_t)1, f); + nbytes = fread(&(bdz->ranktablesize), sizeof(cmph_uint32), (size_t)1, f); + + bdz->ranktable = (cmph_uint32 *)calloc((size_t)bdz->ranktablesize, sizeof(cmph_uint32)); + nbytes = fread(bdz->ranktable, sizeof(cmph_uint32)*(bdz->ranktablesize), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return; + } + + #ifdef DEBUG + i = 0; + fprintf(stderr, "G: "); + for (i = 0; i < bdz->n; ++i) fprintf(stderr, "%u ", GETVALUE(bdz->g,i)); + fprintf(stderr, "\n"); + #endif + return; +} + + +/* +static cmph_uint32 bdz_search_ph(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + bdz_data_t *bdz = mphf->data; + cmph_uint32 hl[3]; + hash_vector(bdz->hl, key, keylen, hl); + cmph_uint32 vertex; + hl[0] = hl[0] % bdz->r; + hl[1] = hl[1] % bdz->r + bdz->r; + hl[2] = hl[2] % bdz->r + (bdz->r << 1); + vertex = hl[(GETVALUE(bdz->g, hl[0]) + GETVALUE(bdz->g, hl[1]) + GETVALUE(bdz->g, hl[2])) % 3]; + return vertex; +} +*/ + +static inline cmph_uint32 rank(cmph_uint32 b, cmph_uint32 * ranktable, cmph_uint8 * g, cmph_uint32 vertex) +{ + register cmph_uint32 index = vertex >> b; + register cmph_uint32 base_rank = ranktable[index]; + register cmph_uint32 beg_idx_v = index << b; + register cmph_uint32 beg_idx_b = beg_idx_v >> 2; + register cmph_uint32 end_idx_b = vertex >> 2; + while(beg_idx_b < end_idx_b) + { + base_rank += bdz_lookup_table[*(g + beg_idx_b++)]; + + } + beg_idx_v = beg_idx_b << 2; + while(beg_idx_v < vertex) + { + if(GETVALUE(g, beg_idx_v) != UNASSIGNED) base_rank++; + beg_idx_v++; + } + + return base_rank; +} + +cmph_uint32 bdz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint32 vertex; + register bdz_data_t *bdz = mphf->data; + cmph_uint32 hl[3]; + hash_vector(bdz->hl, key, keylen, hl); + hl[0] = hl[0] % bdz->r; + hl[1] = hl[1] % bdz->r + bdz->r; + hl[2] = hl[2] % bdz->r + (bdz->r << 1); + vertex = hl[(GETVALUE(bdz->g, hl[0]) + GETVALUE(bdz->g, hl[1]) + GETVALUE(bdz->g, hl[2])) % 3]; + return rank(bdz->b, bdz->ranktable, bdz->g, vertex); +} + + +void bdz_destroy(cmph_t *mphf) +{ + bdz_data_t *data = (bdz_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hl); + free(data->ranktable); + free(data); + free(mphf); +} + +/** \fn void bdz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bdz_pack(cmph_t *mphf, void *packed_mphf) +{ + bdz_data_t *data = (bdz_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + cmph_uint32 sizeg; + + // packing hl type + CMPH_HASH hl_type = hash_get_type(data->hl); + *((cmph_uint32 *) ptr) = hl_type; + ptr += sizeof(cmph_uint32); + + // packing hl + hash_state_pack(data->hl, ptr); + ptr += hash_state_packed_size(hl_type); + + // packing r + *((cmph_uint32 *) ptr) = data->r; + ptr += sizeof(data->r); + + // packing ranktablesize + *((cmph_uint32 *) ptr) = data->ranktablesize; + ptr += sizeof(data->ranktablesize); + + // packing ranktable + memcpy(ptr, data->ranktable, sizeof(cmph_uint32)*(data->ranktablesize)); + ptr += sizeof(cmph_uint32)*(data->ranktablesize); + + // packing b + *ptr++ = data->b; + + // packing g + sizeg = (cmph_uint32)ceil(data->n/4.0); + memcpy(ptr, data->g, sizeof(cmph_uint8)*sizeg); +} + +/** \fn cmph_uint32 bdz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bdz_packed_size(cmph_t *mphf) +{ + bdz_data_t *data = (bdz_data_t *)mphf->data; + + CMPH_HASH hl_type = hash_get_type(data->hl); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(hl_type) + 3*sizeof(cmph_uint32) + sizeof(cmph_uint32)*(data->ranktablesize) + sizeof(cmph_uint8) + sizeof(cmph_uint8)* (cmph_uint32)(ceil(data->n/4.0))); +} + +/** cmph_uint32 bdz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bdz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + + register cmph_uint32 vertex; + register CMPH_HASH hl_type = *(cmph_uint32 *)packed_mphf; + register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4; + + register cmph_uint32 *ranktable = (cmph_uint32*)(hl_ptr + hash_state_packed_size(hl_type)); + + register cmph_uint32 r = *ranktable++; + register cmph_uint32 ranktablesize = *ranktable++; + register cmph_uint8 * g = (cmph_uint8 *)(ranktable + ranktablesize); + register cmph_uint8 b = *g++; + + cmph_uint32 hl[3]; + hash_vector_packed(hl_ptr, hl_type, key, keylen, hl); + hl[0] = hl[0] % r; + hl[1] = hl[1] % r + r; + hl[2] = hl[2] % r + (r << 1); + vertex = hl[(GETVALUE(g, hl[0]) + GETVALUE(g, hl[1]) + GETVALUE(g, hl[2])) % 3]; + return rank(b, ranktable, g, vertex); +} diff --git a/girepository/cmph/bdz.h b/girepository/cmph/bdz.h new file mode 100644 index 0000000..7116933 --- /dev/null +++ b/girepository/cmph/bdz.h @@ -0,0 +1,43 @@ +#ifndef __CMPH_BDZ_H__ +#define __CMPH_BDZ_H__ + +#include "cmph.h" + +typedef struct __bdz_data_t bdz_data_t; +typedef struct __bdz_config_data_t bdz_config_data_t; + +bdz_config_data_t *bdz_config_new(void); +void bdz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void bdz_config_destroy(cmph_config_t *mph); +void bdz_config_set_b(cmph_config_t *mph, cmph_uint32 b); +cmph_t *bdz_new(cmph_config_t *mph, double c); + +void bdz_load(FILE *f, cmph_t *mphf); +int bdz_dump(cmph_t *mphf, FILE *f); +void bdz_destroy(cmph_t *mphf); +cmph_uint32 bdz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void bdz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bdz_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 bdz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bdz_packed_size(cmph_t *mphf); + +/** cmph_uint32 bdz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bdz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/bdz_gen_lookup_table.c b/girepository/cmph/bdz_gen_lookup_table.c new file mode 100644 index 0000000..b8f6606 --- /dev/null +++ b/girepository/cmph/bdz_gen_lookup_table.c @@ -0,0 +1,33 @@ +#include +#include +#include +void help(char * prname) +{ + fprintf(stderr, "USE: %s \n", prname); + exit(1); +} + +int main(int argc, char ** argv) +{ + if(argc != 3) help(argv[0]); + int n = atoi(argv[1]); + int wordsize = (atoi(argv[2]) >> 1); + int i, j, n_assigned; + for(i = 0; i < n; i++) + { + int num = i; + n_assigned = 0; + for(j = 0; j < wordsize; j++) + { + if ((num & 0x0003) != 3) + { + n_assigned++; + //fprintf(stderr, "num:%d\n", num); + } + num = num >> 2; + } + if(i%16 == 0) fprintf(stderr, "\n"); + fprintf(stderr, "%d, ", n_assigned); + } + fprintf(stderr, "\n"); +} diff --git a/girepository/cmph/bdz_ph.c b/girepository/cmph/bdz_ph.c new file mode 100644 index 0000000..2095f11 --- /dev/null +++ b/girepository/cmph/bdz_ph.c @@ -0,0 +1,633 @@ +#include "bdz_ph.h" +#include "cmph_structs.h" +#include "bdz_structs_ph.h" +#include "hash.h" +#include "bitbool.h" + +#include +#include +#include +#include +#include +#include +//#define DEBUG +#include "debug.h" +#define UNASSIGNED 3 +#define NULL_EDGE 0xffffffff + + +static cmph_uint8 pow3_table[5] = {1,3,9,27,81}; +static cmph_uint8 lookup_table[5][256] = { + {0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0, 1, 2, 0}, + {0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1, 1, 1, 2, 2, 2, 0, 0, 0, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, + {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}, +}; + +typedef struct +{ + cmph_uint32 vertices[3]; + cmph_uint32 next_edges[3]; +}bdz_ph_edge_t; + +typedef cmph_uint32 * bdz_ph_queue_t; + +static void bdz_ph_alloc_queue(bdz_ph_queue_t * queuep, cmph_uint32 nedges) +{ + (*queuep)=malloc(nedges*sizeof(cmph_uint32)); +}; +static void bdz_ph_free_queue(bdz_ph_queue_t * queue) +{ + free(*queue); +}; + +typedef struct +{ + cmph_uint32 nedges; + bdz_ph_edge_t * edges; + cmph_uint32 * first_edge; + cmph_uint8 * vert_degree; +}bdz_ph_graph3_t; + + +static void bdz_ph_alloc_graph3(bdz_ph_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + graph3->edges=malloc(nedges*sizeof(bdz_ph_edge_t)); + graph3->first_edge=malloc(nvertices*sizeof(cmph_uint32)); + graph3->vert_degree=malloc((size_t)nvertices); +}; +static void bdz_ph_init_graph3(bdz_ph_graph3_t * graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + memset(graph3->first_edge,0xff,nvertices*sizeof(cmph_uint32)); + memset(graph3->vert_degree,0,(size_t)nvertices); + graph3->nedges=0; +}; +static void bdz_ph_free_graph3(bdz_ph_graph3_t *graph3) +{ + free(graph3->edges); + free(graph3->first_edge); + free(graph3->vert_degree); +}; + +static void bdz_ph_partial_free_graph3(bdz_ph_graph3_t *graph3) +{ + free(graph3->first_edge); + free(graph3->vert_degree); + graph3->first_edge = NULL; + graph3->vert_degree = NULL; +}; + +static void bdz_ph_add_edge(bdz_ph_graph3_t * graph3, cmph_uint32 v0, cmph_uint32 v1, cmph_uint32 v2) +{ + graph3->edges[graph3->nedges].vertices[0]=v0; + graph3->edges[graph3->nedges].vertices[1]=v1; + graph3->edges[graph3->nedges].vertices[2]=v2; + graph3->edges[graph3->nedges].next_edges[0]=graph3->first_edge[v0]; + graph3->edges[graph3->nedges].next_edges[1]=graph3->first_edge[v1]; + graph3->edges[graph3->nedges].next_edges[2]=graph3->first_edge[v2]; + graph3->first_edge[v0]=graph3->first_edge[v1]=graph3->first_edge[v2]=graph3->nedges; + graph3->vert_degree[v0]++; + graph3->vert_degree[v1]++; + graph3->vert_degree[v2]++; + graph3->nedges++; +}; + +static void bdz_ph_dump_graph(bdz_ph_graph3_t* graph3, cmph_uint32 nedges, cmph_uint32 nvertices) +{ + cmph_uint32 i; + for(i=0;iedges[i].vertices[0], + graph3->edges[i].vertices[1],graph3->edges[i].vertices[2]); + printf(" nexts %d %d %d",graph3->edges[i].next_edges[0], + graph3->edges[i].next_edges[1],graph3->edges[i].next_edges[2]); + }; + + for(i=0;ifirst_edge[i]); + + }; +}; + +static void bdz_ph_remove_edge(bdz_ph_graph3_t * graph3, cmph_uint32 curr_edge) +{ + cmph_uint32 i,j=0,vert,edge1,edge2; + for(i=0;i<3;i++){ + vert=graph3->edges[curr_edge].vertices[i]; + edge1=graph3->first_edge[vert]; + edge2=NULL_EDGE; + while(edge1!=curr_edge&&edge1!=NULL_EDGE){ + edge2=edge1; + if(graph3->edges[edge1].vertices[0]==vert){ + j=0; + } else if(graph3->edges[edge1].vertices[1]==vert){ + j=1; + } else + j=2; + edge1=graph3->edges[edge1].next_edges[j]; + }; + if(edge1==NULL_EDGE){ + printf("\nerror remove edge %d dump graph",curr_edge); + bdz_ph_dump_graph(graph3,graph3->nedges,graph3->nedges+graph3->nedges/4); + exit(-1); + }; + + if(edge2!=NULL_EDGE){ + graph3->edges[edge2].next_edges[j] = + graph3->edges[edge1].next_edges[i]; + } else + graph3->first_edge[vert]= + graph3->edges[edge1].next_edges[i]; + graph3->vert_degree[vert]--; + }; + +}; + +static int bdz_ph_generate_queue(cmph_uint32 nedges, cmph_uint32 nvertices, bdz_ph_queue_t queue, bdz_ph_graph3_t* graph3) +{ + cmph_uint32 i,v0,v1,v2; + cmph_uint32 queue_head=0,queue_tail=0; + cmph_uint32 curr_edge; + cmph_uint32 tmp_edge; + cmph_uint8 * marked_edge =malloc((size_t)(nedges >> 3) + 1); + memset(marked_edge, 0, (size_t)(nedges >> 3) + 1); + + for(i=0;iedges[i].vertices[0]; + v1=graph3->edges[i].vertices[1]; + v2=graph3->edges[i].vertices[2]; + if(graph3->vert_degree[v0]==1 || + graph3->vert_degree[v1]==1 || + graph3->vert_degree[v2]==1){ + if(!GETBIT(marked_edge,i)) { + queue[queue_head++]=i; + SETBIT(marked_edge,i); + } + }; + }; + while(queue_tail!=queue_head){ + curr_edge=queue[queue_tail++]; + bdz_ph_remove_edge(graph3,curr_edge); + v0=graph3->edges[curr_edge].vertices[0]; + v1=graph3->edges[curr_edge].vertices[1]; + v2=graph3->edges[curr_edge].vertices[2]; + if(graph3->vert_degree[v0]==1 ) { + tmp_edge=graph3->first_edge[v0]; + if(!GETBIT(marked_edge,tmp_edge)) { + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + + }; + if(graph3->vert_degree[v1]==1) { + tmp_edge=graph3->first_edge[v1]; + if(!GETBIT(marked_edge,tmp_edge)){ + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + + }; + if(graph3->vert_degree[v2]==1){ + tmp_edge=graph3->first_edge[v2]; + if(!GETBIT(marked_edge,tmp_edge)){ + queue[queue_head++]=tmp_edge; + SETBIT(marked_edge,tmp_edge); + }; + }; + }; + free(marked_edge); + return (int)queue_head - (int)nedges;/* returns 0 if successful otherwies return negative number*/ +}; + +static int bdz_ph_mapping(cmph_config_t *mph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue); +static void assigning(bdz_ph_config_data_t *bdz_ph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue); +static void bdz_ph_optimization(bdz_ph_config_data_t *bdz_ph); + +bdz_ph_config_data_t *bdz_ph_config_new(void) +{ + bdz_ph_config_data_t *bdz_ph; + bdz_ph = (bdz_ph_config_data_t *)malloc(sizeof(bdz_ph_config_data_t)); + assert(bdz_ph); + memset(bdz_ph, 0, sizeof(bdz_ph_config_data_t)); + bdz_ph->hashfunc = CMPH_HASH_JENKINS; + bdz_ph->g = NULL; + bdz_ph->hl = NULL; + return bdz_ph; +} + +void bdz_ph_config_destroy(cmph_config_t *mph) +{ + bdz_ph_config_data_t *data = (bdz_ph_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void bdz_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 1) break; //bdz_ph only uses one linear hash function + bdz_ph->hashfunc = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *bdz_ph_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + bdz_ph_data_t *bdz_phf = NULL; + cmph_uint32 iterations; + bdz_ph_queue_t edges; + bdz_ph_graph3_t graph3; + bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data; + #ifdef CMPH_TIMING + double construction_time_begin = 0.0; + double construction_time = 0.0; + ELAPSED_TIME_IN_SECONDS(&construction_time_begin); + #endif + + + if (c == 0) c = 1.23; // validating restrictions over parameter c. + DEBUGP("c: %f\n", c); + bdz_ph->m = mph->key_source->nkeys; + bdz_ph->r = (cmph_uint32)ceil((c * mph->key_source->nkeys)/3); + if ((bdz_ph->r % 2) == 0) bdz_ph->r += 1; + bdz_ph->n = 3*bdz_ph->r; + + + bdz_ph_alloc_graph3(&graph3, bdz_ph->m, bdz_ph->n); + bdz_ph_alloc_queue(&edges,bdz_ph->m); + DEBUGP("Created hypergraph\n"); + + DEBUGP("m (edges): %u n (vertices): %u r: %u c: %f \n", bdz_ph->m, bdz_ph->n, bdz_ph->r, c); + + // Mapping step + iterations = 100; + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bdz_ph->m, bdz_ph->n); + } + while(1) + { + int ok; + DEBUGP("linear hash function \n"); + bdz_ph->hl = hash_state_new(bdz_ph->hashfunc, 15); + + ok = bdz_ph_mapping(mph, &graph3, edges); + if (!ok) + { + --iterations; + hash_state_destroy(bdz_ph->hl); + bdz_ph->hl = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "acyclic graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + + if (iterations == 0) + { +// free(bdz_ph->g); + bdz_ph_free_queue(&edges); + bdz_ph_free_graph3(&graph3); + return NULL; + } + bdz_ph_partial_free_graph3(&graph3); + // Assigning step + if (mph->verbosity) + { + fprintf(stderr, "Entering assigning step for mph creation of %u keys with graph sized %u\n", bdz_ph->m, bdz_ph->n); + } + assigning(bdz_ph, &graph3, edges); + + bdz_ph_free_queue(&edges); + bdz_ph_free_graph3(&graph3); + + if (mph->verbosity) + { + fprintf(stderr, "Starting optimization step\n"); + } + + bdz_ph_optimization(bdz_ph); + + #ifdef CMPH_TIMING + ELAPSED_TIME_IN_SECONDS(&construction_time); + #endif + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + bdz_phf = (bdz_ph_data_t *)malloc(sizeof(bdz_ph_data_t)); + bdz_phf->g = bdz_ph->g; + bdz_ph->g = NULL; //transfer memory ownership + bdz_phf->hl = bdz_ph->hl; + bdz_ph->hl = NULL; //transfer memory ownership + bdz_phf->n = bdz_ph->n; + bdz_phf->m = bdz_ph->m; + bdz_phf->r = bdz_ph->r; + mphf->data = bdz_phf; + mphf->size = bdz_ph->n; + + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + + #ifdef CMPH_TIMING + register cmph_uint32 space_usage = bdz_ph_packed_size(mphf)*8; + register cmph_uint32 keys_per_bucket = 1; + construction_time = construction_time - construction_time_begin; + fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", bdz_ph->m, bdz_ph->m/(double)bdz_ph->n, keys_per_bucket, construction_time, space_usage/(double)bdz_ph->m); + #endif + + return mphf; +} + + +static int bdz_ph_mapping(cmph_config_t *mph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue) +{ + cmph_uint32 e; + int cycles = 0; + cmph_uint32 hl[3]; + + bdz_ph_config_data_t *bdz_ph = (bdz_ph_config_data_t *)mph->data; + bdz_ph_init_graph3(graph3, bdz_ph->m, bdz_ph->n); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint32 h0, h1, h2; + cmph_uint32 keylen; + char *key = NULL; + mph->key_source->read(mph->key_source->data, &key, &keylen); + hash_vector(bdz_ph->hl, key, keylen, hl); + h0 = hl[0] % bdz_ph->r; + h1 = hl[1] % bdz_ph->r + bdz_ph->r; + h2 = hl[2] % bdz_ph->r + (bdz_ph->r << 1); + mph->key_source->dispose(mph->key_source->data, key, keylen); + bdz_ph_add_edge(graph3,h0,h1,h2); + } + cycles = bdz_ph_generate_queue(bdz_ph->m, bdz_ph->n, queue, graph3); + return (cycles == 0); +} + +static void assigning(bdz_ph_config_data_t *bdz_ph, bdz_ph_graph3_t* graph3, bdz_ph_queue_t queue) +{ + cmph_uint32 i; + cmph_uint32 nedges=graph3->nedges; + cmph_uint32 curr_edge; + cmph_uint32 v0,v1,v2; + cmph_uint8 * marked_vertices =malloc((size_t)(bdz_ph->n >> 3) + 1); + cmph_uint32 sizeg = (cmph_uint32)ceil(bdz_ph->n/4.0); + bdz_ph->g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8)); + memset(marked_vertices, 0, (size_t)(bdz_ph->n >> 3) + 1); + //memset(bdz_ph->g, 0xff, sizeg); + + for(i=nedges-1;i+1>=1;i--){ + curr_edge=queue[i]; + v0=graph3->edges[curr_edge].vertices[0]; + v1=graph3->edges[curr_edge].vertices[1]; + v2=graph3->edges[curr_edge].vertices[2]; + DEBUGP("B:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz_ph->g, v0), GETVALUE(bdz_ph->g, v1), GETVALUE(bdz_ph->g, v2)); + if(!GETBIT(marked_vertices, v0)){ + if(!GETBIT(marked_vertices,v1)) + { + //SETVALUE(bdz_ph->g, v1, UNASSIGNED); + SETBIT(marked_vertices, v1); + } + if(!GETBIT(marked_vertices,v2)) + { + //SETVALUE(bdz_ph->g, v2, UNASSIGNED); + SETBIT(marked_vertices, v2); + } + SETVALUE0(bdz_ph->g, v0, (6-(GETVALUE(bdz_ph->g, v1) + GETVALUE(bdz_ph->g,v2)))%3); + SETBIT(marked_vertices, v0); + } else if(!GETBIT(marked_vertices, v1)) { + if(!GETBIT(marked_vertices, v2)) + { + //SETVALUE(bdz_ph->g, v2, UNASSIGNED); + SETBIT(marked_vertices, v2); + } + SETVALUE0(bdz_ph->g, v1, (7 - (GETVALUE(bdz_ph->g, v0)+GETVALUE(bdz_ph->g, v2)))%3); + SETBIT(marked_vertices, v1); + }else { + SETVALUE0(bdz_ph->g, v2, (8-(GETVALUE(bdz_ph->g,v0)+GETVALUE(bdz_ph->g, v1)))%3); + SETBIT(marked_vertices, v2); + } + DEBUGP("A:%u %u %u -- %u %u %u\n", v0, v1, v2, GETVALUE(bdz_ph->g, v0), GETVALUE(bdz_ph->g, v1), GETVALUE(bdz_ph->g, v2)); + }; + free(marked_vertices); +} + +static void bdz_ph_optimization(bdz_ph_config_data_t *bdz_ph) +{ + cmph_uint32 i; + cmph_uint8 byte = 0; + cmph_uint32 sizeg = (cmph_uint32)ceil(bdz_ph->n/5.0); + cmph_uint8 * new_g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8)); + cmph_uint8 value; + cmph_uint32 idx; + for(i = 0; i < bdz_ph->n; i++) + { + idx = i/5; + byte = new_g[idx]; + value = GETVALUE(bdz_ph->g, i); + byte = (cmph_uint8) (byte + value*pow3_table[i%5U]); + new_g[idx] = byte; + } + free(bdz_ph->g); + bdz_ph->g = new_g; +} + + +int bdz_ph_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 sizeg = 0; + register size_t nbytes; + bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data; +#ifdef DEBUG + cmph_uint32 i; +#endif + + __cmph_dump(mphf, fd); + + hash_state_dump(data->hl, &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->r), sizeof(cmph_uint32), (size_t)1, fd); + sizeg = (cmph_uint32)ceil(data->n/5.0); + nbytes = fwrite(data->g, sizeof(cmph_uint8)*sizeg, (size_t)1, fd); + + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", GETVALUE(data->g, i)); + fprintf(stderr, "\n"); + #endif + return 1; +} + +void bdz_ph_load(FILE *f, cmph_t *mphf) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 sizeg = 0; + register size_t nbytes; + bdz_ph_data_t *bdz_ph = (bdz_ph_data_t *)malloc(sizeof(bdz_ph_data_t)); + + DEBUGP("Loading bdz_ph mphf\n"); + mphf->data = bdz_ph; + + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + bdz_ph->hl = hash_state_load(buf, buflen); + free(buf); + + + DEBUGP("Reading m and n\n"); + nbytes = fread(&(bdz_ph->n), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bdz_ph->m), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bdz_ph->r), sizeof(cmph_uint32), (size_t)1, f); + sizeg = (cmph_uint32)ceil(bdz_ph->n/5.0); + bdz_ph->g = (cmph_uint8 *)calloc((size_t)sizeg, sizeof(cmph_uint8)); + nbytes = fread(bdz_ph->g, sizeg*sizeof(cmph_uint8), (size_t)1, f); + + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } + return; +} + + +cmph_uint32 bdz_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + register bdz_ph_data_t *bdz_ph = mphf->data; + cmph_uint32 hl[3]; + register cmph_uint8 byte0, byte1, byte2; + register cmph_uint32 vertex; + + hash_vector(bdz_ph->hl, key, keylen,hl); + hl[0] = hl[0] % bdz_ph->r; + hl[1] = hl[1] % bdz_ph->r + bdz_ph->r; + hl[2] = hl[2] % bdz_ph->r + (bdz_ph->r << 1); + + byte0 = bdz_ph->g[hl[0]/5]; + byte1 = bdz_ph->g[hl[1]/5]; + byte2 = bdz_ph->g[hl[2]/5]; + + byte0 = lookup_table[hl[0]%5U][byte0]; + byte1 = lookup_table[hl[1]%5U][byte1]; + byte2 = lookup_table[hl[2]%5U][byte2]; + vertex = hl[(byte0 + byte1 + byte2)%3]; + + return vertex; +} + + +void bdz_ph_destroy(cmph_t *mphf) +{ + bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hl); + free(data); + free(mphf); +} + +/** \fn void bdz_ph_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bdz_ph_pack(cmph_t *mphf, void *packed_mphf) +{ + bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + cmph_uint32 sizeg; + + // packing hl type + CMPH_HASH hl_type = hash_get_type(data->hl); + *((cmph_uint32 *) ptr) = hl_type; + ptr += sizeof(cmph_uint32); + + // packing hl + hash_state_pack(data->hl, ptr); + ptr += hash_state_packed_size(hl_type); + + // packing r + *((cmph_uint32 *) ptr) = data->r; + ptr += sizeof(data->r); + + // packing g + sizeg = (cmph_uint32)ceil(data->n/5.0); + memcpy(ptr, data->g, sizeof(cmph_uint8)*sizeg); +} + +/** \fn cmph_uint32 bdz_ph_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bdz_ph_packed_size(cmph_t *mphf) +{ + bdz_ph_data_t *data = (bdz_ph_data_t *)mphf->data; + CMPH_HASH hl_type = hash_get_type(data->hl); + cmph_uint32 sizeg = (cmph_uint32)ceil(data->n/5.0); + return (cmph_uint32) (sizeof(CMPH_ALGO) + hash_state_packed_size(hl_type) + 2*sizeof(cmph_uint32) + sizeof(cmph_uint8)*sizeg); +} + +/** cmph_uint32 bdz_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bdz_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + + register CMPH_HASH hl_type = *(cmph_uint32 *)packed_mphf; + register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4; + + register cmph_uint8 * ptr = hl_ptr + hash_state_packed_size(hl_type); + + register cmph_uint32 r = *((cmph_uint32*) ptr); + register cmph_uint8 * g = ptr + 4; + + cmph_uint32 hl[3]; + register cmph_uint8 byte0, byte1, byte2; + register cmph_uint32 vertex; + + hash_vector_packed(hl_ptr, hl_type, key, keylen, hl); + + hl[0] = hl[0] % r; + hl[1] = hl[1] % r + r; + hl[2] = hl[2] % r + (r << 1); + + byte0 = g[hl[0]/5]; + byte1 = g[hl[1]/5]; + byte2 = g[hl[2]/5]; + + byte0 = lookup_table[hl[0]%5][byte0]; + byte1 = lookup_table[hl[1]%5][byte1]; + byte2 = lookup_table[hl[2]%5][byte2]; + vertex = hl[(byte0 + byte1 + byte2)%3]; + + return vertex; +} diff --git a/girepository/cmph/bdz_ph.h b/girepository/cmph/bdz_ph.h new file mode 100644 index 0000000..67b1fac --- /dev/null +++ b/girepository/cmph/bdz_ph.h @@ -0,0 +1,42 @@ +#ifndef __CMPH_BDZ_PH_H__ +#define __CMPH_BDZ_PH_H__ + +#include "cmph.h" + +typedef struct __bdz_ph_data_t bdz_ph_data_t; +typedef struct __bdz_ph_config_data_t bdz_ph_config_data_t; + +bdz_ph_config_data_t *bdz_ph_config_new(void); +void bdz_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void bdz_ph_config_destroy(cmph_config_t *mph); +cmph_t *bdz_ph_new(cmph_config_t *mph, double c); + +void bdz_ph_load(FILE *f, cmph_t *mphf); +int bdz_ph_dump(cmph_t *mphf, FILE *f); +void bdz_ph_destroy(cmph_t *mphf); +cmph_uint32 bdz_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void bdz_ph_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bdz_ph_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 bdz_ph_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bdz_ph_packed_size(cmph_t *mphf); + +/** cmph_uint32 bdz_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bdz_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/bdz_structs.h b/girepository/cmph/bdz_structs.h new file mode 100644 index 0000000..ba7dc3c --- /dev/null +++ b/girepository/cmph/bdz_structs.h @@ -0,0 +1,36 @@ +#ifndef __CMPH_BDZ_STRUCTS_H__ +#define __CMPH_BDZ_STRUCTS_H__ + +#include "hash_state.h" + +struct __bdz_data_t +{ + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 r; //partition vertex count + cmph_uint8 *g; + hash_state_t *hl; // linear hashing + + cmph_uint32 k; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$ + cmph_uint8 b; // number of bits of k + cmph_uint32 ranktablesize; //number of entries in ranktable, $n/k +1$ + cmph_uint32 *ranktable; // rank table +}; + + +struct __bdz_config_data_t +{ + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 r; //partition vertex count + cmph_uint8 *g; + hash_state_t *hl; // linear hashing + + cmph_uint32 k; //kth index in ranktable, $k = log_2(n=3r)/\varepsilon$ + cmph_uint8 b; // number of bits of k + cmph_uint32 ranktablesize; //number of entries in ranktable, $n/k +1$ + cmph_uint32 *ranktable; // rank table + CMPH_HASH hashfunc; +}; + +#endif diff --git a/girepository/cmph/bdz_structs_ph.h b/girepository/cmph/bdz_structs_ph.h new file mode 100644 index 0000000..5874a26 --- /dev/null +++ b/girepository/cmph/bdz_structs_ph.h @@ -0,0 +1,26 @@ +#ifndef __CMPH_BDZ_STRUCTS_PH_H__ +#define __CMPH_BDZ_STRUCTS_PH_H__ + +#include "hash_state.h" + +struct __bdz_ph_data_t +{ + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 r; //partition vertex count + cmph_uint8 *g; + hash_state_t *hl; // linear hashing +}; + + +struct __bdz_ph_config_data_t +{ + CMPH_HASH hashfunc; + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 r; //partition vertex count + cmph_uint8 *g; + hash_state_t *hl; // linear hashing +}; + +#endif diff --git a/girepository/cmph/bitbool.h b/girepository/cmph/bitbool.h new file mode 100644 index 0000000..a3286c3 --- /dev/null +++ b/girepository/cmph/bitbool.h @@ -0,0 +1,179 @@ +#ifndef _CMPH_BITBOOL_H__ +#define _CMPH_BITBOOL_H__ +#include "cmph_types.h" + +static const cmph_uint8 bitmask[] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; + +static const cmph_uint32 bitmask32[] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7, + 1 << 8, 1 << 9, 1 << 10, 1 << 11, 1 << 12, 1 << 13, 1 << 14, 1 << 15, + 1 << 16, 1 << 17, 1 << 18, 1 << 19, 1 << 20, 1 << 21, 1 << 22, 1 << 23, + 1 << 24, 1 << 25, 1 << 26, 1 << 27, 1 << 28, 1 << 29, 1 << 30, 1U << 31 + }; + +static const cmph_uint8 valuemask[] = { 0xfc, 0xf3, 0xcf, 0x3f}; + + +/** \def GETBIT(array, i) + * \brief get the value of an 1-bit integer stored in an array. + * \param array to get 1-bit integer values from + * \param i is the index in array to get the 1-bit integer value from + * + * GETBIT(array, i) is a macro that gets the value of an 1-bit integer stored in array. + */ +#define GETBIT(array, i) ((array[i >> 3] & bitmask[i & 0x00000007]) >> (i & 0x00000007)) + +/** \def SETBIT(array, i) + * \brief set 1 to an 1-bit integer stored in an array. + * \param array to store 1-bit integer values + * \param i is the index in array to set the the bit to 1 + * + * SETBIT(array, i) is a macro that sets 1 to an 1-bit integer stored in an array. + */ +#define SETBIT(array, i) (array[i >> 3] |= bitmask[i & 0x00000007]) + +/** \def UNSETBIT(array, i) + * \brief set 0 to an 1-bit integer stored in an array. + * \param array to store 1-bit integer values + * \param i is the index in array to set the the bit to 0 + * + * UNSETBIT(array, i) is a macro that sets 0 to an 1-bit integer stored in an array. + */ +#define UNSETBIT(array, i) (array[i >> 3] ^= ((bitmask[i & 0x00000007]))) + +//#define GETBIT(array, i) (array[(i) / 8] & bitmask[(i) % 8]) +//#define SETBIT(array, i) (array[(i) / 8] |= bitmask[(i) % 8]) +//#define UNSETBIT(array, i) (array[(i) / 8] ^= ((bitmask[(i) % 8]))) + + +/** \def SETVALUE1(array, i, v) + * \brief set a value for a 2-bit integer stored in an array initialized with 1s. + * \param array to store 2-bit integer values + * \param i is the index in array to set the value v + * \param v is the value to be set + * + * SETVALUE1(array, i, v) is a macro that set a value for a 2-bit integer stored in an array. + * The array should be initialized with all bits set to 1. For example: + * memset(array, 0xff, arraySize); + */ +#define SETVALUE1(array, i, v) (array[i >> 2] &= (cmph_uint8)((v << ((i & 0x00000003) << 1)) | valuemask[i & 0x00000003])) + +/** \def SETVALUE0(array, i, v) + * \brief set a value for a 2-bit integer stored in an array initialized with 0s. + * \param array to store 2-bit integer values + * \param i is the index in array to set the value v + * \param v is the value to be set + * + * SETVALUE0(array, i, v) is a macro that set a value for a 2-bit integer stored in an array. + * The array should be initialized with all bits set to 0. For example: + * memset(array, 0, arraySize); + */ +#define SETVALUE0(array, i, v) (array[i >> 2] |= (cmph_uint8)(v << ((i & 0x00000003) << 1))) + + +/** \def GETVALUE(array, i) + * \brief get a value for a 2-bit integer stored in an array. + * \param array to get 2-bit integer values from + * \param i is the index in array to get the value from + * + * GETVALUE(array, i) is a macro that get a value for a 2-bit integer stored in an array. + */ +#define GETVALUE(array, i) ((cmph_uint8)((array[i >> 2] >> ((i & 0x00000003U) << 1U)) & 0x00000003U)) + + + +/** \def SETBIT32(array, i) + * \brief set 1 to an 1-bit integer stored in an array of 32-bit words. + * \param array to store 1-bit integer values. The entries are 32-bit words. + * \param i is the index in array to set the the bit to 1 + * + * SETBIT32(array, i) is a macro that sets 1 to an 1-bit integer stored in an array of 32-bit words. + */ +#define SETBIT32(array, i) (array[i >> 5] |= bitmask32[i & 0x0000001f]) + +/** \def GETBIT32(array, i) + * \brief get the value of an 1-bit integer stored in an array of 32-bit words. + * \param array to get 1-bit integer values from. The entries are 32-bit words. + * \param i is the index in array to get the 1-bit integer value from + * + * GETBIT32(array, i) is a macro that gets the value of an 1-bit integer stored in an array of 32-bit words. + */ +#define GETBIT32(array, i) (array[i >> 5] & bitmask32[i & 0x0000001f]) + +/** \def UNSETBIT32(array, i) + * \brief set 0 to an 1-bit integer stored in an array of 32-bit words. + * \param array to store 1-bit integer values. The entries ar 32-bit words + * \param i is the index in array to set the the bit to 0 + * + * UNSETBIT32(array, i) is a macro that sets 0 to an 1-bit integer stored in an array of 32-bit words. + */ +#define UNSETBIT32(array, i) (array[i >> 5] ^= ((bitmask32[i & 0x0000001f]))) + +#define BITS_TABLE_SIZE(n, bits_length) ((n * bits_length + 31) >> 5) + +static inline void set_bits_value(cmph_uint32 * bits_table, cmph_uint32 index, cmph_uint32 bits_string, + cmph_uint32 string_length, cmph_uint32 string_mask) +{ + register cmph_uint32 bit_idx = index * string_length; + register cmph_uint32 word_idx = bit_idx >> 5; + register cmph_uint32 shift1 = bit_idx & 0x0000001f; + register cmph_uint32 shift2 = 32 - shift1; + + bits_table[word_idx] &= ~((string_mask) << shift1); + bits_table[word_idx] |= bits_string << shift1; + + if(shift2 < string_length) + { + bits_table[word_idx+1] &= ~((string_mask) >> shift2); + bits_table[word_idx+1] |= bits_string >> shift2; + }; +}; + +static inline cmph_uint32 get_bits_value(cmph_uint32 * bits_table,cmph_uint32 index, cmph_uint32 string_length, cmph_uint32 string_mask) +{ + register cmph_uint32 bit_idx = index * string_length; + register cmph_uint32 word_idx = bit_idx >> 5; + register cmph_uint32 shift1 = bit_idx & 0x0000001f; + register cmph_uint32 shift2 = 32-shift1; + register cmph_uint32 bits_string; + + bits_string = (bits_table[word_idx] >> shift1) & string_mask; + + if(shift2 < string_length) + bits_string |= (bits_table[word_idx+1] << shift2) & string_mask; + + return bits_string; +}; + +static inline void set_bits_at_pos(cmph_uint32 * bits_table, cmph_uint32 pos, cmph_uint32 bits_string, cmph_uint32 string_length) +{ + register cmph_uint32 word_idx = pos >> 5; + register cmph_uint32 shift1 = pos & 0x0000001f; + register cmph_uint32 shift2 = 32-shift1; + register cmph_uint32 string_mask = (1U << string_length) - 1; + + bits_table[word_idx] &= ~((string_mask) << shift1); + bits_table[word_idx] |= bits_string << shift1; + if(shift2 < string_length) + { + bits_table[word_idx+1] &= ~((string_mask) >> shift2); + bits_table[word_idx+1] |= bits_string >> shift2; + } +}; + +static inline cmph_uint32 get_bits_at_pos(cmph_uint32 * bits_table,cmph_uint32 pos,cmph_uint32 string_length) +{ + register cmph_uint32 word_idx = pos >> 5; + register cmph_uint32 shift1 = pos & 0x0000001f; + register cmph_uint32 shift2 = 32 - shift1; + register cmph_uint32 string_mask = (1U << string_length) - 1; + register cmph_uint32 bits_string; + + bits_string = (bits_table[word_idx] >> shift1) & string_mask; + + if(shift2 < string_length) + bits_string |= (bits_table[word_idx+1] << shift2) & string_mask; + return bits_string; +} + + +#endif diff --git a/girepository/cmph/bmz.c b/girepository/cmph/bmz.c new file mode 100644 index 0000000..9573825 --- /dev/null +++ b/girepository/cmph/bmz.c @@ -0,0 +1,638 @@ +#include "graph.h" +#include "bmz.h" +#include "cmph_structs.h" +#include "bmz_structs.h" +#include "hash.h" +#include "vqueue.h" +#include "bitbool.h" + +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +static int bmz_gen_edges(cmph_config_t *mph); +static cmph_uint8 bmz_traverse_critical_nodes(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited); +static cmph_uint8 bmz_traverse_critical_nodes_heuristic(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited); +static void bmz_traverse_non_critical_nodes(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint8 * visited); + +bmz_config_data_t *bmz_config_new(void) +{ + bmz_config_data_t *bmz = NULL; + bmz = (bmz_config_data_t *)malloc(sizeof(bmz_config_data_t)); + assert(bmz); + memset(bmz, 0, sizeof(bmz_config_data_t)); + bmz->hashfuncs[0] = CMPH_HASH_JENKINS; + bmz->hashfuncs[1] = CMPH_HASH_JENKINS; + bmz->g = NULL; + bmz->graph = NULL; + bmz->hashes = NULL; + return bmz; +} + +void bmz_config_destroy(cmph_config_t *mph) +{ + bmz_config_data_t *data = (bmz_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void bmz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 2) break; //bmz only uses two hash functions + bmz->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *bmz_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + bmz_data_t *bmzf = NULL; + cmph_uint32 i; + cmph_uint32 iterations; + cmph_uint32 iterations_map = 20; + cmph_uint8 *used_edges = NULL; + cmph_uint8 restart_mapping = 0; + cmph_uint8 * visited = NULL; + + bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data; + if (c == 0) c = 1.15; // validating restrictions over parameter c. + DEBUGP("c: %f\n", c); + bmz->m = mph->key_source->nkeys; + bmz->n = (cmph_uint32)ceil(c * mph->key_source->nkeys); + DEBUGP("m (edges): %u n (vertices): %u c: %f\n", bmz->m, bmz->n, c); + bmz->graph = graph_new(bmz->n, bmz->m); + DEBUGP("Created graph\n"); + + bmz->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3); + for(i = 0; i < 3; ++i) bmz->hashes[i] = NULL; + + do + { + // Mapping step + cmph_uint32 biggest_g_value = 0; + cmph_uint32 biggest_edge_value = 1; + iterations = 100; + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bmz->m, bmz->n); + } + while(1) + { + int ok; + DEBUGP("hash function 1\n"); + bmz->hashes[0] = hash_state_new(bmz->hashfuncs[0], bmz->n); + DEBUGP("hash function 2\n"); + bmz->hashes[1] = hash_state_new(bmz->hashfuncs[1], bmz->n); + DEBUGP("Generating edges\n"); + ok = bmz_gen_edges(mph); + if (!ok) + { + --iterations; + hash_state_destroy(bmz->hashes[0]); + bmz->hashes[0] = NULL; + hash_state_destroy(bmz->hashes[1]); + bmz->hashes[1] = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "simple graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + if (iterations == 0) + { + graph_destroy(bmz->graph); + return NULL; + } + // Ordering step + if (mph->verbosity) + { + fprintf(stderr, "Starting ordering step\n"); + } + graph_obtain_critical_nodes(bmz->graph); + + // Searching step + if (mph->verbosity) + { + fprintf(stderr, "Starting Searching step.\n"); + fprintf(stderr, "\tTraversing critical vertices.\n"); + } + DEBUGP("Searching step\n"); + visited = (cmph_uint8 *)malloc((size_t)bmz->n/8 + 1); + memset(visited, 0, (size_t)bmz->n/8 + 1); + used_edges = (cmph_uint8 *)malloc((size_t)bmz->m/8 + 1); + memset(used_edges, 0, (size_t)bmz->m/8 + 1); + free(bmz->g); + bmz->g = (cmph_uint32 *)calloc((size_t)bmz->n, sizeof(cmph_uint32)); + assert(bmz->g); + for (i = 0; i < bmz->n; ++i) // critical nodes + { + if (graph_node_is_critical(bmz->graph, i) && (!GETBIT(visited,i))) + { + if(c > 1.14) restart_mapping = bmz_traverse_critical_nodes(bmz, i, &biggest_g_value, &biggest_edge_value, used_edges, visited); + else restart_mapping = bmz_traverse_critical_nodes_heuristic(bmz, i, &biggest_g_value, &biggest_edge_value, used_edges, visited); + if(restart_mapping) break; + } + } + if(!restart_mapping) + { + if (mph->verbosity) + { + fprintf(stderr, "\tTraversing non critical vertices.\n"); + } + bmz_traverse_non_critical_nodes(bmz, used_edges, visited); // non_critical_nodes + } + else + { + iterations_map--; + if (mph->verbosity) fprintf(stderr, "Restarting mapping step. %u iterations remaining.\n", iterations_map); + } + free(used_edges); + free(visited); + }while(restart_mapping && iterations_map > 0); + graph_destroy(bmz->graph); + bmz->graph = NULL; + if (iterations_map == 0) + { + return NULL; + } + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + bmzf = (bmz_data_t *)malloc(sizeof(bmz_data_t)); + bmzf->g = bmz->g; + bmz->g = NULL; //transfer memory ownership + bmzf->hashes = bmz->hashes; + bmz->hashes = NULL; //transfer memory ownership + bmzf->n = bmz->n; + bmzf->m = bmz->m; + mphf->data = bmzf; + mphf->size = bmz->m; + + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +static cmph_uint8 bmz_traverse_critical_nodes(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + cmph_uint32 next_g; + cmph_uint32 u; /* Auxiliary vertex */ + cmph_uint32 lav; /* lookahead vertex */ + cmph_uint8 collision; + vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz->graph)) + 1); + graph_iterator_t it, it1; + + DEBUGP("Labelling critical vertices\n"); + bmz->g[v] = (cmph_uint32)ceil ((double)(*biggest_edge_value)/2) - 1; + SETBIT(visited, v); + next_g = (cmph_uint32)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/ + vqueue_insert(q, v); + while(!vqueue_is_empty(q)) + { + v = vqueue_remove(q); + it = graph_neighbors_it(bmz->graph, v); + while ((u = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, u) && (!GETBIT(visited,u))) + { + collision = 1; + while(collision) // lookahead to resolve collisions + { + next_g = *biggest_g_value + 1; + it1 = graph_neighbors_it(bmz->graph, u); + collision = 0; + while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited,lav)) + { + if(next_g + bmz->g[lav] >= bmz->m) + { + vqueue_destroy(q); + return 1; // restart mapping step. + } + if (GETBIT(used_edges, (next_g + bmz->g[lav]))) + { + collision = 1; + break; + } + } + } + if (next_g > *biggest_g_value) *biggest_g_value = next_g; + } + // Marking used edges... + it1 = graph_neighbors_it(bmz->graph, u); + while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited, lav)) + { + SETBIT(used_edges,(next_g + bmz->g[lav])); + if(next_g + bmz->g[lav] > *biggest_edge_value) *biggest_edge_value = next_g + bmz->g[lav]; + } + } + bmz->g[u] = next_g; // Labelling vertex u. + SETBIT(visited,u); + vqueue_insert(q, u); + } + } + + } + vqueue_destroy(q); + return 0; +} + +static cmph_uint8 bmz_traverse_critical_nodes_heuristic(bmz_config_data_t *bmz, cmph_uint32 v, cmph_uint32 * biggest_g_value, cmph_uint32 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + cmph_uint32 next_g; + cmph_uint32 u; /* Auxiliary vertex */ + cmph_uint32 lav; /* lookahead vertex */ + cmph_uint8 collision; + cmph_uint32 * unused_g_values = NULL; + cmph_uint32 unused_g_values_capacity = 0; + cmph_uint32 nunused_g_values = 0; + vqueue_t * q = vqueue_new((cmph_uint32)(0.5*graph_ncritical_nodes(bmz->graph))+1); + graph_iterator_t it, it1; + + DEBUGP("Labelling critical vertices\n"); + bmz->g[v] = (cmph_uint32)ceil ((double)(*biggest_edge_value)/2) - 1; + SETBIT(visited, v); + next_g = (cmph_uint32)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/ + vqueue_insert(q, v); + while(!vqueue_is_empty(q)) + { + v = vqueue_remove(q); + it = graph_neighbors_it(bmz->graph, v); + while ((u = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, u) && (!GETBIT(visited,u))) + { + cmph_uint32 next_g_index = 0; + collision = 1; + while(collision) // lookahead to resolve collisions + { + if (next_g_index < nunused_g_values) + { + next_g = unused_g_values[next_g_index++]; + } + else + { + next_g = *biggest_g_value + 1; + next_g_index = UINT_MAX; + } + it1 = graph_neighbors_it(bmz->graph, u); + collision = 0; + while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited,lav)) + { + if(next_g + bmz->g[lav] >= bmz->m) + { + vqueue_destroy(q); + free(unused_g_values); + return 1; // restart mapping step. + } + if (GETBIT(used_edges, (next_g + bmz->g[lav]))) + { + collision = 1; + break; + } + } + } + if(collision && (next_g > *biggest_g_value)) // saving the current g value stored in next_g. + { + if(nunused_g_values == unused_g_values_capacity) + { + unused_g_values = (cmph_uint32 *)realloc(unused_g_values, (unused_g_values_capacity + BUFSIZ)*sizeof(cmph_uint32)); + unused_g_values_capacity += BUFSIZ; + } + unused_g_values[nunused_g_values++] = next_g; + + } + if (next_g > *biggest_g_value) *biggest_g_value = next_g; + } + next_g_index--; + if (next_g_index < nunused_g_values) unused_g_values[next_g_index] = unused_g_values[--nunused_g_values]; + + // Marking used edges... + it1 = graph_neighbors_it(bmz->graph, u); + while((lav = graph_next_neighbor(bmz->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz->graph, lav) && GETBIT(visited, lav)) + { + SETBIT(used_edges,(next_g + bmz->g[lav])); + if(next_g + bmz->g[lav] > *biggest_edge_value) *biggest_edge_value = next_g + bmz->g[lav]; + } + } + bmz->g[u] = next_g; // Labelling vertex u. + SETBIT(visited, u); + vqueue_insert(q, u); + } + } + + } + vqueue_destroy(q); + free(unused_g_values); + return 0; +} + +static cmph_uint32 next_unused_edge(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint32 unused_edge_index) +{ + while(1) + { + assert(unused_edge_index < bmz->m); + if(GETBIT(used_edges, unused_edge_index)) unused_edge_index ++; + else break; + } + return unused_edge_index; +} + +static void bmz_traverse(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint32 v, cmph_uint32 * unused_edge_index, cmph_uint8 * visited) +{ + graph_iterator_t it = graph_neighbors_it(bmz->graph, v); + cmph_uint32 neighbor = 0; + while((neighbor = graph_next_neighbor(bmz->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if(GETBIT(visited,neighbor)) continue; + //DEBUGP("Visiting neighbor %u\n", neighbor); + *unused_edge_index = next_unused_edge(bmz, used_edges, *unused_edge_index); + bmz->g[neighbor] = *unused_edge_index - bmz->g[v]; + //if (bmz->g[neighbor] >= bmz->m) bmz->g[neighbor] += bmz->m; + SETBIT(visited, neighbor); + (*unused_edge_index)++; + bmz_traverse(bmz, used_edges, neighbor, unused_edge_index, visited); + + } +} + +static void bmz_traverse_non_critical_nodes(bmz_config_data_t *bmz, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + + cmph_uint32 i, v1, v2, unused_edge_index = 0; + DEBUGP("Labelling non critical vertices\n"); + for(i = 0; i < bmz->m; i++) + { + v1 = graph_vertex_id(bmz->graph, i, 0); + v2 = graph_vertex_id(bmz->graph, i, 1); + if((GETBIT(visited,v1) && GETBIT(visited,v2)) || (!GETBIT(visited,v1) && !GETBIT(visited,v2))) continue; + if(GETBIT(visited,v1)) bmz_traverse(bmz, used_edges, v1, &unused_edge_index, visited); + else bmz_traverse(bmz, used_edges, v2, &unused_edge_index, visited); + + } + + for(i = 0; i < bmz->n; i++) + { + if(!GETBIT(visited,i)) + { + bmz->g[i] = 0; + SETBIT(visited, i); + bmz_traverse(bmz, used_edges, i, &unused_edge_index, visited); + } + } + +} + +static int bmz_gen_edges(cmph_config_t *mph) +{ + cmph_uint32 e; + bmz_config_data_t *bmz = (bmz_config_data_t *)mph->data; + cmph_uint8 multiple_edges = 0; + DEBUGP("Generating edges for %u vertices\n", bmz->n); + graph_clear_edges(bmz->graph); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint32 h1, h2; + cmph_uint32 keylen; + char *key = NULL; + mph->key_source->read(mph->key_source->data, &key, &keylen); + +// if (key == NULL)fprintf(stderr, "key = %s -- read BMZ\n", key); + h1 = hash(bmz->hashes[0], key, keylen) % bmz->n; + h2 = hash(bmz->hashes[1], key, keylen) % bmz->n; + if (h1 == h2) if (++h2 >= bmz->n) h2 = 0; + if (h1 == h2) + { + if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e); + mph->key_source->dispose(mph->key_source->data, key, keylen); + return 0; + } + //DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key); + mph->key_source->dispose(mph->key_source->data, key, keylen); +// fprintf(stderr, "key = %s -- dispose BMZ\n", key); + multiple_edges = graph_contains_edge(bmz->graph, h1, h2); + if (mph->verbosity && multiple_edges) fprintf(stderr, "A non simple graph was generated\n"); + if (multiple_edges) return 0; // checking multiple edge restriction. + graph_add_edge(bmz->graph, h1, h2); + } + return !multiple_edges; +} + +int bmz_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 two = 2; //number of hash functions + bmz_data_t *data = (bmz_data_t *)mphf->data; + register size_t nbytes; +#ifdef DEBUG + cmph_uint32 i; +#endif + + __cmph_dump(mphf, fd); + + nbytes = fwrite(&two, sizeof(cmph_uint32), (size_t)1, fd); + + hash_state_dump(data->hashes[0], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + hash_state_dump(data->hashes[1], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + + nbytes = fwrite(data->g, sizeof(cmph_uint32)*(data->n), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]); + fprintf(stderr, "\n"); + #endif + return 1; +} + +void bmz_load(FILE *f, cmph_t *mphf) +{ + cmph_uint32 nhashes; + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 i; + bmz_data_t *bmz = (bmz_data_t *)malloc(sizeof(bmz_data_t)); + register size_t nbytes; + DEBUGP("Loading bmz mphf\n"); + mphf->data = bmz; + nbytes = fread(&nhashes, sizeof(cmph_uint32), (size_t)1, f); + bmz->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1)); + bmz->hashes[nhashes] = NULL; + DEBUGP("Reading %u hashes\n", nhashes); + for (i = 0; i < nhashes; ++i) + { + hash_state_t *state = NULL; + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + state = hash_state_load(buf, buflen); + bmz->hashes[i] = state; + free(buf); + } + + DEBUGP("Reading m and n\n"); + nbytes = fread(&(bmz->n), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(bmz->m), sizeof(cmph_uint32), (size_t)1, f); + + bmz->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*bmz->n); + nbytes = fread(bmz->g, bmz->n*sizeof(cmph_uint32), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return; + } + + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < bmz->n; ++i) fprintf(stderr, "%u ", bmz->g[i]); + fprintf(stderr, "\n"); + #endif + return; +} + + +cmph_uint32 bmz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + bmz_data_t *bmz = mphf->data; + cmph_uint32 h1 = hash(bmz->hashes[0], key, keylen) % bmz->n; + cmph_uint32 h2 = hash(bmz->hashes[1], key, keylen) % bmz->n; + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 > bmz->n) h2 = 0; + DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, bmz->g[h1], bmz->g[h2], bmz->m); + return bmz->g[h1] + bmz->g[h2]; +} +void bmz_destroy(cmph_t *mphf) +{ + bmz_data_t *data = (bmz_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hashes[0]); + hash_state_destroy(data->hashes[1]); + free(data->hashes); + free(data); + free(mphf); +} + +/** \fn void bmz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bmz_pack(cmph_t *mphf, void *packed_mphf) +{ + + bmz_data_t *data = (bmz_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + CMPH_HASH h2_type; + + // packing h1 type + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + *((cmph_uint32 *) ptr) = h1_type; + ptr += sizeof(cmph_uint32); + + // packing h1 + hash_state_pack(data->hashes[0], ptr); + ptr += hash_state_packed_size(h1_type); + + // packing h2 type + h2_type = hash_get_type(data->hashes[1]); + *((cmph_uint32 *) ptr) = h2_type; + ptr += sizeof(cmph_uint32); + + // packing h2 + hash_state_pack(data->hashes[1], ptr); + ptr += hash_state_packed_size(h2_type); + + // packing n + *((cmph_uint32 *) ptr) = data->n; + ptr += sizeof(data->n); + + // packing g + memcpy(ptr, data->g, sizeof(cmph_uint32)*data->n); +} + +/** \fn cmph_uint32 bmz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bmz_packed_size(cmph_t *mphf) +{ + bmz_data_t *data = (bmz_data_t *)mphf->data; + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + CMPH_HASH h2_type = hash_get_type(data->hashes[1]); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + + 3*sizeof(cmph_uint32) + sizeof(cmph_uint32)*data->n); +} + +/** cmph_uint32 bmz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bmz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint8 *h1_ptr = packed_mphf; + register CMPH_HASH h1_type = *((cmph_uint32 *)h1_ptr); + register cmph_uint8 *h2_ptr; + register CMPH_HASH h2_type; + register cmph_uint32 *g_ptr, n, h1, h2; + + h1_ptr += 4; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + h2_type = *((cmph_uint32 *)h2_ptr); + h2_ptr += 4; + + g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type)); + + n = *g_ptr++; + + h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n; + h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n; + if (h1 == h2 && ++h2 > n) h2 = 0; + return (g_ptr[h1] + g_ptr[h2]); +} diff --git a/girepository/cmph/bmz.h b/girepository/cmph/bmz.h new file mode 100644 index 0000000..9821aa8 --- /dev/null +++ b/girepository/cmph/bmz.h @@ -0,0 +1,42 @@ +#ifndef __CMPH_BMZ_H__ +#define __CMPH_BMZ_H__ + +#include "cmph.h" + +typedef struct __bmz_data_t bmz_data_t; +typedef struct __bmz_config_data_t bmz_config_data_t; + +bmz_config_data_t *bmz_config_new(void); +void bmz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void bmz_config_destroy(cmph_config_t *mph); +cmph_t *bmz_new(cmph_config_t *mph, double c); + +void bmz_load(FILE *f, cmph_t *mphf); +int bmz_dump(cmph_t *mphf, FILE *f); +void bmz_destroy(cmph_t *mphf); +cmph_uint32 bmz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void bmz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bmz_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 bmz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bmz_packed_size(cmph_t *mphf); + +/** cmph_uint32 bmz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 bmz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/bmz8.c b/girepository/cmph/bmz8.c new file mode 100644 index 0000000..15853c0 --- /dev/null +++ b/girepository/cmph/bmz8.c @@ -0,0 +1,647 @@ +#include "graph.h" +#include "bmz8.h" +#include "cmph_structs.h" +#include "bmz8_structs.h" +#include "hash.h" +#include "vqueue.h" +#include "bitbool.h" +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +static int bmz8_gen_edges(cmph_config_t *mph); +static cmph_uint8 bmz8_traverse_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited); +static cmph_uint8 bmz8_traverse_critical_nodes_heuristic(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited); +static void bmz8_traverse_non_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint8 * visited); + +bmz8_config_data_t *bmz8_config_new(void) +{ + bmz8_config_data_t *bmz8; + bmz8 = (bmz8_config_data_t *)malloc(sizeof(bmz8_config_data_t)); + assert(bmz8); + memset(bmz8, 0, sizeof(bmz8_config_data_t)); + bmz8->hashfuncs[0] = CMPH_HASH_JENKINS; + bmz8->hashfuncs[1] = CMPH_HASH_JENKINS; + bmz8->g = NULL; + bmz8->graph = NULL; + bmz8->hashes = NULL; + return bmz8; +} + +void bmz8_config_destroy(cmph_config_t *mph) +{ + bmz8_config_data_t *data = (bmz8_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void bmz8_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint8 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 2) break; //bmz8 only uses two hash functions + bmz8->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *bmz8_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + bmz8_data_t *bmz8f = NULL; + cmph_uint8 i; + cmph_uint8 iterations; + cmph_uint8 iterations_map = 20; + cmph_uint8 *used_edges = NULL; + cmph_uint8 restart_mapping = 0; + cmph_uint8 * visited = NULL; + bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data; + + if (mph->key_source->nkeys >= 256) + { + if (mph->verbosity) fprintf(stderr, "The number of keys in BMZ8 must be lower than 256.\n"); + return NULL; + } + if (c == 0) c = 1.15; // validating restrictions over parameter c. + DEBUGP("c: %f\n", c); + bmz8->m = (cmph_uint8) mph->key_source->nkeys; + bmz8->n = (cmph_uint8) ceil(c * mph->key_source->nkeys); + DEBUGP("m (edges): %u n (vertices): %u c: %f\n", bmz8->m, bmz8->n, c); + bmz8->graph = graph_new(bmz8->n, bmz8->m); + DEBUGP("Created graph\n"); + + bmz8->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3); + for(i = 0; i < 3; ++i) bmz8->hashes[i] = NULL; + + do + { + // Mapping step + cmph_uint8 biggest_g_value = 0; + cmph_uint8 biggest_edge_value = 1; + iterations = 100; + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", bmz8->m, bmz8->n); + } + while(1) + { + int ok; + DEBUGP("hash function 1\n"); + bmz8->hashes[0] = hash_state_new(bmz8->hashfuncs[0], bmz8->n); + DEBUGP("hash function 2\n"); + bmz8->hashes[1] = hash_state_new(bmz8->hashfuncs[1], bmz8->n); + DEBUGP("Generating edges\n"); + ok = bmz8_gen_edges(mph); + if (!ok) + { + --iterations; + hash_state_destroy(bmz8->hashes[0]); + bmz8->hashes[0] = NULL; + hash_state_destroy(bmz8->hashes[1]); + bmz8->hashes[1] = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "simple graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + if (iterations == 0) + { + graph_destroy(bmz8->graph); + return NULL; + } + + // Ordering step + if (mph->verbosity) + { + fprintf(stderr, "Starting ordering step\n"); + } + + graph_obtain_critical_nodes(bmz8->graph); + + // Searching step + if (mph->verbosity) + { + fprintf(stderr, "Starting Searching step.\n"); + fprintf(stderr, "\tTraversing critical vertices.\n"); + } + DEBUGP("Searching step\n"); + visited = (cmph_uint8 *)malloc((size_t)bmz8->n/8 + 1); + memset(visited, 0, (size_t)bmz8->n/8 + 1); + used_edges = (cmph_uint8 *)malloc((size_t)bmz8->m/8 + 1); + memset(used_edges, 0, (size_t)bmz8->m/8 + 1); + free(bmz8->g); + bmz8->g = (cmph_uint8 *)calloc((size_t)bmz8->n, sizeof(cmph_uint8)); + assert(bmz8->g); + for (i = 0; i < bmz8->n; ++i) // critical nodes + { + if (graph_node_is_critical(bmz8->graph, i) && (!GETBIT(visited,i))) + { + if(c > 1.14) restart_mapping = bmz8_traverse_critical_nodes(bmz8, i, &biggest_g_value, &biggest_edge_value, used_edges, visited); + else restart_mapping = bmz8_traverse_critical_nodes_heuristic(bmz8, i, &biggest_g_value, &biggest_edge_value, used_edges, visited); + if(restart_mapping) break; + } + } + if(!restart_mapping) + { + if (mph->verbosity) + { + fprintf(stderr, "\tTraversing non critical vertices.\n"); + } + bmz8_traverse_non_critical_nodes(bmz8, used_edges, visited); // non_critical_nodes + } + else + { + iterations_map--; + if (mph->verbosity) fprintf(stderr, "Restarting mapping step. %u iterations remaining.\n", iterations_map); + } + + free(used_edges); + free(visited); + + }while(restart_mapping && iterations_map > 0); + graph_destroy(bmz8->graph); + bmz8->graph = NULL; + if (iterations_map == 0) + { + return NULL; + } + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + bmz8f = (bmz8_data_t *)malloc(sizeof(bmz8_data_t)); + bmz8f->g = bmz8->g; + bmz8->g = NULL; //transfer memory ownership + bmz8f->hashes = bmz8->hashes; + bmz8->hashes = NULL; //transfer memory ownership + bmz8f->n = bmz8->n; + bmz8f->m = bmz8->m; + mphf->data = bmz8f; + mphf->size = bmz8->m; + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +static cmph_uint8 bmz8_traverse_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + cmph_uint8 next_g; + cmph_uint32 u; /* Auxiliary vertex */ + cmph_uint32 lav; /* lookahead vertex */ + cmph_uint8 collision; + vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz8->graph))); + graph_iterator_t it, it1; + + DEBUGP("Labelling critical vertices\n"); + bmz8->g[v] = (cmph_uint8)(ceil ((double)(*biggest_edge_value)/2) - 1); + SETBIT(visited, v); + next_g = (cmph_uint8)floor((double)(*biggest_edge_value/2)); /* next_g is incremented in the do..while statement*/ + vqueue_insert(q, v); + while(!vqueue_is_empty(q)) + { + v = vqueue_remove(q); + it = graph_neighbors_it(bmz8->graph, v); + while ((u = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, u) && (!GETBIT(visited,u))) + { + collision = 1; + while(collision) // lookahead to resolve collisions + { + next_g = (cmph_uint8)(*biggest_g_value + 1); + it1 = graph_neighbors_it(bmz8->graph, u); + collision = 0; + while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited,lav)) + { + if(next_g + bmz8->g[lav] >= bmz8->m) + { + vqueue_destroy(q); + return 1; // restart mapping step. + } + if (GETBIT(used_edges, (next_g + bmz8->g[lav]))) + { + collision = 1; + break; + } + } + } + if (next_g > *biggest_g_value) *biggest_g_value = next_g; + } + // Marking used edges... + it1 = graph_neighbors_it(bmz8->graph, u); + while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited, lav)) + { + SETBIT(used_edges,(next_g + bmz8->g[lav])); + + if(next_g + bmz8->g[lav] > *biggest_edge_value) + *biggest_edge_value = (cmph_uint8)(next_g + bmz8->g[lav]); + } + } + bmz8->g[u] = next_g; // Labelling vertex u. + SETBIT(visited,u); + vqueue_insert(q, u); + } + } + + } + vqueue_destroy(q); + return 0; +} + +static cmph_uint8 bmz8_traverse_critical_nodes_heuristic(bmz8_config_data_t *bmz8, cmph_uint32 v, cmph_uint8 * biggest_g_value, cmph_uint8 * biggest_edge_value, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + cmph_uint8 next_g; + cmph_uint32 u; + cmph_uint32 lav; + cmph_uint8 collision; + cmph_uint8 * unused_g_values = NULL; + cmph_uint8 unused_g_values_capacity = 0; + cmph_uint8 nunused_g_values = 0; + vqueue_t * q = vqueue_new((cmph_uint32)(graph_ncritical_nodes(bmz8->graph))); + graph_iterator_t it, it1; + + DEBUGP("Labelling critical vertices\n"); + bmz8->g[v] = (cmph_uint8)(ceil ((double)(*biggest_edge_value)/2) - 1); + SETBIT(visited, v); + next_g = (cmph_uint8)floor((double)(*biggest_edge_value/2)); + vqueue_insert(q, v); + while(!vqueue_is_empty(q)) + { + v = vqueue_remove(q); + it = graph_neighbors_it(bmz8->graph, v); + while ((u = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, u) && (!GETBIT(visited,u))) + { + cmph_uint8 next_g_index = 0; + collision = 1; + while(collision) // lookahead to resolve collisions + { + if (next_g_index < nunused_g_values) + { + next_g = unused_g_values[next_g_index++]; + } + else + { + next_g = (cmph_uint8)(*biggest_g_value + 1); + next_g_index = 255;//UINT_MAX; + } + it1 = graph_neighbors_it(bmz8->graph, u); + collision = 0; + while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited,lav)) + { + if(next_g + bmz8->g[lav] >= bmz8->m) + { + vqueue_destroy(q); + free(unused_g_values); + return 1; // restart mapping step. + } + if (GETBIT(used_edges, (next_g + bmz8->g[lav]))) + { + collision = 1; + break; + } + } + } + if(collision && (next_g > *biggest_g_value)) // saving the current g value stored in next_g. + { + if(nunused_g_values == unused_g_values_capacity) + { + unused_g_values = (cmph_uint8*)realloc(unused_g_values, ((size_t)(unused_g_values_capacity + BUFSIZ))*sizeof(cmph_uint8)); + unused_g_values_capacity += (cmph_uint8)BUFSIZ; + } + unused_g_values[nunused_g_values++] = next_g; + + } + if (next_g > *biggest_g_value) *biggest_g_value = next_g; + } + + next_g_index--; + if (next_g_index < nunused_g_values) unused_g_values[next_g_index] = unused_g_values[--nunused_g_values]; + + // Marking used edges... + it1 = graph_neighbors_it(bmz8->graph, u); + while((lav = graph_next_neighbor(bmz8->graph, &it1)) != GRAPH_NO_NEIGHBOR) + { + if (graph_node_is_critical(bmz8->graph, lav) && GETBIT(visited, lav)) + { + SETBIT(used_edges,(next_g + bmz8->g[lav])); + if(next_g + bmz8->g[lav] > *biggest_edge_value) + *biggest_edge_value = (cmph_uint8)(next_g + bmz8->g[lav]); + } + } + + bmz8->g[u] = next_g; // Labelling vertex u. + SETBIT(visited, u); + vqueue_insert(q, u); + + } + } + + } + vqueue_destroy(q); + free(unused_g_values); + return 0; +} + +static cmph_uint8 next_unused_edge(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint32 unused_edge_index) +{ + while(1) + { + assert(unused_edge_index < bmz8->m); + if(GETBIT(used_edges, unused_edge_index)) unused_edge_index ++; + else break; + } + return (cmph_uint8)unused_edge_index; +} + +static void bmz8_traverse(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint32 v, cmph_uint8 * unused_edge_index, cmph_uint8 * visited) +{ + graph_iterator_t it = graph_neighbors_it(bmz8->graph, v); + cmph_uint32 neighbor = 0; + while((neighbor = graph_next_neighbor(bmz8->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + if(GETBIT(visited,neighbor)) continue; + //DEBUGP("Visiting neighbor %u\n", neighbor); + *unused_edge_index = next_unused_edge(bmz8, used_edges, *unused_edge_index); + bmz8->g[neighbor] = (cmph_uint8)(*unused_edge_index - bmz8->g[v]); + //if (bmz8->g[neighbor] >= bmz8->m) bmz8->g[neighbor] += bmz8->m; + SETBIT(visited, neighbor); + (*unused_edge_index)++; + bmz8_traverse(bmz8, used_edges, neighbor, unused_edge_index, visited); + + } +} + +static void bmz8_traverse_non_critical_nodes(bmz8_config_data_t *bmz8, cmph_uint8 * used_edges, cmph_uint8 * visited) +{ + + cmph_uint8 i, v1, v2, unused_edge_index = 0; + DEBUGP("Labelling non critical vertices\n"); + for(i = 0; i < bmz8->m; i++) + { + v1 = (cmph_uint8)graph_vertex_id(bmz8->graph, i, 0); + v2 = (cmph_uint8)graph_vertex_id(bmz8->graph, i, 1); + if((GETBIT(visited,v1) && GETBIT(visited,v2)) || (!GETBIT(visited,v1) && !GETBIT(visited,v2))) continue; + if(GETBIT(visited,v1)) bmz8_traverse(bmz8, used_edges, v1, &unused_edge_index, visited); + else bmz8_traverse(bmz8, used_edges, v2, &unused_edge_index, visited); + + } + + for(i = 0; i < bmz8->n; i++) + { + if(!GETBIT(visited,i)) + { + bmz8->g[i] = 0; + SETBIT(visited, i); + bmz8_traverse(bmz8, used_edges, i, &unused_edge_index, visited); + } + } + +} + +static int bmz8_gen_edges(cmph_config_t *mph) +{ + cmph_uint8 e; + bmz8_config_data_t *bmz8 = (bmz8_config_data_t *)mph->data; + cmph_uint8 multiple_edges = 0; + DEBUGP("Generating edges for %u vertices\n", bmz8->n); + graph_clear_edges(bmz8->graph); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint8 h1, h2; + cmph_uint32 keylen; + char *key = NULL; + mph->key_source->read(mph->key_source->data, &key, &keylen); + +// if (key == NULL)fprintf(stderr, "key = %s -- read BMZ\n", key); + h1 = (cmph_uint8)(hash(bmz8->hashes[0], key, keylen) % bmz8->n); + h2 = (cmph_uint8)(hash(bmz8->hashes[1], key, keylen) % bmz8->n); + if (h1 == h2) if (++h2 >= bmz8->n) h2 = 0; + if (h1 == h2) + { + if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e); + mph->key_source->dispose(mph->key_source->data, key, keylen); + return 0; + } + //DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key); + mph->key_source->dispose(mph->key_source->data, key, keylen); +// fprintf(stderr, "key = %s -- dispose BMZ\n", key); + multiple_edges = graph_contains_edge(bmz8->graph, h1, h2); + if (mph->verbosity && multiple_edges) fprintf(stderr, "A non simple graph was generated\n"); + if (multiple_edges) return 0; // checking multiple edge restriction. + graph_add_edge(bmz8->graph, h1, h2); + } + return !multiple_edges; +} + +int bmz8_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint8 two = 2; //number of hash functions + bmz8_data_t *data = (bmz8_data_t *)mphf->data; + register size_t nbytes; + __cmph_dump(mphf, fd); + + nbytes = fwrite(&two, sizeof(cmph_uint8), (size_t)1, fd); + + hash_state_dump(data->hashes[0], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + hash_state_dump(data->hashes[1], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->n), sizeof(cmph_uint8), (size_t)1, fd); + nbytes = fwrite(&(data->m), sizeof(cmph_uint8), (size_t)1, fd); + + nbytes = fwrite(data->g, sizeof(cmph_uint8)*(data->n), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } +/* #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]); + fprintf(stderr, "\n"); + #endif*/ + return 1; +} + +void bmz8_load(FILE *f, cmph_t *mphf) +{ + cmph_uint8 nhashes; + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint8 i; + register size_t nbytes; + bmz8_data_t *bmz8 = (bmz8_data_t *)malloc(sizeof(bmz8_data_t)); + + DEBUGP("Loading bmz8 mphf\n"); + mphf->data = bmz8; + nbytes = fread(&nhashes, sizeof(cmph_uint8), (size_t)1, f); + bmz8->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(size_t)(nhashes + 1)); + bmz8->hashes[nhashes] = NULL; + DEBUGP("Reading %u hashes\n", nhashes); + for (i = 0; i < nhashes; ++i) + { + hash_state_t *state = NULL; + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + state = hash_state_load(buf, buflen); + bmz8->hashes[i] = state; + free(buf); + } + + DEBUGP("Reading m and n\n"); + nbytes = fread(&(bmz8->n), sizeof(cmph_uint8), (size_t)1, f); + nbytes = fread(&(bmz8->m), sizeof(cmph_uint8), (size_t)1, f); + + bmz8->g = (cmph_uint8 *)malloc(sizeof(cmph_uint8)*bmz8->n); + nbytes = fread(bmz8->g, bmz8->n*sizeof(cmph_uint8), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return; + } + + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < bmz8->n; ++i) fprintf(stderr, "%u ", bmz8->g[i]); + fprintf(stderr, "\n"); + #endif + return; +} + + +cmph_uint8 bmz8_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + bmz8_data_t *bmz8 = mphf->data; + cmph_uint8 h1 = (cmph_uint8)(hash(bmz8->hashes[0], key, keylen) % bmz8->n); + cmph_uint8 h2 = (cmph_uint8)(hash(bmz8->hashes[1], key, keylen) % bmz8->n); + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 > bmz8->n) h2 = 0; + DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, bmz8->g[h1], bmz8->g[h2], bmz8->m); + return (cmph_uint8)(bmz8->g[h1] + bmz8->g[h2]); +} +void bmz8_destroy(cmph_t *mphf) +{ + bmz8_data_t *data = (bmz8_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hashes[0]); + hash_state_destroy(data->hashes[1]); + free(data->hashes); + free(data); + free(mphf); +} + +/** \fn void bmz8_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bmz8_pack(cmph_t *mphf, void *packed_mphf) +{ + bmz8_data_t *data = (bmz8_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + CMPH_HASH h2_type; + + // packing h1 type + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + *((cmph_uint32 *) ptr) = h1_type; + ptr += sizeof(cmph_uint32); + + // packing h1 + hash_state_pack(data->hashes[0], ptr); + ptr += hash_state_packed_size(h1_type); + + // packing h2 type + h2_type = hash_get_type(data->hashes[1]); + *((cmph_uint32 *) ptr) = h2_type; + ptr += sizeof(cmph_uint32); + + // packing h2 + hash_state_pack(data->hashes[1], ptr); + ptr += hash_state_packed_size(h2_type); + + // packing n + *ptr++ = data->n; + + // packing g + memcpy(ptr, data->g, sizeof(cmph_uint8)*data->n); +} + +/** \fn cmph_uint32 bmz8_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bmz8_packed_size(cmph_t *mphf) +{ + bmz8_data_t *data = (bmz8_data_t *)mphf->data; + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + CMPH_HASH h2_type = hash_get_type(data->hashes[1]); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + + 2*sizeof(cmph_uint32) + sizeof(cmph_uint8) + sizeof(cmph_uint8)*data->n); +} + +/** cmph_uint8 bmz8_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint8 bmz8_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint8 *h1_ptr = packed_mphf; + register CMPH_HASH h1_type = *((cmph_uint32 *)h1_ptr); + register cmph_uint8 *h2_ptr; + register CMPH_HASH h2_type; + register cmph_uint8 *g_ptr, n, h1, h2; + + h1_ptr += 4; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + h2_type = *((cmph_uint32 *)h2_ptr); + h2_ptr += 4; + + g_ptr = h2_ptr + hash_state_packed_size(h2_type); + + n = *g_ptr++; + + h1 = (cmph_uint8)(hash_packed(h1_ptr, h1_type, key, keylen) % n); + h2 = (cmph_uint8)(hash_packed(h2_ptr, h2_type, key, keylen) % n); + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 > n) h2 = 0; + return (cmph_uint8)(g_ptr[h1] + g_ptr[h2]); +} diff --git a/girepository/cmph/bmz8.h b/girepository/cmph/bmz8.h new file mode 100644 index 0000000..99f7e30 --- /dev/null +++ b/girepository/cmph/bmz8.h @@ -0,0 +1,42 @@ +#ifndef __CMPH_BMZ8_H__ +#define __CMPH_BMZ8_H__ + +#include "cmph.h" + +typedef struct __bmz8_data_t bmz8_data_t; +typedef struct __bmz8_config_data_t bmz8_config_data_t; + +bmz8_config_data_t *bmz8_config_new(void); +void bmz8_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void bmz8_config_destroy(cmph_config_t *mph); +cmph_t *bmz8_new(cmph_config_t *mph, double c); + +void bmz8_load(FILE *f, cmph_t *mphf); +int bmz8_dump(cmph_t *mphf, FILE *f); +void bmz8_destroy(cmph_t *mphf); +cmph_uint8 bmz8_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void bmz8_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void bmz8_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 bmz8_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 bmz8_packed_size(cmph_t *mphf); + +/** cmph_uint8 bmz8_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint8 bmz8_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/bmz8_structs.h b/girepository/cmph/bmz8_structs.h new file mode 100644 index 0000000..408b529 --- /dev/null +++ b/girepository/cmph/bmz8_structs.h @@ -0,0 +1,25 @@ +#ifndef __CMPH_BMZ8_STRUCTS_H__ +#define __CMPH_BMZ8_STRUCTS_H__ + +#include "hash_state.h" + +struct __bmz8_data_t +{ + cmph_uint8 m; //edges (words) count + cmph_uint8 n; //vertex count + cmph_uint8 *g; + hash_state_t **hashes; +}; + + +struct __bmz8_config_data_t +{ + CMPH_HASH hashfuncs[2]; + cmph_uint8 m; //edges (words) count + cmph_uint8 n; //vertex count + graph_t *graph; + cmph_uint8 *g; + hash_state_t **hashes; +}; + +#endif diff --git a/girepository/cmph/bmz_structs.h b/girepository/cmph/bmz_structs.h new file mode 100644 index 0000000..67065a0 --- /dev/null +++ b/girepository/cmph/bmz_structs.h @@ -0,0 +1,25 @@ +#ifndef __CMPH_BMZ_STRUCTS_H__ +#define __CMPH_BMZ_STRUCTS_H__ + +#include "hash_state.h" + +struct __bmz_data_t +{ + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 *g; + hash_state_t **hashes; +}; + + +struct __bmz_config_data_t +{ + CMPH_HASH hashfuncs[2]; + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + graph_t *graph; + cmph_uint32 *g; + hash_state_t **hashes; +}; + +#endif diff --git a/girepository/cmph/brz.c b/girepository/cmph/brz.c new file mode 100644 index 0000000..25feb65 --- /dev/null +++ b/girepository/cmph/brz.c @@ -0,0 +1,1040 @@ +#include "graph.h" +#include "fch.h" +#include "fch_structs.h" +#include "bmz8.h" +#include "bmz8_structs.h" +#include "brz.h" +#include "cmph_structs.h" +#include "brz_structs.h" +#include "buffer_manager.h" +#include "cmph.h" +#include "hash.h" +#include "bitbool.h" +#include +#include +#include +#include +#include +#include +#define MAX_BUCKET_SIZE 255 +//#define DEBUG +#include "debug.h" + +#if defined (__ia64) || defined (__x86_64__) || defined (_WIN64) +# define __brz_use_64bit__ +#endif + +static int brz_gen_mphf(cmph_config_t *mph); +static cmph_uint32 brz_min_index(cmph_uint32 * vector, cmph_uint32 n); +static void brz_destroy_keys_vd(cmph_uint8 ** keys_vd, cmph_uint32 nkeys); +static char * brz_copy_partial_fch_mphf(brz_config_data_t *brz, fch_data_t * fchf, cmph_uint32 index, cmph_uint32 *buflen); +static char * brz_copy_partial_bmz8_mphf(brz_config_data_t *brz, bmz8_data_t * bmzf, cmph_uint32 index, cmph_uint32 *buflen); +brz_config_data_t *brz_config_new(void) +{ + brz_config_data_t *brz = NULL; + brz = (brz_config_data_t *)malloc(sizeof(brz_config_data_t)); + brz->algo = CMPH_FCH; + brz->b = 128; + brz->hashfuncs[0] = CMPH_HASH_JENKINS; + brz->hashfuncs[1] = CMPH_HASH_JENKINS; + brz->hashfuncs[2] = CMPH_HASH_JENKINS; + brz->size = NULL; + brz->offset = NULL; + brz->g = NULL; + brz->h1 = NULL; + brz->h2 = NULL; + brz->h0 = NULL; + brz->memory_availability = 1024*1024; + brz->tmp_dir = (cmph_uint8 *)calloc((size_t)10, sizeof(cmph_uint8)); + brz->mphf_fd = NULL; + strcpy((char *)(brz->tmp_dir), "/var/tmp/"); + assert(brz); + return brz; +} + +void brz_config_destroy(cmph_config_t *mph) +{ + brz_config_data_t *data = (brz_config_data_t *)mph->data; + free(data->tmp_dir); + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void brz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 3) break; //brz only uses three hash functions + brz->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +void brz_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability) +{ + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + if(memory_availability > 0) brz->memory_availability = memory_availability*1024*1024; +} + +void brz_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir) +{ + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + if(tmp_dir) + { + size_t len = strlen((char *)tmp_dir); + free(brz->tmp_dir); + if(tmp_dir[len-1] != '/') + { + brz->tmp_dir = (cmph_uint8 *)calloc((size_t)len+2, sizeof(cmph_uint8)); + sprintf((char *)(brz->tmp_dir), "%s/", (char *)tmp_dir); + } + else + { + brz->tmp_dir = (cmph_uint8 *)calloc((size_t)len+1, sizeof(cmph_uint8)); + sprintf((char *)(brz->tmp_dir), "%s", (char *)tmp_dir); + } + + } +} + +void brz_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd) +{ + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + brz->mphf_fd = mphf_fd; + assert(brz->mphf_fd); +} + +void brz_config_set_b(cmph_config_t *mph, cmph_uint32 b) +{ + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + if(b <= 64 || b >= 175) + { + b = 128; + } + brz->b = (cmph_uint8)b; +} + +void brz_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo) +{ + if (algo == CMPH_BMZ8 || algo == CMPH_FCH) // supported algorithms + { + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + brz->algo = algo; + } +} + +cmph_t *brz_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + brz_data_t *brzf = NULL; + cmph_uint32 i; + cmph_uint32 iterations = 20; + brz_config_data_t *brz; + + DEBUGP("c: %f\n", c); + brz = (brz_config_data_t *)mph->data; + switch(brz->algo) // validating restrictions over parameter c. + { + case CMPH_BMZ8: + if (c == 0 || c >= 2.0) c = 1; + break; + case CMPH_FCH: + if (c <= 2.0) c = 2.6; + break; + default: + assert(0); + } + brz->c = c; + brz->m = mph->key_source->nkeys; + DEBUGP("m: %u\n", brz->m); + brz->k = (cmph_uint32)ceil(brz->m/((double)brz->b)); + DEBUGP("k: %u\n", brz->k); + brz->size = (cmph_uint8 *) calloc((size_t)brz->k, sizeof(cmph_uint8)); + + // Clustering the keys by graph id. + if (mph->verbosity) + { + fprintf(stderr, "Partioning the set of keys.\n"); + } + + while(1) + { + int ok; + DEBUGP("hash function 3\n"); + brz->h0 = hash_state_new(brz->hashfuncs[2], brz->k); + DEBUGP("Generating graphs\n"); + ok = brz_gen_mphf(mph); + if (!ok) + { + --iterations; + hash_state_destroy(brz->h0); + brz->h0 = NULL; + DEBUGP("%u iterations remaining to create the graphs in a external file\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "Failure: A graph with more than 255 keys was created - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + if (iterations == 0) + { + DEBUGP("Graphs with more than 255 keys were created in all 20 iterations\n"); + free(brz->size); + return NULL; + } + DEBUGP("Graphs generated\n"); + + brz->offset = (cmph_uint32 *)calloc((size_t)brz->k, sizeof(cmph_uint32)); + for (i = 1; i < brz->k; ++i) + { + brz->offset[i] = brz->size[i-1] + brz->offset[i-1]; + } + // Generating a mphf + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + brzf = (brz_data_t *)malloc(sizeof(brz_data_t)); + brzf->g = brz->g; + brz->g = NULL; //transfer memory ownership + brzf->h1 = brz->h1; + brz->h1 = NULL; //transfer memory ownership + brzf->h2 = brz->h2; + brz->h2 = NULL; //transfer memory ownership + brzf->h0 = brz->h0; + brz->h0 = NULL; //transfer memory ownership + brzf->size = brz->size; + brz->size = NULL; //transfer memory ownership + brzf->offset = brz->offset; + brz->offset = NULL; //transfer memory ownership + brzf->k = brz->k; + brzf->c = brz->c; + brzf->m = brz->m; + brzf->algo = brz->algo; + mphf->data = brzf; + mphf->size = brz->m; + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +static int brz_gen_mphf(cmph_config_t *mph) +{ + cmph_uint32 i, e, error; + brz_config_data_t *brz = (brz_config_data_t *)mph->data; + cmph_uint32 memory_usage = 0; + cmph_uint32 nkeys_in_buffer = 0; + cmph_uint8 *buffer = (cmph_uint8 *)malloc((size_t)brz->memory_availability); + cmph_uint32 *buckets_size = (cmph_uint32 *)calloc((size_t)brz->k, sizeof(cmph_uint32)); + cmph_uint32 *keys_index = NULL; + cmph_uint8 **buffer_merge = NULL; + cmph_uint32 *buffer_h0 = NULL; + cmph_uint32 nflushes = 0; + cmph_uint32 h0; + register size_t nbytes; + FILE * tmp_fd = NULL; + buffer_manager_t * buff_manager = NULL; + char *filename = NULL; + char *key = NULL; + cmph_uint32 keylen; + cmph_uint32 cur_bucket = 0; + cmph_uint8 nkeys_vd = 0; + cmph_uint8 ** keys_vd = NULL; + + mph->key_source->rewind(mph->key_source->data); + DEBUGP("Generating graphs from %u keys\n", brz->m); + // Partitioning + for (e = 0; e < brz->m; ++e) + { + mph->key_source->read(mph->key_source->data, &key, &keylen); + + /* Buffers management */ + if (memory_usage + keylen + sizeof(keylen) > brz->memory_availability) // flush buffers + { + cmph_uint32 value, sum, keylen1; + if(mph->verbosity) + { + fprintf(stderr, "Flushing %u\n", nkeys_in_buffer); + } + value = buckets_size[0]; + sum = 0; + keylen1 = 0; + buckets_size[0] = 0; + for(i = 1; i < brz->k; i++) + { + if(buckets_size[i] == 0) continue; + sum += value; + value = buckets_size[i]; + buckets_size[i] = sum; + + } + memory_usage = 0; + keys_index = (cmph_uint32 *)calloc((size_t)nkeys_in_buffer, sizeof(cmph_uint32)); + for(i = 0; i < nkeys_in_buffer; i++) + { + memcpy(&keylen1, buffer + memory_usage, sizeof(keylen1)); + h0 = hash(brz->h0, (char *)(buffer + memory_usage + sizeof(keylen1)), keylen1) % brz->k; + keys_index[buckets_size[h0]] = memory_usage; + buckets_size[h0]++; + memory_usage += keylen1 + (cmph_uint32)sizeof(keylen1); + } + filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char)); + sprintf(filename, "%s%u.cmph",brz->tmp_dir, nflushes); + tmp_fd = fopen(filename, "wb"); + free(filename); + filename = NULL; + for(i = 0; i < nkeys_in_buffer; i++) + { + memcpy(&keylen1, buffer + keys_index[i], sizeof(keylen1)); + nbytes = fwrite(buffer + keys_index[i], (size_t)1, keylen1 + sizeof(keylen1), tmp_fd); + } + nkeys_in_buffer = 0; + memory_usage = 0; + memset((void *)buckets_size, 0, brz->k*sizeof(cmph_uint32)); + nflushes++; + free(keys_index); + fclose(tmp_fd); + } + memcpy(buffer + memory_usage, &keylen, sizeof(keylen)); + memcpy(buffer + memory_usage + sizeof(keylen), key, (size_t)keylen); + memory_usage += keylen + (cmph_uint32)sizeof(keylen); + h0 = hash(brz->h0, key, keylen) % brz->k; + + if ((brz->size[h0] == MAX_BUCKET_SIZE) || (brz->algo == CMPH_BMZ8 && ((brz->c >= 1.0) && (cmph_uint8)(brz->c * brz->size[h0]) < brz->size[h0]))) + { + free(buffer); + free(buckets_size); + return 0; + } + brz->size[h0] = (cmph_uint8)(brz->size[h0] + 1U); + buckets_size[h0] ++; + nkeys_in_buffer++; + mph->key_source->dispose(mph->key_source->data, key, keylen); + } + if (memory_usage != 0) // flush buffers + { + cmph_uint32 value; + cmph_uint32 sum, keylen1; + if(mph->verbosity) + { + fprintf(stderr, "Flushing %u\n", nkeys_in_buffer); + } + value = buckets_size[0]; + sum = 0; + keylen1 = 0; + buckets_size[0] = 0; + for(i = 1; i < brz->k; i++) + { + if(buckets_size[i] == 0) continue; + sum += value; + value = buckets_size[i]; + buckets_size[i] = sum; + } + memory_usage = 0; + keys_index = (cmph_uint32 *)calloc((size_t)nkeys_in_buffer, sizeof(cmph_uint32)); + for(i = 0; i < nkeys_in_buffer; i++) + { + memcpy(&keylen1, buffer + memory_usage, sizeof(keylen1)); + h0 = hash(brz->h0, (char *)(buffer + memory_usage + sizeof(keylen1)), keylen1) % brz->k; + keys_index[buckets_size[h0]] = memory_usage; + buckets_size[h0]++; + memory_usage += keylen1 + (cmph_uint32)sizeof(keylen1); + } + filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char)); + sprintf(filename, "%s%u.cmph",brz->tmp_dir, nflushes); + tmp_fd = fopen(filename, "wb"); + free(filename); + filename = NULL; + for(i = 0; i < nkeys_in_buffer; i++) + { + memcpy(&keylen1, buffer + keys_index[i], sizeof(keylen1)); + nbytes = fwrite(buffer + keys_index[i], (size_t)1, keylen1 + sizeof(keylen1), tmp_fd); + } + nkeys_in_buffer = 0; + memory_usage = 0; + memset((void *)buckets_size, 0, brz->k*sizeof(cmph_uint32)); + nflushes++; + free(keys_index); + fclose(tmp_fd); + } + + free(buffer); + free(buckets_size); + if(nflushes > 1024) return 0; // Too many files generated. + // mphf generation + if(mph->verbosity) + { + fprintf(stderr, "\nMPHF generation \n"); + } + /* Starting to dump to disk the resultant MPHF: __cmph_dump function */ + nbytes = fwrite(cmph_names[CMPH_BRZ], (size_t)(strlen(cmph_names[CMPH_BRZ]) + 1), (size_t)1, brz->mphf_fd); + nbytes = fwrite(&(brz->m), sizeof(brz->m), (size_t)1, brz->mphf_fd); + nbytes = fwrite(&(brz->c), sizeof(double), (size_t)1, brz->mphf_fd); + nbytes = fwrite(&(brz->algo), sizeof(brz->algo), (size_t)1, brz->mphf_fd); + nbytes = fwrite(&(brz->k), sizeof(cmph_uint32), (size_t)1, brz->mphf_fd); // number of MPHFs + nbytes = fwrite(brz->size, sizeof(cmph_uint8)*(brz->k), (size_t)1, brz->mphf_fd); + if (nbytes == 0 && ferror(brz->mphf_fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + + //tmp_fds = (FILE **)calloc(nflushes, sizeof(FILE *)); + buff_manager = buffer_manager_new(brz->memory_availability, nflushes); + buffer_merge = (cmph_uint8 **)calloc((size_t)nflushes, sizeof(cmph_uint8 *)); + buffer_h0 = (cmph_uint32 *)calloc((size_t)nflushes, sizeof(cmph_uint32)); + + memory_usage = 0; + for(i = 0; i < nflushes; i++) + { + filename = (char *)calloc(strlen((char *)(brz->tmp_dir)) + 11, sizeof(char)); + sprintf(filename, "%s%u.cmph",brz->tmp_dir, i); + buffer_manager_open(buff_manager, i, filename); + free(filename); + filename = NULL; + key = (char *)buffer_manager_read_key(buff_manager, i, &keylen); + h0 = hash(brz->h0, key+sizeof(keylen), keylen) % brz->k; + buffer_h0[i] = h0; + buffer_merge[i] = (cmph_uint8 *)key; + key = NULL; //transfer memory ownership + } + e = 0; + keys_vd = (cmph_uint8 **)calloc((size_t)MAX_BUCKET_SIZE, sizeof(cmph_uint8 *)); + nkeys_vd = 0; + error = 0; + while(e < brz->m) + { + i = brz_min_index(buffer_h0, nflushes); + cur_bucket = buffer_h0[i]; + key = (char *)buffer_manager_read_key(buff_manager, i, &keylen); + if(key) + { + while(key) + { + //keylen = strlen(key); + h0 = hash(brz->h0, key+sizeof(keylen), keylen) % brz->k; + if (h0 != buffer_h0[i]) break; + keys_vd[nkeys_vd++] = (cmph_uint8 *)key; + key = NULL; //transfer memory ownership + e++; + key = (char *)buffer_manager_read_key(buff_manager, i, &keylen); + } + if (key) + { + assert(nkeys_vd < brz->size[cur_bucket]); + keys_vd[nkeys_vd++] = buffer_merge[i]; + buffer_merge[i] = NULL; //transfer memory ownership + e++; + buffer_h0[i] = h0; + buffer_merge[i] = (cmph_uint8 *)key; + } + } + if(!key) + { + assert(nkeys_vd < brz->size[cur_bucket]); + keys_vd[nkeys_vd++] = buffer_merge[i]; + buffer_merge[i] = NULL; //transfer memory ownership + e++; + buffer_h0[i] = UINT_MAX; + } + + if(nkeys_vd == brz->size[cur_bucket]) // Generating mphf for each bucket. + { + cmph_io_adapter_t *source = NULL; + cmph_config_t *config = NULL; + cmph_t *mphf_tmp = NULL; + char *bufmphf = NULL; + cmph_uint32 buflenmphf = 0; + // Source of keys + source = cmph_io_byte_vector_adapter(keys_vd, (cmph_uint32)nkeys_vd); + config = cmph_config_new(source); + cmph_config_set_algo(config, brz->algo); + //cmph_config_set_algo(config, CMPH_BMZ8); + cmph_config_set_graphsize(config, brz->c); + mphf_tmp = cmph_new(config); + if (mphf_tmp == NULL) + { + if(mph->verbosity) fprintf(stderr, "ERROR: Can't generate MPHF for bucket %u out of %u\n", cur_bucket + 1, brz->k); + error = 1; + cmph_config_destroy(config); + brz_destroy_keys_vd(keys_vd, nkeys_vd); + cmph_io_byte_vector_adapter_destroy(source); + break; + } + if(mph->verbosity) + { + if (cur_bucket % 1000 == 0) + { + fprintf(stderr, "MPHF for bucket %u out of %u was generated.\n", cur_bucket + 1, brz->k); + } + } + switch(brz->algo) + { + case CMPH_FCH: + { + fch_data_t * fchf = NULL; + fchf = (fch_data_t *)mphf_tmp->data; + bufmphf = brz_copy_partial_fch_mphf(brz, fchf, cur_bucket, &buflenmphf); + } + break; + case CMPH_BMZ8: + { + bmz8_data_t * bmzf = NULL; + bmzf = (bmz8_data_t *)mphf_tmp->data; + bufmphf = brz_copy_partial_bmz8_mphf(brz, bmzf, cur_bucket, &buflenmphf); + } + break; + default: assert(0); + } + nbytes = fwrite(bufmphf, (size_t)buflenmphf, (size_t)1, brz->mphf_fd); + free(bufmphf); + bufmphf = NULL; + cmph_config_destroy(config); + brz_destroy_keys_vd(keys_vd, nkeys_vd); + cmph_destroy(mphf_tmp); + cmph_io_byte_vector_adapter_destroy(source); + nkeys_vd = 0; + } + } + buffer_manager_destroy(buff_manager); + free(keys_vd); + free(buffer_merge); + free(buffer_h0); + if (error) return 0; + return 1; +} + +static cmph_uint32 brz_min_index(cmph_uint32 * vector, cmph_uint32 n) +{ + cmph_uint32 i, min_index = 0; + for(i = 1; i < n; i++) + { + if(vector[i] < vector[min_index]) min_index = i; + } + return min_index; +} + +static void brz_destroy_keys_vd(cmph_uint8 ** keys_vd, cmph_uint32 nkeys) +{ + cmph_uint8 i; + for(i = 0; i < nkeys; i++) { free(keys_vd[i]); keys_vd[i] = NULL;} +} + +static char * brz_copy_partial_fch_mphf(brz_config_data_t *brz, fch_data_t * fchf, cmph_uint32 index, cmph_uint32 *buflen) +{ + cmph_uint32 i = 0; + cmph_uint32 buflenh1 = 0; + cmph_uint32 buflenh2 = 0; + char * bufh1 = NULL; + char * bufh2 = NULL; + char * buf = NULL; + cmph_uint32 n = fchf->b;//brz->size[index]; + hash_state_dump(fchf->h1, &bufh1, &buflenh1); + hash_state_dump(fchf->h2, &bufh2, &buflenh2); + *buflen = buflenh1 + buflenh2 + n + 2U * (cmph_uint32)sizeof(cmph_uint32); + buf = (char *)malloc((size_t)(*buflen)); + memcpy(buf, &buflenh1, sizeof(cmph_uint32)); + memcpy(buf+sizeof(cmph_uint32), bufh1, (size_t)buflenh1); + memcpy(buf+sizeof(cmph_uint32)+buflenh1, &buflenh2, sizeof(cmph_uint32)); + memcpy(buf+2*sizeof(cmph_uint32)+buflenh1, bufh2, (size_t)buflenh2); + for (i = 0; i < n; i++) memcpy(buf+2*sizeof(cmph_uint32)+buflenh1+buflenh2+i,(fchf->g + i), (size_t)1); + free(bufh1); + free(bufh2); + return buf; +} +static char * brz_copy_partial_bmz8_mphf(brz_config_data_t *brz, bmz8_data_t * bmzf, cmph_uint32 index, cmph_uint32 *buflen) +{ + cmph_uint32 buflenh1 = 0; + cmph_uint32 buflenh2 = 0; + char * bufh1 = NULL; + char * bufh2 = NULL; + char * buf = NULL; + cmph_uint32 n = (cmph_uint32)ceil(brz->c * brz->size[index]); + hash_state_dump(bmzf->hashes[0], &bufh1, &buflenh1); + hash_state_dump(bmzf->hashes[1], &bufh2, &buflenh2); + *buflen = buflenh1 + buflenh2 + n + 2U * (cmph_uint32)sizeof(cmph_uint32); + buf = (char *)malloc((size_t)(*buflen)); + memcpy(buf, &buflenh1, sizeof(cmph_uint32)); + memcpy(buf+sizeof(cmph_uint32), bufh1, (size_t)buflenh1); + memcpy(buf+sizeof(cmph_uint32)+buflenh1, &buflenh2, sizeof(cmph_uint32)); + memcpy(buf+2*sizeof(cmph_uint32)+buflenh1, bufh2, (size_t)buflenh2); + memcpy(buf+2*sizeof(cmph_uint32)+buflenh1+buflenh2,bmzf->g, (size_t)n); + free(bufh1); + free(bufh2); + return buf; +} + + +int brz_dump(cmph_t *mphf, FILE *fd) +{ + brz_data_t *data = (brz_data_t *)mphf->data; + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + DEBUGP("Dumping brzf\n"); + // The initial part of the MPHF have already been dumped to disk during construction + // Dumping h0 + hash_state_dump(data->h0, &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + // Dumping m and the vector offset. + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(data->offset, sizeof(cmph_uint32)*(data->k), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + return 1; +} + +void brz_load(FILE *f, cmph_t *mphf) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + cmph_uint32 i, n; + brz_data_t *brz = (brz_data_t *)malloc(sizeof(brz_data_t)); + + DEBUGP("Loading brz mphf\n"); + mphf->data = brz; + nbytes = fread(&(brz->c), sizeof(double), (size_t)1, f); + nbytes = fread(&(brz->algo), sizeof(brz->algo), (size_t)1, f); // Reading algo. + nbytes = fread(&(brz->k), sizeof(cmph_uint32), (size_t)1, f); + brz->size = (cmph_uint8 *) malloc(sizeof(cmph_uint8)*brz->k); + nbytes = fread(brz->size, sizeof(cmph_uint8)*(brz->k), (size_t)1, f); + brz->h1 = (hash_state_t **)malloc(sizeof(hash_state_t *)*brz->k); + brz->h2 = (hash_state_t **)malloc(sizeof(hash_state_t *)*brz->k); + brz->g = (cmph_uint8 **) calloc((size_t)brz->k, sizeof(cmph_uint8 *)); + DEBUGP("Reading c = %f k = %u algo = %u \n", brz->c, brz->k, brz->algo); + //loading h_i1, h_i2 and g_i. + for(i = 0; i < brz->k; i++) + { + // h1 + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state 1 has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + brz->h1[i] = hash_state_load(buf, buflen); + free(buf); + //h2 + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state 2 has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + brz->h2[i] = hash_state_load(buf, buflen); + free(buf); + switch(brz->algo) + { + case CMPH_FCH: + n = fch_calc_b(brz->c, brz->size[i]); + break; + case CMPH_BMZ8: + n = (cmph_uint32)ceil(brz->c * brz->size[i]); + break; + default: assert(0); + } + DEBUGP("g_i has %u bytes\n", n); + brz->g[i] = (cmph_uint8 *)calloc((size_t)n, sizeof(cmph_uint8)); + nbytes = fread(brz->g[i], sizeof(cmph_uint8)*n, (size_t)1, f); + } + //loading h0 + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + brz->h0 = hash_state_load(buf, buflen); + free(buf); + + //loading c, m, and the vector offset. + nbytes = fread(&(brz->m), sizeof(cmph_uint32), (size_t)1, f); + brz->offset = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*brz->k); + nbytes = fread(brz->offset, sizeof(cmph_uint32)*(brz->k), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } + + return; +} + +static cmph_uint32 brz_bmz8_search(brz_data_t *brz, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint) +{ + register cmph_uint32 h0; + register cmph_uint32 m, n, h1, h2; + register cmph_uint8 mphf_bucket; + + hash_vector(brz->h0, key, keylen, fingerprint); + h0 = fingerprint[2] % brz->k; + + m = brz->size[h0]; + n = (cmph_uint32)ceil(brz->c * m); + h1 = hash(brz->h1[h0], key, keylen) % n; + h2 = hash(brz->h2[h0], key, keylen) % n; + + if (h1 == h2 && ++h2 >= n) h2 = 0; + mphf_bucket = (cmph_uint8)(brz->g[h0][h1] + brz->g[h0][h2]); + DEBUGP("key: %s h1: %u h2: %u h0: %u\n", key, h1, h2, h0); + DEBUGP("key: %s g[h1]: %u g[h2]: %u offset[h0]: %u edges: %u\n", key, brz->g[h0][h1], brz->g[h0][h2], brz->offset[h0], brz->m); + DEBUGP("Address: %u\n", mphf_bucket + brz->offset[h0]); + return (mphf_bucket + brz->offset[h0]); +} + +static cmph_uint32 brz_fch_search(brz_data_t *brz, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint) +{ + register cmph_uint32 h0; + register cmph_uint32 m, b, h1, h2; + register double p1, p2; + register cmph_uint8 mphf_bucket; + + hash_vector(brz->h0, key, keylen, fingerprint); + h0 = fingerprint[2] % brz->k; + + m = brz->size[h0]; + b = fch_calc_b(brz->c, m); + p1 = fch_calc_p1(m); + p2 = fch_calc_p2(b); + h1 = hash(brz->h1[h0], key, keylen) % m; + h2 = hash(brz->h2[h0], key, keylen) % m; + mphf_bucket = 0; + h1 = mixh10h11h12(b, p1, p2, h1); + mphf_bucket = (cmph_uint8)((h2 + brz->g[h0][h1]) % m); + return (mphf_bucket + brz->offset[h0]); +} + +cmph_uint32 brz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + brz_data_t *brz = mphf->data; + cmph_uint32 fingerprint[3]; + switch(brz->algo) + { + case CMPH_FCH: + return brz_fch_search(brz, key, keylen, fingerprint); + case CMPH_BMZ8: + return brz_bmz8_search(brz, key, keylen, fingerprint); + default: assert(0); + } + return 0; +} +void brz_destroy(cmph_t *mphf) +{ + cmph_uint32 i; + brz_data_t *data = (brz_data_t *)mphf->data; + if(data->g) + { + for(i = 0; i < data->k; i++) + { + free(data->g[i]); + hash_state_destroy(data->h1[i]); + hash_state_destroy(data->h2[i]); + } + free(data->g); + free(data->h1); + free(data->h2); + } + hash_state_destroy(data->h0); + free(data->size); + free(data->offset); + free(data); + free(mphf); +} + +/** \fn void brz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void brz_pack(cmph_t *mphf, void *packed_mphf) +{ + brz_data_t *data = (brz_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + cmph_uint32 i,n; + CMPH_HASH h0_type, h1_type, h2_type; +#ifdef __brz_use_64bit__ + cmph_uint64 * g_is_ptr; +#else + cmph_uint32 * g_is_ptr; +#endif + cmph_uint8 * g_i; + + // packing internal algo type + memcpy(ptr, &(data->algo), sizeof(data->algo)); + ptr += sizeof(data->algo); + + // packing h0 type + h0_type = hash_get_type(data->h0); + memcpy(ptr, &h0_type, sizeof(h0_type)); + ptr += sizeof(h0_type); + + // packing h0 + hash_state_pack(data->h0, ptr); + ptr += hash_state_packed_size(h0_type); + + // packing k + memcpy(ptr, &(data->k), sizeof(data->k)); + ptr += sizeof(data->k); + + // packing c + *((cmph_uint64 *)ptr) = (cmph_uint64)data->c; + ptr += sizeof(data->c); + + // packing h1 type + h1_type = hash_get_type(data->h1[0]); + memcpy(ptr, &h1_type, sizeof(h1_type)); + ptr += sizeof(h1_type); + + // packing h2 type + h2_type = hash_get_type(data->h2[0]); + memcpy(ptr, &h2_type, sizeof(h2_type)); + ptr += sizeof(h2_type); + + // packing size + memcpy(ptr, data->size, sizeof(cmph_uint8)*data->k); + ptr += data->k; + + // packing offset + memcpy(ptr, data->offset, sizeof(cmph_uint32)*data->k); + ptr += sizeof(cmph_uint32)*data->k; + + #ifdef __brz_use_64bit__ + g_is_ptr = (cmph_uint64 *)ptr; + #else + g_is_ptr = (cmph_uint32 *)ptr; + #endif + + g_i = (cmph_uint8 *) (g_is_ptr + data->k); + + for(i = 0; i < data->k; i++) + { + #ifdef __brz_use_64bit__ + *g_is_ptr++ = (cmph_uint64)g_i; + #else + *g_is_ptr++ = (cmph_uint32)g_i; + #endif + // packing h1[i] + hash_state_pack(data->h1[i], g_i); + g_i += hash_state_packed_size(h1_type); + + // packing h2[i] + hash_state_pack(data->h2[i], g_i); + g_i += hash_state_packed_size(h2_type); + + // packing g_i + switch(data->algo) + { + case CMPH_FCH: + n = fch_calc_b(data->c, data->size[i]); + break; + case CMPH_BMZ8: + n = (cmph_uint32)ceil(data->c * data->size[i]); + break; + default: assert(0); + } + memcpy(g_i, data->g[i], sizeof(cmph_uint8)*n); + g_i += n; + + } + +} + +/** \fn cmph_uint32 brz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 brz_packed_size(cmph_t *mphf) +{ + cmph_uint32 i; + cmph_uint32 size = 0; + brz_data_t *data = (brz_data_t *)mphf->data; + CMPH_HASH h0_type = hash_get_type(data->h0); + CMPH_HASH h1_type = hash_get_type(data->h1[0]); + CMPH_HASH h2_type = hash_get_type(data->h2[0]); + cmph_uint32 n; + size = (cmph_uint32)(2*sizeof(CMPH_ALGO) + 3*sizeof(CMPH_HASH) + hash_state_packed_size(h0_type) + sizeof(cmph_uint32) + + sizeof(double) + sizeof(cmph_uint8)*data->k + sizeof(cmph_uint32)*data->k); + // pointers to g_is + #ifdef __brz_use_64bit__ + size += (cmph_uint32) sizeof(cmph_uint64)*data->k; + #else + size += (cmph_uint32) sizeof(cmph_uint32)*data->k; + #endif + + size += hash_state_packed_size(h1_type) * data->k; + size += hash_state_packed_size(h2_type) * data->k; + + n = 0; + for(i = 0; i < data->k; i++) + { + switch(data->algo) + { + case CMPH_FCH: + n = fch_calc_b(data->c, data->size[i]); + break; + case CMPH_BMZ8: + n = (cmph_uint32)ceil(data->c * data->size[i]); + break; + default: assert(0); + } + size += n; + } + return size; +} + + + +static cmph_uint32 brz_bmz8_search_packed(cmph_uint32 *packed_mphf, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint) +{ + register CMPH_HASH h0_type = *packed_mphf++; + register cmph_uint32 *h0_ptr = packed_mphf; + register cmph_uint32 k, h0, m, n, h1, h2; + register cmph_uint32 *offset; + register double c; + register CMPH_HASH h1_type, h2_type; + register cmph_uint8 * size; +#ifdef __brz_use_64bit__ + register cmph_uint64 * g_is_ptr; +#else + register cmph_uint32 * g_is_ptr; +#endif + register cmph_uint8 *h1_ptr, *h2_ptr, *g; + register cmph_uint8 mphf_bucket; + + packed_mphf = (cmph_uint32 *)(((cmph_uint8 *)packed_mphf) + hash_state_packed_size(h0_type)); + + k = *packed_mphf++; + + c = (double)(*((cmph_uint64*)packed_mphf)); + packed_mphf += 2; + + h1_type = *packed_mphf++; + + h2_type = *packed_mphf++; + + size = (cmph_uint8 *) packed_mphf; + packed_mphf = (cmph_uint32 *)(size + k); + + offset = packed_mphf; + packed_mphf += k; + + + hash_vector_packed(h0_ptr, h0_type, key, keylen, fingerprint); + h0 = fingerprint[2] % k; + + m = size[h0]; + n = (cmph_uint32)ceil(c * m); + + #ifdef __brz_use_64bit__ + g_is_ptr = (cmph_uint64 *)packed_mphf; + #else + g_is_ptr = packed_mphf; + #endif + + h1_ptr = (cmph_uint8 *) g_is_ptr[h0]; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + + g = h2_ptr + hash_state_packed_size(h2_type); + + h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n; + h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n; + + if (h1 == h2 && ++h2 >= n) h2 = 0; + mphf_bucket = (cmph_uint8)(g[h1] + g[h2]); + DEBUGP("key: %s h1: %u h2: %u h0: %u\n", key, h1, h2, h0); + DEBUGP("Address: %u\n", mphf_bucket + offset[h0]); + return (mphf_bucket + offset[h0]); +} + +static cmph_uint32 brz_fch_search_packed(cmph_uint32 *packed_mphf, const char *key, cmph_uint32 keylen, cmph_uint32 * fingerprint) +{ + register CMPH_HASH h0_type = *packed_mphf++; + + register cmph_uint32 *h0_ptr = packed_mphf; + register cmph_uint32 k, h0, m, b, h1, h2; + register double c, p1, p2; + register CMPH_HASH h1_type, h2_type; + register cmph_uint8 *size, *h1_ptr, *h2_ptr, *g; + register cmph_uint32 *offset; +#ifdef __brz_use_64bit__ + register cmph_uint64 * g_is_ptr; +#else + register cmph_uint32 * g_is_ptr; +#endif + register cmph_uint8 mphf_bucket; + + packed_mphf = (cmph_uint32 *)(((cmph_uint8 *)packed_mphf) + hash_state_packed_size(h0_type)); + + k = *packed_mphf++; + + c = (double)(*((cmph_uint64*)packed_mphf)); + packed_mphf += 2; + + h1_type = *packed_mphf++; + + h2_type = *packed_mphf++; + + size = (cmph_uint8 *) packed_mphf; + packed_mphf = (cmph_uint32 *)(size + k); + + offset = packed_mphf; + packed_mphf += k; + + hash_vector_packed(h0_ptr, h0_type, key, keylen, fingerprint); + h0 = fingerprint[2] % k; + + m = size[h0]; + b = fch_calc_b(c, m); + p1 = fch_calc_p1(m); + p2 = fch_calc_p2(b); + + #ifdef __brz_use_64bit__ + g_is_ptr = (cmph_uint64 *)packed_mphf; + #else + g_is_ptr = packed_mphf; + #endif + + h1_ptr = (cmph_uint8 *) g_is_ptr[h0]; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + + g = h2_ptr + hash_state_packed_size(h2_type); + + h1 = hash_packed(h1_ptr, h1_type, key, keylen) % m; + h2 = hash_packed(h2_ptr, h2_type, key, keylen) % m; + + mphf_bucket = 0; + h1 = mixh10h11h12(b, p1, p2, h1); + mphf_bucket = (cmph_uint8)((h2 + g[h1]) % m); + return (mphf_bucket + offset[h0]); +} + +/** cmph_uint32 brz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 brz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint32 *ptr = (cmph_uint32 *)packed_mphf; + register CMPH_ALGO algo = *ptr++; + cmph_uint32 fingerprint[3]; + switch(algo) + { + case CMPH_FCH: + return brz_fch_search_packed(ptr, key, keylen, fingerprint); + case CMPH_BMZ8: + return brz_bmz8_search_packed(ptr, key, keylen, fingerprint); + default: + assert(0); + return 0; /* To avoid warnings that value must be returned */ + } +} + diff --git a/girepository/cmph/brz.h b/girepository/cmph/brz.h new file mode 100644 index 0000000..648f174 --- /dev/null +++ b/girepository/cmph/brz.h @@ -0,0 +1,47 @@ +#ifndef __CMPH_BRZ_H__ +#define __CMPH_BRZ_H__ + +#include "cmph.h" + +typedef struct __brz_data_t brz_data_t; +typedef struct __brz_config_data_t brz_config_data_t; + +brz_config_data_t *brz_config_new(void); +void brz_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void brz_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir); +void brz_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd); +void brz_config_set_b(cmph_config_t *mph, cmph_uint32 b); +void brz_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo); +void brz_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability); +void brz_config_destroy(cmph_config_t *mph); +cmph_t *brz_new(cmph_config_t *mph, double c); + +void brz_load(FILE *f, cmph_t *mphf); +int brz_dump(cmph_t *mphf, FILE *f); +void brz_destroy(cmph_t *mphf); +cmph_uint32 brz_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void brz_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void brz_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 brz_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 brz_packed_size(cmph_t *mphf); + +/** cmph_uint32 brz_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 brz_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/brz_structs.h b/girepository/cmph/brz_structs.h new file mode 100644 index 0000000..b781107 --- /dev/null +++ b/girepository/cmph/brz_structs.h @@ -0,0 +1,39 @@ +#ifndef __CMPH_BRZ_STRUCTS_H__ +#define __CMPH_BRZ_STRUCTS_H__ + +#include "hash_state.h" + +struct __brz_data_t +{ + CMPH_ALGO algo; // CMPH algo for generating the MPHFs for the buckets (Just CMPH_FCH and CMPH_BMZ8) + cmph_uint32 m; // edges (words) count + double c; // constant c + cmph_uint8 *size; // size[i] stores the number of edges represented by g[i][...]. + cmph_uint32 *offset; // offset[i] stores the sum: size[0] + size[1] + ... size[i-1]. + cmph_uint8 **g; // g function. + cmph_uint32 k; // number of components + hash_state_t **h1; + hash_state_t **h2; + hash_state_t * h0; +}; + +struct __brz_config_data_t +{ + CMPH_HASH hashfuncs[3]; + CMPH_ALGO algo; // CMPH algo for generating the MPHFs for the buckets (Just CMPH_FCH and CMPH_BMZ8) + double c; // constant c + cmph_uint32 m; // edges (words) count + cmph_uint8 *size; // size[i] stores the number of edges represented by g[i][...]. + cmph_uint32 *offset; // offset[i] stores the sum: size[0] + size[1] + ... size[i-1]. + cmph_uint8 **g; // g function. + cmph_uint8 b; // parameter b. + cmph_uint32 k; // number of components + hash_state_t **h1; + hash_state_t **h2; + hash_state_t * h0; + cmph_uint32 memory_availability; + cmph_uint8 * tmp_dir; // temporary directory + FILE * mphf_fd; // mphf file +}; + +#endif diff --git a/girepository/cmph/buffer_entry.c b/girepository/cmph/buffer_entry.c new file mode 100644 index 0000000..5dcc4d5 --- /dev/null +++ b/girepository/cmph/buffer_entry.c @@ -0,0 +1,103 @@ +#include "buffer_entry.h" +#include +#include +#include +#include + +struct __buffer_entry_t +{ + FILE *fd; + cmph_uint8 * buff; + cmph_uint32 capacity, // buffer entry capacity + nbytes, // buffer entry used bytes + pos; // current read position in buffer entry + cmph_uint8 eof; // flag to indicate end of file +}; + +buffer_entry_t * buffer_entry_new(cmph_uint32 capacity) +{ + buffer_entry_t *buff_entry = (buffer_entry_t *)malloc(sizeof(buffer_entry_t)); + assert(buff_entry); + buff_entry->fd = NULL; + buff_entry->buff = NULL; + buff_entry->capacity = capacity; + buff_entry->nbytes = capacity; + buff_entry->pos = capacity; + buff_entry->eof = 0; + return buff_entry; +} + +void buffer_entry_open(buffer_entry_t * buffer_entry, char * filename) +{ + buffer_entry->fd = fopen(filename, "rb"); +} + +void buffer_entry_set_capacity(buffer_entry_t * buffer_entry, cmph_uint32 capacity) +{ + buffer_entry->capacity = capacity; +} + + +cmph_uint32 buffer_entry_get_capacity(buffer_entry_t * buffer_entry) +{ + return buffer_entry->capacity; +} + +static void buffer_entry_load(buffer_entry_t * buffer_entry) +{ + free(buffer_entry->buff); + buffer_entry->buff = (cmph_uint8 *)calloc((size_t)buffer_entry->capacity, sizeof(cmph_uint8)); + buffer_entry->nbytes = (cmph_uint32)fread(buffer_entry->buff, (size_t)1, (size_t)buffer_entry->capacity, buffer_entry->fd); + if (buffer_entry->nbytes != buffer_entry->capacity) buffer_entry->eof = 1; + buffer_entry->pos = 0; +} + +cmph_uint8 * buffer_entry_read_key(buffer_entry_t * buffer_entry, cmph_uint32 * keylen) +{ + cmph_uint8 * buf = NULL; + cmph_uint32 lacked_bytes = sizeof(*keylen); + cmph_uint32 copied_bytes = 0; + if(buffer_entry->eof && (buffer_entry->pos == buffer_entry->nbytes)) // end + { + free(buf); + return NULL; + } + if((buffer_entry->pos + lacked_bytes) > buffer_entry->nbytes) + { + copied_bytes = buffer_entry->nbytes - buffer_entry->pos; + lacked_bytes = (buffer_entry->pos + lacked_bytes) - buffer_entry->nbytes; + if (copied_bytes != 0) memcpy(keylen, buffer_entry->buff + buffer_entry->pos, (size_t)copied_bytes); + buffer_entry_load(buffer_entry); + } + memcpy(keylen + copied_bytes, buffer_entry->buff + buffer_entry->pos, (size_t)lacked_bytes); + buffer_entry->pos += lacked_bytes; + + lacked_bytes = *keylen; + copied_bytes = 0; + buf = (cmph_uint8 *)malloc(*keylen + sizeof(*keylen)); + memcpy(buf, keylen, sizeof(*keylen)); + if((buffer_entry->pos + lacked_bytes) > buffer_entry->nbytes) { + copied_bytes = buffer_entry->nbytes - buffer_entry->pos; + lacked_bytes = (buffer_entry->pos + lacked_bytes) - buffer_entry->nbytes; + if (copied_bytes != 0) { + memcpy(buf + sizeof(*keylen), buffer_entry->buff + buffer_entry->pos, (size_t)copied_bytes); + } + buffer_entry_load(buffer_entry); + } + memcpy(buf+sizeof(*keylen)+copied_bytes, buffer_entry->buff + buffer_entry->pos, (size_t)lacked_bytes); + buffer_entry->pos += lacked_bytes; + return buf; +} + +void buffer_entry_destroy(buffer_entry_t * buffer_entry) +{ + fclose(buffer_entry->fd); + buffer_entry->fd = NULL; + free(buffer_entry->buff); + buffer_entry->buff = NULL; + buffer_entry->capacity = 0; + buffer_entry->nbytes = 0; + buffer_entry->pos = 0; + buffer_entry->eof = 0; + free(buffer_entry); +} diff --git a/girepository/cmph/buffer_entry.h b/girepository/cmph/buffer_entry.h new file mode 100644 index 0000000..62102ba --- /dev/null +++ b/girepository/cmph/buffer_entry.h @@ -0,0 +1,14 @@ +#ifndef __CMPH_BUFFER_ENTRY_H__ +#define __CMPH_BUFFER_ENTRY_H__ + +#include "cmph_types.h" +#include +typedef struct __buffer_entry_t buffer_entry_t; + +buffer_entry_t * buffer_entry_new(cmph_uint32 capacity); +void buffer_entry_set_capacity(buffer_entry_t * buffer_entry, cmph_uint32 capacity); +cmph_uint32 buffer_entry_get_capacity(buffer_entry_t * buffer_entry); +void buffer_entry_open(buffer_entry_t * buffer_entry, char * filename); +cmph_uint8 * buffer_entry_read_key(buffer_entry_t * buffer_entry, cmph_uint32 * keylen); +void buffer_entry_destroy(buffer_entry_t * buffer_entry); +#endif diff --git a/girepository/cmph/buffer_manage.c b/girepository/cmph/buffer_manage.c new file mode 100644 index 0000000..fdefc62 --- /dev/null +++ b/girepository/cmph/buffer_manage.c @@ -0,0 +1,66 @@ +#include "buffer_manage.h" +#include "buffer_entry.h" +#include +#include +#include +struct __buffer_manage_t +{ + cmph_uint32 memory_avail; // memory available + buffer_entry_t ** buffer_entries; // buffer entries to be managed + cmph_uint32 nentries; // number of entries to be managed + cmph_uint32 *memory_avail_list; // memory available list + int pos_avail_list; // current position in memory available list +}; + +buffer_manage_t * buffer_manage_new(cmph_uint32 memory_avail, cmph_uint32 nentries) +{ + cmph_uint32 memory_avail_entry, i; + buffer_manage_t *buff_manage = (buffer_manage_t *)malloc(sizeof(buffer_manage_t)); + assert(buff_manage); + buff_manage->memory_avail = memory_avail; + buff_manage->buffer_entries = (buffer_entry_t **)calloc((size_t)nentries, sizeof(buffer_entry_t *)); + buff_manage->memory_avail_list = (cmph_uint32 *)calloc((size_t)nentries, sizeof(cmph_uint32)); + buff_manage->pos_avail_list = -1; + buff_manage->nentries = nentries; + memory_avail_entry = buff_manage->memory_avail/buff_manage->nentries + 1; + for(i = 0; i < buff_manage->nentries; i++) + { + buff_manage->buffer_entries[i] = buffer_entry_new(memory_avail_entry); + } + return buff_manage; +} + +void buffer_manage_open(buffer_manage_t * buffer_manage, cmph_uint32 index, char * filename) +{ + buffer_entry_open(buffer_manage->buffer_entries[index], filename); +} + +cmph_uint8 * buffer_manage_read_key(buffer_manage_t * buffer_manage, cmph_uint32 index) +{ + cmph_uint8 * key = NULL; + if (buffer_manage->pos_avail_list >= 0 ) // recovering memory + { + cmph_uint32 new_capacity = buffer_entry_get_capacity(buffer_manage->buffer_entries[index]) + buffer_manage->memory_avail_list[(buffer_manage->pos_avail_list)--]; + buffer_entry_set_capacity(buffer_manage->buffer_entries[index], new_capacity); + //fprintf(stderr, "recovering memory\n"); + } + key = buffer_entry_read_key(buffer_manage->buffer_entries[index]); + if (key == NULL) // storing memory to be recovered + { + buffer_manage->memory_avail_list[++(buffer_manage->pos_avail_list)] = buffer_entry_get_capacity(buffer_manage->buffer_entries[index]); + //fprintf(stderr, "storing memory to be recovered\n"); + } + return key; +} + +void buffer_manage_destroy(buffer_manage_t * buffer_manage) +{ + cmph_uint32 i; + for(i = 0; i < buffer_manage->nentries; i++) + { + buffer_entry_destroy(buffer_manage->buffer_entries[i]); + } + free(buffer_manage->memory_avail_list); + free(buffer_manage->buffer_entries); + free(buffer_manage); +} diff --git a/girepository/cmph/buffer_manage.h b/girepository/cmph/buffer_manage.h new file mode 100644 index 0000000..8c66cff --- /dev/null +++ b/girepository/cmph/buffer_manage.h @@ -0,0 +1,12 @@ +#ifndef __CMPH_BUFFER_MANAGE_H__ +#define __CMPH_BUFFER_MANAGE_H__ + +#include "cmph_types.h" +#include +typedef struct __buffer_manage_t buffer_manage_t; + +buffer_manage_t * buffer_manage_new(cmph_uint32 memory_avail, cmph_uint32 nentries); +void buffer_manage_open(buffer_manage_t * buffer_manage, cmph_uint32 index, char * filename); +cmph_uint8 * buffer_manage_read_key(buffer_manage_t * buffer_manage, cmph_uint32 index); +void buffer_manage_destroy(buffer_manage_t * buffer_manage); +#endif diff --git a/girepository/cmph/buffer_manager.c b/girepository/cmph/buffer_manager.c new file mode 100644 index 0000000..5a051e2 --- /dev/null +++ b/girepository/cmph/buffer_manager.c @@ -0,0 +1,64 @@ +#include "buffer_manager.h" +#include "buffer_entry.h" +#include +#include +#include +struct __buffer_manager_t +{ + cmph_uint32 memory_avail; // memory available + buffer_entry_t ** buffer_entries; // buffer entries to be managed + cmph_uint32 nentries; // number of entries to be managed + cmph_uint32 *memory_avail_list; // memory available list + int pos_avail_list; // current position in memory available list +}; + +buffer_manager_t * buffer_manager_new(cmph_uint32 memory_avail, cmph_uint32 nentries) +{ + cmph_uint32 memory_avail_entry, i; + buffer_manager_t *buff_manager = (buffer_manager_t *)malloc(sizeof(buffer_manager_t)); + assert(buff_manager); + buff_manager->memory_avail = memory_avail; + buff_manager->buffer_entries = (buffer_entry_t **)calloc((size_t)nentries, sizeof(buffer_entry_t *)); + buff_manager->memory_avail_list = (cmph_uint32 *)calloc((size_t)nentries, sizeof(cmph_uint32)); + buff_manager->pos_avail_list = -1; + buff_manager->nentries = nentries; + memory_avail_entry = buff_manager->memory_avail/buff_manager->nentries + 1; + for(i = 0; i < buff_manager->nentries; i++) + { + buff_manager->buffer_entries[i] = buffer_entry_new(memory_avail_entry); + } + return buff_manager; +} + +void buffer_manager_open(buffer_manager_t * buffer_manager, cmph_uint32 index, char * filename) +{ + buffer_entry_open(buffer_manager->buffer_entries[index], filename); +} + +cmph_uint8 * buffer_manager_read_key(buffer_manager_t * buffer_manager, cmph_uint32 index, cmph_uint32 * keylen) +{ + cmph_uint8 * key = NULL; + if (buffer_manager->pos_avail_list >= 0 ) // recovering memory + { + cmph_uint32 new_capacity = buffer_entry_get_capacity(buffer_manager->buffer_entries[index]) + buffer_manager->memory_avail_list[(buffer_manager->pos_avail_list)--]; + buffer_entry_set_capacity(buffer_manager->buffer_entries[index], new_capacity); + } + key = buffer_entry_read_key(buffer_manager->buffer_entries[index], keylen); + if (key == NULL) // storing memory to be recovered + { + buffer_manager->memory_avail_list[++(buffer_manager->pos_avail_list)] = buffer_entry_get_capacity(buffer_manager->buffer_entries[index]); + } + return key; +} + +void buffer_manager_destroy(buffer_manager_t * buffer_manager) +{ + cmph_uint32 i; + for(i = 0; i < buffer_manager->nentries; i++) + { + buffer_entry_destroy(buffer_manager->buffer_entries[i]); + } + free(buffer_manager->memory_avail_list); + free(buffer_manager->buffer_entries); + free(buffer_manager); +} diff --git a/girepository/cmph/buffer_manager.h b/girepository/cmph/buffer_manager.h new file mode 100644 index 0000000..af99c20 --- /dev/null +++ b/girepository/cmph/buffer_manager.h @@ -0,0 +1,12 @@ +#ifndef __CMPH_BUFFER_MANAGE_H__ +#define __CMPH_BUFFER_MANAGE_H__ + +#include "cmph_types.h" +#include +typedef struct __buffer_manager_t buffer_manager_t; + +buffer_manager_t * buffer_manager_new(cmph_uint32 memory_avail, cmph_uint32 nentries); +void buffer_manager_open(buffer_manager_t * buffer_manager, cmph_uint32 index, char * filename); +cmph_uint8 * buffer_manager_read_key(buffer_manager_t * buffer_manager, cmph_uint32 index, cmph_uint32 * keylen); +void buffer_manager_destroy(buffer_manager_t * buffer_manager); +#endif diff --git a/girepository/cmph/chd.c b/girepository/cmph/chd.c new file mode 100644 index 0000000..46aec52 --- /dev/null +++ b/girepository/cmph/chd.c @@ -0,0 +1,280 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmph_structs.h" +#include "chd_structs.h" +#include "chd.h" +#include "bitbool.h" +//#define DEBUG +#include "debug.h" + +chd_config_data_t *chd_config_new(cmph_config_t *mph) +{ + cmph_io_adapter_t *key_source = mph->key_source; + chd_config_data_t *chd; + chd = (chd_config_data_t *)malloc(sizeof(chd_config_data_t)); + assert(chd); + memset(chd, 0, sizeof(chd_config_data_t)); + + chd->chd_ph = cmph_config_new(key_source); + cmph_config_set_algo(chd->chd_ph, CMPH_CHD_PH); + + return chd; +} + +void chd_config_destroy(cmph_config_t *mph) +{ + chd_config_data_t *data = (chd_config_data_t *) mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + if(data->chd_ph) + { + cmph_config_destroy(data->chd_ph); + data->chd_ph = NULL; + } + free(data); +} + + +void chd_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + chd_config_data_t *data = (chd_config_data_t *) mph->data; + cmph_config_set_hashfuncs(data->chd_ph, hashfuncs); +} + + +void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket) +{ + chd_config_data_t *data = (chd_config_data_t *) mph->data; + cmph_config_set_b(data->chd_ph, keys_per_bucket); +} + + +void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin) +{ + chd_config_data_t *data = (chd_config_data_t *) mph->data; + cmph_config_set_keys_per_bin(data->chd_ph, keys_per_bin); +} + + +cmph_t *chd_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + chd_data_t *chdf = NULL; + chd_config_data_t *chd = (chd_config_data_t *)mph->data; + chd_ph_config_data_t * chd_ph = (chd_ph_config_data_t *)chd->chd_ph->data; + compressed_rank_t cr; + + register cmph_t * chd_phf = NULL; + register cmph_uint32 packed_chd_phf_size = 0; + cmph_uint8 * packed_chd_phf = NULL; + + register cmph_uint32 packed_cr_size = 0; + cmph_uint8 * packed_cr = NULL; + + register cmph_uint32 i, idx, nkeys, nvals, nbins; + cmph_uint32 * vals_table = NULL; + register cmph_uint32 * occup_table = NULL; + #ifdef CMPH_TIMING + double construction_time_begin = 0.0; + double construction_time = 0.0; + ELAPSED_TIME_IN_SECONDS(&construction_time_begin); + #endif + + cmph_config_set_verbosity(chd->chd_ph, mph->verbosity); + cmph_config_set_graphsize(chd->chd_ph, c); + + if (mph->verbosity) + { + fprintf(stderr, "Generating a CHD_PH perfect hash function with a load factor equal to %.3f\n", c); + } + + chd_phf = cmph_new(chd->chd_ph); + + if(chd_phf == NULL) + { + return NULL; + } + + packed_chd_phf_size = cmph_packed_size(chd_phf); + DEBUGP("packed_chd_phf_size = %u\n", packed_chd_phf_size); + + /* Make sure that we have enough space to pack the mphf. */ + packed_chd_phf = calloc((size_t)packed_chd_phf_size,(size_t)1); + + /* Pack the mphf. */ + cmph_pack(chd_phf, packed_chd_phf); + + cmph_destroy(chd_phf); + + + if (mph->verbosity) + { + fprintf(stderr, "Compressing the range of the resulting CHD_PH perfect hash function\n"); + } + + compressed_rank_init(&cr); + nbins = chd_ph->n; + nkeys = chd_ph->m; + nvals = nbins - nkeys; + + vals_table = (cmph_uint32 *)calloc(nvals, sizeof(cmph_uint32)); + occup_table = (cmph_uint32 *)chd_ph->occup_table; + + for(i = 0, idx = 0; i < nbins; i++) + { + if(!GETBIT32(occup_table, i)) + { + vals_table[idx++] = i; + } + } + + compressed_rank_generate(&cr, vals_table, nvals); + free(vals_table); + + packed_cr_size = compressed_rank_packed_size(&cr); + packed_cr = (cmph_uint8 *) calloc(packed_cr_size, sizeof(cmph_uint8)); + compressed_rank_pack(&cr, packed_cr); + compressed_rank_destroy(&cr); + + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + chdf = (chd_data_t *)malloc(sizeof(chd_data_t)); + + chdf->packed_cr = packed_cr; + packed_cr = NULL; //transfer memory ownership + + chdf->packed_chd_phf = packed_chd_phf; + packed_chd_phf = NULL; //transfer memory ownership + + chdf->packed_chd_phf_size = packed_chd_phf_size; + chdf->packed_cr_size = packed_cr_size; + + mphf->data = chdf; + mphf->size = nkeys; + + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + #ifdef CMPH_TIMING + ELAPSED_TIME_IN_SECONDS(&construction_time); + register cmph_uint32 space_usage = chd_packed_size(mphf)*8; + construction_time = construction_time - construction_time_begin; + fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\n", nkeys, c, chd_ph->keys_per_bucket, construction_time, space_usage/(double)nkeys); + #endif + + return mphf; +} + +void chd_load(FILE *fd, cmph_t *mphf) +{ + register size_t nbytes; + chd_data_t *chd = (chd_data_t *)malloc(sizeof(chd_data_t)); + + DEBUGP("Loading chd mphf\n"); + mphf->data = chd; + + nbytes = fread(&chd->packed_chd_phf_size, sizeof(cmph_uint32), (size_t)1, fd); + DEBUGP("Loading CHD_PH perfect hash function with %u bytes to disk\n", chd->packed_chd_phf_size); + chd->packed_chd_phf = (cmph_uint8 *) calloc((size_t)chd->packed_chd_phf_size,(size_t)1); + nbytes = fread(chd->packed_chd_phf, chd->packed_chd_phf_size, (size_t)1, fd); + + nbytes = fread(&chd->packed_cr_size, sizeof(cmph_uint32), (size_t)1, fd); + DEBUGP("Loading Compressed rank structure, which has %u bytes\n", chd->packed_cr_size); + chd->packed_cr = (cmph_uint8 *) calloc((size_t)chd->packed_cr_size, (size_t)1); + nbytes = fread(chd->packed_cr, chd->packed_cr_size, (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } + +} + +int chd_dump(cmph_t *mphf, FILE *fd) +{ + register size_t nbytes; + chd_data_t *data = (chd_data_t *)mphf->data; + + __cmph_dump(mphf, fd); + // Dumping CHD_PH perfect hash function + + DEBUGP("Dumping CHD_PH perfect hash function with %u bytes to disk\n", data->packed_chd_phf_size); + nbytes = fwrite(&data->packed_chd_phf_size, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(data->packed_chd_phf, data->packed_chd_phf_size, (size_t)1, fd); + + DEBUGP("Dumping compressed rank structure with %u bytes to disk\n", data->packed_cr_size); + nbytes = fwrite(&data->packed_cr_size, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(data->packed_cr, data->packed_cr_size, (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + + return 1; +} + +void chd_destroy(cmph_t *mphf) +{ + chd_data_t *data = (chd_data_t *)mphf->data; + free(data->packed_chd_phf); + free(data->packed_cr); + free(data); + free(mphf); +} + +static inline cmph_uint32 _chd_search(void * packed_chd_phf, void * packed_cr, const char *key, cmph_uint32 keylen) +{ + register cmph_uint32 bin_idx = cmph_search_packed(packed_chd_phf, key, keylen); + register cmph_uint32 rank = compressed_rank_query_packed(packed_cr, bin_idx); + return bin_idx - rank; +} + +cmph_uint32 chd_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + register chd_data_t * chd = mphf->data; + return _chd_search(chd->packed_chd_phf, chd->packed_cr, key, keylen); +} + +void chd_pack(cmph_t *mphf, void *packed_mphf) +{ + chd_data_t *data = (chd_data_t *)mphf->data; + cmph_uint32 * ptr = packed_mphf; + cmph_uint8 * ptr8; + + // packing packed_cr_size and packed_cr + *ptr = data->packed_cr_size; + ptr8 = (cmph_uint8 *) (ptr + 1); + + memcpy(ptr8, data->packed_cr, data->packed_cr_size); + ptr8 += data->packed_cr_size; + + ptr = (cmph_uint32 *) ptr8; + *ptr = data->packed_chd_phf_size; + + ptr8 = (cmph_uint8 *) (ptr + 1); + memcpy(ptr8, data->packed_chd_phf, data->packed_chd_phf_size); +} + +cmph_uint32 chd_packed_size(cmph_t *mphf) +{ + register chd_data_t *data = (chd_data_t *)mphf->data; + return (cmph_uint32)(sizeof(CMPH_ALGO) + 2*sizeof(cmph_uint32) + data->packed_cr_size + data->packed_chd_phf_size); + +} + +cmph_uint32 chd_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + + register cmph_uint32 * ptr = packed_mphf; + register cmph_uint32 packed_cr_size = *ptr++; + register cmph_uint8 * packed_chd_phf = ((cmph_uint8 *) ptr) + packed_cr_size + sizeof(cmph_uint32); + return _chd_search(packed_chd_phf, ptr, key, keylen); +} + + diff --git a/girepository/cmph/chd.h b/girepository/cmph/chd.h new file mode 100644 index 0000000..e829df8 --- /dev/null +++ b/girepository/cmph/chd.h @@ -0,0 +1,59 @@ +#ifndef _CMPH_CHD_H__ +#define _CMPH_CHD_H__ + +#include "cmph.h" + +typedef struct __chd_data_t chd_data_t; +typedef struct __chd_config_data_t chd_config_data_t; + +/* Config API */ +chd_config_data_t *chd_config_new(cmph_config_t * mph); +void chd_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); + +/** \fn void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin); + * \brief Allows to set the number of keys per bin. + * \param mph pointer to the configuration structure + * \param keys_per_bin value for the number of keys per bin + */ +void chd_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin); + +/** \fn void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket); + * \brief Allows to set the number of keys per bucket. + * \param mph pointer to the configuration structure + * \param keys_per_bucket value for the number of keys per bucket + */ +void chd_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket); +void chd_config_destroy(cmph_config_t *mph); + + +/* Chd algorithm API */ +cmph_t *chd_new(cmph_config_t *mph, double c); +void chd_load(FILE *fd, cmph_t *mphf); +int chd_dump(cmph_t *mphf, FILE *fd); +void chd_destroy(cmph_t *mphf); +cmph_uint32 chd_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void chd_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void chd_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 chd_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 chd_packed_size(cmph_t *mphf); + +/** cmph_uint32 chd_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 chd_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/chd_ph.c b/girepository/cmph/chd_ph.c new file mode 100644 index 0000000..ae986b4 --- /dev/null +++ b/girepository/cmph/chd_ph.c @@ -0,0 +1,1001 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +#include "cmph_structs.h" +#include "chd_structs_ph.h" +#include "chd_ph.h" +#include"miller_rabin.h" +#include"bitbool.h" + + +//#define DEBUG +#include "debug.h" + +// NO_ELEMENT is equivalent to null pointer +#ifndef NO_ELEMENT +#define NO_ELEMENT UINT_MAX +#endif + +// struct used to represent items at mapping, ordering and searching phases +struct _chd_ph_item_t +{ + cmph_uint32 f; + cmph_uint32 h; +}; +typedef struct _chd_ph_item_t chd_ph_item_t; + +// struct to represent the items at mapping phase only. +struct _chd_ph_map_item_t +{ + cmph_uint32 f; + cmph_uint32 h; + cmph_uint32 bucket_num; +}; +typedef struct _chd_ph_map_item_t chd_ph_map_item_t; + +// struct to represent a bucket +struct _chd_ph_bucket_t +{ + cmph_uint32 items_list; // offset + union + { + cmph_uint32 size; + cmph_uint32 bucket_id; + }; +}; + +typedef struct _chd_ph_bucket_t chd_ph_bucket_t; + +struct _chd_ph_sorted_list_t +{ + cmph_uint32 buckets_list; + cmph_uint32 size; +}; + +typedef struct _chd_ph_sorted_list_t chd_ph_sorted_list_t; + + +static inline chd_ph_bucket_t * chd_ph_bucket_new(cmph_uint32 nbuckets); +static inline void chd_ph_bucket_clean(chd_ph_bucket_t * buckets, cmph_uint32 nbuckets); +static inline void chd_ph_bucket_destroy(chd_ph_bucket_t * buckets); + +chd_ph_bucket_t * chd_ph_bucket_new(cmph_uint32 nbuckets) +{ + chd_ph_bucket_t * buckets = (chd_ph_bucket_t *) calloc(nbuckets, sizeof(chd_ph_bucket_t)); + return buckets; +} + +void chd_ph_bucket_clean(chd_ph_bucket_t * buckets, cmph_uint32 nbuckets) +{ + register cmph_uint32 i = 0; + assert(buckets); + for(i = 0; i < nbuckets; i++) + buckets[i].size = 0; +} +static cmph_uint8 chd_ph_bucket_insert(chd_ph_bucket_t * buckets,chd_ph_map_item_t * map_items, chd_ph_item_t * items, + cmph_uint32 nbuckets,cmph_uint32 item_idx) +{ + register cmph_uint32 i = 0; + register chd_ph_item_t * tmp_item; + register chd_ph_map_item_t * tmp_map_item = map_items + item_idx; + register chd_ph_bucket_t * bucket = buckets + tmp_map_item->bucket_num; + tmp_item = items + bucket->items_list; + + for(i = 0; i < bucket->size; i++) + { + if(tmp_item->f == tmp_map_item->f && tmp_item->h == tmp_map_item->h) + { + DEBUGP("Item not added\n"); + return 0; + }; + tmp_item++; + }; + tmp_item->f = tmp_map_item->f; + tmp_item->h = tmp_map_item->h; + bucket->size++; + return 1; +}; +void chd_ph_bucket_destroy(chd_ph_bucket_t * buckets) +{ + free(buckets); +} + +static inline cmph_uint8 chd_ph_mapping(cmph_config_t *mph, chd_ph_bucket_t * buckets, chd_ph_item_t * items, + cmph_uint32 *max_bucket_size); + +static chd_ph_sorted_list_t * chd_ph_ordering(chd_ph_bucket_t ** _buckets,chd_ph_item_t ** items, + cmph_uint32 nbuckets,cmph_uint32 nitems, cmph_uint32 max_bucket_size); + +static cmph_uint8 chd_ph_searching(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items , + cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, cmph_uint32 * disp_table); + +static inline double chd_ph_space_lower_bound(cmph_uint32 _n, cmph_uint32 _r) +{ + double r = _r, n = _n; + return (1 + (r/n - 1.0 + 1.0/(2.0*n))*log(1 - n/r))/log(2); +}; + +/* computes the entropy of non empty buckets.*/ +static inline double chd_ph_get_entropy(cmph_uint32 * disp_table, cmph_uint32 n, cmph_uint32 max_probes) +{ + register cmph_uint32 * probe_counts = (cmph_uint32 *) calloc(max_probes, sizeof(cmph_uint32)); + register cmph_uint32 i; + register double entropy = 0; + + for(i = 0; i < n; i++) + { + probe_counts[disp_table[i]]++; + }; + + for(i = 0; i < max_probes; i++) + { + if(probe_counts[i] > 0) + entropy -= probe_counts[i]*log((double)probe_counts[i]/(double)n)/log(2); + }; + free(probe_counts); + return entropy; +}; + +chd_ph_config_data_t *chd_ph_config_new(void) +{ + chd_ph_config_data_t *chd_ph; + chd_ph = (chd_ph_config_data_t *)malloc(sizeof(chd_ph_config_data_t)); + assert(chd_ph); + memset(chd_ph, 0, sizeof(chd_ph_config_data_t)); + + chd_ph->hashfunc = CMPH_HASH_JENKINS; + chd_ph->cs = NULL; + chd_ph->nbuckets = 0; + chd_ph->n = 0; + chd_ph->hl = NULL; + + chd_ph->m = 0; + chd_ph->use_h = 1; + chd_ph->keys_per_bin = 1; + chd_ph->keys_per_bucket = 4; + chd_ph->occup_table = 0; + + return chd_ph; +} + +void chd_ph_config_destroy(cmph_config_t *mph) +{ + chd_ph_config_data_t *data = (chd_ph_config_data_t *) mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + if(data->occup_table) + { + free(data->occup_table); + data->occup_table = NULL; + } + free(data); +} + + +void chd_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 1) break; //chd_ph only uses one linear hash function + chd_ph->hashfunc = *hashptr; + ++i, ++hashptr; + } +} + + +void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket) +{ + chd_ph_config_data_t *chd_ph; + assert(mph); + chd_ph = (chd_ph_config_data_t *)mph->data; + if(keys_per_bucket < 1 || keys_per_bucket >= 15) + { + keys_per_bucket = 4; + } + chd_ph->keys_per_bucket = keys_per_bucket; +} + + +void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin) +{ + chd_ph_config_data_t *chd_ph; + assert(mph); + chd_ph = (chd_ph_config_data_t *)mph->data; + if(keys_per_bin <= 1 || keys_per_bin >= 128) + { + keys_per_bin = 1; + } + chd_ph->keys_per_bin = keys_per_bin; +} + +cmph_uint8 chd_ph_mapping(cmph_config_t *mph, chd_ph_bucket_t * buckets, chd_ph_item_t * items, cmph_uint32 *max_bucket_size) +{ + register cmph_uint32 i = 0, g = 0; + cmph_uint32 hl[3]; + chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data; + char * key = NULL; + cmph_uint32 keylen = 0; + chd_ph_map_item_t * map_item; + chd_ph_map_item_t * map_items = malloc(chd_ph->m*sizeof(chd_ph_map_item_t)); + register cmph_uint32 mapping_iterations = 1000; + *max_bucket_size = 0; + while(1) + { + mapping_iterations--; + if (chd_ph->hl) hash_state_destroy(chd_ph->hl); + chd_ph->hl = hash_state_new(chd_ph->hashfunc, chd_ph->m); + + chd_ph_bucket_clean(buckets, chd_ph->nbuckets); + + mph->key_source->rewind(mph->key_source->data); + + for(i = 0; i < chd_ph->m; i++) + { + mph->key_source->read(mph->key_source->data, &key, &keylen); + hash_vector(chd_ph->hl, key, keylen, hl); + + map_item = (map_items + i); + + g = hl[0] % chd_ph->nbuckets; + map_item->f = hl[1] % chd_ph->n; + map_item->h = hl[2] % (chd_ph->n - 1) + 1; + map_item->bucket_num=g; + mph->key_source->dispose(mph->key_source->data, key, keylen); +// if(buckets[g].size == (chd_ph->keys_per_bucket << 2)) +// { +// DEBUGP("BUCKET = %u -- SIZE = %u -- MAXIMUM SIZE = %u\n", g, buckets[g].size, (chd_ph->keys_per_bucket << 2)); +// goto error; +// } + buckets[g].size++; + if(buckets[g].size > *max_bucket_size) + { + *max_bucket_size = buckets[g].size; + } + } + buckets[0].items_list = 0; + for(i = 1; i < chd_ph->nbuckets; i++) + { + buckets[i].items_list = buckets[i-1].items_list + buckets[i - 1].size; + buckets[i - 1].size = 0; + }; + buckets[i - 1].size = 0; + for(i = 0; i < chd_ph->m; i++) + { + map_item = (map_items + i); + if(!chd_ph_bucket_insert(buckets, map_items, items, chd_ph->nbuckets, i)) + break; + } + if(i == chd_ph->m) + { + free(map_items); + return 1; // SUCCESS + } + + if(mapping_iterations == 0) + { + goto error; + } + } +error: + free(map_items); + hash_state_destroy(chd_ph->hl); + chd_ph->hl = NULL; + return 0; // FAILURE +} + +chd_ph_sorted_list_t * chd_ph_ordering(chd_ph_bucket_t ** _buckets, chd_ph_item_t ** _items, + cmph_uint32 nbuckets, cmph_uint32 nitems, cmph_uint32 max_bucket_size) +{ + chd_ph_sorted_list_t * sorted_lists = (chd_ph_sorted_list_t *) calloc(max_bucket_size + 1, sizeof(chd_ph_sorted_list_t)); + + chd_ph_bucket_t * input_buckets = (*_buckets); + chd_ph_bucket_t * output_buckets; + chd_ph_item_t * input_items = (*_items); + chd_ph_item_t * output_items; + register cmph_uint32 i, j, bucket_size, position, position2; +// cmph_uint32 non_empty_buckets; + DEBUGP("MAX BUCKET SIZE = %u\n", max_bucket_size); + // Determine size of each list of buckets + for(i = 0; i < nbuckets; i++) + { + bucket_size = input_buckets[i].size; + if(bucket_size == 0) + continue; + sorted_lists[bucket_size].size++; + }; + sorted_lists[1].buckets_list = 0; + // Determine final position of list of buckets into the contiguous array that will store all the buckets + for(i = 2; i <= max_bucket_size; i++) + { + sorted_lists[i].buckets_list = sorted_lists[i-1].buckets_list + sorted_lists[i-1].size; + sorted_lists[i-1].size = 0; + }; + sorted_lists[i-1].size = 0; + // Store the buckets in a new array which is sorted by bucket sizes + output_buckets = calloc(nbuckets, sizeof(chd_ph_bucket_t)); // everything is initialized with zero +// non_empty_buckets = nbuckets; + + for(i = 0; i < nbuckets; i++) + { + bucket_size = input_buckets[i].size; + if(bucket_size == 0) + { +// non_empty_buckets--; + continue; + }; + position = sorted_lists[bucket_size].buckets_list + sorted_lists[bucket_size].size; + output_buckets[position].bucket_id = i; + output_buckets[position].items_list = input_buckets[i].items_list; + sorted_lists[bucket_size].size++; + }; +/* for(i = non_empty_buckets; i < nbuckets; i++) + output_buckets[i].size=0;*/ + // Return the buckets sorted in new order and free the old buckets sorted in old order + free(input_buckets); + (*_buckets) = output_buckets; + + + // Store the items according to the new order of buckets. + output_items = (chd_ph_item_t*)calloc(nitems, sizeof(chd_ph_item_t)); + position = 0; + i = 0; + for(bucket_size = 1; bucket_size <= max_bucket_size; bucket_size++) + { + for(i = sorted_lists[bucket_size].buckets_list; i < sorted_lists[bucket_size].size + sorted_lists[bucket_size].buckets_list; i++) + { + position2 = output_buckets[i].items_list; + output_buckets[i].items_list = position; + for(j = 0; j < bucket_size; j++) + { + output_items[position].f = input_items[position2].f; + output_items[position].h = input_items[position2].h; + position++; + position2++; + }; + }; + }; + //Return the items sorted in new order and free the old items sorted in old order + free(input_items); + (*_items) = output_items; + return sorted_lists; +}; + +static inline cmph_uint8 place_bucket_probe(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, + chd_ph_item_t *items, cmph_uint32 probe0_num, cmph_uint32 probe1_num, + cmph_uint32 bucket_num, cmph_uint32 size) +{ + register cmph_uint32 i; + register chd_ph_item_t * item; + register cmph_uint32 position; + + item = items + buckets[bucket_num].items_list; + // try place bucket with probe_num + if(chd_ph->keys_per_bin > 1) + { + for(i = 0; i < size; i++) // placement + { + position = (cmph_uint32)((item->f + ((cmph_uint64)item->h)*probe0_num + probe1_num) % chd_ph->n); + if(chd_ph->occup_table[position] >= chd_ph->keys_per_bin) + { + break; + } + (chd_ph->occup_table[position])++; + item++; + }; + } else + { + for(i = 0; i < size; i++) // placement + { + position = (cmph_uint32)((item->f + ((cmph_uint64)item->h)*probe0_num + probe1_num) % chd_ph->n); + if(GETBIT32(((cmph_uint32 *)chd_ph->occup_table), position)) + { + break; + } + SETBIT32(((cmph_uint32*)chd_ph->occup_table), position); + item++; + }; + }; + if(i != size) // Undo the placement + { + item = items + buckets[bucket_num].items_list; + if(chd_ph->keys_per_bin > 1) + { + while(1) + { + if(i == 0) + { + break; + } + position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n); + (chd_ph->occup_table[position])--; + item++; + i--; + }; + } else + { + while(1) + { + if(i == 0) + { + break; + } + position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n); + UNSETBIT32(((cmph_uint32*)chd_ph->occup_table), position); + +// ([position/32]^=(1<<(position%32)); + item++; + i--; + }; + }; + return 0; + } + return 1; +}; + +static inline cmph_uint8 place_bucket(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t * items, cmph_uint32 max_probes, + cmph_uint32 * disp_table, cmph_uint32 bucket_num, cmph_uint32 size) + +{ + register cmph_uint32 probe0_num, probe1_num, probe_num; + probe0_num = 0; + probe1_num = 0; + probe_num = 0; + + while(1) + { + if(place_bucket_probe(chd_ph, buckets, items, probe0_num, probe1_num, bucket_num,size)) + { + disp_table[buckets[bucket_num].bucket_id] = probe0_num + probe1_num * chd_ph->n; + return 1; + } + probe0_num++; + if(probe0_num >= chd_ph->n) + { + probe0_num -= chd_ph->n; + probe1_num++; + }; + probe_num++; + if(probe_num >= max_probes || probe1_num >= chd_ph->n) + { + return 0; + }; + }; + return 0; +}; + +static inline cmph_uint8 place_buckets1(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t * buckets, chd_ph_item_t *items, + cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, + cmph_uint32 * disp_table) +{ + register cmph_uint32 i = 0; + register cmph_uint32 curr_bucket = 0; + + for(i = max_bucket_size; i > 0; i--) + { + curr_bucket = sorted_lists[i].buckets_list; + while(curr_bucket < sorted_lists[i].size + sorted_lists[i].buckets_list) + { + if(!place_bucket(chd_ph, buckets, items, max_probes, disp_table, curr_bucket, i)) + { + return 0; + } + curr_bucket++; + }; + }; + return 1; +}; + +static inline cmph_uint8 place_buckets2(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t * items, + cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, + cmph_uint32 * disp_table) +{ + register cmph_uint32 i,j, non_placed_bucket; + register cmph_uint32 curr_bucket; + register cmph_uint32 probe_num, probe0_num, probe1_num; + cmph_uint32 sorted_list_size; +#ifdef DEBUG + cmph_uint32 items_list; + cmph_uint32 bucket_id; +#endif + DEBUGP("USING HEURISTIC TO PLACE BUCKETS\n"); + for(i = max_bucket_size; i > 0; i--) + { + probe_num = 0; + probe0_num = 0; + probe1_num = 0; + sorted_list_size = sorted_lists[i].size; + while(sorted_lists[i].size != 0) + { + curr_bucket = sorted_lists[i].buckets_list; + for(j = 0, non_placed_bucket = 0; j < sorted_lists[i].size; j++) + { + // if bucket is successfully placed remove it from list + if(place_bucket_probe(chd_ph, buckets, items, probe0_num, probe1_num, curr_bucket, i)) + { + disp_table[buckets[curr_bucket].bucket_id] = probe0_num + probe1_num * chd_ph->n; +// DEBUGP("BUCKET %u PLACED --- DISPLACEMENT = %u\n", curr_bucket, disp_table[curr_bucket]); + } + else + { +// DEBUGP("BUCKET %u NOT PLACED\n", curr_bucket); +#ifdef DEBUG + items_list = buckets[non_placed_bucket + sorted_lists[i].buckets_list].items_list; + bucket_id = buckets[non_placed_bucket + sorted_lists[i].buckets_list].bucket_id; +#endif + buckets[non_placed_bucket + sorted_lists[i].buckets_list].items_list = buckets[curr_bucket].items_list; + buckets[non_placed_bucket + sorted_lists[i].buckets_list].bucket_id = buckets[curr_bucket].bucket_id; +#ifdef DEBUG + buckets[curr_bucket].items_list=items_list; + buckets[curr_bucket].bucket_id=bucket_id; +#endif + non_placed_bucket++; + } + curr_bucket++; + }; + sorted_lists[i].size = non_placed_bucket; + probe0_num++; + if(probe0_num >= chd_ph->n) + { + probe0_num -= chd_ph->n; + probe1_num++; + }; + probe_num++; + if(probe_num >= max_probes || probe1_num >= chd_ph->n) + { + sorted_lists[i].size = sorted_list_size; + return 0; + }; + }; + sorted_lists[i].size = sorted_list_size; + }; + return 1; +}; + +cmph_uint8 chd_ph_searching(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items , + cmph_uint32 max_bucket_size, chd_ph_sorted_list_t *sorted_lists, cmph_uint32 max_probes, + cmph_uint32 * disp_table) +{ + if(chd_ph->use_h) + { + return place_buckets2(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table); + } + else + { + return place_buckets1(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table); + } + +} + +static inline cmph_uint8 chd_ph_check_bin_hashing(chd_ph_config_data_t *chd_ph, chd_ph_bucket_t *buckets, chd_ph_item_t *items, + cmph_uint32 * disp_table, chd_ph_sorted_list_t * sorted_lists,cmph_uint32 max_bucket_size) +{ + register cmph_uint32 bucket_size, i, j; + register cmph_uint32 position, probe0_num, probe1_num; + G_GNUC_UNUSED register cmph_uint32 m = 0; + register chd_ph_item_t * item; + if(chd_ph->keys_per_bin > 1) + memset(chd_ph->occup_table, 0, chd_ph->n); + else + memset(chd_ph->occup_table, 0, ((chd_ph->n + 31)/32) * sizeof(cmph_uint32)); + + for(bucket_size = 1; bucket_size <= max_bucket_size; bucket_size++) + for(i = sorted_lists[bucket_size].buckets_list; i < sorted_lists[bucket_size].size + + sorted_lists[bucket_size].buckets_list; i++) + { + j = bucket_size; + item = items + buckets[i].items_list; + probe0_num = disp_table[buckets[i].bucket_id] % chd_ph->n; + probe1_num = disp_table[buckets[i].bucket_id] / chd_ph->n; + for(; j > 0; j--) + { +#ifdef DEBUG + m++; +#endif + position = (cmph_uint32)((item->f + ((cmph_uint64 )item->h) * probe0_num + probe1_num) % chd_ph->n); + if(chd_ph->keys_per_bin > 1) + { + if(chd_ph->occup_table[position] >= chd_ph->keys_per_bin) + { + return 0; + } + (chd_ph->occup_table[position])++; + } + else + { + if(GETBIT32(((cmph_uint32*)chd_ph->occup_table), position)) + { + return 0; + } + SETBIT32(((cmph_uint32*)chd_ph->occup_table), position); + }; + item++; + }; + }; + DEBUGP("We were able to place m = %u keys\n", m); + return 1; +}; + + +cmph_t *chd_ph_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + chd_ph_data_t *chd_phf = NULL; + chd_ph_config_data_t *chd_ph = (chd_ph_config_data_t *)mph->data; + + register double load_factor = c; + register cmph_uint8 searching_success = 0; + register cmph_uint32 max_probes = 1 << 20; // default value for max_probes + register cmph_uint32 iterations = 100; + chd_ph_bucket_t * buckets = NULL; + chd_ph_item_t * items = NULL; + register cmph_uint8 failure = 0; + cmph_uint32 max_bucket_size = 0; + chd_ph_sorted_list_t * sorted_lists = NULL; + cmph_uint32 * disp_table = NULL; + register double space_lower_bound = 0; + #ifdef CMPH_TIMING + double construction_time_begin = 0.0; + double construction_time = 0.0; + ELAPSED_TIME_IN_SECONDS(&construction_time_begin); + #endif + + + chd_ph->m = mph->key_source->nkeys; + DEBUGP("m = %u\n", chd_ph->m); + + chd_ph->nbuckets = (cmph_uint32)(chd_ph->m/chd_ph->keys_per_bucket) + 1; + DEBUGP("nbuckets = %u\n", chd_ph->nbuckets); + + if(load_factor < 0.5 ) + { + load_factor = 0.5; + } + + if(load_factor >= 0.99) + { + load_factor = 0.99; + } + + DEBUGP("load_factor = %.3f\n", load_factor); + + chd_ph->n = (cmph_uint32)(chd_ph->m/(chd_ph->keys_per_bin * load_factor)) + 1; + + //Round the number of bins to the prime immediately above + if(chd_ph->n % 2 == 0) chd_ph->n++; + for(;;) + { + if(check_primality(chd_ph->n) == 1) + break; + chd_ph->n += 2; // just odd numbers can be primes for n > 2 + + }; + + DEBUGP("n = %u \n", chd_ph->n); + if(chd_ph->keys_per_bin == 1) + { + space_lower_bound = chd_ph_space_lower_bound(chd_ph->m, chd_ph->n); + } + + if(mph->verbosity) + { + fprintf(stderr, "space lower bound is %.3f bits per key\n", space_lower_bound); + } + + // We allocate the working tables + buckets = chd_ph_bucket_new(chd_ph->nbuckets); + items = (chd_ph_item_t *) calloc(chd_ph->m, sizeof(chd_ph_item_t)); + + max_probes = (cmph_uint32)(((log(chd_ph->m)/log(2))/20) * max_probes); + + if(chd_ph->keys_per_bin == 1) + chd_ph->occup_table = (cmph_uint8 *) calloc(((chd_ph->n + 31)/32), sizeof(cmph_uint32)); + else + chd_ph->occup_table = (cmph_uint8 *) calloc(chd_ph->n, sizeof(cmph_uint8)); + + disp_table = (cmph_uint32 *) calloc(chd_ph->nbuckets, sizeof(cmph_uint32)); +// +// init_genrand(time(0)); + + while(1) + { + iterations --; + if (mph->verbosity) + { + fprintf(stderr, "Starting mapping step for mph creation of %u keys with %u bins\n", chd_ph->m, chd_ph->n); + } + + if(!chd_ph_mapping(mph, buckets, items, &max_bucket_size)) + { + if (mph->verbosity) + { + fprintf(stderr, "Failure in mapping step\n"); + } + failure = 1; + goto cleanup; + } + + if (mph->verbosity) + { + fprintf(stderr, "Starting ordering step\n"); + } + if(sorted_lists) + { + free(sorted_lists); + } + + sorted_lists = chd_ph_ordering(&buckets, &items, chd_ph->nbuckets, chd_ph->m, max_bucket_size); + + if (mph->verbosity) + { + fprintf(stderr, "Starting searching step\n"); + } + + searching_success = chd_ph_searching(chd_ph, buckets, items, max_bucket_size, sorted_lists, max_probes, disp_table); + if(searching_success) break; + + // reset occup_table + if(chd_ph->keys_per_bin > 1) + memset(chd_ph->occup_table, 0, chd_ph->n); + else + memset(chd_ph->occup_table, 0, ((chd_ph->n + 31)/32) * sizeof(cmph_uint32)); + if(iterations == 0) + { + // Cleanup memory + if (mph->verbosity) + { + fprintf(stderr, "Failure because the max trials was exceeded\n"); + } + failure = 1; + goto cleanup; + }; + } + + #ifdef DEBUG + { + if(!chd_ph_check_bin_hashing(chd_ph, buckets, items, disp_table,sorted_lists,max_bucket_size)) + { + + DEBUGP("Error for bin packing generation"); + failure = 1; + goto cleanup; + } + } + #endif + + if (mph->verbosity) + { + fprintf(stderr, "Starting compressing step\n"); + } + + if(chd_ph->cs) + { + free(chd_ph->cs); + } + chd_ph->cs = (compressed_seq_t *) calloc(1, sizeof(compressed_seq_t)); + compressed_seq_init(chd_ph->cs); + compressed_seq_generate(chd_ph->cs, disp_table, chd_ph->nbuckets); + + #ifdef CMPH_TIMING + ELAPSED_TIME_IN_SECONDS(&construction_time); + register double entropy = chd_ph_get_entropy(disp_table, chd_ph->nbuckets, max_probes); + DEBUGP("Entropy = %.4f\n", entropy/chd_ph->m); + #endif + +cleanup: + chd_ph_bucket_destroy(buckets); + free(items); + free(sorted_lists); + free(disp_table); + if(failure) + { + if(chd_ph->hl) + { + hash_state_destroy(chd_ph->hl); + } + chd_ph->hl = NULL; + return NULL; + } + + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + chd_phf = (chd_ph_data_t *)malloc(sizeof(chd_ph_data_t)); + + chd_phf->cs = chd_ph->cs; + chd_ph->cs = NULL; //transfer memory ownership + chd_phf->hl = chd_ph->hl; + chd_ph->hl = NULL; //transfer memory ownership + chd_phf->n = chd_ph->n; + chd_phf->nbuckets = chd_ph->nbuckets; + + mphf->data = chd_phf; + mphf->size = chd_ph->n; + + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + + #ifdef CMPH_TIMING + register cmph_uint32 space_usage = chd_ph_packed_size(mphf)*8; + construction_time = construction_time - construction_time_begin; + fprintf(stdout, "%u\t%.2f\t%u\t%.4f\t%.4f\t%.4f\t%.4f\n", chd_ph->m, load_factor, chd_ph->keys_per_bucket, construction_time, space_usage/(double)chd_ph->m, space_lower_bound, entropy/chd_ph->m); + #endif + + return mphf; +} + + + +void chd_ph_load(FILE *fd, cmph_t *mphf) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + chd_ph_data_t *chd_ph = (chd_ph_data_t *)malloc(sizeof(chd_ph_data_t)); + + DEBUGP("Loading chd_ph mphf\n"); + mphf->data = chd_ph; + + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, fd); + chd_ph->hl = hash_state_load(buf, buflen); + free(buf); + + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + DEBUGP("Compressed sequence structure has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, fd); + chd_ph->cs = (compressed_seq_t *) calloc(1, sizeof(compressed_seq_t)); + compressed_seq_load(chd_ph->cs, buf, buflen); + free(buf); + + // loading n and nbuckets + DEBUGP("Reading n and nbuckets\n"); + nbytes = fread(&(chd_ph->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fread(&(chd_ph->nbuckets), sizeof(cmph_uint32), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } + +} + +int chd_ph_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + chd_ph_data_t *data = (chd_ph_data_t *)mphf->data; + + __cmph_dump(mphf, fd); + + hash_state_dump(data->hl, &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + compressed_seq_dump(data->cs, &buf, &buflen); + DEBUGP("Dumping compressed sequence structure with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + // dumping n and nbuckets + nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->nbuckets), sizeof(cmph_uint32), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + return 1; +} + +void chd_ph_destroy(cmph_t *mphf) +{ + chd_ph_data_t *data = (chd_ph_data_t *)mphf->data; + compressed_seq_destroy(data->cs); + free(data->cs); + hash_state_destroy(data->hl); + free(data); + free(mphf); + +} + +cmph_uint32 chd_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + register chd_ph_data_t * chd_ph = mphf->data; + cmph_uint32 hl[3]; + register cmph_uint32 disp,position; + register cmph_uint32 probe0_num,probe1_num; + register cmph_uint32 f,g,h; + hash_vector(chd_ph->hl, key, keylen, hl); + g = hl[0] % chd_ph->nbuckets; + f = hl[1] % chd_ph->n; + h = hl[2] % (chd_ph->n-1) + 1; + + disp = compressed_seq_query(chd_ph->cs, g); + probe0_num = disp % chd_ph->n; + probe1_num = disp/chd_ph->n; + position = (cmph_uint32)((f + ((cmph_uint64 )h)*probe0_num + probe1_num) % chd_ph->n); + return position; +} + +void chd_ph_pack(cmph_t *mphf, void *packed_mphf) +{ + chd_ph_data_t *data = (chd_ph_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + + // packing hl type + CMPH_HASH hl_type = hash_get_type(data->hl); + *((cmph_uint32 *) ptr) = hl_type; + ptr += sizeof(cmph_uint32); + + // packing hl + hash_state_pack(data->hl, ptr); + ptr += hash_state_packed_size(hl_type); + + // packing n + *((cmph_uint32 *) ptr) = data->n; + ptr += sizeof(data->n); + + // packing nbuckets + *((cmph_uint32 *) ptr) = data->nbuckets; + ptr += sizeof(data->nbuckets); + + // packing cs + compressed_seq_pack(data->cs, ptr); + //ptr += compressed_seq_packed_size(data->cs); + +} + +cmph_uint32 chd_ph_packed_size(cmph_t *mphf) +{ + register chd_ph_data_t *data = (chd_ph_data_t *)mphf->data; + register CMPH_HASH hl_type = hash_get_type(data->hl); + register cmph_uint32 hash_state_pack_size = hash_state_packed_size(hl_type); + register cmph_uint32 cs_pack_size = compressed_seq_packed_size(data->cs); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_pack_size + cs_pack_size + 3*sizeof(cmph_uint32)); + +} + +cmph_uint32 chd_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register CMPH_HASH hl_type = *(cmph_uint32 *)packed_mphf; + register cmph_uint8 *hl_ptr = (cmph_uint8 *)(packed_mphf) + 4; + + register cmph_uint32 * ptr = (cmph_uint32 *)(hl_ptr + hash_state_packed_size(hl_type)); + register cmph_uint32 n = *ptr++; + register cmph_uint32 nbuckets = *ptr++; + cmph_uint32 hl[3]; + + register cmph_uint32 disp,position; + register cmph_uint32 probe0_num,probe1_num; + register cmph_uint32 f,g,h; + + hash_vector_packed(hl_ptr, hl_type, key, keylen, hl); + + g = hl[0] % nbuckets; + f = hl[1] % n; + h = hl[2] % (n-1) + 1; + + disp = compressed_seq_query_packed(ptr, g); + probe0_num = disp % n; + probe1_num = disp/n; + position = (cmph_uint32)((f + ((cmph_uint64 )h)*probe0_num + probe1_num) % n); + return position; +} + + + diff --git a/girepository/cmph/chd_ph.h b/girepository/cmph/chd_ph.h new file mode 100644 index 0000000..03e4087 --- /dev/null +++ b/girepository/cmph/chd_ph.h @@ -0,0 +1,59 @@ +#ifndef _CMPH_CHD_PH_H__ +#define _CMPH_CHD_PH_H__ + +#include "cmph.h" + +typedef struct __chd_ph_data_t chd_ph_data_t; +typedef struct __chd_ph_config_data_t chd_ph_config_data_t; + +/* Config API */ +chd_ph_config_data_t *chd_ph_config_new(void); +void chd_ph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); + +/** \fn void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin); + * \brief Allows to set the number of keys per bin. + * \param mph pointer to the configuration structure + * \param keys_per_bin value for the number of keys per bin + */ +void chd_ph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin); + +/** \fn void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket); + * \brief Allows to set the number of keys per bucket. + * \param mph pointer to the configuration structure + * \param keys_per_bucket value for the number of keys per bucket + */ +void chd_ph_config_set_b(cmph_config_t *mph, cmph_uint32 keys_per_bucket); +void chd_ph_config_destroy(cmph_config_t *mph); + + +/* Chd algorithm API */ +cmph_t *chd_ph_new(cmph_config_t *mph, double c); +void chd_ph_load(FILE *fd, cmph_t *mphf); +int chd_ph_dump(cmph_t *mphf, FILE *fd); +void chd_ph_destroy(cmph_t *mphf); +cmph_uint32 chd_ph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void chd_ph_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void chd_ph_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 chd_ph_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 chd_ph_packed_size(cmph_t *mphf); + +/** cmph_uint32 chd_ph_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 chd_ph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/chd_structs.h b/girepository/cmph/chd_structs.h new file mode 100644 index 0000000..d62f682 --- /dev/null +++ b/girepository/cmph/chd_structs.h @@ -0,0 +1,21 @@ +#ifndef __CMPH_CHD_STRUCTS_H__ +#define __CMPH_CHD_STRUCTS_H__ + +#include "chd_structs_ph.h" +#include "chd_ph.h" +#include "compressed_rank.h" + +struct __chd_data_t +{ + cmph_uint32 packed_cr_size; + cmph_uint8 * packed_cr; // packed compressed rank structure to control the number of zeros in a bit vector + + cmph_uint32 packed_chd_phf_size; + cmph_uint8 * packed_chd_phf; +}; + +struct __chd_config_data_t +{ + cmph_config_t *chd_ph; // chd_ph algorithm must be used here +}; +#endif diff --git a/girepository/cmph/chd_structs_ph.h b/girepository/cmph/chd_structs_ph.h new file mode 100644 index 0000000..d869218 --- /dev/null +++ b/girepository/cmph/chd_structs_ph.h @@ -0,0 +1,29 @@ +#ifndef __CMPH_CHD_PH_STRUCTS_H__ +#define __CMPH_CHD_PH_STRUCTS_H__ + +#include "hash_state.h" +#include "compressed_seq.h" + +struct __chd_ph_data_t +{ + compressed_seq_t * cs; // compressed displacement values + cmph_uint32 nbuckets; // number of buckets + cmph_uint32 n; // number of bins + hash_state_t *hl; // linear hash function +}; + +struct __chd_ph_config_data_t +{ + CMPH_HASH hashfunc; // linear hash function to be used + compressed_seq_t * cs; // compressed displacement values + cmph_uint32 nbuckets; // number of buckets + cmph_uint32 n; // number of bins + hash_state_t *hl; // linear hash function + + cmph_uint32 m; // number of keys + cmph_uint8 use_h; // flag to indicate the of use of a heuristic (use_h = 1) + cmph_uint32 keys_per_bin;//maximum number of keys per bin + cmph_uint32 keys_per_bucket; // average number of keys per bucket + cmph_uint8 *occup_table; // table that indicates occupied positions +}; +#endif diff --git a/girepository/cmph/chm.c b/girepository/cmph/chm.c new file mode 100644 index 0000000..36a07a0 --- /dev/null +++ b/girepository/cmph/chm.c @@ -0,0 +1,396 @@ +#include "graph.h" +#include "chm.h" +#include "cmph_structs.h" +#include "chm_structs.h" +#include "hash.h" +#include "bitbool.h" + +#include +#include +#include +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +static int chm_gen_edges(cmph_config_t *mph); +static void chm_traverse(chm_config_data_t *chm, cmph_uint8 *visited, cmph_uint32 v); + +chm_config_data_t *chm_config_new(void) +{ + chm_config_data_t *chm = NULL; + chm = (chm_config_data_t *)malloc(sizeof(chm_config_data_t)); + assert(chm); + memset(chm, 0, sizeof(chm_config_data_t)); + chm->hashfuncs[0] = CMPH_HASH_JENKINS; + chm->hashfuncs[1] = CMPH_HASH_JENKINS; + chm->g = NULL; + chm->graph = NULL; + chm->hashes = NULL; + return chm; +} +void chm_config_destroy(cmph_config_t *mph) +{ + chm_config_data_t *data = (chm_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void chm_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + chm_config_data_t *chm = (chm_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 2) break; //chm only uses two hash functions + chm->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *chm_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + chm_data_t *chmf = NULL; + + cmph_uint32 i; + cmph_uint32 iterations = 20; + cmph_uint8 *visited = NULL; + chm_config_data_t *chm = (chm_config_data_t *)mph->data; + chm->m = mph->key_source->nkeys; + if (c == 0) c = 2.09; + chm->n = (cmph_uint32)ceil(c * mph->key_source->nkeys); + DEBUGP("m (edges): %u n (vertices): %u c: %f\n", chm->m, chm->n, c); + chm->graph = graph_new(chm->n, chm->m); + DEBUGP("Created graph\n"); + + chm->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3); + for(i = 0; i < 3; ++i) chm->hashes[i] = NULL; + //Mapping step + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", chm->m, chm->n); + } + while(1) + { + int ok; + chm->hashes[0] = hash_state_new(chm->hashfuncs[0], chm->n); + chm->hashes[1] = hash_state_new(chm->hashfuncs[1], chm->n); + ok = chm_gen_edges(mph); + if (!ok) + { + --iterations; + hash_state_destroy(chm->hashes[0]); + chm->hashes[0] = NULL; + hash_state_destroy(chm->hashes[1]); + chm->hashes[1] = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "Acyclic graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + if (iterations == 0) + { + graph_destroy(chm->graph); + return NULL; + } + + //Assignment step + if (mph->verbosity) + { + fprintf(stderr, "Starting assignment step\n"); + } + DEBUGP("Assignment step\n"); + visited = (cmph_uint8 *)malloc((size_t)(chm->n/8 + 1)); + memset(visited, 0, (size_t)(chm->n/8 + 1)); + free(chm->g); + chm->g = (cmph_uint32 *)malloc(chm->n * sizeof(cmph_uint32)); + assert(chm->g); + for (i = 0; i < chm->n; ++i) + { + if (!GETBIT(visited,i)) + { + chm->g[i] = 0; + chm_traverse(chm, visited, i); + } + } + graph_destroy(chm->graph); + free(visited); + chm->graph = NULL; + + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + chmf = (chm_data_t *)malloc(sizeof(chm_data_t)); + chmf->g = chm->g; + chm->g = NULL; //transfer memory ownership + chmf->hashes = chm->hashes; + chm->hashes = NULL; //transfer memory ownership + chmf->n = chm->n; + chmf->m = chm->m; + mphf->data = chmf; + mphf->size = chm->m; + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +static void chm_traverse(chm_config_data_t *chm, cmph_uint8 *visited, cmph_uint32 v) +{ + + graph_iterator_t it = graph_neighbors_it(chm->graph, v); + cmph_uint32 neighbor = 0; + SETBIT(visited,v); + + DEBUGP("Visiting vertex %u\n", v); + while((neighbor = graph_next_neighbor(chm->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + DEBUGP("Visiting neighbor %u\n", neighbor); + if(GETBIT(visited,neighbor)) continue; + DEBUGP("Visiting neighbor %u\n", neighbor); + DEBUGP("Visiting edge %u->%u with id %u\n", v, neighbor, graph_edge_id(chm->graph, v, neighbor)); + chm->g[neighbor] = graph_edge_id(chm->graph, v, neighbor) - chm->g[v]; + DEBUGP("g is %u (%u - %u mod %u)\n", chm->g[neighbor], graph_edge_id(chm->graph, v, neighbor), chm->g[v], chm->m); + chm_traverse(chm, visited, neighbor); + } +} + +static int chm_gen_edges(cmph_config_t *mph) +{ + cmph_uint32 e; + chm_config_data_t *chm = (chm_config_data_t *)mph->data; + int cycles = 0; + + DEBUGP("Generating edges for %u vertices with hash functions %s and %s\n", chm->n, cmph_hash_names[chm->hashfuncs[0]], cmph_hash_names[chm->hashfuncs[1]]); + graph_clear_edges(chm->graph); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint32 h1, h2; + cmph_uint32 keylen; + char *key; + mph->key_source->read(mph->key_source->data, &key, &keylen); + h1 = hash(chm->hashes[0], key, keylen) % chm->n; + h2 = hash(chm->hashes[1], key, keylen) % chm->n; + if (h1 == h2) if (++h2 >= chm->n) h2 = 0; + if (h1 == h2) + { + if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e); + mph->key_source->dispose(mph->key_source->data, key, keylen); + return 0; + } + DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key); + mph->key_source->dispose(mph->key_source->data, key, keylen); + graph_add_edge(chm->graph, h1, h2); + } + cycles = graph_is_cyclic(chm->graph); + if (mph->verbosity && cycles) fprintf(stderr, "Cyclic graph generated\n"); + DEBUGP("Looking for cycles: %u\n", cycles); + + return ! cycles; +} + +int chm_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 two = 2; //number of hash functions + chm_data_t *data = (chm_data_t *)mphf->data; + register size_t nbytes; + + __cmph_dump(mphf, fd); + + nbytes = fwrite(&two, sizeof(cmph_uint32), (size_t)1, fd); + hash_state_dump(data->hashes[0], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + hash_state_dump(data->hashes[1], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->n), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + + nbytes = fwrite(data->g, sizeof(cmph_uint32)*data->n, (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } +/* #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]); + fprintf(stderr, "\n"); + #endif*/ + return 1; +} + +void chm_load(FILE *f, cmph_t *mphf) +{ + cmph_uint32 nhashes; + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 i; + chm_data_t *chm = (chm_data_t *)malloc(sizeof(chm_data_t)); + register size_t nbytes; + DEBUGP("Loading chm mphf\n"); + mphf->data = chm; + nbytes = fread(&nhashes, sizeof(cmph_uint32), (size_t)1, f); + chm->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1)); + chm->hashes[nhashes] = NULL; + DEBUGP("Reading %u hashes\n", nhashes); + for (i = 0; i < nhashes; ++i) + { + hash_state_t *state = NULL; + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + state = hash_state_load(buf, buflen); + chm->hashes[i] = state; + free(buf); + } + + DEBUGP("Reading m and n\n"); + nbytes = fread(&(chm->n), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(chm->m), sizeof(cmph_uint32), (size_t)1, f); + + chm->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*chm->n); + nbytes = fread(chm->g, chm->n*sizeof(cmph_uint32), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return; + } + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < chm->n; ++i) fprintf(stderr, "%u ", chm->g[i]); + fprintf(stderr, "\n"); + #endif + return; +} + + +cmph_uint32 chm_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + chm_data_t *chm = mphf->data; + cmph_uint32 h1 = hash(chm->hashes[0], key, keylen) % chm->n; + cmph_uint32 h2 = hash(chm->hashes[1], key, keylen) % chm->n; + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 >= chm->n) h2 = 0; + DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, chm->g[h1], chm->g[h2], chm->m); + return (chm->g[h1] + chm->g[h2]) % chm->m; +} +void chm_destroy(cmph_t *mphf) +{ + chm_data_t *data = (chm_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hashes[0]); + hash_state_destroy(data->hashes[1]); + free(data->hashes); + free(data); + free(mphf); +} + +/** \fn void chm_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void chm_pack(cmph_t *mphf, void *packed_mphf) +{ + chm_data_t *data = (chm_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + CMPH_HASH h2_type; + + // packing h1 type + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + *((cmph_uint32 *) ptr) = h1_type; + ptr += sizeof(cmph_uint32); + + // packing h1 + hash_state_pack(data->hashes[0], ptr); + ptr += hash_state_packed_size(h1_type); + + // packing h2 type + h2_type = hash_get_type(data->hashes[1]); + *((cmph_uint32 *) ptr) = h2_type; + ptr += sizeof(cmph_uint32); + + // packing h2 + hash_state_pack(data->hashes[1], ptr); + ptr += hash_state_packed_size(h2_type); + + // packing n + *((cmph_uint32 *) ptr) = data->n; + ptr += sizeof(data->n); + + // packing m + *((cmph_uint32 *) ptr) = data->m; + ptr += sizeof(data->m); + + // packing g + memcpy(ptr, data->g, sizeof(cmph_uint32)*data->n); +} + +/** \fn cmph_uint32 chm_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 chm_packed_size(cmph_t *mphf) +{ + chm_data_t *data = (chm_data_t *)mphf->data; + CMPH_HASH h1_type = hash_get_type(data->hashes[0]); + CMPH_HASH h2_type = hash_get_type(data->hashes[1]); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + + 4*sizeof(cmph_uint32) + sizeof(cmph_uint32)*data->n); +} + +/** cmph_uint32 chm_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 chm_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint8 *h1_ptr = packed_mphf; + register CMPH_HASH h1_type = *((cmph_uint32 *)h1_ptr); + register cmph_uint8 *h2_ptr; + register CMPH_HASH h2_type; + register cmph_uint32 *g_ptr; + register cmph_uint32 n, m, h1, h2; + + h1_ptr += 4; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + h2_type = *((cmph_uint32 *)h2_ptr); + h2_ptr += 4; + + g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type)); + + n = *g_ptr++; + m = *g_ptr++; + + h1 = hash_packed(h1_ptr, h1_type, key, keylen) % n; + h2 = hash_packed(h2_ptr, h2_type, key, keylen) % n; + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 >= n) h2 = 0; + DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, g_ptr[h1], g_ptr[h2], m); + return (g_ptr[h1] + g_ptr[h2]) % m; +} diff --git a/girepository/cmph/chm.h b/girepository/cmph/chm.h new file mode 100644 index 0000000..392d23a --- /dev/null +++ b/girepository/cmph/chm.h @@ -0,0 +1,42 @@ +#ifndef __CMPH_CHM_H__ +#define __CMPH_CHM_H__ + +#include "cmph.h" + +typedef struct __chm_data_t chm_data_t; +typedef struct __chm_config_data_t chm_config_data_t; + +chm_config_data_t *chm_config_new(void); +void chm_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void chm_config_destroy(cmph_config_t *mph); +cmph_t *chm_new(cmph_config_t *mph, double c); + +void chm_load(FILE *f, cmph_t *mphf); +int chm_dump(cmph_t *mphf, FILE *f); +void chm_destroy(cmph_t *mphf); +cmph_uint32 chm_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void chm_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void chm_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 chm_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 chm_packed_size(cmph_t *mphf); + +/** cmph_uint32 chm_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 chm_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/chm_structs.h b/girepository/cmph/chm_structs.h new file mode 100644 index 0000000..fcad1bc --- /dev/null +++ b/girepository/cmph/chm_structs.h @@ -0,0 +1,24 @@ +#ifndef __CMPH_CHM_STRUCTS_H__ +#define __CMPH_CHM_STRUCTS_H__ + +#include "hash_state.h" + +struct __chm_data_t +{ + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + cmph_uint32 *g; + hash_state_t **hashes; +}; + +struct __chm_config_data_t +{ + CMPH_HASH hashfuncs[2]; + cmph_uint32 m; //edges (words) count + cmph_uint32 n; //vertex count + graph_t *graph; + cmph_uint32 *g; + hash_state_t **hashes; +}; + +#endif diff --git a/girepository/cmph/cmph.c b/girepository/cmph/cmph.c new file mode 100644 index 0000000..3fd40a2 --- /dev/null +++ b/girepository/cmph/cmph.c @@ -0,0 +1,844 @@ +#include "cmph.h" +#include "cmph_structs.h" +#include "chm.h" +#include "bmz.h" +#include "bmz8.h" +#include "brz.h" +#include "fch.h" +#include "bdz.h" +#include "bdz_ph.h" +#include "chd_ph.h" +#include "chd.h" + +#include +#include +#include +//#define DEBUG +#include "debug.h" + +const char *cmph_names[] = {"bmz", "bmz8", "chm", "brz", "fch", "bdz", "bdz_ph", "chd_ph", "chd", NULL }; + +typedef struct +{ + void *vector; + cmph_uint32 position; // access position when data is a vector +} cmph_vector_t; + + + +/** + * Support a vector of struct as the source of keys. + * + * E.g. The keys could be the fieldB's in a vector of struct rec where + * struct rec is defined as: + * struct rec { + * fieldA; + * fieldB; + * fieldC; + * } + */ +typedef struct +{ + void *vector; /* Pointer to the vector of struct */ + cmph_uint32 position; /* current position */ + cmph_uint32 struct_size; /* The size of the struct */ + cmph_uint32 key_offset; /* The byte offset of the key in the struct */ + cmph_uint32 key_len; /* The length of the key */ +} cmph_struct_vector_t; + + +static cmph_io_adapter_t *cmph_io_vector_new(void * vector, cmph_uint32 nkeys); +static void cmph_io_vector_destroy(cmph_io_adapter_t * key_source); + +static cmph_io_adapter_t *cmph_io_struct_vector_new(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys); +static void cmph_io_struct_vector_destroy(cmph_io_adapter_t * key_source); + +static int key_nlfile_read(void *data, char **key, cmph_uint32 *keylen) +{ + FILE *fd = (FILE *)data; + *key = NULL; + *keylen = 0; + while(1) + { + char buf[BUFSIZ]; + char *c = fgets(buf, BUFSIZ, fd); + if (c == NULL) return -1; + if (feof(fd)) return -1; + *key = (char *)realloc(*key, *keylen + strlen(buf) + 1); + memcpy(*key + *keylen, buf, strlen(buf)); + *keylen += (cmph_uint32)strlen(buf); + if (buf[strlen(buf) - 1] != '\n') continue; + break; + } + if ((*keylen) && (*key)[*keylen - 1] == '\n') + { + (*key)[(*keylen) - 1] = 0; + --(*keylen); + } + return (int)(*keylen); +} + +static int key_byte_vector_read(void *data, char **key, cmph_uint32 *keylen) +{ + cmph_vector_t *cmph_vector = (cmph_vector_t *)data; + cmph_uint8 **keys_vd = (cmph_uint8 **)cmph_vector->vector; + size_t size; + memcpy(keylen, keys_vd[cmph_vector->position], sizeof(*keylen)); + size = *keylen; + *key = (char *)malloc(size); + memcpy(*key, keys_vd[cmph_vector->position] + sizeof(*keylen), size); + cmph_vector->position = cmph_vector->position + 1; + return (int)(*keylen); + +} + +static int key_struct_vector_read(void *data, char **key, cmph_uint32 *keylen) +{ + cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)data; + char *keys_vd = (char *)cmph_struct_vector->vector; + size_t size; + *keylen = cmph_struct_vector->key_len; + size = *keylen; + *key = (char *)malloc(size); + memcpy(*key, (keys_vd + (cmph_struct_vector->position * cmph_struct_vector->struct_size) + cmph_struct_vector->key_offset), size); + cmph_struct_vector->position = cmph_struct_vector->position + 1; + return (int)(*keylen); +} + +static int key_vector_read(void *data, char **key, cmph_uint32 *keylen) +{ + cmph_vector_t *cmph_vector = (cmph_vector_t *)data; + char **keys_vd = (char **)cmph_vector->vector; + size_t size; + *keylen = (cmph_uint32)strlen(keys_vd[cmph_vector->position]); + size = *keylen; + *key = (char *)malloc(size + 1); + strcpy(*key, keys_vd[cmph_vector->position]); + cmph_vector->position = cmph_vector->position + 1; + return (int)(*keylen); + +} + + +static void key_nlfile_dispose(void *data, char *key, cmph_uint32 keylen) +{ + free(key); +} + +static void key_vector_dispose(void *data, char *key, cmph_uint32 keylen) +{ + free(key); +} + +static void key_nlfile_rewind(void *data) +{ + FILE *fd = (FILE *)data; + rewind(fd); +} + +static void key_struct_vector_rewind(void *data) +{ + cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)data; + cmph_struct_vector->position = 0; +} + +static void key_vector_rewind(void *data) +{ + cmph_vector_t *cmph_vector = (cmph_vector_t *)data; + cmph_vector->position = 0; +} + +static cmph_uint32 count_nlfile_keys(FILE *fd) +{ + cmph_uint32 count = 0; + rewind(fd); + while(1) + { + char buf[BUFSIZ]; + if (fgets(buf, BUFSIZ, fd) == NULL) break; + if (feof(fd)) break; + if (buf[strlen(buf) - 1] != '\n') continue; + ++count; + } + rewind(fd); + return count; +} + +cmph_io_adapter_t *cmph_io_nlfile_adapter(FILE * keys_fd) +{ + cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t)); + assert(key_source); + key_source->data = (void *)keys_fd; + key_source->nkeys = count_nlfile_keys(keys_fd); + key_source->read = key_nlfile_read; + key_source->dispose = key_nlfile_dispose; + key_source->rewind = key_nlfile_rewind; + return key_source; +} + +void cmph_io_nlfile_adapter_destroy(cmph_io_adapter_t * key_source) +{ + free(key_source); +} + +cmph_io_adapter_t *cmph_io_nlnkfile_adapter(FILE * keys_fd, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t)); + assert(key_source); + key_source->data = (void *)keys_fd; + key_source->nkeys = nkeys; + key_source->read = key_nlfile_read; + key_source->dispose = key_nlfile_dispose; + key_source->rewind = key_nlfile_rewind; + return key_source; +} + +void cmph_io_nlnkfile_adapter_destroy(cmph_io_adapter_t * key_source) +{ + free(key_source); +} + + +static cmph_io_adapter_t *cmph_io_struct_vector_new(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t)); + cmph_struct_vector_t * cmph_struct_vector = (cmph_struct_vector_t *)malloc(sizeof(cmph_struct_vector_t)); + assert(key_source); + assert(cmph_struct_vector); + cmph_struct_vector->vector = vector; + cmph_struct_vector->position = 0; + cmph_struct_vector->struct_size = struct_size; + cmph_struct_vector->key_offset = key_offset; + cmph_struct_vector->key_len = key_len; + key_source->data = (void *)cmph_struct_vector; + key_source->nkeys = nkeys; + return key_source; +} + +static void cmph_io_struct_vector_destroy(cmph_io_adapter_t * key_source) +{ + cmph_struct_vector_t *cmph_struct_vector = (cmph_struct_vector_t *)key_source->data; + cmph_struct_vector->vector = NULL; + free(cmph_struct_vector); + free(key_source); +} + +static cmph_io_adapter_t *cmph_io_vector_new(void * vector, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = (cmph_io_adapter_t *)malloc(sizeof(cmph_io_adapter_t)); + cmph_vector_t * cmph_vector = (cmph_vector_t *)malloc(sizeof(cmph_vector_t)); + assert(key_source); + assert(cmph_vector); + cmph_vector->vector = vector; + cmph_vector->position = 0; + key_source->data = (void *)cmph_vector; + key_source->nkeys = nkeys; + return key_source; +} + +static void cmph_io_vector_destroy(cmph_io_adapter_t * key_source) +{ + cmph_vector_t *cmph_vector = (cmph_vector_t *)key_source->data; + cmph_vector->vector = NULL; + free(cmph_vector); + free(key_source); +} + +cmph_io_adapter_t *cmph_io_byte_vector_adapter(cmph_uint8 ** vector, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = cmph_io_vector_new(vector, nkeys); + key_source->read = key_byte_vector_read; + key_source->dispose = key_vector_dispose; + key_source->rewind = key_vector_rewind; + return key_source; +} +void cmph_io_byte_vector_adapter_destroy(cmph_io_adapter_t * key_source) +{ + cmph_io_vector_destroy(key_source); +} + +cmph_io_adapter_t *cmph_io_struct_vector_adapter(void * vector, cmph_uint32 struct_size, cmph_uint32 key_offset, cmph_uint32 key_len, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = cmph_io_struct_vector_new(vector, struct_size, key_offset, key_len, nkeys); + key_source->read = key_struct_vector_read; + key_source->dispose = key_vector_dispose; + key_source->rewind = key_struct_vector_rewind; + return key_source; +} + +void cmph_io_struct_vector_adapter_destroy(cmph_io_adapter_t * key_source) +{ + cmph_io_struct_vector_destroy(key_source); +} + +cmph_io_adapter_t *cmph_io_vector_adapter(char ** vector, cmph_uint32 nkeys) +{ + cmph_io_adapter_t * key_source = cmph_io_vector_new(vector, nkeys); + key_source->read = key_vector_read; + key_source->dispose = key_vector_dispose; + key_source->rewind = key_vector_rewind; + return key_source; +} + +void cmph_io_vector_adapter_destroy(cmph_io_adapter_t * key_source) +{ + cmph_io_vector_destroy(key_source); +} + +cmph_config_t *cmph_config_new(cmph_io_adapter_t *key_source) +{ + cmph_config_t *mph = NULL; + mph = __config_new(key_source); + assert(mph); + mph->algo = CMPH_CHM; // default value + mph->data = chm_config_new(); + return mph; +} + +void cmph_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo) +{ + if (algo != mph->algo) + { + switch (mph->algo) + { + case CMPH_CHM: + chm_config_destroy(mph); + break; + case CMPH_BMZ: + bmz_config_destroy(mph); + break; + case CMPH_BMZ8: + bmz8_config_destroy(mph); + break; + case CMPH_BRZ: + brz_config_destroy(mph); + break; + case CMPH_FCH: + fch_config_destroy(mph); + break; + case CMPH_BDZ: + bdz_config_destroy(mph); + break; + case CMPH_BDZ_PH: + bdz_ph_config_destroy(mph); + break; + case CMPH_CHD_PH: + chd_ph_config_destroy(mph); + break; + case CMPH_CHD: + chd_config_destroy(mph); + break; + default: + assert(0); + } + switch(algo) + { + case CMPH_CHM: + mph->data = chm_config_new(); + break; + case CMPH_BMZ: + mph->data = bmz_config_new(); + break; + case CMPH_BMZ8: + mph->data = bmz8_config_new(); + break; + case CMPH_BRZ: + mph->data = brz_config_new(); + break; + case CMPH_FCH: + mph->data = fch_config_new(); + break; + case CMPH_BDZ: + mph->data = bdz_config_new(); + break; + case CMPH_BDZ_PH: + mph->data = bdz_ph_config_new(); + break; + case CMPH_CHD_PH: + mph->data = chd_ph_config_new(); + break; + case CMPH_CHD: + mph->data = chd_config_new(mph); + break; + default: + assert(0); + } + } + mph->algo = algo; +} + +void cmph_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir) +{ + if (mph->algo == CMPH_BRZ) + { + brz_config_set_tmp_dir(mph, tmp_dir); + } +} + + +void cmph_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd) +{ + if (mph->algo == CMPH_BRZ) + { + brz_config_set_mphf_fd(mph, mphf_fd); + } +} + +void cmph_config_set_b(cmph_config_t *mph, cmph_uint32 b) +{ + if (mph->algo == CMPH_BRZ) + { + brz_config_set_b(mph, b); + } + else if (mph->algo == CMPH_BDZ) + { + bdz_config_set_b(mph, b); + } + else if (mph->algo == CMPH_CHD_PH) + { + chd_ph_config_set_b(mph, b); + } + else if (mph->algo == CMPH_CHD) + { + chd_config_set_b(mph, b); + } +} + +void cmph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin) +{ + if (mph->algo == CMPH_CHD_PH) + { + chd_ph_config_set_keys_per_bin(mph, keys_per_bin); + } + else if (mph->algo == CMPH_CHD) + { + chd_config_set_keys_per_bin(mph, keys_per_bin); + } +} + +void cmph_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability) +{ + if (mph->algo == CMPH_BRZ) + { + brz_config_set_memory_availability(mph, memory_availability); + } +} + +void cmph_config_destroy(cmph_config_t *mph) +{ + if(mph) + { + DEBUGP("Destroying mph with algo %s\n", cmph_names[mph->algo]); + switch (mph->algo) + { + case CMPH_CHM: + chm_config_destroy(mph); + break; + case CMPH_BMZ: /* included -- Fabiano */ + bmz_config_destroy(mph); + break; + case CMPH_BMZ8: /* included -- Fabiano */ + bmz8_config_destroy(mph); + break; + case CMPH_BRZ: /* included -- Fabiano */ + brz_config_destroy(mph); + break; + case CMPH_FCH: /* included -- Fabiano */ + fch_config_destroy(mph); + break; + case CMPH_BDZ: /* included -- Fabiano */ + bdz_config_destroy(mph); + break; + case CMPH_BDZ_PH: /* included -- Fabiano */ + bdz_ph_config_destroy(mph); + break; + case CMPH_CHD_PH: /* included -- Fabiano */ + chd_ph_config_destroy(mph); + break; + case CMPH_CHD: /* included -- Fabiano */ + chd_config_destroy(mph); + break; + default: + assert(0); + } + __config_destroy(mph); + } +} + +void cmph_config_set_verbosity(cmph_config_t *mph, cmph_uint32 verbosity) +{ + mph->verbosity = verbosity; +} + +void cmph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + switch (mph->algo) + { + case CMPH_CHM: + chm_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_BMZ: /* included -- Fabiano */ + bmz_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_BMZ8: /* included -- Fabiano */ + bmz8_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_BRZ: /* included -- Fabiano */ + brz_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_FCH: /* included -- Fabiano */ + fch_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_BDZ: /* included -- Fabiano */ + bdz_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_BDZ_PH: /* included -- Fabiano */ + bdz_ph_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_CHD_PH: /* included -- Fabiano */ + chd_ph_config_set_hashfuncs(mph, hashfuncs); + break; + case CMPH_CHD: /* included -- Fabiano */ + chd_config_set_hashfuncs(mph, hashfuncs); + break; + default: + break; + } + return; +} +void cmph_config_set_graphsize(cmph_config_t *mph, double c) +{ + mph->c = c; + return; +} + +cmph_t *cmph_new(cmph_config_t *mph) +{ + cmph_t *mphf = NULL; + double c = mph->c; + + DEBUGP("Creating mph with algorithm %s\n", cmph_names[mph->algo]); + switch (mph->algo) + { + case CMPH_CHM: + DEBUGP("Creating chm hash\n"); + mphf = chm_new(mph, c); + break; + case CMPH_BMZ: /* included -- Fabiano */ + DEBUGP("Creating bmz hash\n"); + mphf = bmz_new(mph, c); + break; + case CMPH_BMZ8: /* included -- Fabiano */ + DEBUGP("Creating bmz8 hash\n"); + mphf = bmz8_new(mph, c); + break; + case CMPH_BRZ: /* included -- Fabiano */ + DEBUGP("Creating brz hash\n"); + if (c >= 2.0) brz_config_set_algo(mph, CMPH_FCH); + else brz_config_set_algo(mph, CMPH_BMZ8); + mphf = brz_new(mph, c); + break; + case CMPH_FCH: /* included -- Fabiano */ + DEBUGP("Creating fch hash\n"); + mphf = fch_new(mph, c); + break; + case CMPH_BDZ: /* included -- Fabiano */ + DEBUGP("Creating bdz hash\n"); + mphf = bdz_new(mph, c); + break; + case CMPH_BDZ_PH: /* included -- Fabiano */ + DEBUGP("Creating bdz_ph hash\n"); + mphf = bdz_ph_new(mph, c); + break; + case CMPH_CHD_PH: /* included -- Fabiano */ + DEBUGP("Creating chd_ph hash\n"); + mphf = chd_ph_new(mph, c); + break; + case CMPH_CHD: /* included -- Fabiano */ + DEBUGP("Creating chd hash\n"); + mphf = chd_new(mph, c); + break; + default: + assert(0); + } + return mphf; +} + +int cmph_dump(cmph_t *mphf, FILE *f) +{ + switch (mphf->algo) + { + case CMPH_CHM: + return chm_dump(mphf, f); + case CMPH_BMZ: /* included -- Fabiano */ + return bmz_dump(mphf, f); + case CMPH_BMZ8: /* included -- Fabiano */ + return bmz8_dump(mphf, f); + case CMPH_BRZ: /* included -- Fabiano */ + return brz_dump(mphf, f); + case CMPH_FCH: /* included -- Fabiano */ + return fch_dump(mphf, f); + case CMPH_BDZ: /* included -- Fabiano */ + return bdz_dump(mphf, f); + case CMPH_BDZ_PH: /* included -- Fabiano */ + return bdz_ph_dump(mphf, f); + case CMPH_CHD_PH: /* included -- Fabiano */ + return chd_ph_dump(mphf, f); + case CMPH_CHD: /* included -- Fabiano */ + return chd_dump(mphf, f); + default: + assert(0); + } + assert(0); + return 0; +} +cmph_t *cmph_load(FILE *f) +{ + cmph_t *mphf = NULL; + DEBUGP("Loading mphf generic parts\n"); + mphf = __cmph_load(f); + if (mphf == NULL) return NULL; + DEBUGP("Loading mphf algorithm dependent parts\n"); + + switch (mphf->algo) + { + case CMPH_CHM: + chm_load(f, mphf); + break; + case CMPH_BMZ: /* included -- Fabiano */ + DEBUGP("Loading bmz algorithm dependent parts\n"); + bmz_load(f, mphf); + break; + case CMPH_BMZ8: /* included -- Fabiano */ + DEBUGP("Loading bmz8 algorithm dependent parts\n"); + bmz8_load(f, mphf); + break; + case CMPH_BRZ: /* included -- Fabiano */ + DEBUGP("Loading brz algorithm dependent parts\n"); + brz_load(f, mphf); + break; + case CMPH_FCH: /* included -- Fabiano */ + DEBUGP("Loading fch algorithm dependent parts\n"); + fch_load(f, mphf); + break; + case CMPH_BDZ: /* included -- Fabiano */ + DEBUGP("Loading bdz algorithm dependent parts\n"); + bdz_load(f, mphf); + break; + case CMPH_BDZ_PH: /* included -- Fabiano */ + DEBUGP("Loading bdz_ph algorithm dependent parts\n"); + bdz_ph_load(f, mphf); + break; + case CMPH_CHD_PH: /* included -- Fabiano */ + DEBUGP("Loading chd_ph algorithm dependent parts\n"); + chd_ph_load(f, mphf); + break; + case CMPH_CHD: /* included -- Fabiano */ + DEBUGP("Loading chd algorithm dependent parts\n"); + chd_load(f, mphf); + break; + default: + assert(0); + } + DEBUGP("Loaded mphf\n"); + return mphf; +} + + +cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + DEBUGP("mphf algorithm: %u \n", mphf->algo); + switch(mphf->algo) + { + case CMPH_CHM: + return chm_search(mphf, key, keylen); + case CMPH_BMZ: /* included -- Fabiano */ + DEBUGP("bmz algorithm search\n"); + return bmz_search(mphf, key, keylen); + case CMPH_BMZ8: /* included -- Fabiano */ + DEBUGP("bmz8 algorithm search\n"); + return bmz8_search(mphf, key, keylen); + case CMPH_BRZ: /* included -- Fabiano */ + DEBUGP("brz algorithm search\n"); + return brz_search(mphf, key, keylen); + case CMPH_FCH: /* included -- Fabiano */ + DEBUGP("fch algorithm search\n"); + return fch_search(mphf, key, keylen); + case CMPH_BDZ: /* included -- Fabiano */ + DEBUGP("bdz algorithm search\n"); + return bdz_search(mphf, key, keylen); + case CMPH_BDZ_PH: /* included -- Fabiano */ + DEBUGP("bdz_ph algorithm search\n"); + return bdz_ph_search(mphf, key, keylen); + case CMPH_CHD_PH: /* included -- Fabiano */ + DEBUGP("chd_ph algorithm search\n"); + return chd_ph_search(mphf, key, keylen); + case CMPH_CHD: /* included -- Fabiano */ + DEBUGP("chd algorithm search\n"); + return chd_search(mphf, key, keylen); + default: + assert(0); + } + assert(0); + return 0; +} + +cmph_uint32 cmph_size(cmph_t *mphf) +{ + return mphf->size; +} + +void cmph_destroy(cmph_t *mphf) +{ + switch(mphf->algo) + { + case CMPH_CHM: + chm_destroy(mphf); + return; + case CMPH_BMZ: /* included -- Fabiano */ + bmz_destroy(mphf); + return; + case CMPH_BMZ8: /* included -- Fabiano */ + bmz8_destroy(mphf); + return; + case CMPH_BRZ: /* included -- Fabiano */ + brz_destroy(mphf); + return; + case CMPH_FCH: /* included -- Fabiano */ + fch_destroy(mphf); + return; + case CMPH_BDZ: /* included -- Fabiano */ + bdz_destroy(mphf); + return; + case CMPH_BDZ_PH: /* included -- Fabiano */ + bdz_ph_destroy(mphf); + return; + case CMPH_CHD_PH: /* included -- Fabiano */ + chd_ph_destroy(mphf); + return; + case CMPH_CHD: /* included -- Fabiano */ + chd_destroy(mphf); + return; + default: + assert(0); + } + assert(0); + return; +} + + +/** \fn void cmph_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void cmph_pack(cmph_t *mphf, void *packed_mphf) +{ + // packing algorithm type to be used in cmph.c + cmph_uint32 * ptr = (cmph_uint32 *) packed_mphf; + *ptr++ = mphf->algo; + DEBUGP("mphf->algo = %u\n", mphf->algo); + switch(mphf->algo) + { + case CMPH_CHM: + chm_pack(mphf, ptr); + break; + case CMPH_BMZ: /* included -- Fabiano */ + bmz_pack(mphf, ptr); + break; + case CMPH_BMZ8: /* included -- Fabiano */ + bmz8_pack(mphf, ptr); + break; + case CMPH_BRZ: /* included -- Fabiano */ + brz_pack(mphf, ptr); + break; + case CMPH_FCH: /* included -- Fabiano */ + fch_pack(mphf, ptr); + break; + case CMPH_BDZ: /* included -- Fabiano */ + bdz_pack(mphf, ptr); + break; + case CMPH_BDZ_PH: /* included -- Fabiano */ + bdz_ph_pack(mphf, ptr); + break; + case CMPH_CHD_PH: /* included -- Fabiano */ + chd_ph_pack(mphf, ptr); + break; + case CMPH_CHD: /* included -- Fabiano */ + chd_pack(mphf, ptr); + break; + default: + assert(0); + } + return; +} + +/** \fn cmph_uint32 cmph_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 cmph_packed_size(cmph_t *mphf) +{ + switch(mphf->algo) + { + case CMPH_CHM: + return chm_packed_size(mphf); + case CMPH_BMZ: /* included -- Fabiano */ + return bmz_packed_size(mphf); + case CMPH_BMZ8: /* included -- Fabiano */ + return bmz8_packed_size(mphf); + case CMPH_BRZ: /* included -- Fabiano */ + return brz_packed_size(mphf); + case CMPH_FCH: /* included -- Fabiano */ + return fch_packed_size(mphf); + case CMPH_BDZ: /* included -- Fabiano */ + return bdz_packed_size(mphf); + case CMPH_BDZ_PH: /* included -- Fabiano */ + return bdz_ph_packed_size(mphf); + case CMPH_CHD_PH: /* included -- Fabiano */ + return chd_ph_packed_size(mphf); + case CMPH_CHD: /* included -- Fabiano */ + return chd_packed_size(mphf); + default: + assert(0); + } + return 0; // FAILURE +} + +/** cmph_uint32 cmph_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 cmph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + cmph_uint32 *ptr = (cmph_uint32 *)packed_mphf; +// fprintf(stderr, "algo:%u\n", *ptr); + switch(*ptr) + { + case CMPH_CHM: + return chm_search_packed(++ptr, key, keylen); + case CMPH_BMZ: /* included -- Fabiano */ + return bmz_search_packed(++ptr, key, keylen); + case CMPH_BMZ8: /* included -- Fabiano */ + return bmz8_search_packed(++ptr, key, keylen); + case CMPH_BRZ: /* included -- Fabiano */ + return brz_search_packed(++ptr, key, keylen); + case CMPH_FCH: /* included -- Fabiano */ + return fch_search_packed(++ptr, key, keylen); + case CMPH_BDZ: /* included -- Fabiano */ + return bdz_search_packed(++ptr, key, keylen); + case CMPH_BDZ_PH: /* included -- Fabiano */ + return bdz_ph_search_packed(++ptr, key, keylen); + case CMPH_CHD_PH: /* included -- Fabiano */ + return chd_ph_search_packed(++ptr, key, keylen); + case CMPH_CHD: /* included -- Fabiano */ + return chd_search_packed(++ptr, key, keylen); + default: + assert(0); + } + return 0; // FAILURE +} diff --git a/girepository/cmph/cmph.h b/girepository/cmph/cmph.h new file mode 100644 index 0000000..1bc009e --- /dev/null +++ b/girepository/cmph/cmph.h @@ -0,0 +1,112 @@ +#ifndef __CMPH_H__ +#define __CMPH_H__ + +#include +#include + +#ifdef __cplusplus +extern "C" +{ +#endif + +#include "cmph_types.h" + +typedef struct __config_t cmph_config_t; +typedef struct __cmph_t cmph_t; + +typedef struct +{ + void *data; + cmph_uint32 nkeys; + int (*read)(void *, char **, cmph_uint32 *); + void (*dispose)(void *, char *, cmph_uint32); + void (*rewind)(void *); +} cmph_io_adapter_t; + +/** Adapter pattern API **/ +/* please call free() in the created adapters */ +cmph_io_adapter_t *cmph_io_nlfile_adapter(FILE * keys_fd); +void cmph_io_nlfile_adapter_destroy(cmph_io_adapter_t * key_source); + +cmph_io_adapter_t *cmph_io_nlnkfile_adapter(FILE * keys_fd, cmph_uint32 nkeys); +void cmph_io_nlnkfile_adapter_destroy(cmph_io_adapter_t * key_source); + +cmph_io_adapter_t *cmph_io_vector_adapter(char ** vector, cmph_uint32 nkeys); +void cmph_io_vector_adapter_destroy(cmph_io_adapter_t * key_source); + +cmph_io_adapter_t *cmph_io_byte_vector_adapter(cmph_uint8 ** vector, cmph_uint32 nkeys); +void cmph_io_byte_vector_adapter_destroy(cmph_io_adapter_t * key_source); + +cmph_io_adapter_t *cmph_io_struct_vector_adapter(void * vector, + cmph_uint32 struct_size, + cmph_uint32 key_offset, + cmph_uint32 key_len, + cmph_uint32 nkeys); + +void cmph_io_struct_vector_adapter_destroy(cmph_io_adapter_t * key_source); + +/** Hash configuration API **/ +cmph_config_t *cmph_config_new(cmph_io_adapter_t *key_source); +void cmph_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void cmph_config_set_verbosity(cmph_config_t *mph, cmph_uint32 verbosity); +void cmph_config_set_graphsize(cmph_config_t *mph, double c); +void cmph_config_set_algo(cmph_config_t *mph, CMPH_ALGO algo); +void cmph_config_set_tmp_dir(cmph_config_t *mph, cmph_uint8 *tmp_dir); +void cmph_config_set_mphf_fd(cmph_config_t *mph, FILE *mphf_fd); +void cmph_config_set_b(cmph_config_t *mph, cmph_uint32 b); +void cmph_config_set_keys_per_bin(cmph_config_t *mph, cmph_uint32 keys_per_bin); +void cmph_config_set_memory_availability(cmph_config_t *mph, cmph_uint32 memory_availability); +void cmph_config_destroy(cmph_config_t *mph); + +/** Hash API **/ +cmph_t *cmph_new(cmph_config_t *mph); + +/** cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + * \brief Computes the mphf value. + * \param mphf pointer to the resulting function + * \param key is the key to be hashed + * \param keylen is the key legth in bytes + * \return The mphf value + */ +cmph_uint32 cmph_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +cmph_uint32 cmph_size(cmph_t *mphf); +void cmph_destroy(cmph_t *mphf); + +/** Hash serialization/deserialization */ +int cmph_dump(cmph_t *mphf, FILE *f); +cmph_t *cmph_load(FILE *f); + +/** \fn void cmph_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the + * \param resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void cmph_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 cmph_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 cmph_packed_size(cmph_t *mphf); + +/** cmph_uint32 cmph_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 cmph_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +// TIMING functions. To use the macro CMPH_TIMING must be defined +#include "cmph_time.h" + + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/girepository/cmph/cmph_structs.c b/girepository/cmph/cmph_structs.c new file mode 100644 index 0000000..9ecf5fc --- /dev/null +++ b/girepository/cmph/cmph_structs.c @@ -0,0 +1,76 @@ +#include "cmph_structs.h" + +#include +#include + +//#define DEBUG +#include "debug.h" + +cmph_config_t *__config_new(cmph_io_adapter_t *key_source) +{ + cmph_config_t *mph = (cmph_config_t *)malloc(sizeof(cmph_config_t)); + memset(mph, 0, sizeof(cmph_config_t)); + if (mph == NULL) return NULL; + mph->key_source = key_source; + mph->verbosity = 0; + mph->data = NULL; + mph->c = 0; + return mph; +} + +void __config_destroy(cmph_config_t *mph) +{ + free(mph); +} + +void __cmph_dump(cmph_t *mphf, FILE *fd) +{ + register size_t nbytes; + nbytes = fwrite(cmph_names[mphf->algo], (size_t)(strlen(cmph_names[mphf->algo]) + 1), (size_t)1, fd); + nbytes = fwrite(&(mphf->size), sizeof(mphf->size), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } +} +cmph_t *__cmph_load(FILE *f) +{ + cmph_t *mphf = NULL; + cmph_uint32 i; + char algo_name[BUFSIZ]; + char *ptr = algo_name; + CMPH_ALGO algo = CMPH_COUNT; + register size_t nbytes; + + DEBUGP("Loading mphf\n"); + while(1) + { + size_t c = fread(ptr, (size_t)1, (size_t)1, f); + if (c != 1) return NULL; + if (*ptr == 0) break; + ++ptr; + } + for(i = 0; i < CMPH_COUNT; ++i) + { + if (strcmp(algo_name, cmph_names[i]) == 0) + { + algo = i; + } + } + if (algo == CMPH_COUNT) + { + DEBUGP("Algorithm %s not found\n", algo_name); + return NULL; + } + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = algo; + nbytes = fread(&(mphf->size), sizeof(mphf->size), (size_t)1, f); + mphf->data = NULL; + DEBUGP("Algorithm is %s and mphf is sized %u\n", cmph_names[algo], mphf->size); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + } + + return mphf; +} + + diff --git a/girepository/cmph/cmph_structs.h b/girepository/cmph/cmph_structs.h new file mode 100644 index 0000000..88fafb6 --- /dev/null +++ b/girepository/cmph/cmph_structs.h @@ -0,0 +1,33 @@ +#ifndef __CMPH_STRUCTS_H__ +#define __CMPH_STRUCTS_H__ + +#include "cmph.h" + +/** Hash generation algorithm data + */ +struct __config_t +{ + CMPH_ALGO algo; + cmph_io_adapter_t *key_source; + cmph_uint32 verbosity; + double c; + void *data; // algorithm dependent data +}; + +/** Hash querying algorithm data + */ +struct __cmph_t +{ + CMPH_ALGO algo; + cmph_uint32 size; + cmph_io_adapter_t *key_source; + void *data; // algorithm dependent data +}; + +cmph_config_t *__config_new(cmph_io_adapter_t *key_source); +void __config_destroy(cmph_config_t*); +void __cmph_dump(cmph_t *mphf, FILE *); +cmph_t *__cmph_load(FILE *f); + + +#endif diff --git a/girepository/cmph/cmph_time.h b/girepository/cmph/cmph_time.h new file mode 100644 index 0000000..5d5d893 --- /dev/null +++ b/girepository/cmph/cmph_time.h @@ -0,0 +1,62 @@ +#ifdef ELAPSED_TIME_IN_SECONDS +#undef ELAPSED_TIME_IN_SECONDS +#endif + +#ifdef ELAPSED_TIME_IN_uSECONDS +#undef ELAPSED_TIME_IN_uSECONDS +#endif + +#ifdef __GNUC__ + #include + #ifndef WIN32 + #include + #endif +#endif + +#ifdef __GNUC__ + #ifndef __CMPH_TIME_H__ + #define __CMPH_TIME_H__ + static inline void elapsed_time_in_seconds(double * elapsed_time) + { + struct timeval e_time; + if (gettimeofday(&e_time, NULL) < 0) { + return; + } + *elapsed_time = (double)e_time.tv_sec + ((double)e_time.tv_usec/1000000.0); + } + static inline void dummy_elapsed_time_in_seconds(double * elapsed_time) + { + (void) elapsed_time; + } + static inline void elapsed_time_in_useconds(cmph_uint64 * elapsed_time) + { + struct timeval e_time; + if (gettimeofday(&e_time, NULL) < 0) { + return; + } + *elapsed_time = (cmph_uint64)(e_time.tv_sec*1000000 + e_time.tv_usec); + } + static inline void dummy_elapsed_time_in_useconds(cmph_uint64 * elapsed_time) + { + (void) elapsed_time; + } + #endif +#endif + +#ifdef CMPH_TIMING + #ifdef __GNUC__ + #define ELAPSED_TIME_IN_SECONDS elapsed_time_in_seconds + #define ELAPSED_TIME_IN_uSECONDS elapsed_time_in_useconds + #else + #define ELAPSED_TIME_IN_SECONDS dummy_elapsed_time_in_seconds + #define ELAPSED_TIME_IN_uSECONDS dummy_elapsed_time_in_useconds + #endif +#else + #ifdef __GNUC__ + #define ELAPSED_TIME_IN_SECONDS + #define ELAPSED_TIME_IN_uSECONDS + #else + #define ELAPSED_TIME_IN_SECONDS dummy_elapsed_time_in_seconds + #define ELAPSED_TIME_IN_uSECONDS dummy_elapsed_time_in_useconds + #endif +#endif diff --git a/girepository/cmph/cmph_types.h b/girepository/cmph/cmph_types.h new file mode 100644 index 0000000..2883235 --- /dev/null +++ b/girepository/cmph/cmph_types.h @@ -0,0 +1,25 @@ +#include + +#ifndef __CMPH_TYPES_H__ +#define __CMPH_TYPES_H__ + +typedef gint8 cmph_int8; +typedef guint8 cmph_uint8; + +typedef gint16 cmph_int16; +typedef guint16 cmph_uint16; + +typedef gint32 cmph_int32; +typedef guint32 cmph_uint32; + +typedef gint64 cmph_int64; +typedef guint64 cmph_uint64; + +typedef enum { CMPH_HASH_JENKINS, CMPH_HASH_COUNT } CMPH_HASH; +extern const char *cmph_hash_names[]; +typedef enum { CMPH_BMZ, CMPH_BMZ8, CMPH_CHM, CMPH_BRZ, CMPH_FCH, + CMPH_BDZ, CMPH_BDZ_PH, + CMPH_CHD_PH, CMPH_CHD, CMPH_COUNT } CMPH_ALGO; +extern const char *cmph_names[]; + +#endif diff --git a/girepository/cmph/compressed_rank.c b/girepository/cmph/compressed_rank.c new file mode 100644 index 0000000..8019dbe --- /dev/null +++ b/girepository/cmph/compressed_rank.c @@ -0,0 +1,327 @@ +#include +#include +#include +#include +#include"compressed_rank.h" +#include"bitbool.h" +// #define DEBUG +#include"debug.h" +static inline cmph_uint32 compressed_rank_i_log2(cmph_uint32 x) +{ + register cmph_uint32 res = 0; + + while(x > 1) + { + x >>= 1; + res++; + } + return res; +}; + +void compressed_rank_init(compressed_rank_t * cr) +{ + cr->max_val = 0; + cr->n = 0; + cr->rem_r = 0; + select_init(&cr->sel); + cr->vals_rems = 0; +} + +void compressed_rank_destroy(compressed_rank_t * cr) +{ + free(cr->vals_rems); + cr->vals_rems = 0; + select_destroy(&cr->sel); +} + +void compressed_rank_generate(compressed_rank_t * cr, cmph_uint32 * vals_table, cmph_uint32 n) +{ + register cmph_uint32 i,j; + register cmph_uint32 rems_mask; + register cmph_uint32 * select_vec = 0; + cr->n = n; + cr->max_val = vals_table[cr->n - 1]; + cr->rem_r = compressed_rank_i_log2(cr->max_val/cr->n); + if(cr->rem_r == 0) + { + cr->rem_r = 1; + } + select_vec = (cmph_uint32 *) calloc(cr->max_val >> cr->rem_r, sizeof(cmph_uint32)); + cr->vals_rems = (cmph_uint32 *) calloc(BITS_TABLE_SIZE(cr->n, cr->rem_r), sizeof(cmph_uint32)); + rems_mask = (1U << cr->rem_r) - 1U; + + for(i = 0; i < cr->n; i++) + { + set_bits_value(cr->vals_rems, i, vals_table[i] & rems_mask, cr->rem_r, rems_mask); + } + + for(i = 1, j = 0; i <= cr->max_val >> cr->rem_r; i++) + { + while(i > (vals_table[j] >> cr->rem_r)) + { + j++; + } + select_vec[i - 1] = j; + }; + + + // FABIANO: before it was (cr->total_length >> cr->rem_r) + 1. But I wiped out the + 1 because + // I changed the select structure to work up to m, instead of up to m - 1. + select_generate(&cr->sel, select_vec, cr->max_val >> cr->rem_r, cr->n); + + free(select_vec); +} + +cmph_uint32 compressed_rank_query(compressed_rank_t * cr, cmph_uint32 idx) +{ + register cmph_uint32 rems_mask; + register cmph_uint32 val_quot, val_rem; + register cmph_uint32 sel_res, rank; + + if(idx > cr->max_val) + { + return cr->n; + } + + val_quot = idx >> cr->rem_r; + rems_mask = (1U << cr->rem_r) - 1U; + val_rem = idx & rems_mask; + if(val_quot == 0) + { + rank = sel_res = 0; + } + else + { + sel_res = select_query(&cr->sel, val_quot - 1) + 1; + rank = sel_res - val_quot; + } + + do + { + if(GETBIT32(cr->sel.bits_vec, sel_res)) + { + break; + } + if(get_bits_value(cr->vals_rems, rank, cr->rem_r, rems_mask) >= val_rem) + { + break; + } + sel_res++; + rank++; + } while(1); + + return rank; +} + +cmph_uint32 compressed_rank_get_space_usage(compressed_rank_t * cr) +{ + register cmph_uint32 space_usage = select_get_space_usage(&cr->sel); + space_usage += BITS_TABLE_SIZE(cr->n, cr->rem_r)*(cmph_uint32)sizeof(cmph_uint32)*8; + space_usage += 3*(cmph_uint32)sizeof(cmph_uint32)*8; + return space_usage; +} + +void compressed_rank_dump(compressed_rank_t * cr, char **buf, cmph_uint32 *buflen) +{ + register cmph_uint32 sel_size = select_packed_size(&(cr->sel)); + register cmph_uint32 vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r) * (cmph_uint32)sizeof(cmph_uint32); + register cmph_uint32 pos = 0; + char * buf_sel = 0; + cmph_uint32 buflen_sel = 0; +#ifdef DEBUG + cmph_uint32 i; +#endif + + *buflen = 4*(cmph_uint32)sizeof(cmph_uint32) + sel_size + vals_rems_size; + + DEBUGP("sel_size = %u\n", sel_size); + DEBUGP("vals_rems_size = %u\n", vals_rems_size); + + *buf = (char *)calloc(*buflen, sizeof(char)); + + if (!*buf) + { + *buflen = UINT_MAX; + return; + } + + // dumping max_val, n and rem_r + memcpy(*buf, &(cr->max_val), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("max_val = %u\n", cr->max_val); + + memcpy(*buf + pos, &(cr->n), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("n = %u\n", cr->n); + + memcpy(*buf + pos, &(cr->rem_r), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("rem_r = %u\n", cr->rem_r); + + // dumping sel + select_dump(&cr->sel, &buf_sel, &buflen_sel); + memcpy(*buf + pos, &buflen_sel, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("buflen_sel = %u\n", buflen_sel); + + memcpy(*buf + pos, buf_sel, buflen_sel); + + #ifdef DEBUG + i = 0; + for(i = 0; i < buflen_sel; i++) + { + DEBUGP("pos = %u -- buf_sel[%u] = %u\n", pos, i, *(*buf + pos + i)); + } + #endif + pos += buflen_sel; + + free(buf_sel); + + // dumping vals_rems + memcpy(*buf + pos, cr->vals_rems, vals_rems_size); + #ifdef DEBUG + for(i = 0; i < vals_rems_size; i++) + { + DEBUGP("pos = %u -- vals_rems_size = %u -- vals_rems[%u] = %u\n", pos, vals_rems_size, i, *(*buf + pos + i)); + } + #endif + pos += vals_rems_size; + + DEBUGP("Dumped compressed rank structure with size %u bytes\n", *buflen); +} + +void compressed_rank_load(compressed_rank_t * cr, const char *buf, cmph_uint32 buflen) +{ + register cmph_uint32 pos = 0; + cmph_uint32 buflen_sel = 0; + register cmph_uint32 vals_rems_size = 0; +#ifdef DEBUG + cmph_uint32 i; +#endif + + // loading max_val, n, and rem_r + memcpy(&(cr->max_val), buf, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("max_val = %u\n", cr->max_val); + + memcpy(&(cr->n), buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("n = %u\n", cr->n); + + memcpy(&(cr->rem_r), buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("rem_r = %u\n", cr->rem_r); + + // loading sel + memcpy(&buflen_sel, buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("buflen_sel = %u\n", buflen_sel); + + select_load(&cr->sel, buf + pos, buflen_sel); + #ifdef DEBUG + i = 0; + for(i = 0; i < buflen_sel; i++) + { + DEBUGP("pos = %u -- buf_sel[%u] = %u\n", pos, i, *(buf + pos + i)); + } + #endif + pos += buflen_sel; + + // loading vals_rems + if(cr->vals_rems) + { + free(cr->vals_rems); + } + vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r); + cr->vals_rems = (cmph_uint32 *) calloc(vals_rems_size, sizeof(cmph_uint32)); + vals_rems_size *= 4; + memcpy(cr->vals_rems, buf + pos, vals_rems_size); + + #ifdef DEBUG + for(i = 0; i < vals_rems_size; i++) + { + DEBUGP("pos = %u -- vals_rems_size = %u -- vals_rems[%u] = %u\n", pos, vals_rems_size, i, *(buf + pos + i)); + } + #endif + pos += vals_rems_size; + + DEBUGP("Loaded compressed rank structure with size %u bytes\n", buflen); +} + + + +void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed) +{ + if (cr && cr_packed) + { + char *buf = NULL; + cmph_uint32 buflen = 0; + compressed_rank_dump(cr, &buf, &buflen); + memcpy(cr_packed, buf, buflen); + free(buf); + } +} + +cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr) +{ + register cmph_uint32 sel_size = select_packed_size(&cr->sel); + register cmph_uint32 vals_rems_size = BITS_TABLE_SIZE(cr->n, cr->rem_r) * (cmph_uint32)sizeof(cmph_uint32); + return 4 * (cmph_uint32)sizeof(cmph_uint32) + sel_size + vals_rems_size; +} + +cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx) +{ + // unpacking cr_packed + register cmph_uint32 *ptr = (cmph_uint32 *)cr_packed; + register cmph_uint32 max_val = *ptr++; + register cmph_uint32 n = *ptr++; + register cmph_uint32 rem_r = *ptr++; + register cmph_uint32 buflen_sel = *ptr++; + register cmph_uint32 * sel_packed = ptr; + + register cmph_uint32 * bits_vec = sel_packed + 2; // skipping n and m + + register cmph_uint32 * vals_rems = (ptr += (buflen_sel >> 2)); + + // compressed sequence query computation + register cmph_uint32 rems_mask; + register cmph_uint32 val_quot, val_rem; + register cmph_uint32 sel_res, rank; + + if(idx > max_val) + { + return n; + } + + val_quot = idx >> rem_r; + rems_mask = (1U << rem_r) - 1U; + val_rem = idx & rems_mask; + if(val_quot == 0) + { + rank = sel_res = 0; + } + else + { + sel_res = select_query_packed(sel_packed, val_quot - 1) + 1; + rank = sel_res - val_quot; + } + + do + { + if(GETBIT32(bits_vec, sel_res)) + { + break; + } + if(get_bits_value(vals_rems, rank, rem_r, rems_mask) >= val_rem) + { + break; + } + sel_res++; + rank++; + } while(1); + + return rank; +} + + + diff --git a/girepository/cmph/compressed_rank.h b/girepository/cmph/compressed_rank.h new file mode 100644 index 0000000..bfe930d --- /dev/null +++ b/girepository/cmph/compressed_rank.h @@ -0,0 +1,55 @@ +#ifndef __CMPH_COMPRESSED_RANK_H__ +#define __CMPH_COMPRESSED_RANK_H__ + +#include "select.h" + +struct _compressed_rank_t +{ + cmph_uint32 max_val; + cmph_uint32 n; // number of values stored in vals_rems + // The length in bits of each value is decomposed into two compnents: the lg(n) MSBs are stored in rank_select data structure + // the remaining LSBs are stored in a table of n cells, each one of rem_r bits. + cmph_uint32 rem_r; + select_t sel; + cmph_uint32 * vals_rems; +}; + +typedef struct _compressed_rank_t compressed_rank_t; + +void compressed_rank_init(compressed_rank_t * cr); + +void compressed_rank_destroy(compressed_rank_t * cr); + +void compressed_rank_generate(compressed_rank_t * cr, cmph_uint32 * vals_table, cmph_uint32 n); + +cmph_uint32 compressed_rank_query(compressed_rank_t * cr, cmph_uint32 idx); + +cmph_uint32 compressed_rank_get_space_usage(compressed_rank_t * cr); + +void compressed_rank_dump(compressed_rank_t * cr, char **buf, cmph_uint32 *buflen); + +void compressed_rank_load(compressed_rank_t * cr, const char *buf, cmph_uint32 buflen); + + +/** \fn void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed); + * \brief Support the ability to pack a compressed_rank structure into a preallocated contiguous memory space pointed by cr_packed. + * \param cr points to the compressed_rank structure + * \param cr_packed pointer to the contiguous memory area used to store the compressed_rank structure. The size of cr_packed must be at least @see compressed_rank_packed_size + */ +void compressed_rank_pack(compressed_rank_t *cr, void *cr_packed); + +/** \fn cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr); + * \brief Return the amount of space needed to pack a compressed_rank structure. + * \return the size of the packed compressed_rank structure or zero for failures + */ +cmph_uint32 compressed_rank_packed_size(compressed_rank_t *cr); + + +/** \fn cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx); + * \param cr_packed is a pointer to a contiguous memory area + * \param idx is an index to compute the rank + * \return an integer that represents the compressed_rank value. + */ +cmph_uint32 compressed_rank_query_packed(void * cr_packed, cmph_uint32 idx); + +#endif diff --git a/girepository/cmph/compressed_seq.c b/girepository/cmph/compressed_seq.c new file mode 100644 index 0000000..e5191fd --- /dev/null +++ b/girepository/cmph/compressed_seq.c @@ -0,0 +1,384 @@ +#include "compressed_seq.h" +#include +#include +#include +#include +#include + +#include "bitbool.h" + +// #define DEBUG +#include "debug.h" + +static inline cmph_uint32 compressed_seq_i_log2(cmph_uint32 x) +{ + register cmph_uint32 res = 0; + + while(x > 1) + { + x >>= 1; + res++; + } + return res; +}; + +void compressed_seq_init(compressed_seq_t * cs) +{ + select_init(&cs->sel); + cs->n = 0; + cs->rem_r = 0; + cs->length_rems = 0; + cs->total_length = 0; + cs->store_table = 0; +} + +void compressed_seq_destroy(compressed_seq_t * cs) +{ + free(cs->store_table); + cs->store_table = 0; + free(cs->length_rems); + cs->length_rems = 0; + select_destroy(&cs->sel); +}; + + +void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n) +{ + register cmph_uint32 i; + // lengths: represents lengths of encoded values + register cmph_uint32 * lengths = (cmph_uint32 *)calloc(n, sizeof(cmph_uint32)); + register cmph_uint32 rems_mask; + register cmph_uint32 stored_value; + + cs->n = n; + cs->total_length = 0; + + for(i = 0; i < cs->n; i++) + { + if(vals_table[i] == 0) + { + lengths[i] = 0; + } + else + { + lengths[i] = compressed_seq_i_log2(vals_table[i] + 1); + cs->total_length += lengths[i]; + }; + }; + + if(cs->store_table) + { + free(cs->store_table); + } + cs->store_table = (cmph_uint32 *) calloc(((cs->total_length + 31) >> 5), sizeof(cmph_uint32)); + cs->total_length = 0; + + for(i = 0; i < cs->n; i++) + { + if(vals_table[i] == 0) + continue; + stored_value = vals_table[i] - ((1U << lengths[i]) - 1U); + set_bits_at_pos(cs->store_table, cs->total_length, stored_value, lengths[i]); + cs->total_length += lengths[i]; + }; + + cs->rem_r = compressed_seq_i_log2(cs->total_length/cs->n); + + if(cs->rem_r == 0) + { + cs->rem_r = 1; + } + + if(cs->length_rems) + { + free(cs->length_rems); + } + + cs->length_rems = (cmph_uint32 *) calloc(BITS_TABLE_SIZE(cs->n, cs->rem_r), sizeof(cmph_uint32)); + + rems_mask = (1U << cs->rem_r) - 1U; + cs->total_length = 0; + + for(i = 0; i < cs->n; i++) + { + cs->total_length += lengths[i]; + set_bits_value(cs->length_rems, i, cs->total_length & rems_mask, cs->rem_r, rems_mask); + lengths[i] = cs->total_length >> cs->rem_r; + }; + + select_init(&cs->sel); + + // FABIANO: before it was (cs->total_length >> cs->rem_r) + 1. But I wiped out the + 1 because + // I changed the select structure to work up to m, instead of up to m - 1. + select_generate(&cs->sel, lengths, cs->n, (cs->total_length >> cs->rem_r)); + + free(lengths); +}; + +cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs) +{ + register cmph_uint32 space_usage = select_get_space_usage(&cs->sel); + space_usage += ((cs->total_length + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32) * 8; + space_usage += BITS_TABLE_SIZE(cs->n, cs->rem_r) * (cmph_uint32)sizeof(cmph_uint32) * 8; + return 4 * (cmph_uint32)sizeof(cmph_uint32) * 8 + space_usage; +} + +cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx) +{ + register cmph_uint32 enc_idx, enc_length; + register cmph_uint32 rems_mask; + register cmph_uint32 stored_value; + register cmph_uint32 sel_res; + + assert(idx < cs->n); // FABIANO ADDED + + rems_mask = (1U << cs->rem_r) - 1U; + + if(idx == 0) + { + enc_idx = 0; + sel_res = select_query(&cs->sel, idx); + } + else + { + sel_res = select_query(&cs->sel, idx - 1); + + enc_idx = (sel_res - (idx - 1)) << cs->rem_r; + enc_idx += get_bits_value(cs->length_rems, idx-1, cs->rem_r, rems_mask); + + sel_res = select_next_query(&cs->sel, sel_res); + }; + + enc_length = (sel_res - idx) << cs->rem_r; + enc_length += get_bits_value(cs->length_rems, idx, cs->rem_r, rems_mask); + enc_length -= enc_idx; + if(enc_length == 0) + return 0; + + stored_value = get_bits_at_pos(cs->store_table, enc_idx, enc_length); + return stored_value + ((1U << enc_length) - 1U); +}; + +void compressed_seq_dump(compressed_seq_t * cs, char ** buf, cmph_uint32 * buflen) +{ + register cmph_uint32 sel_size = select_packed_size(&(cs->sel)); + register cmph_uint32 length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r) * 4; + register cmph_uint32 store_table_size = ((cs->total_length + 31) >> 5) * 4; + register cmph_uint32 pos = 0; + char * buf_sel = 0; + cmph_uint32 buflen_sel = 0; +#ifdef DEBUG + cmph_uint32 i; +#endif + + *buflen = 4*(cmph_uint32)sizeof(cmph_uint32) + sel_size + length_rems_size + store_table_size; + + DEBUGP("sel_size = %u\n", sel_size); + DEBUGP("length_rems_size = %u\n", length_rems_size); + DEBUGP("store_table_size = %u\n", store_table_size); + *buf = (char *)calloc(*buflen, sizeof(char)); + + if (!*buf) + { + *buflen = UINT_MAX; + return; + } + + // dumping n, rem_r and total_length + memcpy(*buf, &(cs->n), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("n = %u\n", cs->n); + + memcpy(*buf + pos, &(cs->rem_r), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("rem_r = %u\n", cs->rem_r); + + memcpy(*buf + pos, &(cs->total_length), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("total_length = %u\n", cs->total_length); + + + // dumping sel + select_dump(&cs->sel, &buf_sel, &buflen_sel); + memcpy(*buf + pos, &buflen_sel, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("buflen_sel = %u\n", buflen_sel); + + memcpy(*buf + pos, buf_sel, buflen_sel); + #ifdef DEBUG + i = 0; + for(i = 0; i < buflen_sel; i++) + { + DEBUGP("pos = %u -- buf_sel[%u] = %u\n", pos, i, *(*buf + pos + i)); + } + #endif + pos += buflen_sel; + + free(buf_sel); + + // dumping length_rems + memcpy(*buf + pos, cs->length_rems, length_rems_size); + #ifdef DEBUG + for(i = 0; i < length_rems_size; i++) + { + DEBUGP("pos = %u -- length_rems_size = %u -- length_rems[%u] = %u\n", pos, length_rems_size, i, *(*buf + pos + i)); + } + #endif + pos += length_rems_size; + + // dumping store_table + memcpy(*buf + pos, cs->store_table, store_table_size); + + #ifdef DEBUG + for(i = 0; i < store_table_size; i++) + { + DEBUGP("pos = %u -- store_table_size = %u -- store_table[%u] = %u\n", pos, store_table_size, i, *(*buf + pos + i)); + } + #endif + DEBUGP("Dumped compressed sequence structure with size %u bytes\n", *buflen); +} + +void compressed_seq_load(compressed_seq_t * cs, const char * buf, cmph_uint32 buflen) +{ + register cmph_uint32 pos = 0; + cmph_uint32 buflen_sel = 0; + register cmph_uint32 length_rems_size = 0; + register cmph_uint32 store_table_size = 0; +#ifdef DEBUG + cmph_uint32 i; +#endif + + // loading n, rem_r and total_length + memcpy(&(cs->n), buf, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("n = %u\n", cs->n); + + memcpy(&(cs->rem_r), buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("rem_r = %u\n", cs->rem_r); + + memcpy(&(cs->total_length), buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("total_length = %u\n", cs->total_length); + + // loading sel + memcpy(&buflen_sel, buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + DEBUGP("buflen_sel = %u\n", buflen_sel); + + select_load(&cs->sel, buf + pos, buflen_sel); + #ifdef DEBUG + i = 0; + for(i = 0; i < buflen_sel; i++) + { + DEBUGP("pos = %u -- buf_sel[%u] = %u\n", pos, i, *(buf + pos + i)); + } + #endif + pos += buflen_sel; + + // loading length_rems + if(cs->length_rems) + { + free(cs->length_rems); + } + length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r); + cs->length_rems = (cmph_uint32 *) calloc(length_rems_size, sizeof(cmph_uint32)); + length_rems_size *= 4; + memcpy(cs->length_rems, buf + pos, length_rems_size); + + #ifdef DEBUG + for(i = 0; i < length_rems_size; i++) + { + DEBUGP("pos = %u -- length_rems_size = %u -- length_rems[%u] = %u\n", pos, length_rems_size, i, *(buf + pos + i)); + } + #endif + pos += length_rems_size; + + // loading store_table + store_table_size = ((cs->total_length + 31) >> 5); + if(cs->store_table) + { + free(cs->store_table); + } + cs->store_table = (cmph_uint32 *) calloc(store_table_size, sizeof(cmph_uint32)); + store_table_size *= 4; + memcpy(cs->store_table, buf + pos, store_table_size); + + #ifdef DEBUG + for(i = 0; i < store_table_size; i++) + { + DEBUGP("pos = %u -- store_table_size = %u -- store_table[%u] = %u\n", pos, store_table_size, i, *(buf + pos + i)); + } + #endif + + DEBUGP("Loaded compressed sequence structure with size %u bytes\n", buflen); +} + +void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed) +{ + if (cs && cs_packed) + { + char *buf = NULL; + cmph_uint32 buflen = 0; + compressed_seq_dump(cs, &buf, &buflen); + memcpy(cs_packed, buf, buflen); + free(buf); + } + +} + +cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs) +{ + register cmph_uint32 sel_size = select_packed_size(&cs->sel); + register cmph_uint32 store_table_size = ((cs->total_length + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); + register cmph_uint32 length_rems_size = BITS_TABLE_SIZE(cs->n, cs->rem_r) * (cmph_uint32)sizeof(cmph_uint32); + return 4 * (cmph_uint32)sizeof(cmph_uint32) + sel_size + store_table_size + length_rems_size; +} + + +cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx) +{ + // unpacking cs_packed + register cmph_uint32 *ptr = (cmph_uint32 *)cs_packed; + register cmph_uint32 n = *ptr++; + register cmph_uint32 rem_r = *ptr++; + register cmph_uint32 buflen_sel, length_rems_size, enc_idx, enc_length; + // compressed sequence query computation + register cmph_uint32 rems_mask, stored_value, sel_res; + register cmph_uint32 *sel_packed, *length_rems, *store_table; + + ptr++; // skipping total_length +// register cmph_uint32 total_length = *ptr++; + buflen_sel = *ptr++; + sel_packed = ptr; + length_rems = (ptr += (buflen_sel >> 2)); + length_rems_size = BITS_TABLE_SIZE(n, rem_r); + store_table = (ptr += length_rems_size); + + + rems_mask = (1U << rem_r) - 1U; + + if(idx == 0) + { + enc_idx = 0; + sel_res = select_query_packed(sel_packed, idx); + } + else + { + sel_res = select_query_packed(sel_packed, idx - 1); + + enc_idx = (sel_res - (idx - 1)) << rem_r; + enc_idx += get_bits_value(length_rems, idx-1, rem_r, rems_mask); + + sel_res = select_next_query_packed(sel_packed, sel_res); + }; + + enc_length = (sel_res - idx) << rem_r; + enc_length += get_bits_value(length_rems, idx, rem_r, rems_mask); + enc_length -= enc_idx; + if(enc_length == 0) + return 0; + + stored_value = get_bits_at_pos(store_table, enc_idx, enc_length); + return stored_value + ((1U << enc_length) - 1U); +} diff --git a/girepository/cmph/compressed_seq.h b/girepository/cmph/compressed_seq.h new file mode 100644 index 0000000..8d87fc7 --- /dev/null +++ b/girepository/cmph/compressed_seq.h @@ -0,0 +1,84 @@ +#ifndef __CMPH_COMPRESSED_SEQ_H__ +#define __CMPH_COMPRESSED_SEQ_H__ + +#include"select.h" + +struct _compressed_seq_t +{ + cmph_uint32 n; // number of values stored in store_table + // The length in bits of each value is decomposed into two compnents: the lg(n) MSBs are stored in rank_select data structure + // the remaining LSBs are stored in a table of n cells, each one of rem_r bits. + cmph_uint32 rem_r; + cmph_uint32 total_length; // total length in bits of stored_table + select_t sel; + cmph_uint32 * length_rems; + cmph_uint32 * store_table; +}; + +typedef struct _compressed_seq_t compressed_seq_t; + +/** \fn void compressed_seq_init(compressed_seq_t * cs); + * \brief Initialize a compressed sequence structure. + * \param cs points to the compressed sequence structure to be initialized + */ +void compressed_seq_init(compressed_seq_t * cs); + +/** \fn void compressed_seq_destroy(compressed_seq_t * cs); + * \brief Destroy a compressed sequence given as input. + * \param cs points to the compressed sequence structure to be destroyed + */ +void compressed_seq_destroy(compressed_seq_t * cs); + +/** \fn void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n); + * \brief Generate a compressed sequence from an input array with n values. + * \param cs points to the compressed sequence structure + * \param vals_table poiter to the array given as input + * \param n number of values in @see vals_table + */ +void compressed_seq_generate(compressed_seq_t * cs, cmph_uint32 * vals_table, cmph_uint32 n); + + +/** \fn cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx); + * \brief Returns the value stored at index @see idx of the compressed sequence structure. + * \param cs points to the compressed sequence structure + * \param idx index to retrieve the value from + * \return the value stored at index @see idx of the compressed sequence structure + */ +cmph_uint32 compressed_seq_query(compressed_seq_t * cs, cmph_uint32 idx); + + +/** \fn cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs); + * \brief Returns amount of space (in bits) to store the compressed sequence. + * \param cs points to the compressed sequence structure + * \return the amount of space (in bits) to store @see cs + */ +cmph_uint32 compressed_seq_get_space_usage(compressed_seq_t * cs); + +void compressed_seq_dump(compressed_seq_t * cs, char ** buf, cmph_uint32 * buflen); + +void compressed_seq_load(compressed_seq_t * cs, const char * buf, cmph_uint32 buflen); + + +/** \fn void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed); + * \brief Support the ability to pack a compressed sequence structure into a preallocated contiguous memory space pointed by cs_packed. + * \param cs points to the compressed sequence structure + * \param cs_packed pointer to the contiguous memory area used to store the compressed sequence structure. The size of cs_packed must be at least @see compressed_seq_packed_size + */ +void compressed_seq_pack(compressed_seq_t *cs, void *cs_packed); + +/** \fn cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs); + * \brief Return the amount of space needed to pack a compressed sequence structure. + * \return the size of the packed compressed sequence structure or zero for failures + */ +cmph_uint32 compressed_seq_packed_size(compressed_seq_t *cs); + + +/** \fn cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx); + * \brief Returns the value stored at index @see idx of the packed compressed sequence structure. + * \param cs_packed is a pointer to a contiguous memory area + * \param idx is the index to retrieve the value from + * \return the value stored at index @see idx of the packed compressed sequence structure + */ +cmph_uint32 compressed_seq_query_packed(void * cs_packed, cmph_uint32 idx); + +#endif diff --git a/girepository/cmph/debug.h b/girepository/cmph/debug.h new file mode 100644 index 0000000..0f7ddb1 --- /dev/null +++ b/girepository/cmph/debug.h @@ -0,0 +1,53 @@ +#ifdef DEBUGP +#undef DEBUGP +#endif + +#ifdef __cplusplus +#include +#ifdef WIN32 +#include +#endif +#else +#include +#ifdef WIN32 +#include +#endif +#endif + +#ifndef __GNUC__ +#ifndef __DEBUG_H__ +#define __DEBUG_H__ +#include +static void debugprintf(const char *format, ...) +{ + va_list ap; + char *f = NULL; + const char *p="%s:%d "; + size_t plen = strlen(p); + va_start(ap, format); + f = (char *)malloc(plen + strlen(format) + 1); + if (!f) return; + memcpy(f, p, plen); + memcpy(f + plen, format, strlen(format) + 1); + vfprintf(stderr, f, ap); + va_end(ap); + free(f); +} +static void dummyprintf(const char *format, ...) +{} +#endif +#endif + +#ifdef DEBUG +#ifndef __GNUC__ +#define DEBUGP debugprintf +#else +#define DEBUGP(args...) do { fprintf(stderr, "%s:%d ", __FILE__, __LINE__); fprintf(stderr, ## args); } while(0) +#endif +#else +#ifndef __GNUC__ +#define DEBUGP dummyprintf +#else +#define DEBUGP(args...) +#endif +#endif diff --git a/girepository/cmph/djb2_hash.c b/girepository/cmph/djb2_hash.c new file mode 100644 index 0000000..d3b4330 --- /dev/null +++ b/girepository/cmph/djb2_hash.c @@ -0,0 +1,49 @@ +#include "djb2_hash.h" +#include + +djb2_state_t *djb2_state_new() +{ + djb2_state_t *state = (djb2_state_t *)malloc(sizeof(djb2_state_t)); + state->hashfunc = CMPH_HASH_DJB2; + return state; +} + +void djb2_state_destroy(djb2_state_t *state) +{ + free(state); +} + +cmph_uint32 djb2_hash(djb2_state_t *state, const char *k, cmph_uint32 keylen) +{ + register cmph_uint32 hash = 5381; + const unsigned char *ptr = (unsigned char *)k; + cmph_uint32 i = 0; + while (i < keylen) + { + hash = hash*33 ^ *ptr; + ++ptr, ++i; + } + return hash; +} + + +void djb2_state_dump(djb2_state_t *state, char **buf, cmph_uint32 *buflen) +{ + *buf = NULL; + *buflen = 0; + return; +} + +djb2_state_t *djb2_state_copy(djb2_state_t *src_state) +{ + djb2_state_t *dest_state = (djb2_state_t *)malloc(sizeof(djb2_state_t)); + dest_state->hashfunc = src_state->hashfunc; + return dest_state; +} + +djb2_state_t *djb2_state_load(const char *buf, cmph_uint32 buflen) +{ + djb2_state_t *state = (djb2_state_t *)malloc(sizeof(djb2_state_t)); + state->hashfunc = CMPH_HASH_DJB2; + return state; +} diff --git a/girepository/cmph/djb2_hash.h b/girepository/cmph/djb2_hash.h new file mode 100644 index 0000000..dda97e3 --- /dev/null +++ b/girepository/cmph/djb2_hash.h @@ -0,0 +1,18 @@ +#ifndef __DJB2_HASH_H__ +#define __DJB2_HASH_H__ + +#include "hash.h" + +typedef struct __djb2_state_t +{ + CMPH_HASH hashfunc; +} djb2_state_t; + +djb2_state_t *djb2_state_new(); +cmph_uint32 djb2_hash(djb2_state_t *state, const char *k, cmph_uint32 keylen); +void djb2_state_dump(djb2_state_t *state, char **buf, cmph_uint32 *buflen); +djb2_state_t *djb2_state_copy(djb2_state_t *src_state); +djb2_state_t *djb2_state_load(const char *buf, cmph_uint32 buflen); +void djb2_state_destroy(djb2_state_t *state); + +#endif diff --git a/girepository/cmph/fch.c b/girepository/cmph/fch.c new file mode 100644 index 0000000..f12b6fc --- /dev/null +++ b/girepository/cmph/fch.c @@ -0,0 +1,539 @@ +#include "fch.h" +#include "cmph_structs.h" +#include "fch_structs.h" +#include "hash.h" +#include "bitbool.h" +#include "fch_buckets.h" +#include +#include +#include +#include +#include +#include + +#define INDEX 0 /* alignment index within a bucket */ +//#define DEBUG +#include "debug.h" + +static fch_buckets_t * mapping(cmph_config_t *mph); +static cmph_uint32 * ordering(fch_buckets_t * buckets); +static cmph_uint8 check_for_collisions_h2(fch_config_data_t *fch, fch_buckets_t * buckets, cmph_uint32 *sorted_indexes); +static void permut(cmph_uint32 * vector, cmph_uint32 n); +static cmph_uint8 searching(fch_config_data_t *fch, fch_buckets_t *buckets, cmph_uint32 *sorted_indexes); + +fch_config_data_t *fch_config_new(void) +{ + fch_config_data_t *fch; + fch = (fch_config_data_t *)malloc(sizeof(fch_config_data_t)); + assert(fch); + memset(fch, 0, sizeof(fch_config_data_t)); + fch->hashfuncs[0] = CMPH_HASH_JENKINS; + fch->hashfuncs[1] = CMPH_HASH_JENKINS; + fch->m = fch->b = 0; + fch->c = fch->p1 = fch->p2 = 0.0; + fch->g = NULL; + fch->h1 = NULL; + fch->h2 = NULL; + return fch; +} + +void fch_config_destroy(cmph_config_t *mph) +{ + fch_config_data_t *data = (fch_config_data_t *)mph->data; + //DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void fch_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + fch_config_data_t *fch = (fch_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 2) break; //fch only uses two hash functions + fch->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +cmph_uint32 mixh10h11h12(cmph_uint32 b, double p1, double p2, cmph_uint32 initial_index) +{ + register cmph_uint32 int_p2 = (cmph_uint32)p2; + if (initial_index < p1) initial_index %= int_p2; /* h11 o h10 */ + else { /* h12 o h10 */ + initial_index %= b; + if(initial_index < p2) initial_index += int_p2; + } + return initial_index; +} + + +cmph_uint32 fch_calc_b(double c, cmph_uint32 m) +{ + return (cmph_uint32)ceil((c*m)/(log((double)m)/log(2.0) + 1)); +} + +double fch_calc_p1(cmph_uint32 m) +{ + return ceil(0.55*m); +} + +double fch_calc_p2(cmph_uint32 b) +{ + return ceil(0.3*b); +} + +static fch_buckets_t * mapping(cmph_config_t *mph) +{ + cmph_uint32 i = 0; + fch_buckets_t *buckets = NULL; + fch_config_data_t *fch = (fch_config_data_t *)mph->data; + if (fch->h1) hash_state_destroy(fch->h1); + fch->h1 = hash_state_new(fch->hashfuncs[0], fch->m); + fch->b = fch_calc_b(fch->c, fch->m); + fch->p1 = fch_calc_p1(fch->m); + fch->p2 = fch_calc_p2(fch->b); + //DEBUGP("b:%u p1:%f p2:%f\n", fch->b, fch->p1, fch->p2); + buckets = fch_buckets_new(fch->b); + + mph->key_source->rewind(mph->key_source->data); + for(i = 0; i < fch->m; i++) + { + cmph_uint32 h1, keylen; + char *key = NULL; + mph->key_source->read(mph->key_source->data, &key, &keylen); + h1 = hash(fch->h1, key, keylen) % fch->m; + h1 = mixh10h11h12 (fch->b, fch->p1, fch->p2, h1); + fch_buckets_insert(buckets, h1, key, keylen); + key = NULL; // transger memory ownership + + } + return buckets; +} + + +// returns the buckets indexes sorted by their sizes. +static cmph_uint32 * ordering(fch_buckets_t * buckets) +{ + return fch_buckets_get_indexes_sorted_by_size(buckets); +} + +/* Check whether function h2 causes collisions among the keys of each bucket */ +static cmph_uint8 check_for_collisions_h2(fch_config_data_t *fch, fch_buckets_t * buckets, cmph_uint32 *sorted_indexes) +{ + //cmph_uint32 max_size = fch_buckets_get_max_size(buckets); + cmph_uint8 * hashtable = (cmph_uint8 *)calloc((size_t)fch->m, sizeof(cmph_uint8)); + cmph_uint32 nbuckets = fch_buckets_get_nbuckets(buckets); + cmph_uint32 i = 0, index = 0, j =0; + for (i = 0; i < nbuckets; i++) + { + cmph_uint32 nkeys = fch_buckets_get_size(buckets, sorted_indexes[i]); + memset(hashtable, 0, (size_t)fch->m); + //DEBUGP("bucket %u -- nkeys: %u\n", i, nkeys); + for (j = 0; j < nkeys; j++) + { + char * key = fch_buckets_get_key(buckets, sorted_indexes[i], j); + cmph_uint32 keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], j); + index = hash(fch->h2, key, keylen) % fch->m; + if(hashtable[index]) { // collision detected + free(hashtable); + return 1; + } + hashtable[index] = 1; + } + } + free(hashtable); + return 0; +} + +static void permut(cmph_uint32 * vector, cmph_uint32 n) +{ + cmph_uint32 i, j, b; + for (i = 0; i < n; i++) { + j = (cmph_uint32) rand() % n; + b = vector[i]; + vector[i] = vector[j]; + vector[j] = b; + } +} + +static cmph_uint8 searching(fch_config_data_t *fch, fch_buckets_t *buckets, cmph_uint32 *sorted_indexes) +{ + cmph_uint32 * random_table = (cmph_uint32 *) calloc((size_t)fch->m, sizeof(cmph_uint32)); + cmph_uint32 * map_table = (cmph_uint32 *) calloc((size_t)fch->m, sizeof(cmph_uint32)); + cmph_uint32 iteration_to_generate_h2 = 0; + cmph_uint32 searching_iterations = 0; + cmph_uint8 restart = 0; + cmph_uint32 nbuckets = fch_buckets_get_nbuckets(buckets); + cmph_uint32 i, j, z, counter = 0, filled_count = 0; + if (fch->g) free (fch->g); + fch->g = (cmph_uint32 *) calloc((size_t)fch->b, sizeof(cmph_uint32)); + + //DEBUGP("max bucket size: %u\n", fch_buckets_get_max_size(buckets)); + + for(i = 0; i < fch->m; i++) + { + random_table[i] = i; + } + permut(random_table, fch->m); + for(i = 0; i < fch->m; i++) + { + map_table[random_table[i]] = i; + } + do { + if (fch->h2) hash_state_destroy(fch->h2); + fch->h2 = hash_state_new(fch->hashfuncs[1], fch->m); + restart = check_for_collisions_h2(fch, buckets, sorted_indexes); + filled_count = 0; + if (!restart) + { + searching_iterations++; iteration_to_generate_h2 = 0; + //DEBUGP("searching_iterations: %u\n", searching_iterations); + } + else { + iteration_to_generate_h2++; + //DEBUGP("iteration_to_generate_h2: %u\n", iteration_to_generate_h2); + } + for(i = 0; (i < nbuckets) && !restart; i++) { + cmph_uint32 bucketsize = fch_buckets_get_size(buckets, sorted_indexes[i]); + if (bucketsize == 0) + { + restart = 0; // false + break; + } + else restart = 1; // true + for(z = 0; (z < (fch->m - filled_count)) && restart; z++) { + char * key = fch_buckets_get_key(buckets, sorted_indexes[i], INDEX); + cmph_uint32 keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], INDEX); + cmph_uint32 h2 = hash(fch->h2, key, keylen) % fch->m; + counter = 0; + restart = 0; // false + fch->g[sorted_indexes[i]] = (fch->m + random_table[filled_count + z] - h2) % fch->m; + //DEBUGP("g[%u]: %u\n", sorted_indexes[i], fch->g[sorted_indexes[i]]); + j = INDEX; + do { + cmph_uint32 index = 0; + key = fch_buckets_get_key(buckets, sorted_indexes[i], j); + keylen = fch_buckets_get_keylength(buckets, sorted_indexes[i], j); + h2 = hash(fch->h2, key, keylen) % fch->m; + index = (h2 + fch->g[sorted_indexes[i]]) % fch->m; + //DEBUGP("key:%s keylen:%u index: %u h2:%u bucketsize:%u\n", key, keylen, index, h2, bucketsize); + if (map_table[index] >= filled_count) { + cmph_uint32 y = map_table[index]; + cmph_uint32 ry = random_table[y]; + random_table[y] = random_table[filled_count]; + random_table[filled_count] = ry; + map_table[random_table[y]] = y; + map_table[random_table[filled_count]] = filled_count; + filled_count++; + counter ++; + } + else { + restart = 1; // true + filled_count = filled_count - counter; + counter = 0; + break; + } + j = (j + 1) % bucketsize; + } while(j % bucketsize != INDEX); + } + //getchar(); + } + } while(restart && (searching_iterations < 10) && (iteration_to_generate_h2 < 1000)); + free(map_table); + free(random_table); + return restart; +} + + + +cmph_t *fch_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + fch_data_t *fchf = NULL; + cmph_uint32 iterations = 100; + cmph_uint8 restart_mapping = 0; + fch_buckets_t * buckets = NULL; + cmph_uint32 * sorted_indexes = NULL; + fch_config_data_t *fch = (fch_config_data_t *)mph->data; + fch->m = mph->key_source->nkeys; + //DEBUGP("m: %f\n", fch->m); + if (c <= 2) c = 2.6; // validating restrictions over parameter c. + fch->c = c; + //DEBUGP("c: %f\n", fch->c); + fch->h1 = NULL; + fch->h2 = NULL; + fch->g = NULL; + do + { + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys\n", fch->m); + } + if (buckets) fch_buckets_destroy(buckets); + buckets = mapping(mph); + if (mph->verbosity) + { + fprintf(stderr, "Starting ordering step\n"); + } + if (sorted_indexes) free (sorted_indexes); + sorted_indexes = ordering(buckets); + if (mph->verbosity) + { + fprintf(stderr, "Starting searching step.\n"); + } + restart_mapping = searching(fch, buckets, sorted_indexes); + iterations--; + + } while(restart_mapping && iterations > 0); + if (buckets) fch_buckets_destroy(buckets); + if (sorted_indexes) free (sorted_indexes); + if (iterations == 0) return NULL; + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + fchf = (fch_data_t *)malloc(sizeof(fch_data_t)); + fchf->g = fch->g; + fch->g = NULL; //transfer memory ownership + fchf->h1 = fch->h1; + fch->h1 = NULL; //transfer memory ownership + fchf->h2 = fch->h2; + fch->h2 = NULL; //transfer memory ownership + fchf->p2 = fch->p2; + fchf->p1 = fch->p1; + fchf->b = fch->b; + fchf->c = fch->c; + fchf->m = fch->m; + mphf->data = fchf; + mphf->size = fch->m; + //DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +int fch_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + + fch_data_t *data = (fch_data_t *)mphf->data; + +#ifdef DEBUG + cmph_uint32 i; +#endif + __cmph_dump(mphf, fd); + + hash_state_dump(data->h1, &buf, &buflen); + //DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + hash_state_dump(data->h2, &buf, &buflen); + //DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + nbytes = fwrite(&buflen, sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(buf, (size_t)buflen, (size_t)1, fd); + free(buf); + + nbytes = fwrite(&(data->m), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->c), sizeof(double), (size_t)1, fd); + nbytes = fwrite(&(data->b), sizeof(cmph_uint32), (size_t)1, fd); + nbytes = fwrite(&(data->p1), sizeof(double), (size_t)1, fd); + nbytes = fwrite(&(data->p2), sizeof(double), (size_t)1, fd); + nbytes = fwrite(data->g, sizeof(cmph_uint32)*(data->b), (size_t)1, fd); + if (nbytes == 0 && ferror(fd)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return 0; + } + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->b; ++i) fprintf(stderr, "%u ", data->g[i]); + fprintf(stderr, "\n"); + #endif + return 1; +} + +void fch_load(FILE *f, cmph_t *mphf) +{ + char *buf = NULL; + cmph_uint32 buflen; + register size_t nbytes; + fch_data_t *fch = (fch_data_t *)malloc(sizeof(fch_data_t)); +#ifdef DEBUG + cmph_uint32 i; +#endif + + //DEBUGP("Loading fch mphf\n"); + mphf->data = fch; + //DEBUGP("Reading h1\n"); + fch->h1 = NULL; + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + //DEBUGP("Hash state of h1 has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + fch->h1 = hash_state_load(buf, buflen); + free(buf); + + //DEBUGP("Loading fch mphf\n"); + mphf->data = fch; + //DEBUGP("Reading h2\n"); + fch->h2 = NULL; + nbytes = fread(&buflen, sizeof(cmph_uint32), (size_t)1, f); + //DEBUGP("Hash state of h2 has %u bytes\n", buflen); + buf = (char *)malloc((size_t)buflen); + nbytes = fread(buf, (size_t)buflen, (size_t)1, f); + fch->h2 = hash_state_load(buf, buflen); + free(buf); + + + //DEBUGP("Reading m and n\n"); + nbytes = fread(&(fch->m), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(fch->c), sizeof(double), (size_t)1, f); + nbytes = fread(&(fch->b), sizeof(cmph_uint32), (size_t)1, f); + nbytes = fread(&(fch->p1), sizeof(double), (size_t)1, f); + nbytes = fread(&(fch->p2), sizeof(double), (size_t)1, f); + + fch->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*fch->b); + nbytes = fread(fch->g, fch->b*sizeof(cmph_uint32), (size_t)1, f); + if (nbytes == 0 && ferror(f)) { + fprintf(stderr, "ERROR: %s\n", strerror(errno)); + return; + } + + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < fch->b; ++i) fprintf(stderr, "%u ", fch->g[i]); + fprintf(stderr, "\n"); + #endif + return; +} + +cmph_uint32 fch_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + fch_data_t *fch = mphf->data; + cmph_uint32 h1 = hash(fch->h1, key, keylen) % fch->m; + cmph_uint32 h2 = hash(fch->h2, key, keylen) % fch->m; + h1 = mixh10h11h12 (fch->b, fch->p1, fch->p2, h1); + //DEBUGP("key: %s h1: %u h2: %u g[h1]: %u\n", key, h1, h2, fch->g[h1]); + return (h2 + fch->g[h1]) % fch->m; +} +void fch_destroy(cmph_t *mphf) +{ + fch_data_t *data = (fch_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->h1); + hash_state_destroy(data->h2); + free(data); + free(mphf); +} + +/** \fn void fch_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void fch_pack(cmph_t *mphf, void *packed_mphf) +{ + fch_data_t *data = (fch_data_t *)mphf->data; + cmph_uint8 * ptr = packed_mphf; + + // packing h1 type + CMPH_HASH h1_type = hash_get_type(data->h1); + CMPH_HASH h2_type; + *((cmph_uint32 *) ptr) = h1_type; + ptr += sizeof(cmph_uint32); + + // packing h1 + hash_state_pack(data->h1, ptr); + ptr += hash_state_packed_size(h1_type); + + // packing h2 type + h2_type = hash_get_type(data->h2); + *((cmph_uint32 *) ptr) = h2_type; + ptr += sizeof(cmph_uint32); + + // packing h2 + hash_state_pack(data->h2, ptr); + ptr += hash_state_packed_size(h2_type); + + // packing m + *((cmph_uint32 *) ptr) = data->m; + ptr += sizeof(data->m); + + // packing b + *((cmph_uint32 *) ptr) = data->b; + ptr += sizeof(data->b); + + // packing p1 + *((cmph_uint64 *)ptr) = (cmph_uint64)data->p1; + ptr += sizeof(data->p1); + + // packing p2 + *((cmph_uint64 *)ptr) = (cmph_uint64)data->p2; + ptr += sizeof(data->p2); + + // packing g + memcpy(ptr, data->g, sizeof(cmph_uint32)*(data->b)); +} + +/** \fn cmph_uint32 fch_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 fch_packed_size(cmph_t *mphf) +{ + fch_data_t *data = (fch_data_t *)mphf->data; + CMPH_HASH h1_type = hash_get_type(data->h1); + CMPH_HASH h2_type = hash_get_type(data->h2); + + return (cmph_uint32)(sizeof(CMPH_ALGO) + hash_state_packed_size(h1_type) + hash_state_packed_size(h2_type) + + 4*sizeof(cmph_uint32) + 2*sizeof(double) + sizeof(cmph_uint32)*(data->b)); +} + + +/** cmph_uint32 fch_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 fch_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen) +{ + register cmph_uint8 *h1_ptr = packed_mphf; + register CMPH_HASH h1_type = *((cmph_uint32 *)h1_ptr); + register cmph_uint8 *h2_ptr; + register CMPH_HASH h2_type; + register cmph_uint32 *g_ptr; + register cmph_uint32 m, b, h1, h2; + register double p1, p2; + + h1_ptr += 4; + + h2_ptr = h1_ptr + hash_state_packed_size(h1_type); + h2_type = *((cmph_uint32 *)h2_ptr); + h2_ptr += 4; + + g_ptr = (cmph_uint32 *)(h2_ptr + hash_state_packed_size(h2_type)); + + m = *g_ptr++; + + b = *g_ptr++; + + p1 = (double)(*((cmph_uint64 *)g_ptr)); + g_ptr += 2; + + p2 = (double)(*((cmph_uint64 *)g_ptr)); + g_ptr += 2; + + h1 = hash_packed(h1_ptr, h1_type, key, keylen) % m; + h2 = hash_packed(h2_ptr, h2_type, key, keylen) % m; + h1 = mixh10h11h12 (b, p1, p2, h1); + return (h2 + g_ptr[h1]) % m; +} + diff --git a/girepository/cmph/fch.h b/girepository/cmph/fch.h new file mode 100644 index 0000000..9d13a1c --- /dev/null +++ b/girepository/cmph/fch.h @@ -0,0 +1,48 @@ +#ifndef __CMPH_FCH_H__ +#define __CMPH_FCH_H__ + +#include "cmph.h" + +typedef struct __fch_data_t fch_data_t; +typedef struct __fch_config_data_t fch_config_data_t; + +/* Parameters calculation */ +cmph_uint32 fch_calc_b(double c, cmph_uint32 m); +double fch_calc_p1(cmph_uint32 m); +double fch_calc_p2(cmph_uint32 b); +cmph_uint32 mixh10h11h12(cmph_uint32 b, double p1, double p2, cmph_uint32 initial_index); + +fch_config_data_t *fch_config_new(void); +void fch_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void fch_config_destroy(cmph_config_t *mph); +cmph_t *fch_new(cmph_config_t *mph, double c); + +void fch_load(FILE *f, cmph_t *mphf); +int fch_dump(cmph_t *mphf, FILE *f); +void fch_destroy(cmph_t *mphf); +cmph_uint32 fch_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); + +/** \fn void fch_pack(cmph_t *mphf, void *packed_mphf); + * \brief Support the ability to pack a perfect hash function into a preallocated contiguous memory space pointed by packed_mphf. + * \param mphf pointer to the resulting mphf + * \param packed_mphf pointer to the contiguous memory area used to store the resulting mphf. The size of packed_mphf must be at least cmph_packed_size() + */ +void fch_pack(cmph_t *mphf, void *packed_mphf); + +/** \fn cmph_uint32 fch_packed_size(cmph_t *mphf); + * \brief Return the amount of space needed to pack mphf. + * \param mphf pointer to a mphf + * \return the size of the packed function or zero for failures + */ +cmph_uint32 fch_packed_size(cmph_t *mphf); + +/** cmph_uint32 fch_search(void *packed_mphf, const char *key, cmph_uint32 keylen); + * \brief Use the packed mphf to do a search. + * \param packed_mphf pointer to the packed mphf + * \param key key to be hashed + * \param keylen key legth in bytes + * \return The mphf value + */ +cmph_uint32 fch_search_packed(void *packed_mphf, const char *key, cmph_uint32 keylen); + +#endif diff --git a/girepository/cmph/fch_buckets.c b/girepository/cmph/fch_buckets.c new file mode 100644 index 0000000..a588f14 --- /dev/null +++ b/girepository/cmph/fch_buckets.c @@ -0,0 +1,214 @@ +#include "vqueue.h" +#include "fch_buckets.h" +#include +#include +#include +//#define DEBUG +#include "debug.h" + +typedef struct __fch_bucket_entry_t +{ + char * value; + cmph_uint32 length; +} fch_bucket_entry_t; + +typedef struct __fch_bucket_t +{ + fch_bucket_entry_t * entries; + cmph_uint32 capacity, size; +} fch_bucket_t; + + + +static void fch_bucket_new(fch_bucket_t *bucket) +{ + assert(bucket); + bucket->size = 0; + bucket->entries = NULL; + bucket->capacity = 0; +} + +static void fch_bucket_destroy(fch_bucket_t *bucket) +{ + cmph_uint32 i; + assert(bucket); + for (i = 0; i < bucket->size; i++) + { + free((bucket->entries + i)->value); + } + free(bucket->entries); +} + + +static void fch_bucket_reserve(fch_bucket_t *bucket, cmph_uint32 size) +{ + assert(bucket); + if (bucket->capacity < size) + { + cmph_uint32 new_capacity = bucket->capacity + 1; + DEBUGP("Increasing current capacity %u to %u\n", bucket->capacity, size); + while (new_capacity < size) + { + new_capacity *= 2; + } + bucket->entries = (fch_bucket_entry_t *)realloc(bucket->entries, sizeof(fch_bucket_entry_t)*new_capacity); + assert(bucket->entries); + bucket->capacity = new_capacity; + DEBUGP("Increased\n"); + } +} + +static void fch_bucket_insert(fch_bucket_t *bucket, char *val, cmph_uint32 val_length) +{ + assert(bucket); + fch_bucket_reserve(bucket, bucket->size + 1); + (bucket->entries + bucket->size)->value = val; + (bucket->entries + bucket->size)->length = val_length; + ++(bucket->size); +} + + +static cmph_uint8 fch_bucket_is_empty(fch_bucket_t *bucket) +{ + assert(bucket); + return (cmph_uint8)(bucket->size == 0); +} + +static cmph_uint32 fch_bucket_size(fch_bucket_t *bucket) +{ + assert(bucket); + return bucket->size; +} + +static char * fch_bucket_get_key(fch_bucket_t *bucket, cmph_uint32 index_key) +{ + assert(bucket); assert(index_key < bucket->size); + return (bucket->entries + index_key)->value; +} + +static cmph_uint32 fch_bucket_get_length(fch_bucket_t *bucket, cmph_uint32 index_key) +{ + assert(bucket); assert(index_key < bucket->size); + return (bucket->entries + index_key)->length; +} + +static void fch_bucket_print(fch_bucket_t * bucket, cmph_uint32 index) +{ + cmph_uint32 i; + assert(bucket); + fprintf(stderr, "Printing bucket %u ...\n", index); + for (i = 0; i < bucket->size; i++) + { + fprintf(stderr, " key: %s\n", (bucket->entries + i)->value); + } +} + +////////////////////////////////////////////////////////////////////////////////////// + +struct __fch_buckets_t +{ + fch_bucket_t * values; + cmph_uint32 nbuckets, max_size; + +}; + +fch_buckets_t * fch_buckets_new(cmph_uint32 nbuckets) +{ + cmph_uint32 i; + fch_buckets_t *buckets = (fch_buckets_t *)malloc(sizeof(fch_buckets_t)); + assert(buckets); + buckets->values = (fch_bucket_t *)calloc((size_t)nbuckets, sizeof(fch_bucket_t)); + for (i = 0; i < nbuckets; i++) fch_bucket_new(buckets->values + i); + assert(buckets->values); + buckets->nbuckets = nbuckets; + buckets->max_size = 0; + return buckets; +} + +cmph_uint8 fch_buckets_is_empty(fch_buckets_t * buckets, cmph_uint32 index) +{ + assert(index < buckets->nbuckets); + return fch_bucket_is_empty(buckets->values + index); +} + +void fch_buckets_insert(fch_buckets_t * buckets, cmph_uint32 index, char * key, cmph_uint32 length) +{ + assert(index < buckets->nbuckets); + fch_bucket_insert(buckets->values + index, key, length); + if (fch_bucket_size(buckets->values + index) > buckets->max_size) + { + buckets->max_size = fch_bucket_size(buckets->values + index); + } +} + +cmph_uint32 fch_buckets_get_size(fch_buckets_t * buckets, cmph_uint32 index) +{ + assert(index < buckets->nbuckets); + return fch_bucket_size(buckets->values + index); +} + + +char * fch_buckets_get_key(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key) +{ + assert(index < buckets->nbuckets); + return fch_bucket_get_key(buckets->values + index, index_key); +} + +cmph_uint32 fch_buckets_get_keylength(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key) +{ + assert(index < buckets->nbuckets); + return fch_bucket_get_length(buckets->values + index, index_key); +} + +cmph_uint32 fch_buckets_get_max_size(fch_buckets_t * buckets) +{ + return buckets->max_size; +} + +cmph_uint32 fch_buckets_get_nbuckets(fch_buckets_t * buckets) +{ + return buckets->nbuckets; +} + +cmph_uint32 * fch_buckets_get_indexes_sorted_by_size(fch_buckets_t * buckets) +{ + cmph_uint32 i = 0; + cmph_uint32 sum = 0, value; + cmph_uint32 *nbuckets_size = (cmph_uint32 *) calloc((size_t)buckets->max_size + 1, sizeof(cmph_uint32)); + cmph_uint32 * sorted_indexes = (cmph_uint32 *) calloc((size_t)buckets->nbuckets, sizeof(cmph_uint32)); + + // collect how many buckets for each size. + for(i = 0; i < buckets->nbuckets; i++) nbuckets_size[fch_bucket_size(buckets->values + i)] ++; + + // calculating offset considering a decreasing order of buckets size. + value = nbuckets_size[buckets->max_size]; + nbuckets_size[buckets->max_size] = sum; + for(i = (int)buckets->max_size - 1; i >= 0; i--) + { + sum += value; + value = nbuckets_size[i]; + nbuckets_size[i] = sum; + + } + for(i = 0; i < buckets->nbuckets; i++) + { + sorted_indexes[nbuckets_size[fch_bucket_size(buckets->values + i)]] = (cmph_uint32)i; + nbuckets_size[fch_bucket_size(buckets->values + i)] ++; + } + free(nbuckets_size); + return sorted_indexes; +} + +void fch_buckets_print(fch_buckets_t * buckets) +{ + cmph_uint32 i; + for (i = 0; i < buckets->nbuckets; i++) fch_bucket_print(buckets->values + i, i); +} + +void fch_buckets_destroy(fch_buckets_t * buckets) +{ + cmph_uint32 i; + for (i = 0; i < buckets->nbuckets; i++) fch_bucket_destroy(buckets->values + i); + free(buckets->values); + free(buckets); +} diff --git a/girepository/cmph/fch_buckets.h b/girepository/cmph/fch_buckets.h new file mode 100644 index 0000000..2a1b8b2 --- /dev/null +++ b/girepository/cmph/fch_buckets.h @@ -0,0 +1,30 @@ +#ifndef __CMPH_FCH_BUCKETS_H__ +#define __CMPH_FCH_BUCKETS_H__ + +#include "cmph_types.h" +typedef struct __fch_buckets_t fch_buckets_t; + +fch_buckets_t * fch_buckets_new(cmph_uint32 nbuckets); + +cmph_uint8 fch_buckets_is_empty(fch_buckets_t * buckets, cmph_uint32 index); + +void fch_buckets_insert(fch_buckets_t * buckets, cmph_uint32 index, char * key, cmph_uint32 length); + +cmph_uint32 fch_buckets_get_size(fch_buckets_t * buckets, cmph_uint32 index); + +char * fch_buckets_get_key(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key); + +cmph_uint32 fch_buckets_get_keylength(fch_buckets_t * buckets, cmph_uint32 index, cmph_uint32 index_key); + +// returns the size of biggest bucket. +cmph_uint32 fch_buckets_get_max_size(fch_buckets_t * buckets); + +// returns the number of buckets. +cmph_uint32 fch_buckets_get_nbuckets(fch_buckets_t * buckets); + +cmph_uint32 * fch_buckets_get_indexes_sorted_by_size(fch_buckets_t * buckets); + +void fch_buckets_print(fch_buckets_t * buckets); + +void fch_buckets_destroy(fch_buckets_t * buckets); +#endif diff --git a/girepository/cmph/fch_structs.h b/girepository/cmph/fch_structs.h new file mode 100644 index 0000000..fcd1555 --- /dev/null +++ b/girepository/cmph/fch_structs.h @@ -0,0 +1,30 @@ +#ifndef __CMPH_FCH_STRUCTS_H__ +#define __CMPH_FCH_STRUCTS_H__ + +#include "hash_state.h" + +struct __fch_data_t +{ + cmph_uint32 m; // words count + double c; // constant c + cmph_uint32 b; // parameter b = ceil(c*m/(log(m)/log(2) + 1)). Don't need to be stored + double p1; // constant p1 = ceil(0.6*m). Don't need to be stored + double p2; // constant p2 = ceil(0.3*b). Don't need to be stored + cmph_uint32 *g; // g function. + hash_state_t *h1; // h10 function. + hash_state_t *h2; // h20 function. +}; + +struct __fch_config_data_t +{ + CMPH_HASH hashfuncs[2]; + cmph_uint32 m; // words count + double c; // constant c + cmph_uint32 b; // parameter b = ceil(c*m/(log(m)/log(2) + 1)). Don't need to be stored + double p1; // constant p1 = ceil(0.6*m). Don't need to be stored + double p2; // constant p2 = ceil(0.3*b). Don't need to be stored + cmph_uint32 *g; // g function. + hash_state_t *h1; // h10 function. + hash_state_t *h2; // h20 function. +}; +#endif diff --git a/girepository/cmph/fnv_hash.c b/girepository/cmph/fnv_hash.c new file mode 100644 index 0000000..aeaca8f --- /dev/null +++ b/girepository/cmph/fnv_hash.c @@ -0,0 +1,53 @@ +#include "fnv_hash.h" +#include + +fnv_state_t *fnv_state_new() +{ + fnv_state_t *state = (fnv_state_t *)malloc(sizeof(fnv_state_t)); + state->hashfunc = CMPH_HASH_FNV; + return state; +} + +void fnv_state_destroy(fnv_state_t *state) +{ + free(state); +} + +cmph_uint32 fnv_hash(fnv_state_t *state, const char *k, cmph_uint32 keylen) +{ + const unsigned char *bp = (const unsigned char *)k; + const unsigned char *be = bp + keylen; + static unsigned int hval = 0; + + while (bp < be) + { + + //hval *= 0x01000193; good for non-gcc compiler + hval += (hval << 1) + (hval << 4) + (hval << 7) + (hval << 8) + (hval << 24); //good for gcc + + hval ^= *bp++; + } + return hval; +} + + +void fnv_state_dump(fnv_state_t *state, char **buf, cmph_uint32 *buflen) +{ + *buf = NULL; + *buflen = 0; + return; +} + +fnv_state_t * fnv_state_copy(fnv_state_t *src_state) +{ + fnv_state_t *dest_state = (fnv_state_t *)malloc(sizeof(fnv_state_t)); + dest_state->hashfunc = src_state->hashfunc; + return dest_state; +} + +fnv_state_t *fnv_state_load(const char *buf, cmph_uint32 buflen) +{ + fnv_state_t *state = (fnv_state_t *)malloc(sizeof(fnv_state_t)); + state->hashfunc = CMPH_HASH_FNV; + return state; +} diff --git a/girepository/cmph/fnv_hash.h b/girepository/cmph/fnv_hash.h new file mode 100644 index 0000000..7f57946 --- /dev/null +++ b/girepository/cmph/fnv_hash.h @@ -0,0 +1,18 @@ +#ifndef __FNV_HASH_H__ +#define __FNV_HASH_H__ + +#include "hash.h" + +typedef struct __fnv_state_t +{ + CMPH_HASH hashfunc; +} fnv_state_t; + +fnv_state_t *fnv_state_new(); +cmph_uint32 fnv_hash(fnv_state_t *state, const char *k, cmph_uint32 keylen); +void fnv_state_dump(fnv_state_t *state, char **buf, cmph_uint32 *buflen); +fnv_state_t *fnv_state_copy(fnv_state_t *src_state); +fnv_state_t *fnv_state_load(const char *buf, cmph_uint32 buflen); +void fnv_state_destroy(fnv_state_t *state); + +#endif diff --git a/girepository/cmph/graph.c b/girepository/cmph/graph.c new file mode 100644 index 0000000..c29fd8b --- /dev/null +++ b/girepository/cmph/graph.c @@ -0,0 +1,338 @@ +#include "graph.h" + +#include +#include +#include +#include +#include +#include "vstack.h" +#include "bitbool.h" + +//#define DEBUG +#include "debug.h" + +/* static const cmph_uint8 bitmask[8] = { 1, 1 << 1, 1 << 2, 1 << 3, 1 << 4, 1 << 5, 1 << 6, 1 << 7 }; */ +/* #define GETBIT(array, i) (array[(i) / 8] & bitmask[(i) % 8]) */ +/* #define SETBIT(array, i) (array[(i) / 8] |= bitmask[(i) % 8]) */ +/* #define UNSETBIT(array, i) (array[(i) / 8] &= (~(bitmask[(i) % 8]))) */ + +#define abs_edge(e, i) (e % g->nedges + i * g->nedges) + +struct __graph_t +{ + cmph_uint32 nnodes; + cmph_uint32 nedges; + cmph_uint32 *edges; + cmph_uint32 *first; + cmph_uint32 *next; + cmph_uint8 *critical_nodes; /* included -- Fabiano*/ + cmph_uint32 ncritical_nodes; /* included -- Fabiano*/ + cmph_uint32 cedges; + int shrinking; +}; + +static cmph_uint32 EMPTY = UINT_MAX; + +graph_t *graph_new(cmph_uint32 nnodes, cmph_uint32 nedges) +{ + graph_t *graph = (graph_t *)malloc(sizeof(graph_t)); + if (!graph) return NULL; + + graph->edges = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges); + graph->next = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * 2 * nedges); + graph->first = (cmph_uint32 *)malloc(sizeof(cmph_uint32) * nnodes); + graph->critical_nodes = NULL; /* included -- Fabiano*/ + graph->ncritical_nodes = 0; /* included -- Fabiano*/ + graph->nnodes = nnodes; + graph->nedges = nedges; + + graph_clear_edges(graph); + return graph; +} + + +void graph_destroy(graph_t *graph) +{ + DEBUGP("Destroying graph\n"); + free(graph->edges); + free(graph->first); + free(graph->next); + free(graph->critical_nodes); /* included -- Fabiano*/ + free(graph); + return; +} + +void graph_print(graph_t *g) +{ + cmph_uint32 i, e; + for (i = 0; i < g->nnodes; ++i) + { + DEBUGP("Printing edges connected to %u\n", i); + e = g->first[i]; + if (e != EMPTY) + { + printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]); + while ((e = g->next[e]) != EMPTY) + { + printf("%u -> %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]); + } + } + + } + return; +} + +void graph_add_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) +{ + cmph_uint32 e = g->cedges; + + assert(v1 < g->nnodes); + assert(v2 < g->nnodes); + assert(e < g->nedges); + assert(!g->shrinking); + + g->next[e] = g->first[v1]; + g->first[v1] = e; + g->edges[e] = v2; + + g->next[e + g->nedges] = g->first[v2]; + g->first[v2] = e + g->nedges; + g->edges[e + g->nedges] = v1; + + ++(g->cedges); +} + +static int check_edge(graph_t *g, cmph_uint32 e, cmph_uint32 v1, cmph_uint32 v2) +{ + DEBUGP("Checking edge %u %u looking for %u %u\n", g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)], v1, v2); + if (g->edges[abs_edge(e, 0)] == v1 && g->edges[abs_edge(e, 1)] == v2) return 1; + if (g->edges[abs_edge(e, 0)] == v2 && g->edges[abs_edge(e, 1)] == v1) return 1; + return 0; +} + +cmph_uint32 graph_edge_id(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) +{ + cmph_uint32 e; + e = g->first[v1]; + assert(e != EMPTY); + if (check_edge(g, e, v1, v2)) return abs_edge(e, 0); + do + { + e = g->next[e]; + assert(e != EMPTY); + } + while (!check_edge(g, e, v1, v2)); + return abs_edge(e, 0); +} +static void del_edge_point(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) +{ + cmph_uint32 e, prev; + + DEBUGP("Deleting edge point %u %u\n", v1, v2); + e = g->first[v1]; + if (check_edge(g, e, v1, v2)) + { + g->first[v1] = g->next[e]; + //g->edges[e] = EMPTY; + DEBUGP("Deleted\n"); + return; + } + DEBUGP("Checking linked list\n"); + do + { + prev = e; + e = g->next[e]; + assert(e != EMPTY); + } + while (!check_edge(g, e, v1, v2)); + + g->next[prev] = g->next[e]; + //g->edges[e] = EMPTY; + DEBUGP("Deleted\n"); +} + + +void graph_del_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) +{ + g->shrinking = 1; + del_edge_point(g, v1, v2); + del_edge_point(g, v2, v1); +} + +void graph_clear_edges(graph_t *g) +{ + cmph_uint32 i; + for (i = 0; i < g->nnodes; ++i) g->first[i] = EMPTY; + for (i = 0; i < g->nedges*2; ++i) + { + g->edges[i] = EMPTY; + g->next[i] = EMPTY; + } + g->cedges = 0; + g->shrinking = 0; +} + +static cmph_uint8 find_degree1_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted, cmph_uint32 *e) +{ + cmph_uint32 edge = g->first[v]; + cmph_uint8 found = 0; + DEBUGP("Checking degree of vertex %u\n", v); + if (edge == EMPTY) return 0; + else if (!(GETBIT(deleted, abs_edge(edge, 0)))) + { + found = 1; + *e = edge; + } + while(1) + { + edge = g->next[edge]; + if (edge == EMPTY) break; + if (GETBIT(deleted, abs_edge(edge, 0))) continue; + if (found) return 0; + DEBUGP("Found first edge\n"); + *e = edge; + found = 1; + } + return found; +} + +static void cyclic_del_edge(graph_t *g, cmph_uint32 v, cmph_uint8 *deleted) +{ + + cmph_uint32 e = 0; + cmph_uint8 degree1; + cmph_uint32 v1 = v; + cmph_uint32 v2 = 0; + + degree1 = find_degree1_edge(g, v1, deleted, &e); + if (!degree1) return; + while(1) + { + DEBUGP("Deleting edge %u (%u->%u)\n", e, g->edges[abs_edge(e, 0)], g->edges[abs_edge(e, 1)]); + SETBIT(deleted, abs_edge(e, 0)); + + v2 = g->edges[abs_edge(e, 0)]; + if (v2 == v1) v2 = g->edges[abs_edge(e, 1)]; + + DEBUGP("Checking if second endpoint %u has degree 1\n", v2); + degree1 = find_degree1_edge(g, v2, deleted, &e); + if (degree1) + { + DEBUGP("Inspecting vertex %u\n", v2); + v1 = v2; + } + else break; + } +} + +int graph_is_cyclic(graph_t *g) +{ + cmph_uint32 i; + cmph_uint32 v; + cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8 + 1); + size_t deleted_len = g->nedges/8 + 1; + memset(deleted, 0, deleted_len); + + DEBUGP("Looking for cycles in graph with %u vertices and %u edges\n", g->nnodes, g->nedges); + for (v = 0; v < g->nnodes; ++v) + { + cyclic_del_edge(g, v, deleted); + } + for (i = 0; i < g->nedges; ++i) + { + if (!(GETBIT(deleted, i))) + { + DEBUGP("Edge %u %u->%u was not deleted\n", i, g->edges[i], g->edges[i + g->nedges]); + free(deleted); + return 1; + } + } + free(deleted); + return 0; +} + +cmph_uint8 graph_node_is_critical(graph_t * g, cmph_uint32 v) /* included -- Fabiano */ +{ + return (cmph_uint8)GETBIT(g->critical_nodes,v); +} + +void graph_obtain_critical_nodes(graph_t *g) /* included -- Fabiano*/ +{ + cmph_uint32 i; + cmph_uint32 v; + cmph_uint8 *deleted = (cmph_uint8 *)malloc((g->nedges*sizeof(cmph_uint8))/8+1); + size_t deleted_len = g->nedges/8 + 1; + memset(deleted, 0, deleted_len); + free(g->critical_nodes); + g->critical_nodes = (cmph_uint8 *)malloc((g->nnodes*sizeof(cmph_uint8))/8 + 1); + g->ncritical_nodes = 0; + memset(g->critical_nodes, 0, (g->nnodes*sizeof(cmph_uint8))/8 + 1); + DEBUGP("Looking for the 2-core in graph with %u vertices and %u edges\n", g->nnodes, g->nedges); + for (v = 0; v < g->nnodes; ++v) + { + cyclic_del_edge(g, v, deleted); + } + + for (i = 0; i < g->nedges; ++i) + { + if (!(GETBIT(deleted,i))) + { + DEBUGP("Edge %u %u->%u belongs to the 2-core\n", i, g->edges[i], g->edges[i + g->nedges]); + if(!(GETBIT(g->critical_nodes,g->edges[i]))) + { + g->ncritical_nodes ++; + SETBIT(g->critical_nodes,g->edges[i]); + } + if(!(GETBIT(g->critical_nodes,g->edges[i + g->nedges]))) + { + g->ncritical_nodes ++; + SETBIT(g->critical_nodes,g->edges[i + g->nedges]); + } + } + } + free(deleted); +} + +cmph_uint8 graph_contains_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2) /* included -- Fabiano*/ +{ + cmph_uint32 e; + e = g->first[v1]; + if(e == EMPTY) return 0; + if (check_edge(g, e, v1, v2)) return 1; + do + { + e = g->next[e]; + if(e == EMPTY) return 0; + } + while (!check_edge(g, e, v1, v2)); + return 1; +} + +cmph_uint32 graph_vertex_id(graph_t *g, cmph_uint32 e, cmph_uint32 id) /* included -- Fabiano*/ +{ + return (g->edges[e + id*g->nedges]); +} + +cmph_uint32 graph_ncritical_nodes(graph_t *g) /* included -- Fabiano*/ +{ + return g->ncritical_nodes; +} + +graph_iterator_t graph_neighbors_it(graph_t *g, cmph_uint32 v) +{ + graph_iterator_t it; + it.vertex = v; + it.edge = g->first[v]; + return it; +} +cmph_uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it) +{ + cmph_uint32 ret; + if(it->edge == EMPTY) return GRAPH_NO_NEIGHBOR; + if (g->edges[it->edge] == it->vertex) ret = g->edges[it->edge + g->nedges]; + else ret = g->edges[it->edge]; + it->edge = g->next[it->edge]; + return ret; +} + + diff --git a/girepository/cmph/graph.h b/girepository/cmph/graph.h new file mode 100644 index 0000000..e1b5de6 --- /dev/null +++ b/girepository/cmph/graph.h @@ -0,0 +1,40 @@ +#ifndef _CMPH_GRAPH_H__ +#define _CMPH_GRAPH_H__ + +#include +#include "cmph_types.h" + +#define GRAPH_NO_NEIGHBOR UINT_MAX + +typedef struct __graph_t graph_t; +typedef struct __graph_iterator_t graph_iterator_t; +struct __graph_iterator_t +{ + cmph_uint32 vertex; + cmph_uint32 edge; +}; + + + +graph_t *graph_new(cmph_uint32 nnodes, cmph_uint32 nedges); +void graph_destroy(graph_t *graph); + +void graph_add_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2); +void graph_del_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2); +void graph_clear_edges(graph_t *g); +cmph_uint32 graph_edge_id(graph_t *g, cmph_uint32 v1, cmph_uint32 v2); +cmph_uint8 graph_contains_edge(graph_t *g, cmph_uint32 v1, cmph_uint32 v2); + +graph_iterator_t graph_neighbors_it(graph_t *g, cmph_uint32 v); +cmph_uint32 graph_next_neighbor(graph_t *g, graph_iterator_t* it); + +void graph_obtain_critical_nodes(graph_t *g); /* included -- Fabiano*/ +cmph_uint8 graph_node_is_critical(graph_t * g, cmph_uint32 v); /* included -- Fabiano */ +cmph_uint32 graph_ncritical_nodes(graph_t *g); /* included -- Fabiano*/ +cmph_uint32 graph_vertex_id(graph_t *g, cmph_uint32 e, cmph_uint32 id); /* included -- Fabiano*/ + +int graph_is_cyclic(graph_t *g); + +void graph_print(graph_t *); + +#endif diff --git a/girepository/cmph/hash.c b/girepository/cmph/hash.c new file mode 100644 index 0000000..be86d6e --- /dev/null +++ b/girepository/cmph/hash.c @@ -0,0 +1,216 @@ +#include "hash_state.h" +#include +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +const char *cmph_hash_names[] = { "jenkins", NULL }; + +hash_state_t *hash_state_new(CMPH_HASH hashfunc, cmph_uint32 hashsize) +{ + hash_state_t *state = NULL; + switch (hashfunc) + { + case CMPH_HASH_JENKINS: + DEBUGP("Jenkins function - %u\n", hashsize); + state = (hash_state_t *)jenkins_state_new(hashsize); + DEBUGP("Jenkins function created\n"); + break; + default: + assert(0); + } + state->hashfunc = hashfunc; + return state; +} +cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen) +{ + switch (state->hashfunc) + { + case CMPH_HASH_JENKINS: + return jenkins_hash((jenkins_state_t *)state, key, keylen); + default: + assert(0); + } + assert(0); + return 0; +} + +void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes) +{ + switch (state->hashfunc) + { + case CMPH_HASH_JENKINS: + jenkins_hash_vector_((jenkins_state_t *)state, key, keylen, hashes); + break; + default: + assert(0); + } +} + + +void hash_state_dump(hash_state_t *state, char **buf, cmph_uint32 *buflen) +{ + char *algobuf; + size_t len; + switch (state->hashfunc) + { + case CMPH_HASH_JENKINS: + jenkins_state_dump((jenkins_state_t *)state, &algobuf, buflen); + if (*buflen == UINT_MAX) return; + break; + default: + assert(0); + } + *buf = (char *)malloc(strlen(cmph_hash_names[state->hashfunc]) + 1 + *buflen); + memcpy(*buf, cmph_hash_names[state->hashfunc], strlen(cmph_hash_names[state->hashfunc]) + 1); + DEBUGP("Algobuf is %u\n", *(cmph_uint32 *)algobuf); + len = *buflen; + memcpy(*buf + strlen(cmph_hash_names[state->hashfunc]) + 1, algobuf, len); + *buflen = (cmph_uint32)strlen(cmph_hash_names[state->hashfunc]) + 1 + *buflen; + free(algobuf); + return; +} + +hash_state_t * hash_state_copy(hash_state_t *src_state) +{ + hash_state_t *dest_state = NULL; + switch (src_state->hashfunc) + { + case CMPH_HASH_JENKINS: + dest_state = (hash_state_t *)jenkins_state_copy((jenkins_state_t *)src_state); + break; + default: + assert(0); + } + dest_state->hashfunc = src_state->hashfunc; + return dest_state; +} + +hash_state_t *hash_state_load(const char *buf, cmph_uint32 buflen) +{ + cmph_uint32 i; + cmph_uint32 offset; + CMPH_HASH hashfunc = CMPH_HASH_COUNT; + for (i = 0; i < CMPH_HASH_COUNT; ++i) + { + if (strcmp(buf, cmph_hash_names[i]) == 0) + { + hashfunc = i; + break; + } + } + if (hashfunc == CMPH_HASH_COUNT) return NULL; + offset = (cmph_uint32)strlen(cmph_hash_names[hashfunc]) + 1; + switch (hashfunc) + { + case CMPH_HASH_JENKINS: + return (hash_state_t *)jenkins_state_load(buf + offset, buflen - offset); + default: + return NULL; + } + return NULL; +} +void hash_state_destroy(hash_state_t *state) +{ + switch (state->hashfunc) + { + case CMPH_HASH_JENKINS: + jenkins_state_destroy((jenkins_state_t *)state); + break; + default: + assert(0); + } + return; +} + +/** \fn void hash_state_pack(hash_state_t *state, void *hash_packed) + * \brief Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed. + * \param state points to the hash function + * \param hash_packed pointer to the contiguous memory area used to store the hash function. The size of hash_packed must be at least hash_state_packed_size() + * + * Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed. + * However, the hash function type must be packed outside. + */ +void hash_state_pack(hash_state_t *state, void *hash_packed) +{ + switch (state->hashfunc) + { + case CMPH_HASH_JENKINS: + // pack the jenkins hash function + jenkins_state_pack((jenkins_state_t *)state, hash_packed); + break; + default: + assert(0); + } + return; +} + +/** \fn cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc) + * \brief Return the amount of space needed to pack a hash function. + * \param hashfunc function type + * \return the size of the packed function or zero for failures + */ +cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc) +{ + cmph_uint32 size = 0; + switch (hashfunc) + { + case CMPH_HASH_JENKINS: + size += jenkins_state_packed_size(); + break; + default: + assert(0); + } + return size; +} + +/** \fn cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen) + * \param hash_packed is a pointer to a contiguous memory area + * \param hashfunc is the type of the hash function packed in hash_packed + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen) +{ + switch (hashfunc) + { + case CMPH_HASH_JENKINS: + return jenkins_hash_packed(hash_packed, k, keylen); + default: + assert(0); + } + assert(0); + return 0; +} + +/** \fn hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes) + * \param hash_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes) +{ + switch (hashfunc) + { + case CMPH_HASH_JENKINS: + jenkins_hash_vector_packed(hash_packed, k, keylen, hashes); + break; + default: + assert(0); + } +} + + +/** \fn CMPH_HASH hash_get_type(hash_state_t *state); + * \param state is a pointer to a hash_state_t structure + * \return the hash function type pointed by state + */ +CMPH_HASH hash_get_type(hash_state_t *state) +{ + return state->hashfunc; +} diff --git a/girepository/cmph/hash.h b/girepository/cmph/hash.h new file mode 100644 index 0000000..0ec4ce1 --- /dev/null +++ b/girepository/cmph/hash.h @@ -0,0 +1,76 @@ +#ifndef __CMPH_HASH_H__ +#define __CMPH_HASH_H__ + +#include "cmph_types.h" + +typedef union __hash_state_t hash_state_t; + +hash_state_t *hash_state_new(CMPH_HASH, cmph_uint32 hashsize); + +/** \fn cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen); + * \param state is a pointer to a hash_state_t structure + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 hash(hash_state_t *state, const char *key, cmph_uint32 keylen); + +/** \fn void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes); + * \param state is a pointer to a hash_state_t structure + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void hash_vector(hash_state_t *state, const char *key, cmph_uint32 keylen, cmph_uint32 * hashes); + +void hash_state_dump(hash_state_t *state, char **buf, cmph_uint32 *buflen); + +hash_state_t * hash_state_copy(hash_state_t *src_state); + +hash_state_t *hash_state_load(const char *buf, cmph_uint32 buflen); + +void hash_state_destroy(hash_state_t *state); + +/** \fn void hash_state_pack(hash_state_t *state, void *hash_packed); + * \brief Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed. + * \param state points to the hash function + * \param hash_packed pointer to the contiguous memory area used to store the hash function. The size of hash_packed must be at least hash_state_packed_size() + * + * Support the ability to pack a hash function into a preallocated contiguous memory space pointed by hash_packed. + * However, the hash function type must be packed outside. + */ +void hash_state_pack(hash_state_t *state, void *hash_packed); + +/** \fn cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen); + * \param hash_packed is a pointer to a contiguous memory area + * \param hashfunc is the type of the hash function packed in hash_packed + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 hash_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen); + +/** \fn cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc) + * \brief Return the amount of space needed to pack a hash function. + * \param hashfunc function type + * \return the size of the packed function or zero for failures + */ +cmph_uint32 hash_state_packed_size(CMPH_HASH hashfunc); + + +/** \fn hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + * \param hash_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void hash_vector_packed(void *hash_packed, CMPH_HASH hashfunc, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + + +/** \fn CMPH_HASH hash_get_type(hash_state_t *state); + * \param state is a pointer to a hash_state_t structure + * \return the hash function type pointed by state + */ +CMPH_HASH hash_get_type(hash_state_t *state); + +#endif diff --git a/girepository/cmph/hash_state.h b/girepository/cmph/hash_state.h new file mode 100644 index 0000000..1b567dc --- /dev/null +++ b/girepository/cmph/hash_state.h @@ -0,0 +1,12 @@ +#ifndef __HASH_STATE_H__ +#define __HASH_STATE_H__ + +#include "hash.h" +#include "jenkins_hash.h" +union __hash_state_t +{ + CMPH_HASH hashfunc; + jenkins_state_t jenkins; +}; + +#endif diff --git a/girepository/cmph/hashtree.c b/girepository/cmph/hashtree.c new file mode 100644 index 0000000..2f3567e --- /dev/null +++ b/girepository/cmph/hashtree.c @@ -0,0 +1,289 @@ +#include "graph.h" +#include "hashtree.h" +#include "cmph_structs.h" +#include "hastree_structs.h" +#include "hash.h" +#include "bitbool.h" + +#include +#include +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +hashtree_config_data_t *hashtree_config_new() +{ + hashtree_config_data_t *hashtree; + hashtree = (hashtree_config_data_t *)malloc(sizeof(hashtree_config_data_t)); + if (!hashtree) return NULL; + memset(hashtree, 0, sizeof(hashtree_config_data_t)); + hashtree->hashfuncs[0] = CMPH_HASH_JENKINS; + hashtree->hashfuncs[1] = CMPH_HASH_JENKINS; + hashtree->hashfuncs[2] = CMPH_HASH_JENKINS; + hashtree->memory = 32 * 1024 * 1024; + return hashtree; +} +void hashtree_config_destroy(cmph_config_t *mph) +{ + hashtree_config_data_t *data = (hashtree_config_data_t *)mph->data; + DEBUGP("Destroying algorithm dependent data\n"); + free(data); +} + +void hashtree_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs) +{ + hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data; + CMPH_HASH *hashptr = hashfuncs; + cmph_uint32 i = 0; + while(*hashptr != CMPH_HASH_COUNT) + { + if (i >= 3) break; //hashtree only uses three hash functions + hashtree->hashfuncs[i] = *hashptr; + ++i, ++hashptr; + } +} + +cmph_t *hashtree_new(cmph_config_t *mph, double c) +{ + cmph_t *mphf = NULL; + hashtree_data_t *hashtreef = NULL; + + cmph_uint32 i; + cmph_uint32 iterations = 20; + cmph_uint8 *visited = NULL; + hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data; + hashtree->m = mph->key_source->nkeys; + hashtree->n = ceil(c * mph->key_source->nkeys); + DEBUGP("m (edges): %u n (vertices): %u c: %f\n", hashtree->m, hashtree->n, c); + hashtree->graph = graph_new(hashtree->n, hashtree->m); + DEBUGP("Created graph\n"); + + hashtree->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*3); + for(i = 0; i < 3; ++i) hashtree->hashes[i] = NULL; + //Mapping step + if (mph->verbosity) + { + fprintf(stderr, "Entering mapping step for mph creation of %u keys with graph sized %u\n", hashtree->m, hashtree->n); + } + while(1) + { + int ok; + hashtree->hashes[0] = hash_state_new(hashtree->hashfuncs[0], hashtree->n); + hashtree->hashes[1] = hash_state_new(hashtree->hashfuncs[1], hashtree->n); + ok = hashtree_gen_edges(mph); + if (!ok) + { + --iterations; + hash_state_destroy(hashtree->hashes[0]); + hashtree->hashes[0] = NULL; + hash_state_destroy(hashtree->hashes[1]); + hashtree->hashes[1] = NULL; + DEBUGP("%u iterations remaining\n", iterations); + if (mph->verbosity) + { + fprintf(stderr, "Acyclic graph creation failure - %u iterations remaining\n", iterations); + } + if (iterations == 0) break; + } + else break; + } + if (iterations == 0) + { + graph_destroy(hashtree->graph); + return NULL; + } + + //Assignment step + if (mph->verbosity) + { + fprintf(stderr, "Starting assignment step\n"); + } + DEBUGP("Assignment step\n"); + visited = (char *)malloc(hashtree->n/8 + 1); + memset(visited, 0, hashtree->n/8 + 1); + free(hashtree->g); + hashtree->g = (cmph_uint32 *)malloc(hashtree->n * sizeof(cmph_uint32)); + assert(hashtree->g); + for (i = 0; i < hashtree->n; ++i) + { + if (!GETBIT(visited,i)) + { + hashtree->g[i] = 0; + hashtree_traverse(hashtree, visited, i); + } + } + graph_destroy(hashtree->graph); + free(visited); + hashtree->graph = NULL; + + mphf = (cmph_t *)malloc(sizeof(cmph_t)); + mphf->algo = mph->algo; + hashtreef = (hashtree_data_t *)malloc(sizeof(hashtree_data_t)); + hashtreef->g = hashtree->g; + hashtree->g = NULL; //transfer memory ownership + hashtreef->hashes = hashtree->hashes; + hashtree->hashes = NULL; //transfer memory ownership + hashtreef->n = hashtree->n; + hashtreef->m = hashtree->m; + mphf->data = hashtreef; + mphf->size = hashtree->m; + DEBUGP("Successfully generated minimal perfect hash\n"); + if (mph->verbosity) + { + fprintf(stderr, "Successfully generated minimal perfect hash function\n"); + } + return mphf; +} + +static void hashtree_traverse(hashtree_config_data_t *hashtree, cmph_uint8 *visited, cmph_uint32 v) +{ + + graph_iterator_t it = graph_neighbors_it(hashtree->graph, v); + cmph_uint32 neighbor = 0; + SETBIT(visited,v); + + DEBUGP("Visiting vertex %u\n", v); + while((neighbor = graph_next_neighbor(hashtree->graph, &it)) != GRAPH_NO_NEIGHBOR) + { + DEBUGP("Visiting neighbor %u\n", neighbor); + if(GETBIT(visited,neighbor)) continue; + DEBUGP("Visiting neighbor %u\n", neighbor); + DEBUGP("Visiting edge %u->%u with id %u\n", v, neighbor, graph_edge_id(hashtree->graph, v, neighbor)); + hashtree->g[neighbor] = graph_edge_id(hashtree->graph, v, neighbor) - hashtree->g[v]; + DEBUGP("g is %u (%u - %u mod %u)\n", hashtree->g[neighbor], graph_edge_id(hashtree->graph, v, neighbor), hashtree->g[v], hashtree->m); + hashtree_traverse(hashtree, visited, neighbor); + } +} + +static int hashtree_gen_edges(cmph_config_t *mph) +{ + cmph_uint32 e; + hashtree_config_data_t *hashtree = (hashtree_config_data_t *)mph->data; + int cycles = 0; + + DEBUGP("Generating edges for %u vertices with hash functions %s and %s\n", hashtree->n, cmph_hash_names[hashtree->hashfuncs[0]], cmph_hash_names[hashtree->hashfuncs[1]]); + graph_clear_edges(hashtree->graph); + mph->key_source->rewind(mph->key_source->data); + for (e = 0; e < mph->key_source->nkeys; ++e) + { + cmph_uint32 h1, h2; + cmph_uint32 keylen; + char *key; + mph->key_source->read(mph->key_source->data, &key, &keylen); + h1 = hash(hashtree->hashes[0], key, keylen) % hashtree->n; + h2 = hash(hashtree->hashes[1], key, keylen) % hashtree->n; + if (h1 == h2) if (++h2 >= hashtree->n) h2 = 0; + if (h1 == h2) + { + if (mph->verbosity) fprintf(stderr, "Self loop for key %u\n", e); + mph->key_source->dispose(mph->key_source->data, key, keylen); + return 0; + } + DEBUGP("Adding edge: %u -> %u for key %s\n", h1, h2, key); + mph->key_source->dispose(mph->key_source->data, key, keylen); + graph_add_edge(hashtree->graph, h1, h2); + } + cycles = graph_is_cyclic(hashtree->graph); + if (mph->verbosity && cycles) fprintf(stderr, "Cyclic graph generated\n"); + DEBUGP("Looking for cycles: %u\n", cycles); + + return ! cycles; +} + +int hashtree_dump(cmph_t *mphf, FILE *fd) +{ + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 two = 2; //number of hash functions + hashtree_data_t *data = (hashtree_data_t *)mphf->data; + __cmph_dump(mphf, fd); + + fwrite(&two, sizeof(cmph_uint32), 1, fd); + hash_state_dump(data->hashes[0], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + fwrite(&buflen, sizeof(cmph_uint32), 1, fd); + fwrite(buf, buflen, 1, fd); + free(buf); + + hash_state_dump(data->hashes[1], &buf, &buflen); + DEBUGP("Dumping hash state with %u bytes to disk\n", buflen); + fwrite(&buflen, sizeof(cmph_uint32), 1, fd); + fwrite(buf, buflen, 1, fd); + free(buf); + + fwrite(&(data->n), sizeof(cmph_uint32), 1, fd); + fwrite(&(data->m), sizeof(cmph_uint32), 1, fd); + + fwrite(data->g, sizeof(cmph_uint32)*data->n, 1, fd); + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < data->n; ++i) fprintf(stderr, "%u ", data->g[i]); + fprintf(stderr, "\n"); + #endif + return 1; +} + +void hashtree_load(FILE *f, cmph_t *mphf) +{ + cmph_uint32 nhashes; + char *buf = NULL; + cmph_uint32 buflen; + cmph_uint32 i; + hashtree_data_t *hashtree = (hashtree_data_t *)malloc(sizeof(hashtree_data_t)); + + DEBUGP("Loading hashtree mphf\n"); + mphf->data = hashtree; + fread(&nhashes, sizeof(cmph_uint32), 1, f); + hashtree->hashes = (hash_state_t **)malloc(sizeof(hash_state_t *)*(nhashes + 1)); + hashtree->hashes[nhashes] = NULL; + DEBUGP("Reading %u hashes\n", nhashes); + for (i = 0; i < nhashes; ++i) + { + hash_state_t *state = NULL; + fread(&buflen, sizeof(cmph_uint32), 1, f); + DEBUGP("Hash state has %u bytes\n", buflen); + buf = (char *)malloc(buflen); + fread(buf, buflen, 1, f); + state = hash_state_load(buf, buflen); + hashtree->hashes[i] = state; + free(buf); + } + + DEBUGP("Reading m and n\n"); + fread(&(hashtree->n), sizeof(cmph_uint32), 1, f); + fread(&(hashtree->m), sizeof(cmph_uint32), 1, f); + + hashtree->g = (cmph_uint32 *)malloc(sizeof(cmph_uint32)*hashtree->n); + fread(hashtree->g, hashtree->n*sizeof(cmph_uint32), 1, f); + #ifdef DEBUG + fprintf(stderr, "G: "); + for (i = 0; i < hashtree->n; ++i) fprintf(stderr, "%u ", hashtree->g[i]); + fprintf(stderr, "\n"); + #endif + return; +} + + +cmph_uint32 hashtree_search(cmph_t *mphf, const char *key, cmph_uint32 keylen) +{ + hashtree_data_t *hashtree = mphf->data; + cmph_uint32 h1 = hash(hashtree->hashes[0], key, keylen) % hashtree->n; + cmph_uint32 h2 = hash(hashtree->hashes[1], key, keylen) % hashtree->n; + DEBUGP("key: %s h1: %u h2: %u\n", key, h1, h2); + if (h1 == h2 && ++h2 >= hashtree->n) h2 = 0; + DEBUGP("key: %s g[h1]: %u g[h2]: %u edges: %u\n", key, hashtree->g[h1], hashtree->g[h2], hashtree->m); + return (hashtree->g[h1] + hashtree->g[h2]) % hashtree->m; +} +void hashtree_destroy(cmph_t *mphf) +{ + hashtree_data_t *data = (hashtree_data_t *)mphf->data; + free(data->g); + hash_state_destroy(data->hashes[0]); + hash_state_destroy(data->hashes[1]); + free(data->hashes); + free(data); + free(mphf); +} diff --git a/girepository/cmph/hashtree.h b/girepository/cmph/hashtree.h new file mode 100644 index 0000000..8bff674 --- /dev/null +++ b/girepository/cmph/hashtree.h @@ -0,0 +1,19 @@ +#ifndef __CMPH_HASHTREE_H__ +#define __CMPH_HASHTREE_H__ + +#include "cmph.h" + +typedef struct __hashtree_data_t hashtree_data_t; +typedef struct __hashtree_config_data_t hashtree_config_data_t; + +hashtree_config_data_t *hashtree_config_new(); +void hashtree_config_set_hashfuncs(cmph_config_t *mph, CMPH_HASH *hashfuncs); +void hashtree_config_set_leaf_algo(cmph_config_t *mph, CMPH_ALGO leaf_algo); +void hashtree_config_destroy(cmph_config_t *mph); +cmph_t *hashtree_new(cmph_config_t *mph, double c); + +void hashtree_load(FILE *f, cmph_t *mphf); +int hashtree_dump(cmph_t *mphf, FILE *f); +void hashtree_destroy(cmph_t *mphf); +cmph_uint32 hashtree_search(cmph_t *mphf, const char *key, cmph_uint32 keylen); +#endif diff --git a/girepository/cmph/hashtree_structs.h b/girepository/cmph/hashtree_structs.h new file mode 100644 index 0000000..7258cd3 --- /dev/null +++ b/girepository/cmph/hashtree_structs.h @@ -0,0 +1,32 @@ +#ifndef __CMPH_HASHTREE_STRUCTS_H__ +#define __CMPH_HASHTREE_STRUCTS_H__ + +#include "hash_state.h" + +struct __hashtree_data_t +{ + cmph_uint32 m; //edges (words) count + double c; //constant c + cmph_uint8 *size; //size[i] stores the number of edges represented by g[i] + cmph_uint32 **g; + cmph_uint32 k; //number of components + hash_state_t **h1; + hash_state_t **h2; + hash_state_t *h3; +}; + +struct __hashtree_config_data_t +{ + CMPH_ALGO leaf_algo; + CMPH_HASH hashfuncs[3]; + cmph_uint32 m; //edges (words) count + cmph_uint8 *size; //size[i] stores the number of edges represented by g[i] + cmph_uint32 *offset; //offset[i] stores the sum size[0] + ... size[i - 1] + cmph_uint32 k; //number of components + cmph_uint32 memory; + hash_state_t **h1; + hash_state_t **h2; + hash_state_t *h3; +}; + +#endif diff --git a/girepository/cmph/jenkins_hash.c b/girepository/cmph/jenkins_hash.c new file mode 100644 index 0000000..65cdff9 --- /dev/null +++ b/girepository/cmph/jenkins_hash.c @@ -0,0 +1,297 @@ +#include "jenkins_hash.h" +#include +#ifdef WIN32 +#define _USE_MATH_DEFINES //For M_LOG2E +#endif +#include +#include +#include + +//#define DEBUG +#include "debug.h" + +#define hashsize(n) ((cmph_uint32)1<<(n)) +#define hashmask(n) (hashsize(n)-1) + + + +//#define NM2 /* Define this if you do not want power of 2 table sizes*/ + + +/* + -------------------------------------------------------------------- + mix -- mix 3 32-bit values reversibly. + For every delta with one or two bits set, and the deltas of all three + high bits or all three low bits, whether the original value of a,b,c + is almost all zero or is uniformly distributed, + * If mix() is run forward or backward, at least 32 bits in a,b,c + have at least 1/4 probability of changing. + * If mix() is run forward, every bit of c will change between 1/3 and + 2/3 of the time. (Well, 22/100 and 78/100 for some 2-bit deltas.) + mix() was built out of 36 single-cycle latency instructions in a + structure that could supported 2x parallelism, like so: + a -= b; + a -= c; x = (c>>13); + b -= c; a ^= x; + b -= a; x = (a<<8); + c -= a; b ^= x; + c -= b; x = (b>>13); + ... + Unfortunately, superscalar Pentiums and Sparcs can't take advantage + of that parallelism. They've also turned some of those single-cycle + latency instructions into multi-cycle latency instructions. Still, + this is the fastest good hash I could find. There were about 2^^68 + to choose from. I only looked at a billion or so. + -------------------------------------------------------------------- + */ +#define mix(a,b,c) \ +{ \ + a -= b; a -= c; a ^= (c>>13); \ + b -= c; b -= a; b ^= (a<<8); \ + c -= a; c -= b; c ^= (b>>13); \ + a -= b; a -= c; a ^= (c>>12); \ + b -= c; b -= a; b ^= (a<<16); \ + c -= a; c -= b; c ^= (b>>5); \ + a -= b; a -= c; a ^= (c>>3); \ + b -= c; b -= a; b ^= (a<<10); \ + c -= a; c -= b; c ^= (b>>15); \ +} + +/* + -------------------------------------------------------------------- + hash() -- hash a variable-length key into a 32-bit value +k : the key (the unaligned variable-length array of bytes) +len : the length of the key, counting by bytes +initval : can be any 4-byte value +Returns a 32-bit value. Every bit of the key affects every bit of +the return value. Every 1-bit and 2-bit delta achieves avalanche. +About 6*len+35 instructions. + +The best hash table sizes are powers of 2. There is no need to do +mod a prime (mod is sooo slow!). If you need less than 32 bits, +use a bitmask. For example, if you need only 10 bits, do +h = (h & hashmask(10)); +In which case, the hash table should have hashsize(10) elements. + +If you are hashing n strings (cmph_uint8 **)k, do it like this: +for (i=0, h=0; iseed = ((cmph_uint32)rand() % size); + return state; +} +void jenkins_state_destroy(jenkins_state_t *state) +{ + free(state); +} + + +static inline void __jenkins_hash_vector(cmph_uint32 seed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes) +{ + register cmph_uint32 len, length; + + /* Set up the internal state */ + length = keylen; + len = length; + hashes[0] = hashes[1] = 0x9e3779b9; /* the golden ratio; an arbitrary value */ + hashes[2] = seed; /* the previous hash value - seed in our case */ + + /*---------------------------------------- handle most of the key */ + while (len >= 12) + { + hashes[0] += ((cmph_uint32)k[0] +((cmph_uint32)k[1]<<8) +((cmph_uint32)k[2]<<16) +((cmph_uint32)k[3]<<24)); + hashes[1] += ((cmph_uint32)k[4] +((cmph_uint32)k[5]<<8) +((cmph_uint32)k[6]<<16) +((cmph_uint32)k[7]<<24)); + hashes[2] += ((cmph_uint32)k[8] +((cmph_uint32)k[9]<<8) +((cmph_uint32)k[10]<<16)+((cmph_uint32)k[11]<<24)); + mix(hashes[0],hashes[1],hashes[2]); + k += 12; len -= 12; + } + + /*------------------------------------- handle the last 11 bytes */ + hashes[2] += length; + switch(len) /* all the case statements fall through */ + { + case 11: + hashes[2] +=((cmph_uint32)k[10]<<24); + case 10: + hashes[2] +=((cmph_uint32)k[9]<<16); + case 9 : + hashes[2] +=((cmph_uint32)k[8]<<8); + /* the first byte of hashes[2] is reserved for the length */ + case 8 : + hashes[1] +=((cmph_uint32)k[7]<<24); + case 7 : + hashes[1] +=((cmph_uint32)k[6]<<16); + case 6 : + hashes[1] +=((cmph_uint32)k[5]<<8); + case 5 : + hashes[1] +=(cmph_uint8) k[4]; + case 4 : + hashes[0] +=((cmph_uint32)k[3]<<24); + case 3 : + hashes[0] +=((cmph_uint32)k[2]<<16); + case 2 : + hashes[0] +=((cmph_uint32)k[1]<<8); + case 1 : + hashes[0] +=(cmph_uint8)k[0]; + /* case 0: nothing left to add */ + } + + mix(hashes[0],hashes[1],hashes[2]); +} + +cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen) +{ + cmph_uint32 hashes[3]; + __jenkins_hash_vector(state->seed, k, keylen, hashes); + return hashes[2]; +/* cmph_uint32 a, b, c; + cmph_uint32 len, length; + + // Set up the internal state + length = keylen; + len = length; + a = b = 0x9e3779b9; // the golden ratio; an arbitrary value + c = state->seed; // the previous hash value - seed in our case + + // handle most of the key + while (len >= 12) + { + a += (k[0] +((cmph_uint32)k[1]<<8) +((cmph_uint32)k[2]<<16) +((cmph_uint32)k[3]<<24)); + b += (k[4] +((cmph_uint32)k[5]<<8) +((cmph_uint32)k[6]<<16) +((cmph_uint32)k[7]<<24)); + c += (k[8] +((cmph_uint32)k[9]<<8) +((cmph_uint32)k[10]<<16)+((cmph_uint32)k[11]<<24)); + mix(a,b,c); + k += 12; len -= 12; + } + + // handle the last 11 bytes + c += length; + switch(len) /// all the case statements fall through + { + case 11: + c +=((cmph_uint32)k[10]<<24); + case 10: + c +=((cmph_uint32)k[9]<<16); + case 9 : + c +=((cmph_uint32)k[8]<<8); + // the first byte of c is reserved for the length + case 8 : + b +=((cmph_uint32)k[7]<<24); + case 7 : + b +=((cmph_uint32)k[6]<<16); + case 6 : + b +=((cmph_uint32)k[5]<<8); + case 5 : + b +=k[4]; + case 4 : + a +=((cmph_uint32)k[3]<<24); + case 3 : + a +=((cmph_uint32)k[2]<<16); + case 2 : + a +=((cmph_uint32)k[1]<<8); + case 1 : + a +=k[0]; + // case 0: nothing left to add + } + + mix(a,b,c); + + /// report the result + + return c; + */ +} + +void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes) +{ + __jenkins_hash_vector(state->seed, k, keylen, hashes); +} + +void jenkins_state_dump(jenkins_state_t *state, char **buf, cmph_uint32 *buflen) +{ + *buflen = sizeof(cmph_uint32); + *buf = (char *)malloc(sizeof(cmph_uint32)); + if (!*buf) + { + *buflen = UINT_MAX; + return; + } + memcpy(*buf, &(state->seed), sizeof(cmph_uint32)); + DEBUGP("Dumped jenkins state with seed %u\n", state->seed); + return; +} + +jenkins_state_t *jenkins_state_copy(jenkins_state_t *src_state) +{ + jenkins_state_t *dest_state = (jenkins_state_t *)malloc(sizeof(jenkins_state_t)); + dest_state->hashfunc = src_state->hashfunc; + dest_state->seed = src_state->seed; + return dest_state; +} + +jenkins_state_t *jenkins_state_load(const char *buf, cmph_uint32 buflen) +{ + jenkins_state_t *state = (jenkins_state_t *)malloc(sizeof(jenkins_state_t)); + state->seed = *(cmph_uint32 *)buf; + state->hashfunc = CMPH_HASH_JENKINS; + DEBUGP("Loaded jenkins state with seed %u\n", state->seed); + return state; +} + + +/** \fn void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed); + * \brief Support the ability to pack a jenkins function into a preallocated contiguous memory space pointed by jenkins_packed. + * \param state points to the jenkins function + * \param jenkins_packed pointer to the contiguous memory area used to store the jenkins function. The size of jenkins_packed must be at least jenkins_state_packed_size() + */ +void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed) +{ + if (state && jenkins_packed) + { + memcpy(jenkins_packed, &(state->seed), sizeof(cmph_uint32)); + } +} + +/** \fn cmph_uint32 jenkins_state_packed_size(jenkins_state_t *state); + * \brief Return the amount of space needed to pack a jenkins function. + * \return the size of the packed function or zero for failures + */ +cmph_uint32 jenkins_state_packed_size(void) +{ + return sizeof(cmph_uint32); +} + + +/** \fn cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen); + * \param jenkins_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen) +{ + cmph_uint32 hashes[3]; + __jenkins_hash_vector(*((cmph_uint32 *)jenkins_packed), k, keylen, hashes); + return hashes[2]; +} + +/** \fn jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + * \param jenkins_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes) +{ + __jenkins_hash_vector(*((cmph_uint32 *)jenkins_packed), k, keylen, hashes); +} diff --git a/girepository/cmph/jenkins_hash.h b/girepository/cmph/jenkins_hash.h new file mode 100644 index 0000000..39626e2 --- /dev/null +++ b/girepository/cmph/jenkins_hash.h @@ -0,0 +1,65 @@ +#ifndef __JEKINS_HASH_H__ +#define __JEKINS_HASH_H__ + +#include "hash.h" + +typedef struct __jenkins_state_t +{ + CMPH_HASH hashfunc; + cmph_uint32 seed; +} jenkins_state_t; + +jenkins_state_t *jenkins_state_new(cmph_uint32 size); //size of hash table + +/** \fn cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen); + * \param state is a pointer to a jenkins_state_t structure + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 jenkins_hash(jenkins_state_t *state, const char *k, cmph_uint32 keylen); + +/** \fn void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + * \param state is a pointer to a jenkins_state_t structure + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void jenkins_hash_vector_(jenkins_state_t *state, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + +void jenkins_state_dump(jenkins_state_t *state, char **buf, cmph_uint32 *buflen); +jenkins_state_t *jenkins_state_copy(jenkins_state_t *src_state); +jenkins_state_t *jenkins_state_load(const char *buf, cmph_uint32 buflen); +void jenkins_state_destroy(jenkins_state_t *state); + +/** \fn void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed); + * \brief Support the ability to pack a jenkins function into a preallocated contiguous memory space pointed by jenkins_packed. + * \param state points to the jenkins function + * \param jenkins_packed pointer to the contiguous memory area used to store the jenkins function. The size of jenkins_packed must be at least jenkins_state_packed_size() + */ +void jenkins_state_pack(jenkins_state_t *state, void *jenkins_packed); + +/** \fn cmph_uint32 jenkins_state_packed_size(); + * \brief Return the amount of space needed to pack a jenkins function. + * \return the size of the packed function or zero for failures + */ +cmph_uint32 jenkins_state_packed_size(void); + + +/** \fn cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen); + * \param jenkins_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \return an integer that represents a hash value of 32 bits. + */ +cmph_uint32 jenkins_hash_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen); + +/** \fn jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + * \param jenkins_packed is a pointer to a contiguous memory area + * \param key is a pointer to a key + * \param keylen is the key length + * \param hashes is a pointer to a memory large enough to fit three 32-bit integers. + */ +void jenkins_hash_vector_packed(void *jenkins_packed, const char *k, cmph_uint32 keylen, cmph_uint32 * hashes); + +#endif diff --git a/girepository/cmph/main.c b/girepository/cmph/main.c new file mode 100644 index 0000000..f739b32 --- /dev/null +++ b/girepository/cmph/main.c @@ -0,0 +1,342 @@ +#ifdef WIN32 +#include "wingetopt.h" +#else +#include +#endif +#include +#include +#include +#include +#include +#include +#include +#include "cmph.h" +#include "hash.h" + +#ifdef WIN32 +#define VERSION "0.8" +#else +#include "config.h" +#endif + + +void usage(const char *prg) +{ + fprintf(stderr, "usage: %s [-v] [-h] [-V] [-k nkeys] [-f hash_function] [-g [-c algorithm_dependent_value][-s seed] ] [-a algorithm] [-M memory_in_MB] [-b algorithm_dependent_value] [-t keys_per_bin] [-d tmp_dir] [-m file.mph] keysfile\n", prg); +} +void usage_long(const char *prg) +{ + cmph_uint32 i; + fprintf(stderr, "usage: %s [-v] [-h] [-V] [-k nkeys] [-f hash_function] [-g [-c algorithm_dependent_value][-s seed] ] [-a algorithm] [-M memory_in_MB] [-b algorithm_dependent_value] [-t keys_per_bin] [-d tmp_dir] [-m file.mph] keysfile\n", prg); + fprintf(stderr, "Minimum perfect hashing tool\n\n"); + fprintf(stderr, " -h\t print this help message\n"); + fprintf(stderr, " -c\t c value determines:\n"); + fprintf(stderr, " \t * the number of vertices in the graph for the algorithms BMZ and CHM\n"); + fprintf(stderr, " \t * the number of bits per key required in the FCH algorithm\n"); + fprintf(stderr, " \t * the load factor in the CHD_PH algorithm\n"); + fprintf(stderr, " -a\t algorithm - valid values are\n"); + for (i = 0; i < CMPH_COUNT; ++i) fprintf(stderr, " \t * %s\n", cmph_names[i]); + fprintf(stderr, " -f\t hash function (may be used multiple times) - valid values are\n"); + for (i = 0; i < CMPH_HASH_COUNT; ++i) fprintf(stderr, " \t * %s\n", cmph_hash_names[i]); + fprintf(stderr, " -V\t print version number and exit\n"); + fprintf(stderr, " -v\t increase verbosity (may be used multiple times)\n"); + fprintf(stderr, " -k\t number of keys\n"); + fprintf(stderr, " -g\t generation mode\n"); + fprintf(stderr, " -s\t random seed\n"); + fprintf(stderr, " -m\t minimum perfect hash function file \n"); + fprintf(stderr, " -M\t main memory availability (in MB) used in BRZ algorithm \n"); + fprintf(stderr, " -d\t temporary directory used in BRZ algorithm \n"); + fprintf(stderr, " -b\t the meaning of this parameter depends on the algorithm selected in the -a option:\n"); + fprintf(stderr, " \t * For BRZ it is used to make the maximal number of keys in a bucket lower than 256.\n"); + fprintf(stderr, " \t In this case its value should be an integer in the range [64,175]. Default is 128.\n\n"); + fprintf(stderr, " \t * For BDZ it is used to determine the size of some precomputed rank\n"); + fprintf(stderr, " \t information and its value should be an integer in the range [3,10]. Default\n"); + fprintf(stderr, " \t is 7. The larger is this value, the more compact are the resulting functions\n"); + fprintf(stderr, " \t and the slower are them at evaluation time.\n\n"); + fprintf(stderr, " \t * For CHD and CHD_PH it is used to set the average number of keys per bucket\n"); + fprintf(stderr, " \t and its value should be an integer in the range [1,32]. Default is 4. The\n"); + fprintf(stderr, " \t larger is this value, the slower is the construction of the functions.\n"); + fprintf(stderr, " \t This parameter has no effect for other algorithms.\n\n"); + fprintf(stderr, " -t\t set the number of keys per bin for a t-perfect hashing function. A t-perfect\n"); + fprintf(stderr, " \t hash function allows at most t collisions in a given bin. This parameter applies\n"); + fprintf(stderr, " \t only to the CHD and CHD_PH algorithms. Its value should be an integer in the\n"); + fprintf(stderr, " \t range [1,128]. Defaul is 1\n"); + fprintf(stderr, " keysfile\t line separated file with keys\n"); +} + +int main(int argc, char **argv) +{ + cmph_uint32 verbosity = 0; + char generate = 0; + char *mphf_file = NULL; + FILE *mphf_fd = stdout; + const char *keys_file = NULL; + FILE *keys_fd; + cmph_uint32 nkeys = UINT_MAX; + cmph_uint32 seed = UINT_MAX; + CMPH_HASH *hashes = NULL; + cmph_uint32 nhashes = 0; + cmph_uint32 i; + CMPH_ALGO mph_algo = CMPH_CHM; + double c = 0; + cmph_config_t *config = NULL; + cmph_t *mphf = NULL; + char * tmp_dir = NULL; + cmph_io_adapter_t *source; + cmph_uint32 memory_availability = 0; + cmph_uint32 b = 0; + cmph_uint32 keys_per_bin = 1; + while (1) + { + char ch = (char)getopt(argc, argv, "hVvgc:k:a:M:b:t:f:m:d:s:"); + if (ch == -1) break; + switch (ch) + { + case 's': + { + char *cptr; + seed = (cmph_uint32)strtoul(optarg, &cptr, 10); + if(*cptr != 0) { + fprintf(stderr, "Invalid seed %s\n", optarg); + exit(1); + } + } + break; + case 'c': + { + char *endptr; + c = strtod(optarg, &endptr); + if(*endptr != 0) { + fprintf(stderr, "Invalid c value %s\n", optarg); + exit(1); + } + } + break; + case 'g': + generate = 1; + break; + case 'k': + { + char *endptr; + nkeys = (cmph_uint32)strtoul(optarg, &endptr, 10); + if(*endptr != 0) { + fprintf(stderr, "Invalid number of keys %s\n", optarg); + exit(1); + } + } + break; + case 'm': + mphf_file = strdup(optarg); + break; + case 'd': + tmp_dir = strdup(optarg); + break; + case 'M': + { + char *cptr; + memory_availability = (cmph_uint32)strtoul(optarg, &cptr, 10); + if(*cptr != 0) { + fprintf(stderr, "Invalid memory availability %s\n", optarg); + exit(1); + } + } + break; + case 'b': + { + char *cptr; + b = (cmph_uint32)strtoul(optarg, &cptr, 10); + if(*cptr != 0) { + fprintf(stderr, "Parameter b was not found: %s\n", optarg); + exit(1); + } + } + break; + case 't': + { + char *cptr; + keys_per_bin = (cmph_uint32)strtoul(optarg, &cptr, 10); + if(*cptr != 0) { + fprintf(stderr, "Parameter t was not found: %s\n", optarg); + exit(1); + } + } + break; + case 'v': + ++verbosity; + break; + case 'V': + printf("%s\n", VERSION); + return 0; + case 'h': + usage_long(argv[0]); + return 0; + case 'a': + { + char valid = 0; + for (i = 0; i < CMPH_COUNT; ++i) + { + if (strcmp(cmph_names[i], optarg) == 0) + { + mph_algo = i; + valid = 1; + break; + } + } + if (!valid) + { + fprintf(stderr, "Invalid mph algorithm: %s. It is not available in version %s\n", optarg, VERSION); + return -1; + } + } + break; + case 'f': + { + char valid = 0; + for (i = 0; i < CMPH_HASH_COUNT; ++i) + { + if (strcmp(cmph_hash_names[i], optarg) == 0) + { + hashes = (CMPH_HASH *)realloc(hashes, sizeof(CMPH_HASH) * ( nhashes + 2 )); + hashes[nhashes] = i; + hashes[nhashes + 1] = CMPH_HASH_COUNT; + ++nhashes; + valid = 1; + break; + } + } + if (!valid) + { + fprintf(stderr, "Invalid hash function: %s\n", optarg); + return -1; + } + } + break; + default: + usage(argv[0]); + return 1; + } + } + + if (optind != argc - 1) + { + usage(argv[0]); + return 1; + } + keys_file = argv[optind]; + + if (seed == UINT_MAX) seed = (cmph_uint32)time(NULL); + srand(seed); + int ret = 0; + if (mphf_file == NULL) + { + mphf_file = (char *)malloc(strlen(keys_file) + 5); + memcpy(mphf_file, keys_file, strlen(keys_file)); + memcpy(mphf_file + strlen(keys_file), ".mph\0", (size_t)5); + } + + keys_fd = fopen(keys_file, "r"); + + if (keys_fd == NULL) + { + fprintf(stderr, "Unable to open file %s: %s\n", keys_file, strerror(errno)); + return -1; + } + + if (seed == UINT_MAX) seed = (cmph_uint32)time(NULL); + if(nkeys == UINT_MAX) source = cmph_io_nlfile_adapter(keys_fd); + else source = cmph_io_nlnkfile_adapter(keys_fd, nkeys); + if (generate) + { + //Create mphf + mphf_fd = fopen(mphf_file, "w"); + config = cmph_config_new(source); + cmph_config_set_algo(config, mph_algo); + if (nhashes) cmph_config_set_hashfuncs(config, hashes); + cmph_config_set_verbosity(config, verbosity); + cmph_config_set_tmp_dir(config, (cmph_uint8 *) tmp_dir); + cmph_config_set_mphf_fd(config, mphf_fd); + cmph_config_set_memory_availability(config, memory_availability); + cmph_config_set_b(config, b); + cmph_config_set_keys_per_bin(config, keys_per_bin); + + //if((mph_algo == CMPH_BMZ || mph_algo == CMPH_BRZ) && c >= 2.0) c=1.15; + if(mph_algo == CMPH_BMZ && c >= 2.0) c=1.15; + if (c != 0) cmph_config_set_graphsize(config, c); + mphf = cmph_new(config); + + cmph_config_destroy(config); + if (mphf == NULL) + { + fprintf(stderr, "Unable to create minimum perfect hashing function\n"); + //cmph_config_destroy(config); + free(mphf_file); + return -1; + } + + if (mphf_fd == NULL) + { + fprintf(stderr, "Unable to open output file %s: %s\n", mphf_file, strerror(errno)); + free(mphf_file); + return -1; + } + cmph_dump(mphf, mphf_fd); + cmph_destroy(mphf); + fclose(mphf_fd); + } + else + { + cmph_uint8 * hashtable = NULL; + mphf_fd = fopen(mphf_file, "r"); + if (mphf_fd == NULL) + { + fprintf(stderr, "Unable to open input file %s: %s\n", mphf_file, strerror(errno)); + free(mphf_file); + return -1; + } + mphf = cmph_load(mphf_fd); + fclose(mphf_fd); + if (!mphf) + { + fprintf(stderr, "Unable to parser input file %s\n", mphf_file); + free(mphf_file); + return -1; + } + cmph_uint32 siz = cmph_size(mphf); + hashtable = (cmph_uint8*)calloc(siz, sizeof(cmph_uint8)); + memset(hashtable, 0,(size_t) siz); + //check all keys + for (i = 0; i < source->nkeys; ++i) + { + cmph_uint32 h; + char *buf; + cmph_uint32 buflen = 0; + source->read(source->data, &buf, &buflen); + h = cmph_search(mphf, buf, buflen); + if (!(h < siz)) + { + fprintf(stderr, "Unknown key %*s in the input.\n", buflen, buf); + ret = 1; + } else if(hashtable[h] >= keys_per_bin) + { + fprintf(stderr, "More than %u keys were mapped to bin %u\n", keys_per_bin, h); + fprintf(stderr, "Duplicated or unknown key %*s in the input\n", buflen, buf); + ret = 1; + } else hashtable[h]++; + + if (verbosity) + { + printf("%s -> %u\n", buf, h); + } + source->dispose(source->data, buf, buflen); + } + + cmph_destroy(mphf); + free(hashtable); + } + fclose(keys_fd); + free(mphf_file); + free(tmp_dir); + cmph_io_nlfile_adapter_destroy(source); + return ret; + +} diff --git a/girepository/cmph/meson.build b/girepository/cmph/meson.build new file mode 100644 index 0000000..2f4160f --- /dev/null +++ b/girepository/cmph/meson.build @@ -0,0 +1,86 @@ +cmph_sources = [ + 'bdz.c', + 'bdz_ph.c', + 'bmz8.c', + 'bmz.c', + 'brz.c', + 'buffer_entry.c', + 'buffer_manager.c', + 'chd.c', + 'chd_ph.c', + 'chm.c', + 'cmph.c', + 'cmph_structs.c', + 'compressed_rank.c', + 'compressed_seq.c', + 'fch_buckets.c', + 'fch.c', + 'graph.c', + 'hash.c', + 'jenkins_hash.c', + 'miller_rabin.c', + 'select.c', + 'vqueue.c', + 'vstack.c', +] + +cmph_deps = [ + libglib_dep, + libgobject_dep, + libm, +] + +custom_c_args = [] + +if cc.get_id() != 'msvc' + custom_c_args = cc.get_supported_arguments([ + '-Wno-implicit-fallthrough', + '-Wno-old-style-definition', + '-Wno-suggest-attribute=noreturn', + '-Wno-type-limits', + '-Wno-undef', + '-Wno-unused-parameter', + '-Wno-cast-align', + '-Wno-unused-function', + '-Wno-return-type', + '-Wno-sometimes-uninitialized', + ]) +endif + +cmph = static_library('cmph', + sources: cmph_sources, + c_args: custom_c_args, + dependencies: cmph_deps, +) + +cmph_dep = declare_dependency( + link_with: cmph, + include_directories: include_directories('.'), +) + +if cc.get_id() != 'msvc' + custom_c_args = cc.get_supported_arguments([ + '-Wno-old-style-definition', + '-Wno-type-limits', + ]) +endif + +test_env = environment() +test_env.set('G_TEST_SRCDIR', meson.current_source_dir()) +test_env.set('G_TEST_BUILDDIR', meson.current_build_dir()) + +cmph_test = executable('cmph-bdz-test', '../cmph-bdz-test.c', + dependencies: [ + cmph_dep, + libglib_dep, + libgobject_dep, + ], + c_args: custom_c_args + ['-UG_DISABLE_ASSERT'], +) + +test('cmph-bdz-test', cmph_test, + env: test_env, + protocol: test_protocol, + suite: ['girepository'], + timeout: test_timeout, +) diff --git a/girepository/cmph/miller_rabin.c b/girepository/cmph/miller_rabin.c new file mode 100644 index 0000000..17d0ed3 --- /dev/null +++ b/girepository/cmph/miller_rabin.c @@ -0,0 +1,67 @@ +#include "miller_rabin.h" + +static inline cmph_uint64 int_pow(cmph_uint64 a, cmph_uint64 d, cmph_uint64 n) +{ + cmph_uint64 a_pow = a; + cmph_uint64 res = 1; + while(d > 0) + { + if((d & 1) == 1) + res =(((cmph_uint64)res) * a_pow) % n; + a_pow = (((cmph_uint64)a_pow) * a_pow) % n; + d /= 2; + }; + return res; +}; + +static inline cmph_uint8 check_witness(cmph_uint64 a_exp_d, cmph_uint64 n, cmph_uint64 s) +{ + cmph_uint64 i; + cmph_uint64 a_exp = a_exp_d; + if(a_exp == 1 || a_exp == (n - 1)) + return 1; + for(i = 1; i < s; i++) + { + a_exp = (((cmph_uint64)a_exp) * a_exp) % n; + if(a_exp == (n - 1)) + return 1; + }; + return 0; +}; + +cmph_uint8 check_primality(cmph_uint64 n) +{ + cmph_uint64 a, d, s, a_exp_d; + if((n % 2) == 0) + return 0; + if((n % 3) == 0) + return 0; + if((n % 5) == 0) + return 0; + if((n % 7 ) == 0) + return 0; + //we decompoe the number n - 1 into 2^s*d + s = 0; + d = n - 1; + do + { + s++; + d /= 2; + }while((d % 2) == 0); + + a = 2; + a_exp_d = int_pow(a, d, n); + if(check_witness(a_exp_d, n, s) == 0) + return 0; + a = 7; + a_exp_d = int_pow(a, d, n); + if(check_witness(a_exp_d, n, s) == 0) + return 0; + a = 61; + a_exp_d = int_pow(a, d, n); + if(check_witness(a_exp_d, n, s) == 0) + return 0; + return 1; +}; + + diff --git a/girepository/cmph/miller_rabin.h b/girepository/cmph/miller_rabin.h new file mode 100644 index 0000000..42dc6ce --- /dev/null +++ b/girepository/cmph/miller_rabin.h @@ -0,0 +1,5 @@ +#ifndef _CMPH_MILLER_RABIN_H__ +#define _CMPH_MILLER_RABIN_H__ +#include "cmph_types.h" +cmph_uint8 check_primality(cmph_uint64 n); +#endif diff --git a/girepository/cmph/sdbm_hash.c b/girepository/cmph/sdbm_hash.c new file mode 100644 index 0000000..2f706c9 --- /dev/null +++ b/girepository/cmph/sdbm_hash.c @@ -0,0 +1,49 @@ +#include "sdbm_hash.h" +#include + +sdbm_state_t *sdbm_state_new() +{ + sdbm_state_t *state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t)); + state->hashfunc = CMPH_HASH_SDBM; + return state; +} + +void sdbm_state_destroy(sdbm_state_t *state) +{ + free(state); +} + +cmph_uint32 sdbm_hash(sdbm_state_t *state, const char *k, cmph_uint32 keylen) +{ + register cmph_uint32 hash = 0; + const unsigned char *ptr = (unsigned char *)k; + cmph_uint32 i = 0; + + while(i < keylen) { + hash = *ptr + (hash << 6) + (hash << 16) - hash; + ++ptr, ++i; + } + return hash; +} + + +void sdbm_state_dump(sdbm_state_t *state, char **buf, cmph_uint32 *buflen) +{ + *buf = NULL; + *buflen = 0; + return; +} + +sdbm_state_t *sdbm_state_copy(sdbm_state_t *src_state) +{ + sdbm_state_t *dest_state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t)); + dest_state->hashfunc = src_state->hashfunc; + return dest_state; +} + +sdbm_state_t *sdbm_state_load(const char *buf, cmph_uint32 buflen) +{ + sdbm_state_t *state = (sdbm_state_t *)malloc(sizeof(sdbm_state_t)); + state->hashfunc = CMPH_HASH_SDBM; + return state; +} diff --git a/girepository/cmph/sdbm_hash.h b/girepository/cmph/sdbm_hash.h new file mode 100644 index 0000000..f44b2f1 --- /dev/null +++ b/girepository/cmph/sdbm_hash.h @@ -0,0 +1,18 @@ +#ifndef __SDBM_HASH_H__ +#define __SDBM_HASH_H__ + +#include "hash.h" + +typedef struct __sdbm_state_t +{ + CMPH_HASH hashfunc; +} sdbm_state_t; + +sdbm_state_t *sdbm_state_new(); +cmph_uint32 sdbm_hash(sdbm_state_t *state, const char *k, cmph_uint32 keylen); +void sdbm_state_dump(sdbm_state_t *state, char **buf, cmph_uint32 *buflen); +sdbm_state_t *sdbm_state_copy(sdbm_state_t *src_state); +sdbm_state_t *sdbm_state_load(const char *buf, cmph_uint32 buflen); +void sdbm_state_destroy(sdbm_state_t *state); + +#endif diff --git a/girepository/cmph/select.c b/girepository/cmph/select.c new file mode 100644 index 0000000..fec4b7a --- /dev/null +++ b/girepository/cmph/select.c @@ -0,0 +1,337 @@ +#include +#include +#include +#include +#include +#include "select_lookup_tables.h" +#include "select.h" + +//#define DEBUG +#include "debug.h" + +#ifndef STEP_SELECT_TABLE +#define STEP_SELECT_TABLE 128 +#endif + +#ifndef NBITS_STEP_SELECT_TABLE +#define NBITS_STEP_SELECT_TABLE 7 +#endif + +#ifndef MASK_STEP_SELECT_TABLE +#define MASK_STEP_SELECT_TABLE 0x7f // 0x7f = 127 +#endif + +static inline void select_insert_0(cmph_uint32 * buffer) +{ + (*buffer) >>= 1; +}; + +static inline void select_insert_1(cmph_uint32 * buffer) +{ + (*buffer) >>= 1; + (*buffer) |= 0x80000000; +}; + +void select_init(select_t * sel) +{ + sel->n = 0; + sel->m = 0; + sel->bits_vec = 0; + sel->select_table = 0; +}; + +cmph_uint32 select_get_space_usage(select_t * sel) +{ + register cmph_uint32 nbits; + register cmph_uint32 vec_size; + register cmph_uint32 sel_table_size; + register cmph_uint32 space_usage; + + nbits = sel->n + sel->m; + vec_size = (nbits + 31) >> 5; + sel_table_size = (sel->n >> NBITS_STEP_SELECT_TABLE) + 1; // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE) + + space_usage = 2 * sizeof(cmph_uint32) * 8; // n and m + space_usage += vec_size * (cmph_uint32) sizeof(cmph_uint32) * 8; + space_usage += sel_table_size * (cmph_uint32)sizeof(cmph_uint32) * 8; + return space_usage; +} + +void select_destroy(select_t * sel) +{ + free(sel->bits_vec); + free(sel->select_table); + sel->bits_vec = 0; + sel->select_table = 0; +}; + +static inline void select_generate_sel_table(select_t * sel) +{ + register cmph_uint8 * bits_table = (cmph_uint8 *)sel->bits_vec; + register cmph_uint32 part_sum, old_part_sum; + register cmph_uint32 vec_idx, one_idx, sel_table_idx; + + part_sum = vec_idx = one_idx = sel_table_idx = 0; + + for(;;) + { + // FABIANO: Should'n it be one_idx >= sel->n + if(one_idx >= sel->n) + break; + do + { + old_part_sum = part_sum; + part_sum += rank_lookup_table[bits_table[vec_idx]]; + vec_idx++; + } while (part_sum <= one_idx); + + sel->select_table[sel_table_idx] = select_lookup_table[bits_table[vec_idx - 1]][one_idx - old_part_sum] + ((vec_idx - 1) << 3); // ((vec_idx - 1) << 3) = ((vec_idx - 1) * 8) + one_idx += STEP_SELECT_TABLE ; + sel_table_idx++; + }; +}; + +void select_generate(select_t * sel, cmph_uint32 * keys_vec, cmph_uint32 n, cmph_uint32 m) +{ + register cmph_uint32 i, j, idx; + cmph_uint32 buffer = 0; + + register cmph_uint32 nbits; + register cmph_uint32 vec_size; + register cmph_uint32 sel_table_size; + sel->n = n; + sel->m = m; // n values in the range [0,m-1] + + nbits = sel->n + sel->m; + vec_size = (nbits + 31) >> 5; // (nbits + 31) >> 5 = (nbits + 31)/32 + + sel_table_size = (sel->n >> NBITS_STEP_SELECT_TABLE) + 1; // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE) + + if(sel->bits_vec) + { + free(sel->bits_vec); + } + sel->bits_vec = (cmph_uint32 *)calloc(vec_size, sizeof(cmph_uint32)); + + if(sel->select_table) + { + free(sel->select_table); + } + sel->select_table = (cmph_uint32 *)calloc(sel_table_size, sizeof(cmph_uint32)); + + + + idx = i = j = 0; + + for(;;) + { + while(keys_vec[j]==i) + { + select_insert_1(&buffer); + idx++; + + if((idx & 0x1f) == 0 ) // (idx & 0x1f) = idx % 32 + sel->bits_vec[(idx >> 5) - 1] = buffer; // (idx >> 5) = idx/32 + j++; + + if(j == sel->n) + goto loop_end; + + //assert(keys_vec[j] < keys_vec[j-1]); + } + + if(i == sel->m) + break; + + while(keys_vec[j] > i) + { + select_insert_0(&buffer); + idx++; + + if((idx & 0x1f) == 0 ) // (idx & 0x1f) = idx % 32 + sel->bits_vec[(idx >> 5) - 1] = buffer; // (idx >> 5) = idx/32 + i++; + }; + + }; + loop_end: + if((idx & 0x1f) != 0 ) // (idx & 0x1f) = idx % 32 + { + buffer >>= 32 - (idx & 0x1f); + sel->bits_vec[ (idx - 1) >> 5 ] = buffer; + }; + + select_generate_sel_table(sel); +}; + +static inline cmph_uint32 _select_query(cmph_uint8 * bits_table, cmph_uint32 * select_table, cmph_uint32 one_idx) +{ + register cmph_uint32 vec_bit_idx ,vec_byte_idx; + register cmph_uint32 part_sum, old_part_sum; + + vec_bit_idx = select_table[one_idx >> NBITS_STEP_SELECT_TABLE]; // one_idx >> NBITS_STEP_SELECT_TABLE = one_idx/STEP_SELECT_TABLE + vec_byte_idx = vec_bit_idx >> 3; // vec_bit_idx / 8 + + one_idx &= MASK_STEP_SELECT_TABLE; // one_idx %= STEP_SELECT_TABLE == one_idx &= MASK_STEP_SELECT_TABLE + one_idx += rank_lookup_table[bits_table[vec_byte_idx] & ((1 << (vec_bit_idx & 0x7)) - 1)]; + part_sum = 0; + + do + { + old_part_sum = part_sum; + part_sum += rank_lookup_table[bits_table[vec_byte_idx]]; + vec_byte_idx++; + + }while (part_sum <= one_idx); + + return select_lookup_table[bits_table[vec_byte_idx - 1]][one_idx - old_part_sum] + ((vec_byte_idx-1) << 3); +} + +cmph_uint32 select_query(select_t * sel, cmph_uint32 one_idx) +{ + return _select_query((cmph_uint8 *)sel->bits_vec, sel->select_table, one_idx); +}; + + +static inline cmph_uint32 _select_next_query(cmph_uint8 * bits_table, cmph_uint32 vec_bit_idx) +{ + register cmph_uint32 vec_byte_idx, one_idx; + register cmph_uint32 part_sum, old_part_sum; + + vec_byte_idx = vec_bit_idx >> 3; + + one_idx = rank_lookup_table[bits_table[vec_byte_idx] & ((1U << (vec_bit_idx & 0x7)) - 1U)] + 1U; + part_sum = 0; + + do + { + old_part_sum = part_sum; + part_sum += rank_lookup_table[bits_table[vec_byte_idx]]; + vec_byte_idx++; + + }while (part_sum <= one_idx); + + return select_lookup_table[bits_table[(vec_byte_idx - 1)]][(one_idx - old_part_sum)] + ((vec_byte_idx - 1) << 3); +} + +cmph_uint32 select_next_query(select_t * sel, cmph_uint32 vec_bit_idx) +{ + return _select_next_query((cmph_uint8 *)sel->bits_vec, vec_bit_idx); +}; + +void select_dump(select_t *sel, char **buf, cmph_uint32 *buflen) +{ + register cmph_uint32 nbits = sel->n + sel->m; + register cmph_uint32 vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32 + register cmph_uint32 sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE) + register cmph_uint32 pos = 0; + + *buflen = 2*(cmph_uint32)sizeof(cmph_uint32) + vec_size + sel_table_size; + + *buf = (char *)calloc(*buflen, sizeof(char)); + + if (!*buf) + { + *buflen = UINT_MAX; + return; + } + + memcpy(*buf, &(sel->n), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + memcpy(*buf + pos, &(sel->m), sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + memcpy(*buf + pos, sel->bits_vec, vec_size); + pos += vec_size; + memcpy(*buf + pos, sel->select_table, sel_table_size); + + DEBUGP("Dumped select structure with size %u bytes\n", *buflen); +} + +void select_load(select_t * sel, const char *buf, cmph_uint32 buflen) +{ + register cmph_uint32 pos = 0; + register cmph_uint32 nbits = 0; + register cmph_uint32 vec_size = 0; + register cmph_uint32 sel_table_size = 0; + + memcpy(&(sel->n), buf, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + memcpy(&(sel->m), buf + pos, sizeof(cmph_uint32)); + pos += (cmph_uint32)sizeof(cmph_uint32); + + nbits = sel->n + sel->m; + vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32 + sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE) + + if(sel->bits_vec) + { + free(sel->bits_vec); + } + sel->bits_vec = (cmph_uint32 *)calloc(vec_size/sizeof(cmph_uint32), sizeof(cmph_uint32)); + + if(sel->select_table) + { + free(sel->select_table); + } + sel->select_table = (cmph_uint32 *)calloc(sel_table_size/sizeof(cmph_uint32), sizeof(cmph_uint32)); + + memcpy(sel->bits_vec, buf + pos, vec_size); + pos += vec_size; + memcpy(sel->select_table, buf + pos, sel_table_size); + + DEBUGP("Loaded select structure with size %u bytes\n", buflen); +} + + +/** \fn void select_pack(select_t *sel, void *sel_packed); + * \brief Support the ability to pack a select structure function into a preallocated contiguous memory space pointed by sel_packed. + * \param sel points to the select structure + * \param sel_packed pointer to the contiguous memory area used to store the select structure. The size of sel_packed must be at least @see select_packed_size + */ +void select_pack(select_t *sel, void *sel_packed) +{ + if (sel && sel_packed) + { + char *buf = NULL; + cmph_uint32 buflen = 0; + select_dump(sel, &buf, &buflen); + memcpy(sel_packed, buf, buflen); + free(buf); + } +} + + +/** \fn cmph_uint32 select_packed_size(select_t *sel); + * \brief Return the amount of space needed to pack a select structure. + * \return the size of the packed select structure or zero for failures + */ +cmph_uint32 select_packed_size(select_t *sel) +{ + register cmph_uint32 nbits = sel->n + sel->m; + register cmph_uint32 vec_size = ((nbits + 31) >> 5) * (cmph_uint32)sizeof(cmph_uint32); // (nbits + 31) >> 5 = (nbits + 31)/32 + register cmph_uint32 sel_table_size = ((sel->n >> NBITS_STEP_SELECT_TABLE) + 1) * (cmph_uint32)sizeof(cmph_uint32); // (sel->n >> NBITS_STEP_SELECT_TABLE) = (sel->n/STEP_SELECT_TABLE) + return 2*(cmph_uint32)sizeof(cmph_uint32) + vec_size + sel_table_size; +} + + + +cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx) +{ + register cmph_uint32 *ptr = (cmph_uint32 *)sel_packed; + register cmph_uint32 n = *ptr++; + register cmph_uint32 m = *ptr++; + register cmph_uint32 nbits = n + m; + register cmph_uint32 vec_size = (nbits + 31) >> 5; // (nbits + 31) >> 5 = (nbits + 31)/32 + register cmph_uint8 * bits_vec = (cmph_uint8 *)ptr; + register cmph_uint32 * select_table = ptr + vec_size; + + return _select_query(bits_vec, select_table, one_idx); +} + + +cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx) +{ + register cmph_uint8 * bits_vec = (cmph_uint8 *)sel_packed; + bits_vec += 8; // skipping n and m + return _select_next_query(bits_vec, vec_bit_idx); +} diff --git a/girepository/cmph/select.h b/girepository/cmph/select.h new file mode 100644 index 0000000..a31eb0f --- /dev/null +++ b/girepository/cmph/select.h @@ -0,0 +1,61 @@ +#ifndef __CMPH_SELECT_H__ +#define __CMPH_SELECT_H__ + +#include "cmph_types.h" + +struct _select_t +{ + cmph_uint32 n,m; + cmph_uint32 * bits_vec; + cmph_uint32 * select_table; +}; + +typedef struct _select_t select_t; + +void select_init(select_t * sel); + +void select_destroy(select_t * sel); + +void select_generate(select_t * sel, cmph_uint32 * keys_vec, cmph_uint32 n, cmph_uint32 m); + +cmph_uint32 select_query(select_t * sel, cmph_uint32 one_idx); + +cmph_uint32 select_next_query(select_t * sel, cmph_uint32 vec_bit_idx); + +cmph_uint32 select_get_space_usage(select_t * sel); + +void select_dump(select_t *sel, char **buf, cmph_uint32 *buflen); + +void select_load(select_t * sel, const char *buf, cmph_uint32 buflen); + + +/** \fn void select_pack(select_t *sel, void *sel_packed); + * \brief Support the ability to pack a select structure into a preallocated contiguous memory space pointed by sel_packed. + * \param sel points to the select structure + * \param sel_packed pointer to the contiguous memory area used to store the select structure. The size of sel_packed must be at least @see select_packed_size + */ +void select_pack(select_t *sel, void *sel_packed); + +/** \fn cmph_uint32 select_packed_size(select_t *sel); + * \brief Return the amount of space needed to pack a select structure. + * \return the size of the packed select structure or zero for failures + */ +cmph_uint32 select_packed_size(select_t *sel); + + +/** \fn cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx); + * \param sel_packed is a pointer to a contiguous memory area + * \param one_idx is the rank for which we want to calculate the inverse function select + * \return an integer that represents the select value of rank idx. + */ +cmph_uint32 select_query_packed(void * sel_packed, cmph_uint32 one_idx); + + +/** \fn cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx); + * \param sel_packed is a pointer to a contiguous memory area + * \param vec_bit_idx is a value prior computed by @see select_query_packed + * \return an integer that represents the next select value greater than @see vec_bit_idx. + */ +cmph_uint32 select_next_query_packed(void * sel_packed, cmph_uint32 vec_bit_idx); + +#endif diff --git a/girepository/cmph/select_lookup_tables.h b/girepository/cmph/select_lookup_tables.h new file mode 100644 index 0000000..efd595e --- /dev/null +++ b/girepository/cmph/select_lookup_tables.h @@ -0,0 +1,170 @@ +#ifndef SELECT_LOOKUP_TABLES +#define SELECT_LOOKUP_TABLES + +#include "cmph_types.h" + +/* +rank_lookup_table[i] simply gives the number of bits set to one in the byte of value i. +For example if i = 01010101 in binary then we have : +rank_lookup_table[i] = 4 +*/ + +static cmph_uint8 rank_lookup_table[256] ={ + 0 , 1 , 1 , 2 , 1 , 2 , 2 , 3 , 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 +, 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 +, 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 +, 1 , 2 , 2 , 3 , 2 , 3 , 3 , 4 , 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 +, 2 , 3 , 3 , 4 , 3 , 4 , 4 , 5 , 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 +, 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 +, 3 , 4 , 4 , 5 , 4 , 5 , 5 , 6 , 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 +, 4 , 5 , 5 , 6 , 5 , 6 , 6 , 7 , 5 , 6 , 6 , 7 , 6 , 7 , 7 , 8 + }; + +/* +select_lookup_table[i][j] simply gives the index of the j'th bit set to one in the byte of value i. +For example if i=01010101 in binary then we have : +select_lookup_table[i][0] = 0, the first bit set to one is at position 0 +select_lookup_table[i][1] = 2, the second bit set to one is at position 2 +select_lookup_table[i][2] = 4, the third bit set to one is at position 4 +select_lookup_table[i][3] = 6, the fourth bit set to one is at position 6 +select_lookup_table[i][4] = 255, there is no more than 4 bits set to one in i, so we return escape value 255. +*/ +static cmph_uint8 select_lookup_table[256][8]={ +{ 255 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 255 , 255 , 255 , 255 , 255 } , +{ 3 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 3 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 255 , 255 , 255 , 255 } , +{ 4 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 255 , 255 , 255 , 255 } , +{ 3 , 4 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 255 , 255 , 255 , 255 } , +{ 2 , 3 , 4 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 255 , 255 , 255 } , +{ 5 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 255 , 255 , 255 , 255 } , +{ 3 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 255 , 255 , 255 , 255 } , +{ 2 , 3 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 255 , 255 , 255 } , +{ 4 , 5 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 255 , 255 , 255 , 255 } , +{ 2 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 255 , 255 , 255 } , +{ 3 , 4 , 5 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 255 , 255 , 255 } , +{ 2 , 3 , 4 , 5 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 5 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 255 , 255 } , +{ 6 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 6 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 6 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 6 , 255 , 255 , 255 , 255 } , +{ 3 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 6 , 255 , 255 , 255 , 255 } , +{ 2 , 3 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 6 , 255 , 255 , 255 } , +{ 4 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 6 , 255 , 255 , 255 , 255 } , +{ 2 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 6 , 255 , 255 , 255 } , +{ 3 , 4 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 6 , 255 , 255 , 255 } , +{ 2 , 3 , 4 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 6 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 6 , 255 , 255 } , +{ 5 , 6 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 6 , 255 , 255 , 255 , 255 } , +{ 2 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 6 , 255 , 255 , 255 } , +{ 3 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 6 , 255 , 255 , 255 } , +{ 2 , 3 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 6 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 6 , 255 , 255 } , +{ 4 , 5 , 6 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 6 , 255 , 255 , 255 } , +{ 2 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 6 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 6 , 255 , 255 } , +{ 3 , 4 , 5 , 6 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 6 , 255 , 255 } , +{ 2 , 3 , 4 , 5 , 6 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 6 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 5 , 6 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 255 } , +{ 7 , 255 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 2 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 7 , 255 , 255 , 255 , 255 } , +{ 3 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 7 , 255 , 255 , 255 , 255 } , +{ 2 , 3 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 7 , 255 , 255 , 255 } , +{ 4 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 7 , 255 , 255 , 255 , 255 } , +{ 2 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 7 , 255 , 255 , 255 } , +{ 3 , 4 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 7 , 255 , 255 , 255 } , +{ 2 , 3 , 4 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 7 , 255 , 255 } , +{ 5 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 7 , 255 , 255 , 255 , 255 } , +{ 2 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 7 , 255 , 255 , 255 } , +{ 3 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 7 , 255 , 255 , 255 } , +{ 2 , 3 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 7 , 255 , 255 } , +{ 4 , 5 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 7 , 255 , 255 , 255 } , +{ 2 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 7 , 255 , 255 } , +{ 3 , 4 , 5 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 7 , 255 , 255 } , +{ 2 , 3 , 4 , 5 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 7 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 5 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 7 , 255 } , +{ 6 , 7 , 255 , 255 , 255 , 255 , 255 , 255 } , { 0 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , +{ 1 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 1 , 6 , 7 , 255 , 255 , 255 , 255 } , +{ 2 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 2 , 6 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 2 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 2 , 6 , 7 , 255 , 255 , 255 } , +{ 3 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 3 , 6 , 7 , 255 , 255 , 255 } , +{ 2 , 3 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 3 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 3 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 3 , 6 , 7 , 255 , 255 } , +{ 4 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 4 , 6 , 7 , 255 , 255 , 255 } , +{ 2 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 4 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 4 , 6 , 7 , 255 , 255 } , +{ 3 , 4 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 4 , 6 , 7 , 255 , 255 } , +{ 2 , 3 , 4 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 4 , 6 , 7 , 255 , 255 } , +{ 1 , 2 , 3 , 4 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 4 , 6 , 7 , 255 } , +{ 5 , 6 , 7 , 255 , 255 , 255 , 255 , 255 } , { 0 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , +{ 1 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 1 , 5 , 6 , 7 , 255 , 255 , 255 } , +{ 2 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 2 , 5 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 2 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 2 , 5 , 6 , 7 , 255 , 255 } , +{ 3 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 3 , 5 , 6 , 7 , 255 , 255 } , +{ 2 , 3 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 3 , 5 , 6 , 7 , 255 , 255 } , +{ 1 , 2 , 3 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 3 , 5 , 6 , 7 , 255 } , +{ 4 , 5 , 6 , 7 , 255 , 255 , 255 , 255 } , { 0 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , +{ 1 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 1 , 4 , 5 , 6 , 7 , 255 , 255 } , +{ 2 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 2 , 4 , 5 , 6 , 7 , 255 , 255 } , +{ 1 , 2 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 2 , 4 , 5 , 6 , 7 , 255 } , +{ 3 , 4 , 5 , 6 , 7 , 255 , 255 , 255 } , { 0 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } , +{ 1 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 1 , 3 , 4 , 5 , 6 , 7 , 255 } , +{ 2 , 3 , 4 , 5 , 6 , 7 , 255 , 255 } , { 0 , 2 , 3 , 4 , 5 , 6 , 7 , 255 } , +{ 1 , 2 , 3 , 4 , 5 , 6 , 7 , 255 } , { 0 , 1 , 2 , 3 , 4 , 5 , 6 , 7 } }; + +#endif diff --git a/girepository/cmph/vqueue.c b/girepository/cmph/vqueue.c new file mode 100644 index 0000000..0619dd7 --- /dev/null +++ b/girepository/cmph/vqueue.c @@ -0,0 +1,51 @@ +#include "vqueue.h" +#include +#include +#include +struct __vqueue_t +{ + cmph_uint32 * values; + cmph_uint32 beg, end, capacity; +}; + +vqueue_t * vqueue_new(cmph_uint32 capacity) +{ + size_t capacity_plus_one = capacity + 1; + vqueue_t *q = (vqueue_t *)malloc(sizeof(vqueue_t)); + assert(q); + q->values = (cmph_uint32 *)calloc(capacity_plus_one, sizeof(cmph_uint32)); + q->beg = q->end = 0; + q->capacity = (cmph_uint32) capacity_plus_one; + return q; +} + +cmph_uint8 vqueue_is_empty(vqueue_t * q) +{ + return (cmph_uint8)(q->beg == q->end); +} + +void vqueue_insert(vqueue_t * q, cmph_uint32 val) +{ + assert((q->end + 1)%q->capacity != q->beg); // Is queue full? + q->end = (q->end + 1)%q->capacity; + q->values[q->end] = val; +} + +cmph_uint32 vqueue_remove(vqueue_t * q) +{ + assert(!vqueue_is_empty(q)); // Is queue empty? + q->beg = (q->beg + 1)%q->capacity; + return q->values[q->beg]; +} + +void vqueue_print(vqueue_t * q) +{ + cmph_uint32 i; + for (i = q->beg; i != q->end; i = (i + 1)%q->capacity) + fprintf(stderr, "%u\n", q->values[(i + 1)%q->capacity]); +} + +void vqueue_destroy(vqueue_t *q) +{ + free(q->values); q->values = NULL; free(q); +} diff --git a/girepository/cmph/vqueue.h b/girepository/cmph/vqueue.h new file mode 100644 index 0000000..86fccab --- /dev/null +++ b/girepository/cmph/vqueue.h @@ -0,0 +1,18 @@ +#ifndef __CMPH_VQUEUE_H__ +#define __CMPH_VQUEUE_H__ + +#include "cmph_types.h" +typedef struct __vqueue_t vqueue_t; + +vqueue_t * vqueue_new(cmph_uint32 capacity); + +cmph_uint8 vqueue_is_empty(vqueue_t * q); + +void vqueue_insert(vqueue_t * q, cmph_uint32 val); + +cmph_uint32 vqueue_remove(vqueue_t * q); + +void vqueue_print(vqueue_t * q); + +void vqueue_destroy(vqueue_t * q); +#endif diff --git a/girepository/cmph/vstack.c b/girepository/cmph/vstack.c new file mode 100644 index 0000000..96f5380 --- /dev/null +++ b/girepository/cmph/vstack.c @@ -0,0 +1,79 @@ +#include "vstack.h" + +#include +#include + +//#define DEBUG +#include "debug.h" + +struct __vstack_t +{ + cmph_uint32 pointer; + cmph_uint32 *values; + cmph_uint32 capacity; +}; + +vstack_t *vstack_new(void) +{ + vstack_t *stack = (vstack_t *)malloc(sizeof(vstack_t)); + assert(stack); + stack->pointer = 0; + stack->values = NULL; + stack->capacity = 0; + return stack; +} + +void vstack_destroy(vstack_t *stack) +{ + assert(stack); + free(stack->values); + free(stack); +} + +void vstack_push(vstack_t *stack, cmph_uint32 val) +{ + assert(stack); + vstack_reserve(stack, stack->pointer + 1); + stack->values[stack->pointer] = val; + ++(stack->pointer); +} +void vstack_pop(vstack_t *stack) +{ + assert(stack); + assert(stack->pointer > 0); + --(stack->pointer); +} + +cmph_uint32 vstack_top(vstack_t *stack) +{ + assert(stack); + assert(stack->pointer > 0); + return stack->values[(stack->pointer - 1)]; +} +int vstack_empty(vstack_t *stack) +{ + assert(stack); + return stack->pointer == 0; +} +cmph_uint32 vstack_size(vstack_t *stack) +{ + return stack->pointer; +} +void vstack_reserve(vstack_t *stack, cmph_uint32 size) +{ + assert(stack); + if (stack->capacity < size) + { + cmph_uint32 new_capacity = stack->capacity + 1; + DEBUGP("Increasing current capacity %u to %u\n", stack->capacity, size); + while (new_capacity < size) + { + new_capacity *= 2; + } + stack->values = (cmph_uint32 *)realloc(stack->values, sizeof(cmph_uint32)*new_capacity); + assert(stack->values); + stack->capacity = new_capacity; + DEBUGP("Increased\n"); + } +} + diff --git a/girepository/cmph/vstack.h b/girepository/cmph/vstack.h new file mode 100644 index 0000000..fecc7d5 --- /dev/null +++ b/girepository/cmph/vstack.h @@ -0,0 +1,18 @@ +#ifndef __CMPH_VSTACK_H__ +#define __CMPH_VSTACK_H__ + +#include "cmph_types.h" +typedef struct __vstack_t vstack_t; + +vstack_t *vstack_new(void); +void vstack_destroy(vstack_t *stack); + +void vstack_push(vstack_t *stack, cmph_uint32 val); +cmph_uint32 vstack_top(vstack_t *stack); +void vstack_pop(vstack_t *stack); +int vstack_empty(vstack_t *stack); +cmph_uint32 vstack_size(vstack_t *stack); + +void vstack_reserve(vstack_t *stack, cmph_uint32 size); + +#endif diff --git a/girepository/cmph/wingetopt.c b/girepository/cmph/wingetopt.c new file mode 100644 index 0000000..c981d0f --- /dev/null +++ b/girepository/cmph/wingetopt.c @@ -0,0 +1,179 @@ +#ifdef WIN32 +/***************************************************************************** + * + * MODULE NAME : GETOPT.C + * + * COPYRIGHTS: + * This module contains code made available by IBM + * Corporation on an AS IS basis. Any one receiving the + * module is considered to be licensed under IBM copyrights + * to use the IBM-provided source code in any way he or she + * deems fit, including copying it, compiling it, modifying + * it, and redistributing it, with or without + * modifications. No license under any IBM patents or + * patent applications is to be implied from this copyright + * license. + * + * A user of the module should understand that IBM cannot + * provide technical support for the module and will not be + * responsible for any consequences of use of the program. + * + * Any notices, including this one, are not to be removed + * from the module without the prior written consent of + * IBM. + * + * AUTHOR: Original author: + * G. R. Blair (BOBBLAIR at AUSVM1) + * Internet: bobblair@bobblair.austin.ibm.com + * + * Extensively revised by: + * John Q. Walker II, Ph.D. (JOHHQ at RALVM6) + * Internet: johnq@ralvm6.vnet.ibm.com + * + *****************************************************************************/ + +/****************************************************************************** + * getopt() + * + * The getopt() function is a command line parser. It returns the next + * option character in argv that matches an option character in opstring. + * + * The argv argument points to an array of argc+1 elements containing argc + * pointers to character strings followed by a null pointer. + * + * The opstring argument points to a string of option characters; if an + * option character is followed by a colon, the option is expected to have + * an argument that may or may not be separated from it by white space. + * The external variable optarg is set to point to the start of the option + * argument on return from getopt(). + * + * The getopt() function places in optind the argv index of the next argument + * to be processed. The system initializes the external variable optind to + * 1 before the first call to getopt(). + * + * When all options have been processed (that is, up to the first nonoption + * argument), getopt() returns EOF. The special option "--" may be used to + * delimit the end of the options; EOF will be returned, and "--" will be + * skipped. + * + * The getopt() function returns a question mark (?) when it encounters an + * option character not included in opstring. This error message can be + * disabled by setting opterr to zero. Otherwise, it returns the option + * character that was detected. + * + * If the special option "--" is detected, or all options have been + * processed, EOF is returned. + * + * Options are marked by either a minus sign (-) or a slash (/). + * + * No errors are defined. + *****************************************************************************/ + +#include /* for EOF */ +#include /* for strchr() */ + +/* static (global) variables that are specified as exported by getopt() */ +extern char *optarg; /* pointer to the start of the option argument */ +extern int optind; /* number of the next argv[] to be evaluated */ +extern int opterr; /* non-zero if a question mark should be returned + when a non-valid option character is detected */ + +/* handle possible future character set concerns by putting this in a macro */ +#define _next_char(string) (char)(*(string+1)) + +int getopt(int argc, char *argv[], char *opstring) +{ + static char *pIndexPosition = NULL; /* place inside current argv string */ + char *pArgString = NULL; /* where to start from next */ + char *pOptString; /* the string in our program */ + + + if (pIndexPosition != NULL) { + /* we last left off inside an argv string */ + if (*(++pIndexPosition)) { + /* there is more to come in the most recent argv */ + pArgString = pIndexPosition; + } + } + + if (pArgString == NULL) { + /* we didn't leave off in the middle of an argv string */ + if (optind >= argc) { + /* more command-line arguments than the argument count */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* used up all command-line arguments */ + } + + /*--------------------------------------------------------------------- + * If the next argv[] is not an option, there can be no more options. + *-------------------------------------------------------------------*/ + pArgString = argv[optind++]; /* set this to the next argument ptr */ + + if (('/' != *pArgString) && /* doesn't start with a slash or a dash? */ + ('-' != *pArgString)) { + --optind; /* point to current arg once we're done */ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* used up all the command-line flags */ + } + + /* check for special end-of-flags markers */ + if ((strcmp(pArgString, "-") == 0) || + (strcmp(pArgString, "--") == 0)) { + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return EOF; /* encountered the special flag */ + } + + pArgString++; /* look past the / or - */ + } + + if (':' == *pArgString) { /* is it a colon? */ + /*--------------------------------------------------------------------- + * Rare case: if opterr is non-zero, return a question mark; + * otherwise, just return the colon we're on. + *-------------------------------------------------------------------*/ + return (opterr ? (int)'?' : (int)':'); + } + else if ((pOptString = strchr(opstring, *pArgString)) == 0) { + /*--------------------------------------------------------------------- + * The letter on the command-line wasn't any good. + *-------------------------------------------------------------------*/ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = NULL; /* not in the middle of anything */ + return (opterr ? (int)'?' : (int)*pArgString); + } + else { + /*--------------------------------------------------------------------- + * The letter on the command-line matches one we expect to see + *-------------------------------------------------------------------*/ + if (':' == _next_char(pOptString)) { /* is the next letter a colon? */ + /* It is a colon. Look for an argument string. */ + if ('\0' != _next_char(pArgString)) { /* argument in this argv? */ + optarg = &pArgString[1]; /* Yes, it is */ + } + else { + /*------------------------------------------------------------- + * The argument string must be in the next argv. + * But, what if there is none (bad input from the user)? + * In that case, return the letter, and optarg as NULL. + *-----------------------------------------------------------*/ + if (optind < argc) + optarg = argv[optind++]; + else { + optarg = NULL; + return (opterr ? (int)'?' : (int)*pArgString); + } + } + pIndexPosition = NULL; /* not in the middle of anything */ + } + else { + /* it's not a colon, so just return the letter */ + optarg = NULL; /* no argument follows the option */ + pIndexPosition = pArgString; /* point to the letter we're on */ + } + return (int)*pArgString; /* return the letter that matched */ + } +} + +#endif //WIN32 diff --git a/girepository/cmph/wingetopt.h b/girepository/cmph/wingetopt.h new file mode 100644 index 0000000..9596853 --- /dev/null +++ b/girepository/cmph/wingetopt.h @@ -0,0 +1,25 @@ +#ifdef __cplusplus +extern "C" { +#endif + +#ifndef WIN32 + #include +#else + #ifndef _GETOPT_ + #define _GETOPT_ + + #include /* for EOF */ + #include /* for strchr() */ + + char *optarg = NULL; /* pointer to the start of the option argument */ + int optind = 1; /* number of the next argv[] to be evaluated */ + int opterr = 1; /* non-zero if a question mark should be returned */ + + int getopt(int argc, char *argv[], char *opstring); + #endif //_GETOPT_ +#endif //WIN32 + +#ifdef __cplusplus +} +#endif + diff --git a/girepository/gdump.c b/girepository/gdump.c new file mode 100644 index 0000000..78f4c3c --- /dev/null +++ b/girepository/gdump.c @@ -0,0 +1,748 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Dump introspection data + * + * Copyright (C) 2008 Colin Walters + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +/* This file is both compiled into libgirepository.so, and installed + * on the filesystem. But for the dumper, we want to avoid linking + * to libgirepository; see + * https://bugzilla.gnome.org/show_bug.cgi?id=630342 + */ +#ifdef GI_COMPILATION +#include "config.h" +#include "girepository.h" +#endif + +#include +#include +#include + +#include +#include +#include + +/* Analogue of g_output_stream_write_all(). */ +static gboolean +write_all (FILE *out, + const void *buffer, + gsize count, + gsize *bytes_written, + GError **error) +{ + size_t ret; + + ret = fwrite (buffer, 1, count, out); + + if (bytes_written != NULL) + *bytes_written = ret; + + if (ret < count) + { + g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_FAILED, + "Failed to write to file"); + return FALSE; + } + + return TRUE; +} + +/* Analogue of g_data_input_stream_read_line(). */ +static char * +read_line (FILE *input, + size_t *len_out) +{ + GByteArray *buffer = g_byte_array_new (); + const guint8 nul = '\0'; + + while (TRUE) + { + size_t ret; + guint8 byte; + + ret = fread (&byte, 1, 1, input); + if (ret == 0) + break; + + if (byte == '\n') + break; + + g_byte_array_append (buffer, &byte, 1); + } + + g_byte_array_append (buffer, &nul, 1); + + if (len_out != NULL) + *len_out = buffer->len - 1; /* don’t include terminating nul */ + + return (char *) g_byte_array_free (buffer, FALSE); +} + +static void +escaped_printf (FILE *out, const char *fmt, ...) G_GNUC_PRINTF (2, 3); + +static void +escaped_printf (FILE *out, const char *fmt, ...) +{ + char *str; + va_list args; + gsize written; + GError *error = NULL; + + va_start (args, fmt); + + str = g_markup_vprintf_escaped (fmt, args); + if (!write_all (out, str, strlen (str), &written, &error)) + { + g_critical ("failed to write to iochannel: %s", error->message); + g_clear_error (&error); + } + g_free (str); + + va_end (args); +} + +static void +goutput_write (FILE *out, const char *str) +{ + gsize written; + GError *error = NULL; + if (!write_all (out, str, strlen (str), &written, &error)) + { + g_critical ("failed to write to iochannel: %s", error->message); + g_clear_error (&error); + } +} + +typedef GType (*GetTypeFunc)(void); +typedef GQuark (*ErrorQuarkFunc)(void); + +static GType +invoke_get_type (GModule *self, const char *symbol, GError **error) +{ + GetTypeFunc sym; + GType ret; + + if (!g_module_symbol (self, symbol, (void**)&sym)) + { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "Failed to find symbol '%s'", symbol); + return G_TYPE_INVALID; + } + + ret = sym (); + if (ret == G_TYPE_INVALID) + { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "Function '%s' returned G_TYPE_INVALID", symbol); + } + return ret; +} + +static GQuark +invoke_error_quark (GModule *self, const char *symbol, GError **error) +{ + ErrorQuarkFunc sym; + + if (!g_module_symbol (self, symbol, (void**)&sym)) + { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "Failed to find symbol '%s'", symbol); + return G_TYPE_INVALID; + } + + return sym (); +} + +static char * +value_transform_to_string (const GValue *value) +{ + GValue tmp = G_VALUE_INIT; + char *s = NULL; + + g_value_init (&tmp, G_TYPE_STRING); + + if (g_value_transform (value, &tmp)) + { + const char *str = g_value_get_string (&tmp); + + if (str != NULL) + s = g_strescape (str, NULL); + } + + g_value_unset (&tmp); + + return s; +} + +/* A simpler version of g_strdup_value_contents(), but with stable + * output and less complex semantics + */ +static char * +value_to_string (const GValue *value) +{ + if (value == NULL) + return NULL; + + if (G_VALUE_HOLDS_STRING (value)) + { + const char *s = g_value_get_string (value); + + if (s == NULL) + return g_strdup ("NULL"); + + return g_strescape (s, NULL); + } + else + { + GType value_type = G_VALUE_TYPE (value); + + switch (G_TYPE_FUNDAMENTAL (value_type)) + { + case G_TYPE_BOXED: + if (g_value_get_boxed (value) == NULL) + return NULL; + else + return value_transform_to_string (value); + break; + + case G_TYPE_OBJECT: + if (g_value_get_object (value) == NULL) + return NULL; + else + return value_transform_to_string (value); + break; + + case G_TYPE_POINTER: + return NULL; + + default: + return value_transform_to_string (value); + } + } + + return NULL; +} + +static void +dump_properties (GType type, FILE *out) +{ + guint i; + guint n_properties = 0; + GParamSpec **props; + + if (G_TYPE_FUNDAMENTAL (type) == G_TYPE_OBJECT) + { + GObjectClass *klass; + klass = g_type_class_ref (type); + props = g_object_class_list_properties (klass, &n_properties); + } + else + { + void *klass; + klass = g_type_default_interface_ref (type); + props = g_object_interface_list_properties (klass, &n_properties); + } + + for (i = 0; i < n_properties; i++) + { + GParamSpec *prop; + + prop = props[i]; + if (prop->owner_type != type) + continue; + + const GValue *v = g_param_spec_get_default_value (prop); + char *default_value = value_to_string (v); + + if (v != NULL && default_value != NULL) + { + escaped_printf (out, " \n", + prop->name, + g_type_name (prop->value_type), + prop->flags, + default_value); + } + else + { + escaped_printf (out, " \n", + prop->name, + g_type_name (prop->value_type), + prop->flags); + } + + g_free (default_value); + } + + g_free (props); +} + +static void +dump_signals (GType type, FILE *out) +{ + guint i; + guint n_sigs; + guint *sig_ids; + + sig_ids = g_signal_list_ids (type, &n_sigs); + for (i = 0; i < n_sigs; i++) + { + guint sigid; + GSignalQuery query; + guint j; + + sigid = sig_ids[i]; + g_signal_query (sigid, &query); + + escaped_printf (out, " \n"); + + for (j = 0; j < query.n_params; j++) + { + escaped_printf (out, " \n", + g_type_name (query.param_types[j])); + } + goutput_write (out, " \n"); + } + g_free (sig_ids); +} + +static void +dump_object_type (GType type, const char *symbol, FILE *out) +{ + guint n_interfaces; + guint i; + GType *interfaces; + + escaped_printf (out, " str); + + g_string_free (parent_str, TRUE); + } + + if (G_TYPE_IS_ABSTRACT (type)) + escaped_printf (out, " abstract=\"1\""); + + if (G_TYPE_IS_FINAL (type)) + escaped_printf (out, " final=\"1\""); + + goutput_write (out, ">\n"); + + interfaces = g_type_interfaces (type, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GType itype = interfaces[i]; + escaped_printf (out, " \n", + g_type_name (itype)); + } + g_free (interfaces); + + dump_properties (type, out); + dump_signals (type, out); + goutput_write (out, " \n"); +} + +static void +dump_interface_type (GType type, const char *symbol, FILE *out) +{ + guint n_interfaces; + guint i; + GType *interfaces; + + escaped_printf (out, " \n", + g_type_name (type), symbol); + + interfaces = g_type_interface_prerequisites (type, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GType itype = interfaces[i]; + if (itype == G_TYPE_OBJECT) + { + /* Treat this as implicit for now; in theory GInterfaces are + * supported on things like GstMiniObject, but right now + * the introspection system only supports GObject. + * http://bugzilla.gnome.org/show_bug.cgi?id=559706 + */ + continue; + } + escaped_printf (out, " \n", + g_type_name (itype)); + } + g_free (interfaces); + + dump_properties (type, out); + dump_signals (type, out); + goutput_write (out, " \n"); +} + +static void +dump_boxed_type (GType type, const char *symbol, FILE *out) +{ + escaped_printf (out, " \n", + g_type_name (type), symbol); +} + +static void +dump_flags_type (GType type, const char *symbol, FILE *out) +{ + guint i; + GFlagsClass *klass; + + klass = g_type_class_ref (type); + escaped_printf (out, " \n", + g_type_name (type), symbol); + + for (i = 0; i < klass->n_values; i++) + { + GFlagsValue *value = &(klass->values[i]); + + escaped_printf (out, " \n", + value->value_name, value->value_nick, value->value); + } + goutput_write (out, " \n"); +} + +static void +dump_enum_type (GType type, const char *symbol, FILE *out) +{ + guint i; + GEnumClass *klass; + + klass = g_type_class_ref (type); + escaped_printf (out, " \n", + g_type_name (type), symbol); + + for (i = 0; i < klass->n_values; i++) + { + GEnumValue *value = &(klass->values[i]); + + escaped_printf (out, " \n", + value->value_name, value->value_nick, value->value); + } + goutput_write (out, " "); +} + +static void +dump_fundamental_type (GType type, const char *symbol, FILE *out) +{ + guint n_interfaces; + guint i; + GType *interfaces; + GString *parent_str; + GType parent; + gboolean first = TRUE; + + + escaped_printf (out, " len > 0) + escaped_printf (out, " parents=\"%s\"", parent_str->str); + g_string_free (parent_str, TRUE); + + goutput_write (out, ">\n"); + + interfaces = g_type_interfaces (type, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GType itype = interfaces[i]; + escaped_printf (out, " \n", + g_type_name (itype)); + } + g_free (interfaces); + goutput_write (out, " \n"); +} + +static void +dump_type (GType type, const char *symbol, FILE *out) +{ + switch (g_type_fundamental (type)) + { + case G_TYPE_OBJECT: + dump_object_type (type, symbol, out); + break; + case G_TYPE_INTERFACE: + dump_interface_type (type, symbol, out); + break; + case G_TYPE_BOXED: + dump_boxed_type (type, symbol, out); + break; + case G_TYPE_FLAGS: + dump_flags_type (type, symbol, out); + break; + case G_TYPE_ENUM: + dump_enum_type (type, symbol, out); + break; + case G_TYPE_POINTER: + /* GValue, etc. Just skip them. */ + break; + default: + dump_fundamental_type (type, symbol, out); + break; + } +} + +static void +dump_error_quark (GQuark quark, const char *symbol, FILE *out) +{ + escaped_printf (out, " \n", + symbol, g_quark_to_string (quark)); +} + +/** + * gi_repository_dump: + * @input_filename: (type filename): Input filename (for example `input.txt`) + * @output_filename: (type filename): Output filename (for example `output.xml`) + * @error: a %GError + * + * Dump the introspection data from the types specified in @input_filename to + * @output_filename. + * + * The input file should be a + * UTF-8 Unix-line-ending text file, with each line containing either + * `get-type:` followed by the name of a [type@GObject.Type] `_get_type` + * function, or `error-quark:` followed by the name of an error quark function. + * No extra whitespace is allowed. + * + * This function will overwrite the contents of the output file. + * + * Returns: true on success, false on error + * Since: 2.80 + */ +#ifndef GI_COMPILATION +static gboolean +dump_irepository (const char *input_filename, + const char *output_filename, + GError **error) G_GNUC_UNUSED; +static gboolean +dump_irepository (const char *input_filename, + const char *output_filename, + GError **error) +#else +gboolean +gi_repository_dump (const char *input_filename, + const char *output_filename, + GError **error) +#endif +{ + GHashTable *output_types; + FILE *input; + FILE *output; + GModule *self; + gboolean caught_error = FALSE; + + self = g_module_open (NULL, 0); + if (!self) + { + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + "failed to open self: %s", + g_module_error ()); + return FALSE; + } + + input = fopen (input_filename, "rb"); + if (input == NULL) + { + int saved_errno = errno; + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + "Failed to open ‘%s’: %s", input_filename, g_strerror (saved_errno)); + + g_module_close (self); + + return FALSE; + } + + output = fopen (output_filename, "wb"); + if (output == NULL) + { + int saved_errno = errno; + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + "Failed to open ‘%s’: %s", output_filename, g_strerror (saved_errno)); + + fclose (input); + g_module_close (self); + + return FALSE; + } + + goutput_write (output, "\n"); + goutput_write (output, "\n"); + + output_types = g_hash_table_new (NULL, NULL); + + while (TRUE) + { + gsize len; + char *line = read_line (input, &len); + const char *function; + + if (line == NULL || *line == '\0') + { + g_free (line); + break; + } + + g_strchomp (line); + + if (strncmp (line, "get-type:", strlen ("get-type:")) == 0) + { + GType type; + + function = line + strlen ("get-type:"); + + type = invoke_get_type (self, function, error); + + if (type == G_TYPE_INVALID) + { + g_printerr ("Invalid GType function: '%s'\n", function); + caught_error = TRUE; + g_free (line); + break; + } + + if (g_hash_table_lookup (output_types, (gpointer) type)) + goto next; + g_hash_table_insert (output_types, (gpointer) type, (gpointer) type); + + dump_type (type, function, output); + } + else if (strncmp (line, "error-quark:", strlen ("error-quark:")) == 0) + { + GQuark quark; + function = line + strlen ("error-quark:"); + quark = invoke_error_quark (self, function, error); + + if (quark == 0) + { + g_printerr ("Invalid error quark function: '%s'\n", function); + caught_error = TRUE; + g_free (line); + break; + } + + dump_error_quark (quark, function, output); + } + + + next: + g_free (line); + } + + g_hash_table_destroy (output_types); + + goutput_write (output, "\n"); + + { + /* Avoid overwriting an earlier set error */ + if (fclose (input) != 0 && !caught_error) + { + int saved_errno = errno; + + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + "Error closing input file ‘%s’: %s", input_filename, + g_strerror (saved_errno)); + caught_error = TRUE; + } + + if (fclose (output) != 0 && !caught_error) + { + int saved_errno = errno; + + g_set_error (error, G_FILE_ERROR, g_file_error_from_errno (saved_errno), + "Error closing output file ‘%s’: %s", output_filename, + g_strerror (saved_errno)); + caught_error = TRUE; + } + } + + return !caught_error; +} diff --git a/girepository/gi-dump-types.c b/girepository/gi-dump-types.c new file mode 100644 index 0000000..7e8f95e --- /dev/null +++ b/girepository/gi-dump-types.c @@ -0,0 +1,53 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: typelib validation, auxiliary functions + * related to the binary typelib format + * + * Copyright (C) 2011 Colin Walters + * Copyright (C) 2020 Gisle Vanem + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "gdump.c" + +int +main (int argc, + char **argv) +{ + int i; + GModule *self; + + self = g_module_open (NULL, 0); + + for (i = 1; i < argc; i++) + { + GError *error = NULL; + GType type; + + type = invoke_get_type (self, argv[i], &error); + if (!type) + { + g_printerr ("%s\n", error->message); + g_clear_error (&error); + } + else + dump_type (type, argv[i], stdout); + } + + return 0; +} diff --git a/girepository/giarginfo.c b/girepository/giarginfo.c new file mode 100644 index 0000000..59894c9 --- /dev/null +++ b/girepository/giarginfo.c @@ -0,0 +1,365 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Argument implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include "gibaseinfo-private.h" +#include "gitypelib-internal.h" +#include "girepository-private.h" +#include "giarginfo.h" + + +/* GIArgInfo functions */ + +/** + * GIArgInfo: + * + * `GIArgInfo` represents an argument of a callable. + * + * An argument is always part of a [class@GIRepository.CallableInfo]. + * + * Since: 2.80 + */ + +/** + * gi_arg_info_get_direction: + * @info: a #GIArgInfo + * + * Obtain the direction of the argument. Check [type@GIRepository.Direction] + * for possible direction values. + * + * Returns: The direction + * Since: 2.80 + */ +GIDirection +gi_arg_info_get_direction (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_ARG_INFO (info), -1); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->in && blob->out) + return GI_DIRECTION_INOUT; + else if (blob->out) + return GI_DIRECTION_OUT; + else + return GI_DIRECTION_IN; +} + +/** + * gi_arg_info_is_return_value: + * @info: a #GIArgInfo + * + * Obtain if the argument is a return value. It can either be a + * parameter or a return value. + * + * Returns: `TRUE` if it is a return value + * Since: 2.80 + */ +gboolean +gi_arg_info_is_return_value (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_ARG_INFO (info), FALSE); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->return_value; +} + +/** + * gi_arg_info_is_caller_allocates: + * @info: a #GIArgInfo + * + * Obtain if the argument is a pointer to a struct or object that will + * receive an output of a function. + * + * The default assumption for `GI_DIRECTION_OUT` arguments which have allocation + * is that the callee allocates; if this is `TRUE`, then the caller must + * allocate. + * + * Returns: `TRUE` if caller is required to have allocated the argument + * Since: 2.80 + */ +gboolean +gi_arg_info_is_caller_allocates (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_ARG_INFO (info), FALSE); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->caller_allocates; +} + +/** + * gi_arg_info_is_optional: + * @info: a #GIArgInfo + * + * Obtain if the argument is optional. + * + * For ‘out’ arguments this means that you can pass `NULL` in order to ignore + * the result. + * + * Returns: `TRUE` if it is an optional argument + * Since: 2.80 + */ +gboolean +gi_arg_info_is_optional (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_ARG_INFO (info), FALSE); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->optional; +} + +/** + * gi_arg_info_may_be_null: + * @info: a #GIArgInfo + * + * Obtain if the type of the argument includes the possibility of `NULL`. + * + * For ‘in’ values this means that `NULL` is a valid value. For ‘out’ + * values, this means that `NULL` may be returned. + * + * See also [method@GIRepository.ArgInfo.is_optional]. + * + * Returns: `TRUE` if the value may be `NULL` + * Since: 2.80 + */ +gboolean +gi_arg_info_may_be_null (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_ARG_INFO (info), FALSE); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->nullable; +} + +/** + * gi_arg_info_is_skip: + * @info: a #GIArgInfo + * + * Obtain if an argument is only useful in C. + * + * Returns: `TRUE` if argument is only useful in C. + * Since: 2.80 + */ +gboolean +gi_arg_info_is_skip (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_ARG_INFO (info), FALSE); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->skip; +} + +/** + * gi_arg_info_get_ownership_transfer: + * @info: a #GIArgInfo + * + * Obtain the ownership transfer for this argument. + * [type@GIRepository.Transfer] contains a list of possible values. + * + * Returns: The transfer + * Since: 2.80 + */ +GITransfer +gi_arg_info_get_ownership_transfer (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_ARG_INFO (info), -1); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->transfer_ownership) + return GI_TRANSFER_EVERYTHING; + else if (blob->transfer_container_ownership) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} + +/** + * gi_arg_info_get_scope: + * @info: a #GIArgInfo + * + * Obtain the scope type for this argument. + * + * The scope type explains how a callback is going to be invoked, most + * importantly when the resources required to invoke it can be freed. + * + * [type@GIRepository.ScopeType] contains a list of possible values. + * + * Returns: The scope type + * Since: 2.80 + */ +GIScopeType +gi_arg_info_get_scope (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_ARG_INFO (info), -1); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->scope; +} + +/** + * gi_arg_info_get_closure_index: + * @info: a #GIArgInfo + * + * Obtain the index of the user data argument. This is only valid + * for arguments which are callbacks. + * + * Returns: Index of the user data argument or `-1` if there is none + * Since: 2.80 + */ +gint +gi_arg_info_get_closure_index (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_ARG_INFO (info), -1); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->closure; +} + +/** + * gi_arg_info_get_destroy_index: + * @info: a #GIArgInfo + * + * Obtains the index of the [type@GLib.DestroyNotify] argument. This is only + * valid for arguments which are callbacks. + * + * Returns: Index of the [type@GLib.DestroyNotify] argument or `-1` if there is + * none + * Since: 2.80 + */ +gint +gi_arg_info_get_destroy_index (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ArgBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_ARG_INFO (info), -1); + + blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->destroy; +} + +/** + * gi_arg_info_get_type_info: + * @info: a #GIArgInfo + * + * Obtain the type information for @info. + * + * Returns: (transfer full): The [class@GIRepository.TypeInfo] holding the type + * information for @info, free it with [method@GIRepository.BaseInfo.unref] + * when done + * Since: 2.80 + */ +GITypeInfo * +gi_arg_info_get_type_info (GIArgInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_ARG_INFO (info), NULL); + + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + G_STRUCT_OFFSET (ArgBlob, arg_type)); +} + +/** + * gi_arg_info_load_type: + * @info: a #GIArgInfo + * @type: (out caller-allocates): Initialized with information about type of @info + * + * Obtain information about a the type of given argument @info; this + * function is a variant of [method@GIRepository.ArgInfo.get_type_info] designed + * for stack allocation. + * + * The initialized @type must not be referenced after @info is deallocated. + * + * Since: 2.80 + */ +void +gi_arg_info_load_type (GIArgInfo *info, + GITypeInfo *type) +{ + GIRealInfo *rinfo = (GIRealInfo*) info; + + g_return_if_fail (info != NULL); + g_return_if_fail (GI_IS_ARG_INFO (info)); + + gi_type_info_init ((GIBaseInfo *) type, (GIBaseInfo*)info, rinfo->typelib, rinfo->offset + G_STRUCT_OFFSET (ArgBlob, arg_type)); +} + +void +gi_arg_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_ARG; +} diff --git a/girepository/giarginfo.h b/girepository/giarginfo.h new file mode 100644 index 0000000..2564de8 --- /dev/null +++ b/girepository/giarginfo.h @@ -0,0 +1,83 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Argument + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_ARG_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.ArgInfo]. + * + * Since: 2.80 + */ +#define GI_IS_ARG_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_ARG) + + +GI_AVAILABLE_IN_ALL +GIDirection gi_arg_info_get_direction (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_arg_info_is_return_value (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_arg_info_is_optional (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_arg_info_is_caller_allocates (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_arg_info_may_be_null (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_arg_info_is_skip (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +GITransfer gi_arg_info_get_ownership_transfer (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +GIScopeType gi_arg_info_get_scope (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gint gi_arg_info_get_closure_index (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +gint gi_arg_info_get_destroy_index (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_arg_info_get_type_info (GIArgInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_arg_info_load_type (GIArgInfo *info, + GITypeInfo *type); +G_END_DECLS diff --git a/girepository/gibaseinfo-private.h b/girepository/gibaseinfo-private.h new file mode 100644 index 0000000..4d58353 --- /dev/null +++ b/girepository/gibaseinfo-private.h @@ -0,0 +1,51 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Parsed GIR + * + * Copyright 2023 GNOME Foundation Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +#include "gitypes.h" + +G_BEGIN_DECLS + +#define GI_IS_BASE_INFO_TYPE(info,type) \ + (G_TYPE_INSTANCE_GET_CLASS ((info), GI_TYPE_BASE_INFO, GIBaseInfoClass)->info_type == (type)) + +struct _GIBaseInfoClass +{ + GTypeClass parent_class; + + GIInfoType info_type; + + void (* finalize) (GIBaseInfo *info); +}; + +void gi_base_info_init_types (void); + +GType gi_base_info_type_register_static (const char *type_name, + gsize instance_size, + GClassInitFunc class_init); + +G_END_DECLS diff --git a/girepository/gibaseinfo.c b/girepository/gibaseinfo.c new file mode 100644 index 0000000..ae79bc0 --- /dev/null +++ b/girepository/gibaseinfo.c @@ -0,0 +1,950 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Base struct implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include +#include +#include + +#include "gitypelib-internal.h" +#include "girepository-private.h" +#include "gibaseinfo.h" +#include "gibaseinfo-private.h" + +#define INVALID_REFCOUNT 0x7FFFFFFF + +/* Type registration of BaseInfo. */ +#define GI_BASE_INFO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_TYPE_BASE_INFO, GIBaseInfoClass)) + +static void +value_base_info_init (GValue *value) +{ + value->data[0].v_pointer = NULL; +} + +static void +value_base_info_free_value (GValue *value) +{ + if (value->data[0].v_pointer != NULL) + gi_base_info_unref (value->data[0].v_pointer); +} + +static void +value_base_info_copy_value (const GValue *src, + GValue *dst) +{ + if (src->data[0].v_pointer != NULL) + dst->data[0].v_pointer = gi_base_info_ref (src->data[0].v_pointer); + else + dst->data[0].v_pointer = NULL; +} + +static gpointer +value_base_info_peek_pointer (const GValue *value) +{ + return value->data[0].v_pointer; +} + +static char * +value_base_info_collect_value (GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + GIBaseInfo *info = collect_values[0].v_pointer; + + if (info == NULL) + { + value->data[0].v_pointer = NULL; + return NULL; + } + + if (info->parent_instance.g_class == NULL) + return g_strconcat ("invalid unclassed GIBaseInfo pointer for " + "value type '", + G_VALUE_TYPE_NAME (value), + "'", + NULL); + + value->data[0].v_pointer = gi_base_info_ref (info); + + return NULL; +} + +static gchar * +value_base_info_lcopy_value (const GValue *value, + guint n_collect_values, + GTypeCValue *collect_values, + guint collect_flags) +{ + GIBaseInfo **node_p = collect_values[0].v_pointer; + + if (node_p == NULL) + return g_strconcat ("value location for '", + G_VALUE_TYPE_NAME (value), + "' passed as NULL", + NULL); + + if (value->data[0].v_pointer == NULL) + *node_p = NULL; + else if (collect_flags & G_VALUE_NOCOPY_CONTENTS) + *node_p = value->data[0].v_pointer; + else + *node_p = gi_base_info_ref (value->data[0].v_pointer); + + return NULL; +} + +static void +gi_base_info_finalize (GIBaseInfo *self) +{ + if (self->container && self->container->ref_count != INVALID_REFCOUNT) + gi_base_info_unref (self->container); + + g_clear_object (&self->repository); + + g_type_free_instance ((GTypeInstance *) self); +} + +static void +gi_base_info_class_init (GIBaseInfoClass *klass) +{ + klass->info_type = GI_INFO_TYPE_INVALID; + klass->finalize = gi_base_info_finalize; +} + +static void +gi_base_info_init (GIBaseInfo *self) +{ + g_atomic_ref_count_init (&self->ref_count); +} + +GType +gi_base_info_get_type (void) +{ + static GType base_info_type = 0; + + if (g_once_init_enter_pointer (&base_info_type)) + { + static const GTypeFundamentalInfo finfo = { + (G_TYPE_FLAG_CLASSED | + G_TYPE_FLAG_INSTANTIATABLE | + G_TYPE_FLAG_DERIVABLE | + G_TYPE_FLAG_DEEP_DERIVABLE), + }; + + static const GTypeValueTable value_table = { + value_base_info_init, + value_base_info_free_value, + value_base_info_copy_value, + value_base_info_peek_pointer, + "p", + value_base_info_collect_value, + "p", + value_base_info_lcopy_value, + }; + + const GTypeInfo type_info = { + /* Class */ + sizeof (GIBaseInfoClass), + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + (GClassInitFunc) gi_base_info_class_init, + (GClassFinalizeFunc) NULL, + NULL, + + /* Instance */ + sizeof (GIBaseInfo), + 0, + (GInstanceInitFunc) gi_base_info_init, + + /* GValue */ + &value_table, + }; + + GType _base_info_type = + g_type_register_fundamental (g_type_fundamental_next (), + g_intern_static_string ("GIBaseInfo"), + &type_info, &finfo, + G_TYPE_FLAG_ABSTRACT); + + g_once_init_leave_pointer (&base_info_type, _base_info_type); + } + + return base_info_type; +} + +/*< private > + * gi_base_info_type_register_static: + * @type_name: the name of the type + * @instance_size: size (in bytes) of the type’s instance struct + * @class_init: class init function for the type + * + * Registers a new [type@GIRepository.BaseInfo] type for the given @type_name + * using the type information provided. + * + * Returns: the newly registered [type@GObject.Type] + * Since: 2.80 + */ +GType +gi_base_info_type_register_static (const char *type_name, + gsize instance_size, + GClassInitFunc class_init) +{ + GTypeInfo info; + + info.class_size = sizeof (GIBaseInfoClass); + info.base_init = NULL; + info.base_finalize = NULL; + info.class_init = class_init; + info.class_finalize = NULL; + info.instance_size = instance_size; + info.n_preallocs = 0; + info.instance_init = NULL; + info.value_table = NULL; + + return g_type_register_static (GI_TYPE_BASE_INFO, type_name, &info, 0); +} + +static GType gi_base_info_types[GI_INFO_TYPE_N_TYPES]; + +#define GI_DEFINE_BASE_INFO_TYPE(type_name, TYPE_ENUM_VALUE) \ +GType \ +type_name ## _get_type (void) \ +{ \ + gi_base_info_init_types (); \ + g_assert (gi_base_info_types[TYPE_ENUM_VALUE] != G_TYPE_INVALID); \ + return gi_base_info_types[TYPE_ENUM_VALUE]; \ +} + +GI_DEFINE_BASE_INFO_TYPE (gi_callable_info, GI_INFO_TYPE_CALLABLE) +GI_DEFINE_BASE_INFO_TYPE (gi_function_info, GI_INFO_TYPE_FUNCTION) +GI_DEFINE_BASE_INFO_TYPE (gi_callback_info, GI_INFO_TYPE_CALLBACK) +GI_DEFINE_BASE_INFO_TYPE (gi_registered_type_info, GI_INFO_TYPE_REGISTERED_TYPE) +GI_DEFINE_BASE_INFO_TYPE (gi_struct_info, GI_INFO_TYPE_STRUCT) +GI_DEFINE_BASE_INFO_TYPE (gi_union_info, GI_INFO_TYPE_UNION) +GI_DEFINE_BASE_INFO_TYPE (gi_enum_info, GI_INFO_TYPE_ENUM) +GI_DEFINE_BASE_INFO_TYPE (gi_object_info, GI_INFO_TYPE_OBJECT) +GI_DEFINE_BASE_INFO_TYPE (gi_interface_info, GI_INFO_TYPE_INTERFACE) +GI_DEFINE_BASE_INFO_TYPE (gi_constant_info, GI_INFO_TYPE_CONSTANT) +GI_DEFINE_BASE_INFO_TYPE (gi_value_info, GI_INFO_TYPE_VALUE) +GI_DEFINE_BASE_INFO_TYPE (gi_signal_info, GI_INFO_TYPE_SIGNAL) +GI_DEFINE_BASE_INFO_TYPE (gi_vfunc_info, GI_INFO_TYPE_VFUNC) +GI_DEFINE_BASE_INFO_TYPE (gi_property_info, GI_INFO_TYPE_PROPERTY) +GI_DEFINE_BASE_INFO_TYPE (gi_field_info, GI_INFO_TYPE_FIELD) +GI_DEFINE_BASE_INFO_TYPE (gi_arg_info, GI_INFO_TYPE_ARG) +GI_DEFINE_BASE_INFO_TYPE (gi_type_info, GI_INFO_TYPE_TYPE) +GI_DEFINE_BASE_INFO_TYPE (gi_unresolved_info, GI_INFO_TYPE_UNRESOLVED) + +void +gi_base_info_init_types (void) +{ + static gsize register_types_once = 0; + + if (g_once_init_enter (®ister_types_once)) + { + const struct + { + GIInfoType info_type; + const char *type_name; + gsize instance_size; + GClassInitFunc class_init; + } + types[] = + { + { GI_INFO_TYPE_CALLABLE, "GICallableInfo", sizeof (GICallableInfo), gi_callable_info_class_init }, + { GI_INFO_TYPE_FUNCTION, "GIFunctionInfo", sizeof (GIFunctionInfo), gi_function_info_class_init }, + { GI_INFO_TYPE_CALLBACK, "GICallbackInfo", sizeof (GICallbackInfo), gi_callback_info_class_init }, + { GI_INFO_TYPE_REGISTERED_TYPE, "GIRegisteredTypeInfo", sizeof (GIRegisteredTypeInfo), gi_registered_type_info_class_init }, + { GI_INFO_TYPE_STRUCT, "GIStructInfo", sizeof (GIStructInfo), gi_struct_info_class_init }, + { GI_INFO_TYPE_UNION, "GIUnionInfo", sizeof (GIUnionInfo), gi_union_info_class_init }, + { GI_INFO_TYPE_ENUM, "GIEnumInfo", sizeof (GIEnumInfo), gi_enum_info_class_init }, + { GI_INFO_TYPE_OBJECT, "GIObjectInfo", sizeof (GIObjectInfo), gi_object_info_class_init }, + { GI_INFO_TYPE_INTERFACE, "GIInterfaceInfo", sizeof (GIInterfaceInfo), gi_interface_info_class_init }, + { GI_INFO_TYPE_CONSTANT, "GIConstantInfo", sizeof (GIConstantInfo), gi_constant_info_class_init }, + { GI_INFO_TYPE_VALUE, "GIValueInfo", sizeof (GIValueInfo), gi_value_info_class_init }, + { GI_INFO_TYPE_SIGNAL, "GISignalInfo", sizeof (GISignalInfo), gi_signal_info_class_init }, + { GI_INFO_TYPE_VFUNC, "GIVFuncInfo", sizeof (GIVFuncInfo), gi_vfunc_info_class_init }, + { GI_INFO_TYPE_PROPERTY, "GIPropertyInfo", sizeof (GIPropertyInfo), gi_property_info_class_init }, + { GI_INFO_TYPE_FIELD, "GIFieldInfo", sizeof (GIFieldInfo), gi_field_info_class_init }, + { GI_INFO_TYPE_ARG, "GIArgInfo", sizeof (GIArgInfo), gi_arg_info_class_init }, + { GI_INFO_TYPE_TYPE, "GITypeInfo", sizeof (GITypeInfo), gi_type_info_class_init }, + { GI_INFO_TYPE_UNRESOLVED, "GIUnresolvedInfo", sizeof (GIUnresolvedInfo), gi_unresolved_info_class_init }, + }; + + for (gsize i = 0; i < G_N_ELEMENTS (types); i++) + { + GType registered_type = gi_base_info_type_register_static (g_intern_static_string (types[i].type_name), + types[i].instance_size, + types[i].class_init); + gi_base_info_types[types[i].info_type] = registered_type; + } + + g_once_init_leave (®ister_types_once, 1); + } +} + +/* info creation */ +GIBaseInfo * +gi_info_new_full (GIInfoType type, + GIRepository *repository, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset) +{ + GIRealInfo *info; + + g_return_val_if_fail (container != NULL || repository != NULL, NULL); + g_return_val_if_fail (GI_IS_REPOSITORY (repository), NULL); + + gi_base_info_init_types (); + g_assert (gi_base_info_types[type] != G_TYPE_INVALID); + info = (GIRealInfo *) g_type_create_instance (gi_base_info_types[type]); + + info->typelib = typelib; + info->offset = offset; + + if (container) + info->container = container; + if (container && container->ref_count != INVALID_REFCOUNT) + gi_base_info_ref (info->container); + + info->repository = g_object_ref (repository); + + return (GIBaseInfo*)info; +} + +/** + * gi_info_new: + * @type: type of the info to create + * @container: (nullable): info which contains this one + * @typelib: typelib containing the info + * @offset: offset of the info within @typelib, in bytes + * + * Create a new #GIBaseInfo representing an object of the given @type from + * @offset of @typelib. + * + * Returns: (transfer full): The new #GIBaseInfo, unref with + * [method@GIRepository.BaseInfo.unref] + * Since: 2.80 + */ +GIBaseInfo * +gi_info_new (GIInfoType type, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset) +{ + return gi_info_new_full (type, ((GIRealInfo*)container)->repository, container, typelib, offset); +} + +/*< private > + * gi_info_init: + * @info: (out caller-allocates): caller-allocated #GIRealInfo to populate + * @type: type of the info to create + * @repository: repository the info is in + * @container: (nullable): info which contains this one + * @typelib: typelib containing the info + * @offset: offset of the info within @typelib, in bytes + * + * Initialise a stack-allocated #GIBaseInfo representing an object of the given + * @type from @offset of @typelib. + * + * Since: 2.80 + */ +void +gi_info_init (GIRealInfo *info, + GIInfoType type, + GIRepository *repository, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset) +{ + memset (info, 0, sizeof (GIRealInfo)); + + /* Invalid refcount used to flag stack-allocated infos */ + info->ref_count = INVALID_REFCOUNT; + info->typelib = typelib; + info->offset = offset; + + if (container) + info->container = container; + + g_assert (GI_IS_REPOSITORY (repository)); + info->repository = repository; +} + +GIBaseInfo * +gi_info_from_entry (GIRepository *repository, + GITypelib *typelib, + guint16 index) +{ + GIBaseInfo *result; + DirEntry *entry = gi_typelib_get_dir_entry (typelib, index); + + if (entry->local) + result = gi_info_new_full (entry->blob_type, repository, NULL, typelib, entry->offset); + else + { + const gchar *namespace = gi_typelib_get_string (typelib, entry->offset); + const gchar *name = gi_typelib_get_string (typelib, entry->name); + + result = gi_repository_find_by_name (repository, namespace, name); + if (result == NULL) + { + GIUnresolvedInfo *unresolved; + + unresolved = (GIUnresolvedInfo *) gi_info_new_full (GI_INFO_TYPE_UNRESOLVED, + repository, + NULL, + typelib, + entry->offset); + + unresolved->name = name; + unresolved->namespace = namespace; + + return (GIBaseInfo *)unresolved; + } + return (GIBaseInfo *)result; + } + + return (GIBaseInfo *)result; +} + +GITypeInfo * +gi_type_info_new (GIBaseInfo *container, + GITypelib *typelib, + guint32 offset) +{ + SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset]; + + return (GITypeInfo *) gi_info_new (GI_INFO_TYPE_TYPE, container, typelib, + (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset); +} + +void +gi_type_info_init (GIBaseInfo *info, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset) +{ + GIRealInfo *rinfo = (GIRealInfo*)container; + SimpleTypeBlob *type = (SimpleTypeBlob *)&typelib->data[offset]; + + gi_info_init ((GIRealInfo*)info, GI_INFO_TYPE_TYPE, rinfo->repository, container, typelib, + (type->flags.reserved == 0 && type->flags.reserved2 == 0) ? offset : type->offset); +} + +/* GIBaseInfo functions */ + +/** + * GIBaseInfo: + * + * `GIBaseInfo` is the common base struct of all other Info structs + * accessible through the [class@GIRepository.Repository] API. + * + * All info structures can be cast to a `GIBaseInfo`, for instance: + * + * ```c + * GIFunctionInfo *function_info = …; + * GIBaseInfo *info = (GIBaseInfo *) function_info; + * ``` + * + * Most [class@GIRepository.Repository] APIs returning a `GIBaseInfo` are + * actually creating a new struct; in other words, + * [method@GIRepository.BaseInfo.unref] has to be called when done accessing the + * data. + * + * `GIBaseInfo` structuress are normally accessed by calling either + * [method@GIRepository.Repository.find_by_name], + * [method@GIRepository.Repository.find_by_gtype] or + * [method@GIRepository.get_info]. + * + * ```c + * GIBaseInfo *button_info = + * gi_repository_find_by_name (NULL, "Gtk", "Button"); + * + * // use button_info… + * + * gi_base_info_unref (button_info); + * ``` + * + * Since: 2.80 + */ + +/** + * gi_base_info_ref: + * @info: a #GIBaseInfo + * + * Increases the reference count of @info. + * + * Returns: (transfer full): the same @info. + * Since: 2.80 + */ +GIBaseInfo * +gi_base_info_ref (GIBaseInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + + g_assert (rinfo->ref_count != INVALID_REFCOUNT); + g_atomic_ref_count_inc (&rinfo->ref_count); + + return info; +} + +/** + * gi_base_info_unref: + * @info: (transfer full): a #GIBaseInfo + * + * Decreases the reference count of @info. When its reference count + * drops to 0, the info is freed. + * + * Since: 2.80 + */ +void +gi_base_info_unref (GIBaseInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + + g_assert (rinfo->ref_count > 0 && rinfo->ref_count != INVALID_REFCOUNT); + + if (g_atomic_ref_count_dec (&rinfo->ref_count)) + GI_BASE_INFO_GET_CLASS (info)->finalize (info); +} + +/** + * gi_base_info_get_info_type: + * @info: a #GIBaseInfo + * + * Obtain the info type of the `GIBaseInfo`. + * + * Returns: the info type of @info + * Since: 2.80 + */ +GIInfoType +gi_base_info_get_info_type (GIBaseInfo *info) +{ + return GI_BASE_INFO_GET_CLASS (info)->info_type; +} + +/** + * gi_base_info_get_name: + * @info: a #GIBaseInfo + * + * Obtain the name of the @info. + * + * What the name represents depends on the [type@GIRepository.InfoType] of the + * @info. For instance for [class@GIRepository.FunctionInfo] it is the name of + * the function. + * + * Returns: (nullable): the name of @info or `NULL` if it lacks a name. + * Since: 2.80 + */ +const gchar * +gi_base_info_get_name (GIBaseInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + g_assert (rinfo->ref_count > 0); + switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) + { + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_INVALID_0: + case GI_INFO_TYPE_UNION: + { + CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_VALUE: + { + ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_SIGNAL: + { + SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_PROPERTY: + { + PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_VFUNC: + { + VFuncBlob *blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_FIELD: + { + FieldBlob *blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + + case GI_INFO_TYPE_ARG: + { + ArgBlob *blob = (ArgBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->name); + } + break; + case GI_INFO_TYPE_UNRESOLVED: + { + GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; + + return unresolved->name; + } + break; + case GI_INFO_TYPE_TYPE: + return NULL; + default: ; + g_assert_not_reached (); + /* unnamed */ + } + + return NULL; +} + +/** + * gi_base_info_get_namespace: + * @info: a #GIBaseInfo + * + * Obtain the namespace of @info. + * + * Returns: the namespace + * Since: 2.80 + */ +const gchar * +gi_base_info_get_namespace (GIBaseInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*) info; + Header *header = (Header *)rinfo->typelib->data; + + g_assert (rinfo->ref_count > 0); + + if (gi_base_info_get_info_type (info) == GI_INFO_TYPE_UNRESOLVED) + { + GIUnresolvedInfo *unresolved = (GIUnresolvedInfo *)info; + + return unresolved->namespace; + } + + return gi_typelib_get_string (rinfo->typelib, header->namespace); +} + +/** + * gi_base_info_is_deprecated: + * @info: a #GIBaseInfo + * + * Obtain whether the @info is represents a metadata which is + * deprecated. + * + * Returns: `TRUE` if deprecated + * Since: 2.80 + */ +gboolean +gi_base_info_is_deprecated (GIBaseInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*) info; + switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) + { + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_INVALID_0: + { + CommonBlob *blob = (CommonBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_VALUE: + { + ValueBlob *blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_SIGNAL: + { + SignalBlob *blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_PROPERTY: + { + PropertyBlob *blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->deprecated; + } + break; + + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + default: ; + /* no deprecation flag for these */ + } + + return FALSE; +} + +/** + * gi_base_info_get_attribute: + * @info: a #GIBaseInfo + * @name: a freeform string naming an attribute + * + * Retrieve an arbitrary attribute associated with this node. + * + * Returns: (nullable): The value of the attribute, or `NULL` if no such + * attribute exists + * Since: 2.80 + */ +const gchar * +gi_base_info_get_attribute (GIBaseInfo *info, + const gchar *name) +{ + GIAttributeIter iter = { 0, }; + const char *curname, *curvalue; + while (gi_base_info_iterate_attributes (info, &iter, &curname, &curvalue)) + { + if (strcmp (name, curname) == 0) + return (const gchar*) curvalue; + } + + return NULL; +} + +static int +cmp_attribute (const void *av, + const void *bv) +{ + const AttributeBlob *a = av; + const AttributeBlob *b = bv; + + if (a->offset < b->offset) + return -1; + else if (a->offset == b->offset) + return 0; + else + return 1; +} + +/*< private > + * _attribute_blob_find_first: + * @GIBaseInfo: A #GIBaseInfo. + * @blob_offset: The offset for the blob to find the first attribute for. + * + * Searches for the first #AttributeBlob for @blob_offset and returns + * it if found. + * + * Returns: (transfer none): A pointer to #AttributeBlob or `NULL` if not found. + * Since: 2.80 + */ +AttributeBlob * +_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset) +{ + GIRealInfo *rinfo = (GIRealInfo *) info; + Header *header = (Header *)rinfo->typelib->data; + AttributeBlob blob, *first, *res, *previous; + + blob.offset = blob_offset; + + first = (AttributeBlob *) &rinfo->typelib->data[header->attributes]; + + res = bsearch (&blob, first, header->n_attributes, + header->attribute_blob_size, cmp_attribute); + + if (res == NULL) + return NULL; + + previous = res - 1; + while (previous >= first && previous->offset == blob_offset) + { + res = previous; + previous = res - 1; + } + + return res; +} + +/** + * gi_base_info_iterate_attributes: + * @info: a #GIBaseInfo + * @iterator: (inout): a [type@GIRepository.AttributeIter] structure, must be + * initialized; see below + * @name: (out) (transfer none): Returned name, must not be freed + * @value: (out) (transfer none): Returned name, must not be freed + * + * Iterate over all attributes associated with this node. + * + * The iterator structure is typically stack allocated, and must have its first + * member initialized to `NULL`. Attributes are arbitrary namespaced key–value + * pairs which can be attached to almost any item. They are intended for use + * by software higher in the toolchain than bindings, and are distinct from + * normal GIR annotations. + * + * Both the @name and @value should be treated as constants + * and must not be freed. + * + * ```c + * void + * print_attributes (GIBaseInfo *info) + * { + * GIAttributeIter iter = { 0, }; + * const char *name; + * const char *value; + * while (gi_base_info_iterate_attributes (info, &iter, &name, &value)) + * { + * g_print ("attribute name: %s value: %s", name, value); + * } + * } + * ``` + * + * Returns: `TRUE` if there are more attributes + * Since: 2.80 + */ +gboolean +gi_base_info_iterate_attributes (GIBaseInfo *info, + GIAttributeIter *iterator, + const gchar **name, + const gchar **value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + AttributeBlob *next, *after; + + after = (AttributeBlob *) &rinfo->typelib->data[header->attributes + + header->n_attributes * header->attribute_blob_size]; + + if (iterator->data != NULL) + next = (AttributeBlob *) iterator->data; + else + next = _attribute_blob_find_first (info, rinfo->offset); + + if (next == NULL || next->offset != rinfo->offset || next >= after) + return FALSE; + + *name = gi_typelib_get_string (rinfo->typelib, next->name); + *value = gi_typelib_get_string (rinfo->typelib, next->value); + iterator->data = next + 1; + + return TRUE; +} + +/** + * gi_base_info_get_container: + * @info: a #GIBaseInfo + * + * Obtain the container of the @info. + * + * The container is the parent `GIBaseInfo`. For instance, the parent of a + * [class@GIRepository.FunctionInfo] is an [class@GIRepository.ObjectInfo] or + * [class@GIRepository.InterfaceInfo]. + * + * Returns: (transfer none): the container + * Since: 2.80 + */ +GIBaseInfo * +gi_base_info_get_container (GIBaseInfo *info) +{ + return ((GIRealInfo*)info)->container; +} + +/** + * gi_base_info_get_typelib: + * @info: a #GIBaseInfo + * + * Obtain the typelib this @info belongs to + * + * Returns: (transfer none): the typelib + * Since: 2.80 + */ +GITypelib * +gi_base_info_get_typelib (GIBaseInfo *info) +{ + return ((GIRealInfo*)info)->typelib; +} + +/** + * gi_base_info_equal: + * @info1: a #GIBaseInfo + * @info2: a #GIBaseInfo + * + * Compare two `GIBaseInfo`s. + * + * Using pointer comparison is not practical since many functions return + * different instances of `GIBaseInfo` that refers to the same part of the + * TypeLib; use this function instead to do `GIBaseInfo` comparisons. + * + * Returns: `TRUE` if and only if @info1 equals @info2. + * Since: 2.80 + */ +gboolean +gi_base_info_equal (GIBaseInfo *info1, GIBaseInfo *info2) +{ + /* Compare the TypeLib pointers, which are mmapped. */ + GIRealInfo *rinfo1 = (GIRealInfo*)info1; + GIRealInfo *rinfo2 = (GIRealInfo*)info2; + return rinfo1->typelib->data + rinfo1->offset == rinfo2->typelib->data + rinfo2->offset; +} diff --git a/girepository/gibaseinfo.h b/girepository/gibaseinfo.h new file mode 100644 index 0000000..fdbe91f --- /dev/null +++ b/girepository/gibaseinfo.h @@ -0,0 +1,103 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: GIBaseInfo + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include +#include + +G_BEGIN_DECLS + +/** + * GIAttributeIter: + * + * An opaque structure used to iterate over attributes + * in a [class@GIRepository.BaseInfo] struct. + * + * Since: 2.80 + */ +typedef struct { + /*< private >*/ + gpointer data; + gpointer data2; + gpointer data3; + gpointer data4; +} GIAttributeIter; + +#define GI_TYPE_BASE_INFO (gi_base_info_get_type ()) + + +GI_AVAILABLE_IN_ALL +GType gi_base_info_get_type (void) G_GNUC_CONST; + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_base_info_ref (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_base_info_unref (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +GIInfoType gi_base_info_get_info_type (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_base_info_get_name (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_base_info_get_namespace (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_base_info_is_deprecated (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_base_info_get_attribute (GIBaseInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +gboolean gi_base_info_iterate_attributes (GIBaseInfo *info, + GIAttributeIter *iterator, + const char **name, + const char **value); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_base_info_get_container (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +GITypelib * gi_base_info_get_typelib (GIBaseInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_base_info_equal (GIBaseInfo *info1, + GIBaseInfo *info2); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_info_new (GIInfoType type, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset); + +G_END_DECLS diff --git a/girepository/gicallableinfo.c b/girepository/gicallableinfo.c new file mode 100644 index 0000000..99f5f2d --- /dev/null +++ b/girepository/gicallableinfo.c @@ -0,0 +1,835 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "girffi.h" +#include "gicallableinfo.h" + +/* GICallableInfo functions */ + +/** + * GICallableInfo: + * + * `GICallableInfo` represents an entity which is callable. + * + * Examples of callable are: + * + * - functions ([class@GIRepository.FunctionInfo]) + * - virtual functions ([class@GIRepository.VFuncInfo]) + * - callbacks ([class@GIRepository.CallbackInfo]). + * + * A callable has a list of arguments ([class@GIRepository.ArgInfo]), a return + * type, direction and a flag which decides if it returns `NULL`. + * + * Since: 2.80 + */ + +static guint32 +signature_offset (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + int sigoff = -1; + + switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) + { + case GI_INFO_TYPE_FUNCTION: + sigoff = G_STRUCT_OFFSET (FunctionBlob, signature); + break; + case GI_INFO_TYPE_VFUNC: + sigoff = G_STRUCT_OFFSET (VFuncBlob, signature); + break; + case GI_INFO_TYPE_CALLBACK: + sigoff = G_STRUCT_OFFSET (CallbackBlob, signature); + break; + case GI_INFO_TYPE_SIGNAL: + sigoff = G_STRUCT_OFFSET (SignalBlob, signature); + break; + default: + g_assert_not_reached (); + } + if (sigoff >= 0) + return *(guint32 *)&rinfo->typelib->data[rinfo->offset + sigoff]; + return 0; +} + +/** + * gi_callable_info_can_throw_gerror: + * @info: a #GICallableInfo + * + * Whether the callable can throw a [type@GLib.Error] + * + * Returns: `TRUE` if this `GICallableInfo` can throw a [type@GLib.Error] + * Since: 2.80 + */ +gboolean +gi_callable_info_can_throw_gerror (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + SignatureBlob *signature; + + signature = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)]; + if (signature->throws) + return TRUE; + + /* Functions and VFuncs store "throws" in their own blobs. + * This info was additionally added to the SignatureBlob + * to support the other callables. For Functions and VFuncs, + * also check their legacy flag for compatibility. + */ + switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) { + case GI_INFO_TYPE_FUNCTION: + { + FunctionBlob *blob; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + return blob->throws; + } + case GI_INFO_TYPE_VFUNC: + { + VFuncBlob *blob; + blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + return blob->throws; + } + case GI_INFO_TYPE_CALLBACK: + case GI_INFO_TYPE_SIGNAL: + return FALSE; + default: + g_assert_not_reached (); + } +} + +/** + * gi_callable_info_is_method: + * @info: a #GICallableInfo + * + * Determines if the callable info is a method. + * + * For [class@GIRepository.VFuncInfo]s, [class@GIRepository.CallbackInfo]s, and + * [class@GIRepository.SignalInfo]s, this is always true. Otherwise, this looks + * at the `GI_FUNCTION_IS_METHOD` flag on the [class@GIRepository.FunctionInfo]. + * + * Concretely, this function returns whether + * [method@GIRepository.CallableInfo.get_n_args] matches the number of arguments + * in the raw C method. For methods, there is one more C argument than is + * exposed by introspection: the `self` or `this` object. + * + * Returns: `TRUE` if @info is a method, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_callable_info_is_method (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*)info; + switch (gi_base_info_get_info_type ((GIBaseInfo *) info)) { + case GI_INFO_TYPE_FUNCTION: + { + FunctionBlob *blob; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + return (!blob->constructor && !blob->is_static); + } + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_SIGNAL: + return TRUE; + case GI_INFO_TYPE_CALLBACK: + return FALSE; + default: + g_assert_not_reached (); + } +} + +/** + * gi_callable_info_get_return_type: + * @info: a #GICallableInfo + * + * Obtain the return type of a callable item as a [class@GIRepository.TypeInfo]. + * + * Returns: (transfer full): the [class@GIRepository.TypeInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GITypeInfo * +gi_callable_info_get_return_type (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + guint32 offset; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), NULL); + + offset = signature_offset (info); + + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, offset); +} + +/** + * gi_callable_info_load_return_type: + * @info: a #GICallableInfo + * @type: (out caller-allocates): Initialized with return type of @info + * + * Obtain information about a return value of callable; this + * function is a variant of [method@GIRepository.CallableInfo.get_return_type] + * designed for stack allocation. + * + * The initialized @type must not be referenced after @info is deallocated. + * + * Since: 2.80 + */ +void +gi_callable_info_load_return_type (GICallableInfo *info, + GITypeInfo *type) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + guint32 offset; + + g_return_if_fail (info != NULL); + g_return_if_fail (GI_IS_CALLABLE_INFO (info)); + + offset = signature_offset (info); + + gi_type_info_init ((GIBaseInfo *) type, (GIBaseInfo*)info, rinfo->typelib, offset); +} + +/** + * gi_callable_info_may_return_null: + * @info: a #GICallableInfo + * + * See if a callable could return `NULL`. + * + * Returns: `TRUE` if callable could return `NULL` + * Since: 2.80 + */ +gboolean +gi_callable_info_may_return_null (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SignatureBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), FALSE); + + blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)]; + + return blob->may_return_null; +} + +/** + * gi_callable_info_skip_return: + * @info: a #GICallableInfo + * + * See if a callable’s return value is only useful in C. + * + * Returns: `TRUE` if return value is only useful in C. + * Since: 2.80 + */ +gboolean +gi_callable_info_skip_return (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SignatureBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), FALSE); + + blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)]; + + return blob->skip_return; +} + +/** + * gi_callable_info_get_caller_owns: + * @info: a #GICallableInfo + * + * See whether the caller owns the return value of this callable. + * + * [type@GIRepository.Transfer] contains a list of possible transfer values. + * + * Returns: the transfer mode for the return value of the callable + * Since: 2.80 + */ +GITransfer +gi_callable_info_get_caller_owns (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*) info; + SignatureBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1); + + blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)]; + + if (blob->caller_owns_return_value) + return GI_TRANSFER_EVERYTHING; + else if (blob->caller_owns_return_container) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} + +/** + * gi_callable_info_get_instance_ownership_transfer: + * @info: a #GICallableInfo + * + * Obtains the ownership transfer for the instance argument. + * + * [type@GIRepository.Transfer] contains a list of possible transfer values. + * + * Returns: the transfer mode of the instance argument + * Since: 2.80 + */ +GITransfer +gi_callable_info_get_instance_ownership_transfer (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo*) info; + SignatureBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1); + + blob = (SignatureBlob *)&rinfo->typelib->data[signature_offset (info)]; + + if (blob->instance_transfer_ownership) + return GI_TRANSFER_EVERYTHING; + else + return GI_TRANSFER_NOTHING; +} + +/** + * gi_callable_info_get_n_args: + * @info: a #GICallableInfo + * + * Obtain the number of arguments (both ‘in’ and ‘out’) for this callable. + * + * Returns: The number of arguments this callable expects. + * Since: 2.80 + */ +guint +gi_callable_info_get_n_args (GICallableInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + gint offset; + SignatureBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), -1); + + offset = signature_offset (info); + blob = (SignatureBlob *)&rinfo->typelib->data[offset]; + + return blob->n_arguments; +} + +/** + * gi_callable_info_get_arg: + * @info: a #GICallableInfo + * @n: the argument index to fetch + * + * Obtain information about a particular argument of this callable. + * + * Returns: (transfer full): the [class@GIRepository.ArgInfo]. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIArgInfo * +gi_callable_info_get_arg (GICallableInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + gint offset; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_CALLABLE_INFO (info), NULL); + + offset = signature_offset (info); + header = (Header *)rinfo->typelib->data; + + return (GIArgInfo *) gi_info_new (GI_INFO_TYPE_ARG, (GIBaseInfo*)info, rinfo->typelib, + offset + header->signature_blob_size + n * header->arg_blob_size); +} + +/** + * gi_callable_info_load_arg: + * @info: a #GICallableInfo + * @n: the argument index to fetch + * @arg: (out caller-allocates): Initialize with argument number @n + * + * Obtain information about a particular argument of this callable; this + * function is a variant of [method@GIRepository.CallableInfo.get_arg] designed + * for stack allocation. + * + * The initialized @arg must not be referenced after @info is deallocated. + * + * Since: 2.80 + */ +void +gi_callable_info_load_arg (GICallableInfo *info, + guint n, + GIArgInfo *arg) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + gint offset; + + g_return_if_fail (info != NULL); + g_return_if_fail (GI_IS_CALLABLE_INFO (info)); + + offset = signature_offset (info); + header = (Header *)rinfo->typelib->data; + + gi_info_init ((GIRealInfo*)arg, GI_INFO_TYPE_ARG, rinfo->repository, (GIBaseInfo*)info, rinfo->typelib, + offset + header->signature_blob_size + n * header->arg_blob_size); +} + +/** + * gi_callable_info_get_return_attribute: + * @info: a #GICallableInfo + * @name: a freeform string naming an attribute + * + * Retrieve an arbitrary attribute associated with the return value. + * + * Returns: (nullable): The value of the attribute, or `NULL` if no such + * attribute exists + * Since: 2.80 + */ +const gchar * +gi_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name) +{ + GIAttributeIter iter = { 0, }; + const char *curname, *curvalue; + while (gi_callable_info_iterate_return_attributes (info, &iter, &curname, &curvalue)) + { + if (g_strcmp0 (name, curname) == 0) + return (const gchar*) curvalue; + } + + return NULL; +} + +/** + * gi_callable_info_iterate_return_attributes: + * @info: a #GICallableInfo + * @iterator: (inout): a [type@GIRepository.AttributeIter] structure, must be + * initialized; see below + * @name: (out) (transfer none): Returned name, must not be freed + * @value: (out) (transfer none): Returned name, must not be freed + * + * Iterate over all attributes associated with the return value. + * + * The iterator structure is typically stack allocated, and must have its + * first member initialized to `NULL`. + * + * Both the @name and @value should be treated as constants + * and must not be freed. + * + * See [method@GIRepository.BaseInfo.iterate_attributes] for an example of how + * to use a similar API. + * + * Returns: `TRUE` if there are more attributes + * Since: 2.80 + */ +gboolean +gi_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + const char **name, + const char **value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + AttributeBlob *next, *after; + guint32 blob_offset; + + after = (AttributeBlob *) &rinfo->typelib->data[header->attributes + + header->n_attributes * header->attribute_blob_size]; + + blob_offset = signature_offset (info); + + if (iterator->data != NULL) + next = (AttributeBlob *) iterator->data; + else + next = _attribute_blob_find_first ((GIBaseInfo *) info, blob_offset); + + if (next == NULL || next->offset != blob_offset || next >= after) + return FALSE; + + *name = gi_typelib_get_string (rinfo->typelib, next->name); + *value = gi_typelib_get_string (rinfo->typelib, next->value); + iterator->data = next + 1; + + return TRUE; +} + +/** + * gi_type_tag_extract_ffi_return_value: + * @return_tag: [type@GIRepository.TypeTag] of the return value + * @interface_type: [type@GIRepository.InfoType] of the underlying interface type + * @ffi_value: pointer to [type@GIRepository.FFIReturnValue] union containing + * the return value from `ffi_call()` + * @arg: (out caller-allocates): pointer to an allocated + * [class@GIRepository.Argument] + * + * Extract the correct bits from an `ffi_arg` return value into + * [class@GIRepository.Argument]. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=665152 + * + * Also see [`ffi_call()`](man:ffi_call(3)): the storage requirements for return + * values are ‘special’. + * + * The @interface_type argument only applies if @return_tag is + * `GI_TYPE_TAG_INTERFACE`. Otherwise it is ignored. + * + * Since: 2.80 + */ +void +gi_type_tag_extract_ffi_return_value (GITypeTag return_tag, + GIInfoType interface_type, + GIFFIReturnValue *ffi_value, + GIArgument *arg) +{ + switch (return_tag) { + case GI_TYPE_TAG_INT8: + arg->v_int8 = (gint8) ffi_value->v_long; + break; + case GI_TYPE_TAG_UINT8: + arg->v_uint8 = (guint8) ffi_value->v_ulong; + break; + case GI_TYPE_TAG_INT16: + arg->v_int16 = (gint16) ffi_value->v_long; + break; + case GI_TYPE_TAG_UINT16: + arg->v_uint16 = (guint16) ffi_value->v_ulong; + break; + case GI_TYPE_TAG_INT32: + arg->v_int32 = (gint32) ffi_value->v_long; + break; + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_UNICHAR: + arg->v_uint32 = (guint32) ffi_value->v_ulong; + break; + case GI_TYPE_TAG_INT64: + arg->v_int64 = (gint64) ffi_value->v_int64; + break; + case GI_TYPE_TAG_UINT64: + arg->v_uint64 = (guint64) ffi_value->v_uint64; + break; + case GI_TYPE_TAG_FLOAT: + arg->v_float = ffi_value->v_float; + break; + case GI_TYPE_TAG_DOUBLE: + arg->v_double = ffi_value->v_double; + break; + case GI_TYPE_TAG_INTERFACE: + switch(interface_type) { + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + arg->v_int32 = (gint32) ffi_value->v_long; + break; + default: + arg->v_pointer = (gpointer) ffi_value->v_pointer; + break; + } + break; + default: + arg->v_pointer = (gpointer) ffi_value->v_pointer; + break; + } +} + +/** + * gi_type_info_extract_ffi_return_value: + * @return_info: [type@GIRepository.TypeInfo] describing the return type + * @ffi_value: pointer to [type@GIRepository.FFIReturnValue] union containing + * the return value from `ffi_call()` + * @arg: (out caller-allocates): pointer to an allocated + * [class@GIRepository.Argument] + * + * Extract the correct bits from an `ffi_arg` return value into + * [class@GIRepository.Argument]. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=665152 + * + * Also see [`ffi_call()`](man:ffi_call(3)): the storage requirements for return + * values are ‘special’. + * + * Since: 2.80 + */ +void +gi_type_info_extract_ffi_return_value (GITypeInfo *return_info, + GIFFIReturnValue *ffi_value, + GIArgument *arg) +{ + GITypeTag return_tag = gi_type_info_get_tag (return_info); + GIInfoType interface_type = GI_INFO_TYPE_INVALID; + + if (return_tag == GI_TYPE_TAG_INTERFACE) + { + GIBaseInfo *interface_info = gi_type_info_get_interface (return_info); + interface_type = gi_base_info_get_info_type (interface_info); + gi_base_info_unref (interface_info); + } + + gi_type_tag_extract_ffi_return_value (return_tag, interface_type, + ffi_value, arg); +} + +/** + * gi_callable_info_invoke: + * @info: a #GICallableInfo + * @function: function pointer to call + * @in_args: (array length=n_in_args): array of ‘in’ arguments + * @n_in_args: number of arguments in @in_args + * @out_args: (array length=n_out_args): array of ‘out’ arguments allocated by + * the caller, to be populated with outputted values + * @n_out_args: number of arguments in @out_args + * @return_value: (out caller-allocates) (not optional) (nullable): return + * location for the return value from the callable; `NULL` may be returned if + * the callable returns that + * @is_method: `TRUE` if @info is a method + * @throws: `TRUE` if @info may throw a [type@GLib.Error] + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Invoke the given `GICallableInfo` by calling the given @function pointer. + * + * The set of arguments passed to @function will be constructed according to the + * introspected type of the `GICallableInfo`, using @in_args, @out_args, + * @is_method, @throws and @error. + * + * Returns: `TRUE` if the callable was executed successfully and didn’t throw + * a [type@GLib.Error]; `FALSE` if @error is set + * Since: 2.80 + */ +gboolean +gi_callable_info_invoke (GICallableInfo *info, + gpointer function, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + gboolean is_method, + gboolean throws, + GError **error) +{ + ffi_cif cif; + ffi_type *rtype; + ffi_type **atypes; + GITypeInfo *tinfo; + GITypeInfo *rinfo; + GITypeTag rtag; + GIArgInfo *ainfo; + gsize n_args, n_invoke_args, in_pos, out_pos, i; + gpointer *args; + gboolean success = FALSE; + GError *local_error = NULL; + gpointer error_address = &local_error; + GIFFIReturnValue ffi_return_value; + gpointer return_value_p; /* Will point inside the union return_value */ + + rinfo = gi_callable_info_get_return_type ((GICallableInfo *)info); + rtype = gi_type_info_get_ffi_type (rinfo); + rtag = gi_type_info_get_tag(rinfo); + + in_pos = 0; + out_pos = 0; + + n_args = gi_callable_info_get_n_args ((GICallableInfo *)info); + if (is_method) + { + if (n_in_args == 0) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments (handling this)"); + goto out; + } + n_invoke_args = n_args+1; + in_pos++; + } + else + n_invoke_args = n_args; + + if (throws) + /* Add an argument for the GError */ + n_invoke_args ++; + + atypes = g_alloca (sizeof (ffi_type*) * n_invoke_args); + args = g_alloca (sizeof (gpointer) * n_invoke_args); + + if (is_method) + { + atypes[0] = &ffi_type_pointer; + args[0] = (gpointer) &in_args[0]; + } + for (i = 0; i < n_args; i++) + { + int offset = (is_method ? 1 : 0); + ainfo = gi_callable_info_get_arg ((GICallableInfo *)info, i); + switch (gi_arg_info_get_direction (ainfo)) + { + case GI_DIRECTION_IN: + tinfo = gi_arg_info_get_type_info (ainfo); + atypes[i+offset] = gi_type_info_get_ffi_type (tinfo); + gi_base_info_unref ((GIBaseInfo *)ainfo); + gi_base_info_unref ((GIBaseInfo *)tinfo); + + if (in_pos >= n_in_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments (handling in)"); + goto out; + } + + args[i+offset] = (gpointer)&in_args[in_pos]; + in_pos++; + + break; + case GI_DIRECTION_OUT: + atypes[i+offset] = &ffi_type_pointer; + gi_base_info_unref ((GIBaseInfo *)ainfo); + + if (out_pos >= n_out_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"out\" arguments (handling out)"); + goto out; + } + + args[i+offset] = (gpointer)&out_args[out_pos]; + out_pos++; + break; + case GI_DIRECTION_INOUT: + atypes[i+offset] = &ffi_type_pointer; + gi_base_info_unref ((GIBaseInfo *)ainfo); + + if (in_pos >= n_in_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"in\" arguments (handling inout)"); + goto out; + } + + if (out_pos >= n_out_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too few \"out\" arguments (handling inout)"); + goto out; + } + + args[i+offset] = (gpointer)&in_args[in_pos]; + in_pos++; + out_pos++; + break; + default: + gi_base_info_unref ((GIBaseInfo *)ainfo); + g_assert_not_reached (); + } + } + + if (throws) + { + args[n_invoke_args - 1] = &error_address; + atypes[n_invoke_args - 1] = &ffi_type_pointer; + } + + if (in_pos < n_in_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too many \"in\" arguments (at end)"); + goto out; + } + if (out_pos < n_out_args) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH, + "Too many \"out\" arguments (at end)"); + goto out; + } + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_invoke_args, rtype, atypes) != FFI_OK) + goto out; + + g_return_val_if_fail (return_value, FALSE); + /* See comment for GIFFIReturnValue above */ + switch (rtag) + { + case GI_TYPE_TAG_FLOAT: + return_value_p = &ffi_return_value.v_float; + break; + case GI_TYPE_TAG_DOUBLE: + return_value_p = &ffi_return_value.v_double; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + return_value_p = &ffi_return_value.v_uint64; + break; + default: + return_value_p = &ffi_return_value.v_long; + } + ffi_call (&cif, function, return_value_p, args); + + if (local_error) + { + g_propagate_error (error, local_error); + success = FALSE; + } + else + { + gi_type_info_extract_ffi_return_value (rinfo, &ffi_return_value, return_value); + success = TRUE; + } + out: + gi_base_info_unref ((GIBaseInfo *)rinfo); + return success; +} + +void +gi_callable_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_CALLABLE; +} diff --git a/girepository/gicallableinfo.h b/girepository/gicallableinfo.h new file mode 100644 index 0000000..9ea0473 --- /dev/null +++ b/girepository/gicallableinfo.h @@ -0,0 +1,109 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_CALLABLE_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.CallableInfo] or derived from it. + * + * Since: 2.80 + */ +#define GI_IS_CALLABLE_INFO(info) \ + ((gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_FUNCTION) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_CALLBACK) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_SIGNAL) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_VFUNC)) + + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_is_method (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_can_throw_gerror (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_callable_info_get_return_type (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_callable_info_load_return_type (GICallableInfo *info, + GITypeInfo *type); + +GI_AVAILABLE_IN_ALL +const gchar * gi_callable_info_get_return_attribute (GICallableInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_iterate_return_attributes (GICallableInfo *info, + GIAttributeIter *iterator, + const char **name, + const char **value); + +GI_AVAILABLE_IN_ALL +GITransfer gi_callable_info_get_caller_owns (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_may_return_null (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_skip_return (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +guint gi_callable_info_get_n_args (GICallableInfo *info); + +GI_AVAILABLE_IN_ALL +GIArgInfo * gi_callable_info_get_arg (GICallableInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +void gi_callable_info_load_arg (GICallableInfo *info, + guint n, + GIArgInfo *arg); + +GI_AVAILABLE_IN_ALL +gboolean gi_callable_info_invoke (GICallableInfo *info, + gpointer function, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + gboolean is_method, + gboolean throws, + GError **error); + +GI_AVAILABLE_IN_ALL +GITransfer gi_callable_info_get_instance_ownership_transfer (GICallableInfo *info); + +G_END_DECLS diff --git a/girepository/gicallbackinfo.c b/girepository/gicallbackinfo.c new file mode 100644 index 0000000..8fa4688 --- /dev/null +++ b/girepository/gicallbackinfo.c @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright 2023 GNOME Foundation, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gicallbackinfo.h" + +/** + * GICallbackInfo: + * + * `GICallbackInfo` represents a callback. + * + * Since: 2.80 + */ + +void +gi_callback_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_CALLBACK; +} diff --git a/girepository/gicallbackinfo.h b/girepository/gicallbackinfo.h new file mode 100644 index 0000000..52fd368 --- /dev/null +++ b/girepository/gicallbackinfo.h @@ -0,0 +1,45 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable + * + * Copyright 2023 GNOME Foundation, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_CALLBACK_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.CallbackInfo] or derived from it. + * + * Since: 2.80 + */ +#define GI_IS_CALLBACK_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_CALLBACK) + +G_END_DECLS diff --git a/girepository/giconstantinfo.c b/girepository/giconstantinfo.c new file mode 100644 index 0000000..1383e73 --- /dev/null +++ b/girepository/giconstantinfo.c @@ -0,0 +1,193 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Constant implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include // memcpy + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giconstantinfo.h" + +/** + * GIConstantInfo: + * + * `GIConstantInfo` represents a constant. + * + * A constant has a type associated – which can be obtained by calling + * [method@GIRepository.ConstantInfo.get_type_info] – and a value – which can be + * obtained by calling [method@GIRepository.ConstantInfo.get_value]. + * + * Since: 2.80 + */ + +/** + * gi_constant_info_get_type_info: + * @info: a #GIConstantInfo + * + * Obtain the type of the constant as a [class@GIRepository.TypeInfo]. + * + * Returns: (transfer full): The [class@GIRepository.TypeInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GITypeInfo * +gi_constant_info_get_type_info (GIConstantInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_CONSTANT_INFO (info), NULL); + + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + 8); +} + +#define DO_ALIGNED_COPY(dest_addr, src_addr, type) \ + memcpy((dest_addr), (src_addr), sizeof(type)) + +/** + * gi_constant_info_free_value: (skip) + * @info: a #GIConstantInfo + * @value: the argument + * + * Free the value returned from [method@GIRepository.ConstantInfo.get_value]. + * + * Since: 2.80 + */ +void +gi_constant_info_free_value (GIConstantInfo *info, + GIArgument *value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ConstantBlob *blob; + + g_return_if_fail (info != NULL); + g_return_if_fail (GI_IS_CONSTANT_INFO (info)); + + blob = (ConstantBlob *)&rinfo->typelib->data[rinfo->offset]; + + /* FIXME non-basic types ? */ + if (blob->type.flags.reserved == 0 && blob->type.flags.reserved2 == 0) + { + if (blob->type.flags.pointer) + g_free (value->v_pointer); + } +} + +/** + * gi_constant_info_get_value: (skip) + * @info: a #GIConstantInfo + * @value: (out caller-allocates): an argument + * + * Obtain the value associated with the `GIConstantInfo` and store it in the + * @value parameter. + * + * @argument needs to be allocated before passing it in. + * + * The size of the constant value (in bytes) stored in @argument will be + * returned. + * + * Free the value with [method@GIRepository.ConstantInfo.free_value]. + * + * Returns: size of the constant, in bytes + * Since: 2.80 + */ +gsize +gi_constant_info_get_value (GIConstantInfo *info, + GIArgument *value) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ConstantBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_CONSTANT_INFO (info), 0); + + blob = (ConstantBlob *)&rinfo->typelib->data[rinfo->offset]; + + /* FIXME non-basic types ? */ + if (blob->type.flags.reserved == 0 && blob->type.flags.reserved2 == 0) + { + if (blob->type.flags.pointer) + { + gsize blob_size = blob->size; + + value->v_pointer = g_memdup2 (&rinfo->typelib->data[blob->offset], blob_size); + } + else + { + switch (blob->type.flags.tag) + { + case GI_TYPE_TAG_BOOLEAN: + value->v_boolean = *(gboolean*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_INT8: + value->v_int8 = *(gint8*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT8: + value->v_uint8 = *(guint8*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_INT16: + value->v_int16 = *(gint16*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT16: + value->v_uint16 = *(guint16*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_INT32: + value->v_int32 = *(gint32*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_UINT32: + value->v_uint32 = *(guint32*)&rinfo->typelib->data[blob->offset]; + break; + case GI_TYPE_TAG_INT64: + DO_ALIGNED_COPY(&value->v_int64, &rinfo->typelib->data[blob->offset], gint64); + break; + case GI_TYPE_TAG_UINT64: + DO_ALIGNED_COPY(&value->v_uint64, &rinfo->typelib->data[blob->offset], guint64); + break; + case GI_TYPE_TAG_FLOAT: + DO_ALIGNED_COPY(&value->v_float, &rinfo->typelib->data[blob->offset], gfloat); + break; + case GI_TYPE_TAG_DOUBLE: + DO_ALIGNED_COPY(&value->v_double, &rinfo->typelib->data[blob->offset], gdouble); + break; + default: + g_assert_not_reached (); + } + } + } + + return blob->size; +} + +void +gi_constant_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_CONSTANT; +} diff --git a/girepository/giconstantinfo.h b/girepository/giconstantinfo.h new file mode 100644 index 0000000..c28c5dd --- /dev/null +++ b/girepository/giconstantinfo.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Constant + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_CONSTANT_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.ConstantInfo]. + * + * Since: 2.80 + */ +#define GI_IS_CONSTANT_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_CONSTANT) + + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_constant_info_get_type_info (GIConstantInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_constant_info_free_value (GIConstantInfo *info, + GIArgument *value); + +GI_AVAILABLE_IN_ALL +gsize gi_constant_info_get_value (GIConstantInfo *info, + GIArgument *value); +G_END_DECLS diff --git a/girepository/gienuminfo.c b/girepository/gienuminfo.c new file mode 100644 index 0000000..24e4a4c --- /dev/null +++ b/girepository/gienuminfo.c @@ -0,0 +1,269 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Enum implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gienuminfo.h" + +/** + * GIEnumInfo: + * + * A `GIEnumInfo` represents an enumeration. + * + * The `GIEnumInfo` contains a set of values (each a + * [class@GIRepository.ValueInfo]) and a type. + * + * The [class@GIRepository.ValueInfo] for a value is fetched by calling + * [method@GIRepository.EnumInfo.get_value] on a `GIEnumInfo`. + * + * Since: 2.80 + */ + +/** + * gi_enum_info_get_n_values: + * @info: a #GIEnumInfo + * + * Obtain the number of values this enumeration contains. + * + * Returns: the number of enumeration values + * Since: 2.80 + */ +guint +gi_enum_info_get_n_values (GIEnumInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), 0); + + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_values; +} + +/** + * gi_enum_info_get_error_domain: + * @info: a #GIEnumInfo + * + * Obtain the string form of the quark for the error domain associated with + * this enum, if any. + * + * Returns: (transfer none) (nullable): the string form of the error domain + * associated with this enum, or `NULL`. + * Since: 2.80 + */ +const gchar * +gi_enum_info_get_error_domain (GIEnumInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), 0); + + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->error_domain) + return gi_typelib_get_string (rinfo->typelib, blob->error_domain); + else + return NULL; +} + +/** + * gi_enum_info_get_value: + * @info: a #GIEnumInfo + * @n: index of value to fetch + * + * Obtain a value for this enumeration. + * + * Returns: (transfer full): the enumeration value, free the struct with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIValueInfo * +gi_enum_info_get_value (GIEnumInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + gint offset; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + offset = rinfo->offset + header->enum_blob_size + + n * header->value_blob_size; + + return (GIValueInfo *) gi_info_new (GI_INFO_TYPE_VALUE, (GIBaseInfo*)info, rinfo->typelib, offset); +} + +/** + * gi_enum_info_get_n_methods: + * @info: a #GIEnumInfo + * + * Obtain the number of methods that this enum type has. + * + * Returns: number of methods + * Since: 2.80 + */ +guint +gi_enum_info_get_n_methods (GIEnumInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), 0); + + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_methods; +} + +/** + * gi_enum_info_get_method: + * @info: a #GIEnumInfo + * @n: index of method to get + * + * Obtain an enum type method at index @n. + * + * Returns: (transfer full): the [class@GIRepository.FunctionInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_enum_info_get_method (GIEnumInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->enum_blob_size + + blob->n_values * header->value_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_enum_info_get_storage_type: + * @info: a #GIEnumInfo + * + * Obtain the tag of the type used for the enum in the C ABI. This will + * will be a signed or unsigned integral type. + * + * Note that in the current implementation the width of the type is + * computed correctly, but the signed or unsigned nature of the type + * may not match the sign of the type used by the C compiler. + * + * Returns: the storage type for the enumeration + * Since: 2.80 + */ +GITypeTag +gi_enum_info_get_storage_type (GIEnumInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + EnumBlob *blob; + + g_return_val_if_fail (info != NULL, GI_TYPE_TAG_BOOLEAN); + g_return_val_if_fail (GI_IS_ENUM_INFO (info), GI_TYPE_TAG_BOOLEAN); + + blob = (EnumBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->storage_type; +} + +void +gi_enum_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_ENUM; +} + +/** + * GIValueInfo: + * + * A `GIValueInfo` represents a value in an enumeration. + * + * The `GIValueInfo` is fetched by calling + * [method@GIRepository.EnumInfo.get_value] on a [class@GIRepository.EnumInfo]. + * + * Since: 2.80 + */ + +/** + * gi_value_info_get_value: + * @info: a #GIValueInfo + * + * Obtain the enumeration value of the `GIValueInfo`. + * + * Returns: the enumeration value. This will always be representable + * as a 32-bit signed or unsigned value. The use of `gint64` as the + * return type is to allow both. + * Since: 2.80 + */ +gint64 +gi_value_info_get_value (GIValueInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ValueBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_VALUE_INFO (info), -1); + + blob = (ValueBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->unsigned_value) + return (gint64)(guint32)blob->value; + else + return (gint64)blob->value; +} + +void +gi_value_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_VALUE; +} diff --git a/girepository/gienuminfo.h b/girepository/gienuminfo.h new file mode 100644 index 0000000..c1427b5 --- /dev/null +++ b/girepository/gienuminfo.h @@ -0,0 +1,83 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Enum and Enum values + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_ENUM_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.EnumInfo]. + * + * Since: 2.80 + */ +#define GI_IS_ENUM_INFO(info) \ + ((gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_ENUM) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_FLAGS)) + +/** + * GI_IS_VALUE_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.ValueInfo]. + * + * Since: 2.80 + */ +#define GI_IS_VALUE_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_VALUE) + + +GI_AVAILABLE_IN_ALL +guint gi_enum_info_get_n_values (GIEnumInfo *info); + +GI_AVAILABLE_IN_ALL +GIValueInfo * gi_enum_info_get_value (GIEnumInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_enum_info_get_n_methods (GIEnumInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_enum_info_get_method (GIEnumInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GITypeTag gi_enum_info_get_storage_type (GIEnumInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_enum_info_get_error_domain (GIEnumInfo *info); + + +GI_AVAILABLE_IN_ALL +gint64 gi_value_info_get_value (GIValueInfo *info); + +G_END_DECLS diff --git a/girepository/gifieldinfo.c b/girepository/gifieldinfo.c new file mode 100644 index 0000000..6943332 --- /dev/null +++ b/girepository/gifieldinfo.c @@ -0,0 +1,579 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Field implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "config.h" +#include "gifieldinfo.h" + +/** + * GIFieldInfo: + * + * A `GIFieldInfo` struct represents a field of a struct, union, or object. + * + * The `GIFieldInfo` is fetched by calling + * [method@GIRepository.StructInfo.get_field], + * [method@GIRepository.UnionInfo.get_field] or + * [method@GIRepository.ObjectInfo.get_field]. + * + * A field has a size, type and a struct offset associated and a set of flags, + * which are currently `GI_FIELD_IS_READABLE` or `GI_FIELD_IS_WRITABLE`. + * + * See also: [type@GIRepository.StructInfo], [type@GIRepository.UnionInfo], + * [type@GIRepository.ObjectInfo] + * + * Since: 2.80 + */ + +/** + * gi_field_info_get_flags: + * @info: a #GIFieldInfo + * + * Obtain the flags for this `GIFieldInfo`. See + * [flags@GIRepository.FieldInfoFlags] for possible flag values. + * + * Returns: the flags + * Since: 2.80 + */ +GIFieldInfoFlags +gi_field_info_get_flags (GIFieldInfo *info) +{ + GIFieldInfoFlags flags; + GIRealInfo *rinfo = (GIRealInfo *)info; + FieldBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); + + blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; + + flags = 0; + + if (blob->readable) + flags = flags | GI_FIELD_IS_READABLE; + + if (blob->writable) + flags = flags | GI_FIELD_IS_WRITABLE; + + return flags; +} + +/** + * gi_field_info_get_size: + * @info: a #GIFieldInfo + * + * Obtain the size of the field member, in bits. This is how + * much space you need to allocate to store the field. + * + * Returns: the field size, in bits + * Since: 2.80 + */ +gsize +gi_field_info_get_size (GIFieldInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + FieldBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); + + blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->bits; +} + +/** + * gi_field_info_get_offset: + * @info: a #GIFieldInfo + * + * Obtain the offset of the field member, in bytes. This is relative + * to the beginning of the struct or union. + * + * Returns: the field offset, in bytes + * Since: 2.80 + */ +gsize +gi_field_info_get_offset (GIFieldInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + FieldBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_FIELD_INFO (info), 0); + + blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->struct_offset; +} + +/** + * gi_field_info_get_type_info: + * @info: a #GIFieldInfo + * + * Obtain the type of a field as a [type@GIRepository.TypeInfo]. + * + * Returns: (transfer full): the [type@GIRepository.TypeInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GITypeInfo * +gi_field_info_get_type_info (GIFieldInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + FieldBlob *blob; + GIRealInfo *type_info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_FIELD_INFO (info), NULL); + + blob = (FieldBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->has_embedded_type) + { + type_info = (GIRealInfo *) gi_info_new (GI_INFO_TYPE_TYPE, + (GIBaseInfo*)info, rinfo->typelib, + rinfo->offset + header->field_blob_size); + type_info->type_is_embedded = TRUE; + } + else + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + G_STRUCT_OFFSET (FieldBlob, type)); + + return (GITypeInfo *) type_info; +} + +/** + * gi_field_info_get_field: (skip) + * @field_info: a #GIFieldInfo + * @mem: pointer to a block of memory representing a C structure or union + * @value: a [type@GIRepository.Argument] into which to store the value retrieved + * + * Reads a field identified by a `GIFieldInfo` from a C structure or + * union. + * + * This only handles fields of simple C types. It will fail for a field of a + * composite type like a nested structure or union even if that is actually + * readable. + * + * Returns: `TRUE` if reading the field succeeded, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_field_info_get_field (GIFieldInfo *field_info, + gpointer mem, + GIArgument *value) +{ + int offset; + GITypeInfo *type_info; + gboolean result = FALSE; + + g_return_val_if_fail (field_info != NULL, FALSE); + g_return_val_if_fail (GI_IS_FIELD_INFO (field_info), FALSE); + + if ((gi_field_info_get_flags (field_info) & GI_FIELD_IS_READABLE) == 0) + return FALSE; + + offset = gi_field_info_get_offset (field_info); + type_info = gi_field_info_get_type_info (field_info); + + if (gi_type_info_is_pointer (type_info)) + { + value->v_pointer = G_STRUCT_MEMBER (gpointer, mem, offset); + result = TRUE; + } + else + { + switch (gi_type_info_get_tag (type_info)) + { + case GI_TYPE_TAG_VOID: + g_warning("Field %s: should not be have void type", + gi_base_info_get_name ((GIBaseInfo *)field_info)); + break; + case GI_TYPE_TAG_BOOLEAN: + value->v_boolean = G_STRUCT_MEMBER (gboolean, mem, offset) != FALSE; + result = TRUE; + break; + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + value->v_uint8 = G_STRUCT_MEMBER (guint8, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + value->v_uint16 = G_STRUCT_MEMBER (guint16, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UNICHAR: + value->v_uint32 = G_STRUCT_MEMBER (guint32, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + value->v_uint64 = G_STRUCT_MEMBER (guint64, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_GTYPE: + value->v_size = G_STRUCT_MEMBER (gsize, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_FLOAT: + value->v_float = G_STRUCT_MEMBER (gfloat, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_DOUBLE: + value->v_double = G_STRUCT_MEMBER (gdouble, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_ARRAY: + /* We don't check the array type and that it is fixed-size, + we trust g-ir-compiler to do the right thing */ + value->v_pointer = G_STRUCT_MEMBER_P (mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + g_warning("Field %s: type %s should have is_pointer set", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_type_tag_to_string (gi_type_info_get_tag (type_info))); + break; + case GI_TYPE_TAG_ERROR: + /* Needs to be handled by the language binding directly */ + break; + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *interface = gi_type_info_get_interface (type_info); + switch (gi_base_info_get_info_type (interface)) + { + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_UNION: + case GI_INFO_TYPE_BOXED: + /* Needs to be handled by the language binding directly */ + break; + case GI_INFO_TYPE_OBJECT: + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + /* FIXME: there's a mismatch here between the value->v_int we use + * here and the gint64 result returned from gi_value_info_get_value(). + * But to switch this to gint64, we'd have to make gi_function_info_invoke() + * translate value->v_int64 to the proper ABI for an enum function + * call parameter, which will usually be int, and then fix up language + * bindings. + */ + GITypeTag storage_type = gi_enum_info_get_storage_type ((GIEnumInfo *)interface); + switch (storage_type) + { + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + value->v_int = (gint)G_STRUCT_MEMBER (guint8, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + value->v_int = (gint)G_STRUCT_MEMBER (guint16, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + value->v_int = (gint)G_STRUCT_MEMBER (guint32, mem, offset); + result = TRUE; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + value->v_int = (gint)G_STRUCT_MEMBER (guint64, mem, offset); + result = TRUE; + break; + default: + g_warning("Field %s: Unexpected enum storage type %s", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_type_tag_to_string (storage_type)); + break; + } + break; + } + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_CALLBACK: + g_warning("Field %s: Interface type %d should have is_pointer set", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_base_info_get_info_type (interface)); + break; + case GI_INFO_TYPE_INVALID: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_INVALID_0: + case GI_INFO_TYPE_VALUE: + case GI_INFO_TYPE_SIGNAL: + case GI_INFO_TYPE_PROPERTY: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + case GI_INFO_TYPE_UNRESOLVED: + g_warning("Field %s: Interface type %d not expected", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_base_info_get_info_type (interface)); + break; + default: + break; + } + + gi_base_info_unref ((GIBaseInfo *)interface); + break; + } + break; + default: + break; + } + } + + gi_base_info_unref ((GIBaseInfo *)type_info); + + return result; +} + +/** + * gi_field_info_set_field: (skip) + * @field_info: a #GIFieldInfo + * @mem: pointer to a block of memory representing a C structure or union + * @value: a [type@GIRepository.Argument] holding the value to store + * + * Writes a field identified by a `GIFieldInfo` to a C structure or + * union. + * + * This only handles fields of simple C types. It will fail for a field of a + * composite type like a nested structure or union even if that is actually + * writable. Note also that that it will refuse to write fields where memory + * management would by required. A field with a type such as `char *` must be + * set with a setter function. + * + * Returns: `TRUE` if writing the field succeeded, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_field_info_set_field (GIFieldInfo *field_info, + gpointer mem, + const GIArgument *value) +{ + int offset; + GITypeInfo *type_info; + gboolean result = FALSE; + + g_return_val_if_fail (field_info != NULL, FALSE); + g_return_val_if_fail (GI_IS_FIELD_INFO (field_info), FALSE); + + if ((gi_field_info_get_flags (field_info) & GI_FIELD_IS_WRITABLE) == 0) + return FALSE; + + offset = gi_field_info_get_offset (field_info); + type_info = gi_field_info_get_type_info (field_info); + + if (!gi_type_info_is_pointer (type_info)) + { + switch (gi_type_info_get_tag (type_info)) + { + case GI_TYPE_TAG_VOID: + g_warning("Field %s: should not be have void type", + gi_base_info_get_name ((GIBaseInfo *)field_info)); + break; + case GI_TYPE_TAG_BOOLEAN: + G_STRUCT_MEMBER (gboolean, mem, offset) = value->v_boolean != FALSE; + result = TRUE; + break; + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + G_STRUCT_MEMBER (guint8, mem, offset) = value->v_uint8; + result = TRUE; + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + G_STRUCT_MEMBER (guint16, mem, offset) = value->v_uint16; + result = TRUE; + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UNICHAR: + G_STRUCT_MEMBER (guint32, mem, offset) = value->v_uint32; + result = TRUE; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + G_STRUCT_MEMBER (guint64, mem, offset) = value->v_uint64; + result = TRUE; + break; + case GI_TYPE_TAG_GTYPE: + G_STRUCT_MEMBER (gsize, mem, offset) = value->v_size; + result = TRUE; + break; + case GI_TYPE_TAG_FLOAT: + G_STRUCT_MEMBER (gfloat, mem, offset) = value->v_float; + result = TRUE; + break; + case GI_TYPE_TAG_DOUBLE: + G_STRUCT_MEMBER (gdouble, mem, offset)= value->v_double; + result = TRUE; + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + g_warning("Field %s: type %s should have is_pointer set", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_type_tag_to_string (gi_type_info_get_tag (type_info))); + break; + case GI_TYPE_TAG_ERROR: + /* Needs to be handled by the language binding directly */ + break; + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *interface = gi_type_info_get_interface (type_info); + switch (gi_base_info_get_info_type (interface)) + { + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_UNION: + case GI_INFO_TYPE_BOXED: + /* Needs to be handled by the language binding directly */ + break; + case GI_INFO_TYPE_OBJECT: + break; + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + { + /* See FIXME above + */ + GITypeTag storage_type = gi_enum_info_get_storage_type ((GIEnumInfo *)interface); + switch (storage_type) + { + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + G_STRUCT_MEMBER (guint8, mem, offset) = (guint8)value->v_int; + result = TRUE; + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + G_STRUCT_MEMBER (guint16, mem, offset) = (guint16)value->v_int; + result = TRUE; + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + G_STRUCT_MEMBER (guint32, mem, offset) = (guint32)value->v_int; + result = TRUE; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + G_STRUCT_MEMBER (guint64, mem, offset) = (guint64)value->v_int; + result = TRUE; + break; + default: + g_warning("Field %s: Unexpected enum storage type %s", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_type_tag_to_string (storage_type)); + break; + } + break; + } + break; + case GI_INFO_TYPE_VFUNC: + case GI_INFO_TYPE_CALLBACK: + g_warning("Field%s: Interface type %d should have is_pointer set", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_base_info_get_info_type (interface)); + break; + case GI_INFO_TYPE_INVALID: + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_FUNCTION: + case GI_INFO_TYPE_CONSTANT: + case GI_INFO_TYPE_INVALID_0: + case GI_INFO_TYPE_VALUE: + case GI_INFO_TYPE_SIGNAL: + case GI_INFO_TYPE_PROPERTY: + case GI_INFO_TYPE_FIELD: + case GI_INFO_TYPE_ARG: + case GI_INFO_TYPE_TYPE: + case GI_INFO_TYPE_UNRESOLVED: + g_warning("Field %s: Interface type %d not expected", + gi_base_info_get_name ((GIBaseInfo *)field_info), + gi_base_info_get_info_type (interface)); + break; + default: + break; + } + + gi_base_info_unref ((GIBaseInfo *)interface); + break; + } + break; + default: + break; + } + } else { + switch (gi_type_info_get_tag (type_info)) + { + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *interface = gi_type_info_get_interface (type_info); + switch (gi_base_info_get_info_type (interface)) + { + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + G_STRUCT_MEMBER (gpointer, mem, offset) = (gpointer)value->v_pointer; + result = TRUE; + break; + default: + break; + } + gi_base_info_unref ((GIBaseInfo *)interface); + } + break; + default: + break; + } + } + + gi_base_info_unref ((GIBaseInfo *)type_info); + + return result; +} + +void +gi_field_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_FIELD; +} diff --git a/girepository/gifieldinfo.h b/girepository/gifieldinfo.h new file mode 100644 index 0000000..2227512 --- /dev/null +++ b/girepository/gifieldinfo.h @@ -0,0 +1,69 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Field and Field values + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_FIELD_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.FieldInfo]. + * + * Since: 2.80 + */ +#define GI_IS_FIELD_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_FIELD) + + +GI_AVAILABLE_IN_ALL +GIFieldInfoFlags gi_field_info_get_flags (GIFieldInfo *info); + +GI_AVAILABLE_IN_ALL +gsize gi_field_info_get_size (GIFieldInfo *info); + +GI_AVAILABLE_IN_ALL +gsize gi_field_info_get_offset (GIFieldInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_field_info_get_type_info (GIFieldInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_field_info_get_field (GIFieldInfo *field_info, + gpointer mem, + GIArgument *value); + +GI_AVAILABLE_IN_ALL +gboolean gi_field_info_set_field (GIFieldInfo *field_info, + gpointer mem, + const GIArgument *value); + +G_END_DECLS diff --git a/girepository/gifunctioninfo.c b/girepository/gifunctioninfo.c new file mode 100644 index 0000000..1ad43d0 --- /dev/null +++ b/girepository/gifunctioninfo.c @@ -0,0 +1,316 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Function implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gifunctioninfo.h" + +/** + * GIFunctionInfo: + * + * `GIFunctionInfo` represents a function, method or constructor. + * + * To find out what kind of entity a `GIFunctionInfo` represents, call + * [method@GIRepository.FunctionInfo.get_flags]. + * + * See also [class@GIRepository.CallableInfo] for information on how to retrieve + * arguments and other metadata. + * + * Since: 2.80 + */ + +GIFunctionInfo * +gi_base_info_find_method (GIBaseInfo *base, + guint32 offset, + guint n_methods, + const gchar *name) +{ + /* FIXME hash */ + GIRealInfo *rinfo = (GIRealInfo*)base; + Header *header = (Header *)rinfo->typelib->data; + + for (guint i = 0; i < n_methods; i++) + { + FunctionBlob *fblob = (FunctionBlob *)&rinfo->typelib->data[offset]; + const gchar *fname = (const gchar *)&rinfo->typelib->data[fblob->name]; + + if (strcmp (name, fname) == 0) + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, base, + rinfo->typelib, offset); + + offset += header->function_blob_size; + } + + return NULL; +} + +/** + * gi_function_info_get_symbol: + * @info: a #GIFunctionInfo + * + * Obtain the symbol of the function. + * + * The symbol is the name of the exported function, suitable to be used as an + * argument to [method@GModule.Module.symbol]. + * + * Returns: the symbol + * Since: 2.80 + */ +const gchar * +gi_function_info_get_symbol (GIFunctionInfo *info) +{ + GIRealInfo *rinfo; + FunctionBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_FUNCTION_INFO (info), NULL); + + rinfo = (GIRealInfo *)info; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->symbol); +} + +/** + * gi_function_info_get_flags: + * @info: a #GIFunctionInfo + * + * Obtain the [type@GIRepository.FunctionInfoFlags] for the @info. + * + * Returns: the flags + * Since: 2.80 + */ +GIFunctionInfoFlags +gi_function_info_get_flags (GIFunctionInfo *info) +{ + GIFunctionInfoFlags flags; + GIRealInfo *rinfo; + FunctionBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_FUNCTION_INFO (info), -1); + + rinfo = (GIRealInfo *)info; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + + flags = 0; + + /* Make sure we don't flag Constructors as methods */ + if (!blob->constructor && !blob->is_static) + flags = flags | GI_FUNCTION_IS_METHOD; + + if (blob->constructor) + flags = flags | GI_FUNCTION_IS_CONSTRUCTOR; + + if (blob->getter) + flags = flags | GI_FUNCTION_IS_GETTER; + + if (blob->setter) + flags = flags | GI_FUNCTION_IS_SETTER; + + if (blob->wraps_vfunc) + flags = flags | GI_FUNCTION_WRAPS_VFUNC; + + if (blob->throws) + flags = flags | GI_FUNCTION_THROWS; + + return flags; +} + +/** + * gi_function_info_get_property: + * @info: a #GIFunctionInfo + * + * Obtain the property associated with this `GIFunctionInfo`. + * + * Only `GIFunctionInfo`s with the flag `GI_FUNCTION_IS_GETTER` or + * `GI_FUNCTION_IS_SETTER` have a property set. For other cases, + * `NULL` will be returned. + * + * Returns: (transfer full) (nullable): The property or `NULL` if not set. Free + * it with [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIPropertyInfo * +gi_function_info_get_property (GIFunctionInfo *info) +{ + GIRealInfo *rinfo; + FunctionBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_FUNCTION_INFO (info), NULL); + + rinfo = (GIRealInfo *)info; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (gi_base_info_get_info_type ((GIBaseInfo *) rinfo->container) == GI_INFO_TYPE_INTERFACE) + { + GIInterfaceInfo *container = (GIInterfaceInfo *)rinfo->container; + + return gi_interface_info_get_property (container, blob->index); + } + else if (gi_base_info_get_info_type ((GIBaseInfo *) rinfo->container) == GI_INFO_TYPE_OBJECT) + { + GIObjectInfo *container = (GIObjectInfo *)rinfo->container; + + return gi_object_info_get_property (container, blob->index); + } + else + return NULL; +} + +/** + * gi_function_info_get_vfunc: + * @info: a #GIFunctionInfo + * + * Obtain the virtual function associated with this `GIFunctionInfo`. + * + * Only `GIFunctionInfo`s with the flag `GI_FUNCTION_WRAPS_VFUNC` have + * a virtual function set. For other cases, `NULL` will be returned. + * + * Returns: (transfer full) (nullable): The virtual function or `NULL` if not + * set. Free it by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_function_info_get_vfunc (GIFunctionInfo *info) +{ + GIRealInfo *rinfo; + FunctionBlob *blob; + GIInterfaceInfo *container; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_FUNCTION_INFO (info), NULL); + + rinfo = (GIRealInfo *)info; + blob = (FunctionBlob *)&rinfo->typelib->data[rinfo->offset]; + container = (GIInterfaceInfo *)rinfo->container; + + return gi_interface_info_get_vfunc (container, blob->index); +} + +/** + * gi_invoke_error_quark: + * + * Get the error quark which represents [type@GIRepository.InvokeError]. + * + * Returns: error quark + * Since: 2.80 + */ +GQuark +gi_invoke_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("gi-invoke-error-quark"); + return quark; +} + +/** + * gi_function_info_invoke: (skip) + * @info: a #GIFunctionInfo describing the function to invoke + * @in_args: (array length=n_in_args) (nullable): An array of + * [type@GIRepository.Argument]s, one for each ‘in’ parameter of @info. If + * there are no ‘in’ parameters, @in_args can be `NULL`. + * @n_in_args: the length of the @in_args array + * @out_args: (array length=n_out_args) (nullable): An array of + * [type@GIRepository.Argument]s, one for each ‘out’ parameter of @info. If + * there are no ‘out’ parameters, @out_args may be `NULL`. + * @n_out_args: the length of the @out_args array + * @return_value: (out caller-allocates) (not optional): return location for the + * return value of the function. + * @error: return location for detailed error information, or `NULL` + * + * Invokes the function described in @info with the given + * arguments. + * + * Note that ‘inout’ parameters must appear in both argument lists. This + * function uses [`dlsym()`](man:dlsym(3)) to obtain a pointer to the function, + * so the library or shared object containing the described function must either + * be linked to the caller, or must have been loaded with + * [method@GModule.Module.symbol] before calling this function. + * + * Returns: `TRUE` if the function has been invoked, `FALSE` if an + * error occurred. + * Since: 2.80 + */ +gboolean +gi_function_info_invoke (GIFunctionInfo *info, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + GError **error) +{ + const gchar *symbol; + gpointer func; + gboolean is_method; + gboolean throws; + + symbol = gi_function_info_get_symbol (info); + + if (!gi_typelib_symbol (gi_base_info_get_typelib ((GIBaseInfo *) info), + symbol, &func)) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Could not locate %s: %s", symbol, g_module_error ()); + + return FALSE; + } + + is_method = (gi_function_info_get_flags (info) & GI_FUNCTION_IS_METHOD) != 0 + && (gi_function_info_get_flags (info) & GI_FUNCTION_IS_CONSTRUCTOR) == 0; + throws = gi_function_info_get_flags (info) & GI_FUNCTION_THROWS; + + return gi_callable_info_invoke ((GICallableInfo*) info, + func, + in_args, + n_in_args, + out_args, + n_out_args, + return_value, + is_method, + throws, + error); +} + +void +gi_function_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_FUNCTION; +} diff --git a/girepository/gifunctioninfo.h b/girepository/gifunctioninfo.h new file mode 100644 index 0000000..d0ab0ec --- /dev/null +++ b/girepository/gifunctioninfo.h @@ -0,0 +1,102 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Function + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_FUNCTION_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.FunctionInfo]. + * + * Since: 2.80 + */ +#define GI_IS_FUNCTION_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_FUNCTION) + + +GI_AVAILABLE_IN_ALL +const gchar * gi_function_info_get_symbol (GIFunctionInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfoFlags gi_function_info_get_flags (GIFunctionInfo *info); + +GI_AVAILABLE_IN_ALL +GIPropertyInfo * gi_function_info_get_property (GIFunctionInfo *info); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_function_info_get_vfunc (GIFunctionInfo *info); + +/** + * GI_INVOKE_ERROR: + * + * Type quark function for [enum@GIRepository.InvokeError]. + * + * Since: 2.80 + */ +#define GI_INVOKE_ERROR (gi_invoke_error_quark ()) + +GI_AVAILABLE_IN_ALL +GQuark gi_invoke_error_quark (void); + +/** + * GIInvokeError: + * @GI_INVOKE_ERROR_FAILED: invocation failed, unknown error. + * @GI_INVOKE_ERROR_SYMBOL_NOT_FOUND: symbol couldn’t be found in any of the + * libraries associated with the typelib of the function. + * @GI_INVOKE_ERROR_ARGUMENT_MISMATCH: the arguments provided didn’t match + * the expected arguments for the function’s type signature. + * + * An error occurring while invoking a function via + * [method@GIRepository.FunctionInfo.invoke]. + * + * Since: 2.80 + */ +typedef enum +{ + GI_INVOKE_ERROR_FAILED, + GI_INVOKE_ERROR_SYMBOL_NOT_FOUND, + GI_INVOKE_ERROR_ARGUMENT_MISMATCH +} GIInvokeError; + + +GI_AVAILABLE_IN_ALL +gboolean gi_function_info_invoke (GIFunctionInfo *info, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + GError **error); + + +G_END_DECLS diff --git a/girepository/giinterfaceinfo.c b/girepository/giinterfaceinfo.c new file mode 100644 index 0000000..61a1a84 --- /dev/null +++ b/girepository/giinterfaceinfo.c @@ -0,0 +1,536 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Interface implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giinterfaceinfo.h" + +/** + * GIInterfaceInfo: + * + * `GIInterfaceInfo` represents a `GInterface` type. + * + * A `GInterface` has methods, fields, properties, signals, + * interfaces, constants, virtual functions and prerequisites. + * + * Since: 2.80 + */ + +/** + * gi_interface_info_get_n_prerequisites: + * @info: a #GIInterfaceInfo + * + * Obtain the number of prerequisites for this interface type. + * + * A prerequisite is another interface that needs to be implemented for + * interface, similar to a base class for [class@GObject.Object]s. + * + * Returns: number of prerequisites + * Since: 2.80 + */ +guint +gi_interface_info_get_n_prerequisites (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_prerequisites; +} + +/** + * gi_interface_info_get_prerequisite: + * @info: a #GIInterfaceInfo + * @n: index of prerequisite to get + * + * Obtain an interface type’s prerequisite at index @n. + * + * Returns: (transfer full): The prerequisite as a [class@GIRepository.BaseInfo]. + * Free the struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIBaseInfo * +gi_interface_info_get_prerequisite (GIInterfaceInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_info_from_entry (rinfo->repository, + rinfo->typelib, blob->prerequisites[n]); +} + + +/** + * gi_interface_info_get_n_properties: + * @info: a #GIInterfaceInfo + * + * Obtain the number of properties that this interface type has. + * + * Returns: number of properties + * Since: 2.80 + */ +guint +gi_interface_info_get_n_properties (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_properties; +} + +/** + * gi_interface_info_get_property: + * @info: a #GIInterfaceInfo + * @n: index of property to get + * + * Obtain an interface type property at index @n. + * + * Returns: (transfer full): The [class@GIRepository.PropertyInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIPropertyInfo * +gi_interface_info_get_property (GIInterfaceInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + n * header->property_blob_size; + + return (GIPropertyInfo *) gi_info_new (GI_INFO_TYPE_PROPERTY, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_interface_info_get_n_methods: + * @info: a #GIInterfaceInfo + * + * Obtain the number of methods that this interface type has. + * + * Returns: number of methods + * Since: 2.80 + */ +guint +gi_interface_info_get_n_methods (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_methods; +} + +/** + * gi_interface_info_get_method: + * @info: a #GIInterfaceInfo + * @n: index of method to get + * + * Obtain an interface type method at index @n. + * + * Returns: (transfer full): The [class@GIRepository.FunctionInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_interface_info_get_method (GIInterfaceInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_interface_info_find_method: + * @info: a #GIInterfaceInfo + * @name: name of method to obtain + * + * Obtain a method of the interface type given a @name. + * + * `NULL` will be returned if there’s no method available with that name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.FunctionInfo] or + * `NULL` if none found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_interface_info_find_method (GIInterfaceInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + InterfaceBlob *blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size; + + return gi_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_methods, name); +} + +/** + * gi_interface_info_get_n_signals: + * @info: a #GIInterfaceInfo + * + * Obtain the number of signals that this interface type has. + * + * Returns: number of signals + * Since: 2.80 + */ +guint +gi_interface_info_get_n_signals (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_signals; +} + +/** + * gi_interface_info_get_signal: + * @info: a #GIInterfaceInfo + * @n: index of signal to get + * + * Obtain an interface type signal at index @n. + * + * Returns: (transfer full): The [class@GIRepository.SignalInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GISignalInfo * +gi_interface_info_get_signal (GIInterfaceInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + n * header->signal_blob_size; + + return (GISignalInfo *) gi_info_new (GI_INFO_TYPE_SIGNAL, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_interface_info_find_signal: + * @info: a #GIInterfaceInfo + * @name: name of signal to find + * + * Obtain a signal of the interface type given a @name. + * + * `NULL` will be returned if there’s no signal available with that name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.SignalInfo] or + * `NULL` if none found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GISignalInfo * +gi_interface_info_find_signal (GIInterfaceInfo *info, + const gchar *name) +{ + guint n_signals; + + n_signals = gi_interface_info_get_n_signals (info); + for (guint i = 0; i < n_signals; i++) + { + GISignalInfo *siginfo = gi_interface_info_get_signal (info, i); + + if (g_strcmp0 (gi_base_info_get_name ((GIBaseInfo *) siginfo), name) != 0) + { + gi_base_info_unref ((GIBaseInfo*)siginfo); + continue; + } + + return siginfo; + } + return NULL; +} + +/** + * gi_interface_info_get_n_vfuncs: + * @info: a #GIInterfaceInfo + * + * Obtain the number of virtual functions that this interface type has. + * + * Returns: number of virtual functions + * Since: 2.80 + */ +guint +gi_interface_info_get_n_vfuncs (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_vfuncs; +} + +/** + * gi_interface_info_get_vfunc: + * @info: a #GIInterfaceInfo + * @n: index of virtual function to get + * + * Obtain an interface type virtual function at index @n. + * + * Returns: (transfer full): the [class@GIRepository.VFuncInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_interface_info_get_vfunc (GIInterfaceInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + n * header->vfunc_blob_size; + + return (GIVFuncInfo *) gi_info_new (GI_INFO_TYPE_VFUNC, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_interface_info_find_vfunc: + * @info: a #GIInterfaceInfo + * @name: The name of a virtual function to find. + * + * Locate a virtual function slot with name @name. + * + * See the documentation for [method@GIRepository.ObjectInfo.find_vfunc] for + * more information on virtuals. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.VFuncInfo], or + * `NULL` if none found. Free it with [method@GIRepository.BaseInfo.unref] + * when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_interface_info_find_vfunc (GIInterfaceInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size; + + return gi_base_info_find_vfunc (rinfo, offset, blob->n_vfuncs, name); +} + +/** + * gi_interface_info_get_n_constants: + * @info: a #GIInterfaceInfo + * + * Obtain the number of constants that this interface type has. + * + * Returns: number of constants + * Since: 2.80 + */ +guint +gi_interface_info_get_n_constants (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), 0); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_constants; +} + +/** + * gi_interface_info_get_constant: + * @info: a #GIInterfaceInfo + * @n: index of constant to get + * + * Obtain an interface type constant at index @n. + * + * Returns: (transfer full): The [class@GIRepository.ConstantInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIConstantInfo * +gi_interface_info_get_constant (GIInterfaceInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->interface_blob_size + + (blob->n_prerequisites + (blob->n_prerequisites % 2)) * 2 + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + blob->n_vfuncs * header->vfunc_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) gi_info_new (GI_INFO_TYPE_CONSTANT, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_interface_info_get_iface_struct: + * @info: a #GIInterfaceInfo + * + * Returns the layout C structure associated with this `GInterface`. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.StructInfo] or + * `NULL` if unknown. Free it with [method@GIRepository.BaseInfo.unref] when + * done. + * Since: 2.80 + */ +GIStructInfo * +gi_interface_info_get_iface_struct (GIInterfaceInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + InterfaceBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_INTERFACE_INFO (info), NULL); + + blob = (InterfaceBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->gtype_struct) + return (GIStructInfo *) gi_info_from_entry (rinfo->repository, + rinfo->typelib, blob->gtype_struct); + else + return NULL; +} + +void +gi_interface_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_INTERFACE; +} diff --git a/girepository/giinterfaceinfo.h b/girepository/giinterfaceinfo.h new file mode 100644 index 0000000..80cd018 --- /dev/null +++ b/girepository/giinterfaceinfo.h @@ -0,0 +1,105 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Interface + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_INTERFACE_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.InterfaceInfo]. + * + * Since: 2.80 + */ +#define GI_IS_INTERFACE_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_INTERFACE) + + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_prerequisites (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_interface_info_get_prerequisite (GIInterfaceInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_properties (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GIPropertyInfo * gi_interface_info_get_property (GIInterfaceInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_methods (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_interface_info_get_method (GIInterfaceInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_interface_info_find_method (GIInterfaceInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_signals (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GISignalInfo * gi_interface_info_get_signal (GIInterfaceInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GISignalInfo * gi_interface_info_find_signal (GIInterfaceInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_vfuncs (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_interface_info_get_vfunc (GIInterfaceInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_interface_info_find_vfunc (GIInterfaceInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +guint gi_interface_info_get_n_constants (GIInterfaceInfo *info); + +GI_AVAILABLE_IN_ALL +GIConstantInfo * gi_interface_info_get_constant (GIInterfaceInfo *info, + guint n); + + +GI_AVAILABLE_IN_ALL +GIStructInfo * gi_interface_info_get_iface_struct (GIInterfaceInfo *info); + +G_END_DECLS diff --git a/girepository/ginvoke.c b/girepository/ginvoke.c new file mode 100644 index 0000000..21fabe5 --- /dev/null +++ b/girepository/ginvoke.c @@ -0,0 +1,335 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Invoke functionality + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include + +#include +#include "girffi.h" + +/** + * value_to_ffi_type: + * @gvalue: (transfer none): a [type@GObject.Value] to convert + * @value: (out caller-allocates): return location for the ffi data + * + * Convert @gvalue to a format suitable for passing to ffi. + * + * @value is only valid as long as @gvalue is alive. + * + * Returns: pointer to the `ffi_type` associated with @value + * Since: 2.80 + */ +static ffi_type * +value_to_ffi_type (const GValue *gvalue, gpointer *value) +{ + ffi_type *rettype = NULL; + GType type = g_type_fundamental (G_VALUE_TYPE (gvalue)); + g_assert (type != G_TYPE_INVALID); + + switch (type) + { + case G_TYPE_BOOLEAN: + case G_TYPE_CHAR: + case G_TYPE_INT: + rettype = &ffi_type_sint; + *value = (gpointer)&(gvalue->data[0].v_int); + break; + case G_TYPE_UCHAR: + case G_TYPE_UINT: + rettype = &ffi_type_uint; + *value = (gpointer)&(gvalue->data[0].v_uint); + break; + case G_TYPE_STRING: + case G_TYPE_OBJECT: + case G_TYPE_BOXED: + case G_TYPE_POINTER: + case G_TYPE_PARAM: + rettype = &ffi_type_pointer; + *value = (gpointer)&(gvalue->data[0].v_pointer); + break; + case G_TYPE_FLOAT: + rettype = &ffi_type_float; + *value = (gpointer)&(gvalue->data[0].v_float); + break; + case G_TYPE_DOUBLE: + rettype = &ffi_type_double; + *value = (gpointer)&(gvalue->data[0].v_double); + break; + case G_TYPE_LONG: + rettype = &ffi_type_slong; + *value = (gpointer)&(gvalue->data[0].v_long); + break; + case G_TYPE_ULONG: + rettype = &ffi_type_ulong; + *value = (gpointer)&(gvalue->data[0].v_ulong); + break; + case G_TYPE_INT64: + rettype = &ffi_type_sint64; + *value = (gpointer)&(gvalue->data[0].v_int64); + break; + case G_TYPE_UINT64: + rettype = &ffi_type_uint64; + *value = (gpointer)&(gvalue->data[0].v_uint64); + break; + default: + rettype = &ffi_type_pointer; + *value = NULL; + g_warning ("Unsupported fundamental type: %s", g_type_name (type)); + break; + } + return rettype; +} + +/** + * g_value_to_ffi_return_type: + * @gvalue: (transfer none): a [type@GObject.Value] to convert + * @ffi_value: (transfer none): a [type@GIRepository.Argument] containing the + * data to use + * @value: (out caller-allocates): return location for the ffi data + * + * Convert @ffi_value to a format suitable for passing to ffi, using the type + * data from @gvalue. + * + * @value is only valid as long as @gvalue and @ffi_value are alive. + * + * Returns: pointer to the `ffi_type` associated with @value + * Since: 2.80 + */ +static ffi_type * +g_value_to_ffi_return_type (const GValue *gvalue, + const GIArgument *ffi_value, + gpointer *value) +{ + ffi_type *rettype = NULL; + GType type = g_type_fundamental (G_VALUE_TYPE (gvalue)); + g_assert (type != G_TYPE_INVALID); + + *value = (gpointer)&(ffi_value->v_long); + + switch (type) { + case G_TYPE_CHAR: + rettype = &ffi_type_sint8; + break; + case G_TYPE_UCHAR: + rettype = &ffi_type_uint8; + break; + case G_TYPE_BOOLEAN: + case G_TYPE_INT: + rettype = &ffi_type_sint; + break; + case G_TYPE_UINT: + rettype = &ffi_type_uint; + break; + case G_TYPE_STRING: + case G_TYPE_OBJECT: + case G_TYPE_BOXED: + case G_TYPE_POINTER: + case G_TYPE_PARAM: + rettype = &ffi_type_pointer; + break; + case G_TYPE_FLOAT: + rettype = &ffi_type_float; + *value = (gpointer)&(ffi_value->v_float); + break; + case G_TYPE_DOUBLE: + rettype = &ffi_type_double; + *value = (gpointer)&(ffi_value->v_double); + break; + case G_TYPE_LONG: + rettype = &ffi_type_slong; + break; + case G_TYPE_ULONG: + rettype = &ffi_type_ulong; + break; + case G_TYPE_INT64: + rettype = &ffi_type_sint64; + *value = (gpointer)&(ffi_value->v_int64); + break; + case G_TYPE_UINT64: + rettype = &ffi_type_uint64; + *value = (gpointer)&(ffi_value->v_uint64); + break; + default: + rettype = &ffi_type_pointer; + *value = NULL; + g_warning ("Unsupported fundamental type: %s", g_type_name (type)); + break; + } + return rettype; +} + +/** + * g_value_from_ffi_value: + * @gvalue: (inout): a [type@GObject.Value] to set + * @value: (transfer none): ffi data to convert + * + * Convert @value to a [type@GObject.Value] according to the type already set + * on @gvalue. + * + * @gvalue is valid even after @value is finalised. + * + * Since: 2.80 + */ +static void +g_value_from_ffi_value (GValue *gvalue, + const GIArgument *value) +{ + switch (g_type_fundamental (G_VALUE_TYPE (gvalue))) { + case G_TYPE_INT: + g_value_set_int (gvalue, (gint)value->v_long); + break; + case G_TYPE_FLOAT: + g_value_set_float (gvalue, (gfloat)value->v_float); + break; + case G_TYPE_DOUBLE: + g_value_set_double (gvalue, (gdouble)value->v_double); + break; + case G_TYPE_BOOLEAN: + g_value_set_boolean (gvalue, (gboolean)value->v_long); + break; + case G_TYPE_STRING: + g_value_set_string (gvalue, (gchar*)value->v_pointer); + break; + case G_TYPE_CHAR: + g_value_set_schar (gvalue, (gchar)value->v_long); + break; + case G_TYPE_UCHAR: + g_value_set_uchar (gvalue, (guchar)value->v_ulong); + break; + case G_TYPE_UINT: + g_value_set_uint (gvalue, (guint)value->v_ulong); + break; + case G_TYPE_POINTER: + g_value_set_pointer (gvalue, (gpointer)value->v_pointer); + break; + case G_TYPE_LONG: + g_value_set_long (gvalue, (glong)value->v_long); + break; + case G_TYPE_ULONG: + g_value_set_ulong (gvalue, (gulong)value->v_ulong); + break; + case G_TYPE_INT64: + g_value_set_int64 (gvalue, (gint64)value->v_int64); + break; + case G_TYPE_UINT64: + g_value_set_uint64 (gvalue, (guint64)value->v_uint64); + break; + case G_TYPE_BOXED: + g_value_set_boxed (gvalue, (gpointer)value->v_pointer); + break; + case G_TYPE_PARAM: + g_value_set_param (gvalue, (gpointer)value->v_pointer); + break; + default: + g_warning ("Unsupported fundamental type: %s", + g_type_name (g_type_fundamental (G_VALUE_TYPE (gvalue)))); + } + +} + +/** + * gi_cclosure_marshal_generic: (skip) + * @closure: a [type@GObject.Closure] + * @return_gvalue: (optional) (out caller-allocates): return location for the + * return value from the closure, or `NULL` to ignore + * @n_param_values: number of param values + * @param_values: (array length=n_param_values): values to pass to the closure + * parameters + * @invocation_hint: invocation hint + * @marshal_data: marshal data + * + * A generic C closure marshal function using ffi and + * [type@GIRepository.Argument]. + * + * Since: 2.80 + */ +void +gi_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + GIArgument return_ffi_value = { 0, }; + ffi_type *rtype; + void *rvalue; + int n_args; + ffi_type **atypes; + void **args; + int i; + ffi_cif cif; + GCClosure *cc = (GCClosure*) closure; + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + { + rtype = g_value_to_ffi_return_type (return_gvalue, &return_ffi_value, + &rvalue); + } + else + { + rtype = &ffi_type_void; + rvalue = &return_ffi_value.v_long; + } + + n_args = n_param_values + 1; + atypes = g_alloca (sizeof (ffi_type *) * n_args); + args = g_alloca (sizeof (gpointer) * n_args); + + if (n_param_values > 0) + { + if (G_CCLOSURE_SWAP_DATA (closure)) + { + atypes[n_args-1] = value_to_ffi_type (param_values + 0, + &args[n_args-1]); + atypes[0] = &ffi_type_pointer; + args[0] = &closure->data; + } + else + { + atypes[0] = value_to_ffi_type (param_values + 0, &args[0]); + atypes[n_args-1] = &ffi_type_pointer; + args[n_args-1] = &closure->data; + } + } + else + { + atypes[0] = &ffi_type_pointer; + args[0] = &closure->data; + } + + for (i = 1; i < n_args - 1; i++) + atypes[i] = value_to_ffi_type (param_values + i, &args[i]); + + if (ffi_prep_cif (&cif, FFI_DEFAULT_ABI, n_args, rtype, atypes) != FFI_OK) + return; + + ffi_call (&cif, marshal_data ? marshal_data : cc->callback, rvalue, args); + + if (return_gvalue && G_VALUE_TYPE (return_gvalue)) + g_value_from_ffi_value (return_gvalue, &return_ffi_value); +} diff --git a/girepository/giobjectinfo.c b/girepository/giobjectinfo.c new file mode 100644 index 0000000..67dffb6 --- /dev/null +++ b/girepository/giobjectinfo.c @@ -0,0 +1,1181 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Object implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giobjectinfo.h" + +/** + * GIObjectInfo: + * + * `GIObjectInfo` represents a classed type. + * + * Classed types in [type@GObject.Type] inherit from + * [type@GObject.TypeInstance]; the most common type is [class@GObject.Object]. + * + * A `GIObjectInfo` doesn’t represent a specific instance of a classed type, + * instead this represent the object type (i.e. the class). + * + * A `GIObjectInfo` has methods, fields, properties, signals, interfaces, + * constants and virtual functions. + * + * Since: 2.80 + */ + +/** + * gi_object_info_get_field_offset: + * @info: a #GIObjectInfo + * @n: index of queried field + * + * Obtain the offset of the specified field. + * + * Returns: field offset, in bytes + * Since: 2.80 + */ +static gint32 +gi_object_info_get_field_offset (GIObjectInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + ObjectBlob *blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + guint32 offset; + FieldBlob *field_blob; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2; + + for (guint i = 0; i < n; i++) + { + field_blob = (FieldBlob *)&rinfo->typelib->data[offset]; + offset += header->field_blob_size; + if (field_blob->has_embedded_type) + offset += header->callback_blob_size; + } + + return offset; +} + +/** + * gi_object_info_get_parent: + * @info: a #GIObjectInfo + * + * Obtain the parent of the object type. + * + * Returns: (transfer full) (nullable): The `GIObjectInfo`. Free the struct by + * calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIObjectInfo * +gi_object_info_get_parent (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->parent) + return (GIObjectInfo *) gi_info_from_entry (rinfo->repository, + rinfo->typelib, blob->parent); + else + return NULL; +} + +/** + * gi_object_info_get_abstract: + * @info: a #GIObjectInfo + * + * Obtain if the object type is an abstract type, i.e. if it cannot be + * instantiated. + * + * Returns: `TRUE` if the object type is abstract + * Since: 2.80 + */ +gboolean +gi_object_info_get_abstract (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), FALSE); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->abstract != 0; +} + +/** + * gi_object_info_get_final: + * @info: a #GIObjectInfo + * + * Checks whether the object type is a final type, i.e. if it cannot + * be derived. + * + * Returns: `TRUE` if the object type is final + * Since: 2.80 + */ +gboolean +gi_object_info_get_final (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *) info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), FALSE); + + blob = (ObjectBlob *) &rinfo->typelib->data[rinfo->offset]; + + return blob->final_ != 0; +} + +/** + * gi_object_info_get_fundamental: + * @info: a #GIObjectInfo + * + * Obtain if the object type is of a fundamental type which is not + * `G_TYPE_OBJECT`. + * + * This is mostly for supporting `GstMiniObject`. + * + * Returns: `TRUE` if the object type is a fundamental type + * Since: 2.80 + */ +gboolean +gi_object_info_get_fundamental (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), FALSE); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->fundamental != 0; +} + +/** + * gi_object_info_get_type_name: + * @info: a #GIObjectInfo + * + * Obtain the name of the object’s class/type. + * + * Returns: name of the object’s type + * Since: 2.80 + */ +const gchar * +gi_object_info_get_type_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->gtype_name); +} + +/** + * gi_object_info_get_type_init_function_name: + * @info: a #GIObjectInfo + * + * Obtain the name of the function which, when called, will return the + * [type@GObject.Type] for this object type. + * + * Returns: the type init function name + * Since: 2.80 + */ +const gchar * +gi_object_info_get_type_init_function_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return gi_typelib_get_string (rinfo->typelib, blob->gtype_init); +} + +/** + * gi_object_info_get_n_interfaces: + * @info: a #GIObjectInfo + * + * Obtain the number of interfaces that this object type has. + * + * Returns: number of interfaces + * Since: 2.80 + */ +guint +gi_object_info_get_n_interfaces (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_interfaces; +} + +/** + * gi_object_info_get_interface: + * @info: a #GIObjectInfo + * @n: index of interface to get + * + * Obtain an object type interface at index @n. + * + * Returns: (transfer full): The [class@GIRepository.InterfaceInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIInterfaceInfo * +gi_object_info_get_interface (GIObjectInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return (GIInterfaceInfo *) gi_info_from_entry (rinfo->repository, + rinfo->typelib, blob->interfaces[n]); +} + +/** + * gi_object_info_get_n_fields: + * @info: a #GIObjectInfo + * + * Obtain the number of fields that this object type has. + * + * Returns: number of fields + * Since: 2.80 + */ +guint +gi_object_info_get_n_fields (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_fields; +} + +/** + * gi_object_info_get_field: + * @info: a #GIObjectInfo + * @n: index of field to get + * + * Obtain an object type field at index @n. + * + * Returns: (transfer full): The [class@GIRepository.FieldInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFieldInfo * +gi_object_info_get_field (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + offset = gi_object_info_get_field_offset(info, n); + + return (GIFieldInfo *) gi_info_new (GI_INFO_TYPE_FIELD, (GIBaseInfo*)info, rinfo->typelib, offset); +} + +/** + * gi_object_info_get_n_properties: + * @info: a #GIObjectInfo + * + * Obtain the number of properties that this object type has. + * + * Returns: number of properties + * Since: 2.80 + */ +guint +gi_object_info_get_n_properties (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + return blob->n_properties; +} + +/** + * gi_object_info_get_property: + * @info: a #GIObjectInfo + * @n: index of property to get + * + * Obtain an object type property at index @n. + * + * Returns: (transfer full): The [class@GIRepository.PropertyInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIPropertyInfo * +gi_object_info_get_property (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + n * header->property_blob_size; + + return (GIPropertyInfo *) gi_info_new (GI_INFO_TYPE_PROPERTY, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_object_info_get_n_methods: + * @info: a #GIObjectInfo + * + * Obtain the number of methods that this object type has. + * + * Returns: number of methods + * Since: 2.80 + */ +guint +gi_object_info_get_n_methods (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_methods; +} + +/** + * gi_object_info_get_method: + * @info: a #GIObjectInfo + * @n: index of method to get + * + * Obtain an object type method at index @n. + * + * Returns: (transfer full): The [class@GIRepository.FunctionInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_object_info_get_method (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size + + n * header->function_blob_size; + + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_object_info_find_method: + * @info: a #GIObjectInfo + * @name: name of method to obtain + * + * Obtain a method of the object type given a @name. + * + * `NULL` will be returned if there’s no method available with that name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.FunctionInfo], + * or `NULL` if no method could be found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_object_info_find_method (GIObjectInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size; + + return gi_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_methods, name); +} + +/** + * gi_object_info_find_method_using_interfaces: + * @info: a #GIObjectInfo + * @name: name of method to obtain + * @implementor: (out) (transfer full) (optional) (nullable): The implementor of + * the interface, or `NULL` to ignore. If no method is found, this will return + * `NULL`. + * + * Obtain a method of the object given a @name, searching both the + * object @info and any interfaces it implements. + * + * `NULL` will be returned if there’s no method available with that name. + * + * Note that this function does *not* search parent classes; you will have + * to chain up if that’s desired. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.FunctionInfo], + * or `NULL` if none was found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_object_info_find_method_using_interfaces (GIObjectInfo *info, + const gchar *name, + GIObjectInfo **implementor) +{ + GIFunctionInfo *result = NULL; + GIObjectInfo *implementor_result = NULL; + + result = gi_object_info_find_method (info, name); + if (result) + implementor_result = (GIObjectInfo *) gi_base_info_ref ((GIBaseInfo*) info); + + if (result == NULL) + { + int n_interfaces; + int i; + + n_interfaces = gi_object_info_get_n_interfaces (info); + for (i = 0; i < n_interfaces; ++i) + { + GIInterfaceInfo *iface_info; + + iface_info = gi_object_info_get_interface (info, i); + + result = gi_interface_info_find_method (iface_info, name); + + if (result != NULL) + { + implementor_result = (GIObjectInfo *) iface_info; + break; + } + gi_base_info_unref ((GIBaseInfo*) iface_info); + } + } + if (implementor) + *implementor = implementor_result; + else if (implementor_result != NULL) + gi_base_info_unref ((GIBaseInfo*) implementor_result); + return result; +} + +/** + * gi_object_info_get_n_signals: + * @info: a #GIObjectInfo + * + * Obtain the number of signals that this object type has. + * + * Returns: number of signals + * Since: 2.80 + */ +guint +gi_object_info_get_n_signals (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_signals; +} + +/** + * gi_object_info_get_signal: + * @info: a #GIObjectInfo + * @n: index of signal to get + * + * Obtain an object type signal at index @n. + * + * Returns: (transfer full): The [class@GIRepository.SignalInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GISignalInfo * +gi_object_info_get_signal (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + n * header->signal_blob_size; + + return (GISignalInfo *) gi_info_new (GI_INFO_TYPE_SIGNAL, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_object_info_find_signal: + * @info: a #GIObjectInfo + * @name: name of signal + * + * Obtain a signal of the object type given a @name. + * + * `NULL` will be returned if there’s no signal available with that name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.SignalInfo], + * or `NULL` if no signal could be found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GISignalInfo * +gi_object_info_find_signal (GIObjectInfo *info, + const gchar *name) +{ + guint n_signals; + + n_signals = gi_object_info_get_n_signals (info); + for (guint i = 0; i < n_signals; i++) + { + GISignalInfo *siginfo = gi_object_info_get_signal (info, i); + + if (g_strcmp0 (gi_base_info_get_name ((GIBaseInfo *) siginfo), name) != 0) + { + gi_base_info_unref ((GIBaseInfo*)siginfo); + continue; + } + + return siginfo; + } + return NULL; +} + + +/** + * gi_object_info_get_n_vfuncs: + * @info: a #GIObjectInfo + * + * Obtain the number of virtual functions that this object type has. + * + * Returns: number of virtual functions + * Since: 2.80 + */ +guint +gi_object_info_get_n_vfuncs (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_vfuncs; +} + +/** + * gi_object_info_get_vfunc: + * @info: a #GIObjectInfo + * @n: index of virtual function to get + * + * Obtain an object type virtual function at index @n. + * + * Returns: (transfer full): The [class@GIRepository.VFuncInfo]. Free the struct + * by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_object_info_get_vfunc (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + n * header->vfunc_blob_size; + + return (GIVFuncInfo *) gi_info_new (GI_INFO_TYPE_VFUNC, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_object_info_find_vfunc: + * @info: a #GIObjectInfo + * @name: the name of a virtual function to find. + * + * Locate a virtual function slot with name @name. + * + * Note that the namespace for virtuals is distinct from that of methods; there + * may or may not be a concrete method associated for a virtual. If there is + * one, it may be retrieved using [method@GIRepository.VFuncInfo.get_invoker], + * otherwise that method will return `NULL`. + * + * See the documentation for [method@GIRepository.VFuncInfo.get_invoker] for + * more information on invoking virtuals. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.VFuncInfo], or + * `NULL` if none is found. Free it with [method@GIRepository.BaseInfo.unref] + * when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_object_info_find_vfunc (GIObjectInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size; + + return gi_base_info_find_vfunc (rinfo, offset, blob->n_vfuncs, name); +} + +/** + * gi_object_info_find_vfunc_using_interfaces: + * @info: a #GIObjectInfo + * @name: name of vfunc to obtain + * @implementor: (out) (transfer full) (optional) (nullable): The implementor of + * the interface, or `NULL` to ignore. If no vfunc is found, this will return + * `NULL`. + * + * Locate a virtual function slot with name @name, searching both the object + * @info and any interfaces it implements. + * + * `NULL` will be returned if there’s no vfunc available with that name. + * + * Note that the namespace for virtuals is distinct from that of methods; there + * may or may not be a concrete method associated for a virtual. If there is + * one, it may be retrieved using [method@GIRepository.VFuncInfo.get_invoker], + * otherwise that method will return `NULL`. + * + * Note that this function does *not* search parent classes; you will have + * to chain up if that’s desired. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.VFuncInfo], + * or `NULL` if none was found. Free the struct by calling + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIVFuncInfo * +gi_object_info_find_vfunc_using_interfaces (GIObjectInfo *info, + const gchar *name, + GIObjectInfo **implementor) +{ + GIVFuncInfo *result = NULL; + GIObjectInfo *implementor_result = NULL; + + result = gi_object_info_find_vfunc (info, name); + if (result) + implementor_result = (GIObjectInfo *) gi_base_info_ref ((GIBaseInfo*) info); + + if (result == NULL) + { + int n_interfaces; + int i; + + n_interfaces = gi_object_info_get_n_interfaces (info); + for (i = 0; i < n_interfaces; ++i) + { + GIInterfaceInfo *iface_info; + + iface_info = gi_object_info_get_interface (info, i); + + result = gi_interface_info_find_vfunc (iface_info, name); + + if (result != NULL) + { + implementor_result = (GIObjectInfo *) iface_info; + break; + } + gi_base_info_unref ((GIBaseInfo*) iface_info); + } + } + if (implementor) + *implementor = implementor_result; + else if (implementor_result != NULL) + gi_base_info_unref ((GIBaseInfo*) implementor_result); + return result; +} + +/** + * gi_object_info_get_n_constants: + * @info: a #GIObjectInfo + * + * Obtain the number of constants that this object type has. + * + * Returns: number of constants + * Since: 2.80 + */ +guint +gi_object_info_get_n_constants (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), 0); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_constants; +} + +/** + * gi_object_info_get_constant: + * @info: a #GIObjectInfo + * @n: index of constant to get + * + * Obtain an object type constant at index @n. + * + * Returns: (transfer full): The [class@GIRepository.ConstantInfo]. Free the + * struct by calling [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIConstantInfo * +gi_object_info_get_constant (GIObjectInfo *info, + guint n) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + header = (Header *)rinfo->typelib->data; + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->object_blob_size + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * header->field_blob_size + + blob->n_field_callbacks * header->callback_blob_size + + blob->n_properties * header->property_blob_size + + blob->n_methods * header->function_blob_size + + blob->n_signals * header->signal_blob_size + + blob->n_vfuncs * header->vfunc_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) gi_info_new (GI_INFO_TYPE_CONSTANT, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_object_info_get_class_struct: + * @info: a #GIObjectInfo + * + * Every [class@GObject.Object] has two structures; an instance structure and a + * class structure. This function returns the metadata for the class structure. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.StructInfo] or + * `NULL` if it’s unknown. Free with [method@GIRepository.BaseInfo.unref] when + * done. + * Since: 2.80 + */ +GIStructInfo * +gi_object_info_get_class_struct (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->gtype_struct) + return (GIStructInfo *) gi_info_from_entry (rinfo->repository, + rinfo->typelib, blob->gtype_struct); + else + return NULL; +} + +typedef const char* (*SymbolGetter) (GIObjectInfo *info); + +static void * +_get_func(GIObjectInfo *info, + SymbolGetter getter) +{ + const char* symbol; + GSList *parents = NULL, *l; + GIObjectInfo *parent_info; + gpointer func = NULL; + + parent_info = (GIObjectInfo *) gi_base_info_ref ((GIBaseInfo *) info); + while (parent_info != NULL) + { + parents = g_slist_prepend (parents, parent_info); + parent_info = gi_object_info_get_parent (parent_info); + } + + for (l = parents; l; l = l->next) + { + parent_info = l->data; + symbol = getter (parent_info); + if (symbol == NULL) + continue; + + gi_typelib_symbol (((GIRealInfo *)parent_info)->typelib, symbol, (gpointer*) &func); + if (func) + break; + } + + g_slist_free_full (parents, (GDestroyNotify) gi_base_info_unref); + return func; +} + +/** + * gi_object_info_get_ref_function_name: + * @info: a #GIObjectInfo + * + * Obtain the symbol name of the function that should be called to ref this + * object type. + * + * It’s mainly used for fundamental types. The type signature for + * the symbol is [type@GIRepository.ObjectInfoRefFunction]. To fetch the + * function pointer see + * [method@GIRepository.ObjectInfo.get_ref_function_pointer]. + * + * Returns: (nullable): the symbol, or `NULL` if the object type has no ref + * function + * Since: 2.80 + */ +const char * +gi_object_info_get_ref_function_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->ref_func) + return gi_typelib_get_string (rinfo->typelib, blob->ref_func); + + return NULL; +} + +/** + * gi_object_info_get_ref_function_pointer: (skip) + * @info: a #GIObjectInfo + * + * Obtain a pointer to a function which can be used to + * increase the reference count an instance of this object type. + * + * This takes derivation into account and will reversely traverse + * the base classes of this type, starting at the top type. + * + * Returns: (nullable): the function pointer, or `NULL` if the object type has + * no ref function + * Since: 2.80 + */ +GIObjectInfoRefFunction +gi_object_info_get_ref_function_pointer (GIObjectInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + return (GIObjectInfoRefFunction)_get_func(info, (SymbolGetter)gi_object_info_get_ref_function_name); +} + +/** + * gi_object_info_get_unref_function_name: + * @info: a #GIObjectInfo + * + * Obtain the symbol name of the function that should be called to unref this + * object type. + * + * It’s mainly used for fundamental types. The type signature for the symbol is + * [type@GIRepository.ObjectInfoUnrefFunction]. To fetch the function pointer + * see [method@GIRepository.ObjectInfo.get_unref_function_pointer]. + * + * Returns: (nullable): the symbol, or `NULL` if the object type has no unref + * function + * Since: 2.80 + */ +const char * +gi_object_info_get_unref_function_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->unref_func) + return gi_typelib_get_string (rinfo->typelib, blob->unref_func); + + return NULL; +} + +/** + * gi_object_info_get_unref_function_pointer: (skip) + * @info: a #GIObjectInfo + * + * Obtain a pointer to a function which can be used to + * decrease the reference count an instance of this object type. + * + * This takes derivation into account and will reversely traverse + * the base classes of this type, starting at the top type. + * + * Returns: (nullable): the function pointer, or `NULL` if the object type has + * no unref function + * Since: 2.80 + */ +GIObjectInfoUnrefFunction +gi_object_info_get_unref_function_pointer (GIObjectInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + return (GIObjectInfoUnrefFunction)_get_func(info, (SymbolGetter)gi_object_info_get_unref_function_name); +} + +/** + * gi_object_info_get_set_value_function_name: + * @info: a #GIObjectInfo + * + * Obtain the symbol name of the function that should be called to set a + * [type@GObject.Value], given an object instance pointer of this object type. + * + * It’s mainly used for fundamental types. The type signature for the symbol + * is [type@GIRepository.ObjectInfoSetValueFunction]. To fetch the function + * pointer see [method@GIRepository.ObjectInfo.get_set_value_function_pointer]. + * + * Returns: (nullable): the symbol, or `NULL` if the object type has no + * set-value function + * Since: 2.80 + */ +const char * +gi_object_info_get_set_value_function_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->set_value_func) + return gi_typelib_get_string (rinfo->typelib, blob->set_value_func); + + return NULL; +} + +/** + * gi_object_info_get_set_value_function_pointer: (skip) + * @info: a #GIObjectInfo + * + * Obtain a pointer to a function which can be used to set a + * [type@GObject.Value], given an instance of this object type. + * + * This takes derivation into account and will reversely traverse + * the base classes of this type, starting at the top type. + * + * Returns: (nullable): the function pointer, or `NULL` if the object type has + * no set-value function + * Since: 2.80 + */ +GIObjectInfoSetValueFunction +gi_object_info_get_set_value_function_pointer (GIObjectInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + return (GIObjectInfoSetValueFunction)_get_func(info, (SymbolGetter)gi_object_info_get_set_value_function_name); +} + +/** + * gi_object_info_get_get_value_function_name: + * @info: a #GIObjectInfo + * + * Obtain the symbol name of the function that should be called to convert + * an object instance pointer of this object type to a [type@GObject.Value]. + * + * It’s mainly used for fundamental types. The type signature for the symbol + * is [type@GIRepository.ObjectInfoGetValueFunction]. To fetch the function + * pointer see [method@GIRepository.ObjectInfo.get_get_value_function_pointer]. + * + * Returns: (nullable): the symbol, or `NULL` if the object type has no + * get-value function + * Since: 2.80 + */ +const char * +gi_object_info_get_get_value_function_name (GIObjectInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + ObjectBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + blob = (ObjectBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->get_value_func) + return gi_typelib_get_string (rinfo->typelib, blob->get_value_func); + + return NULL; +} + +/** + * gi_object_info_get_get_value_function_pointer: (skip) + * @info: a #GIObjectInfo + * + * Obtain a pointer to a function which can be used to extract an instance of + * this object type out of a [type@GObject.Value]. + * + * This takes derivation into account and will reversely traverse + * the base classes of this type, starting at the top type. + * + * Returns: (nullable): the function pointer, or `NULL` if the object type has + * no get-value function + * Since: 2.80 + */ +GIObjectInfoGetValueFunction +gi_object_info_get_get_value_function_pointer (GIObjectInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_OBJECT_INFO (info), NULL); + + return (GIObjectInfoGetValueFunction)_get_func(info, (SymbolGetter)gi_object_info_get_get_value_function_name); +} + +void +gi_object_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_OBJECT; +} diff --git a/girepository/giobjectinfo.h b/girepository/giobjectinfo.h new file mode 100644 index 0000000..2259096 --- /dev/null +++ b/girepository/giobjectinfo.h @@ -0,0 +1,215 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Object + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GIObjectInfoRefFunction: (skip) + * @object: object instance pointer + * + * Increases the reference count of an object instance. + * + * Returns: (transfer full): the object instance + * Since: 2.80 + */ +typedef void * (*GIObjectInfoRefFunction) (void *object); + +/** + * GIObjectInfoUnrefFunction: (skip) + * @object: (transfer full): object instance pointer + * + * Decreases the reference count of an object instance. + * + * Since: 2.80 + */ +typedef void (*GIObjectInfoUnrefFunction) (void *object); + +/** + * GIObjectInfoSetValueFunction: (skip) + * @value: a [type@GObject.Value] + * @object: object instance pointer + * + * Update @value and attach the object instance pointer @object to it. + * + * Since: 2.80 + */ +typedef void (*GIObjectInfoSetValueFunction) (GValue *value, void *object); + +/** + * GIObjectInfoGetValueFunction: (skip) + * @value: a [type@GObject.Value] + * + * Extract an object instance out of @value. + * + * Returns: (transfer full): the object instance + * Since: 2.80 + */ +typedef void * (*GIObjectInfoGetValueFunction) (const GValue *value); + +/** + * GI_IS_OBJECT_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.ObjectInfo]. + * + * Since: 2.80 + */ +#define GI_IS_OBJECT_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_OBJECT) + + +GI_AVAILABLE_IN_ALL +const gchar * gi_object_info_get_type_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_object_info_get_type_init_function_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_object_info_get_abstract (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_object_info_get_final (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_object_info_get_fundamental (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIObjectInfo * gi_object_info_get_parent (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_interfaces (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIInterfaceInfo * gi_object_info_get_interface (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_fields (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIFieldInfo * gi_object_info_get_field (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_properties (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIPropertyInfo * gi_object_info_get_property (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_methods (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_object_info_get_method (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_object_info_find_method (GIObjectInfo *info, + const gchar *name); + + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_object_info_find_method_using_interfaces (GIObjectInfo *info, + const gchar *name, + GIObjectInfo **implementor); + + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_signals (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GISignalInfo * gi_object_info_get_signal (GIObjectInfo *info, + guint n); + + +GI_AVAILABLE_IN_ALL +GISignalInfo * gi_object_info_find_signal (GIObjectInfo *info, + const gchar *name); + + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_vfuncs (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_object_info_get_vfunc (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_object_info_find_vfunc (GIObjectInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_object_info_find_vfunc_using_interfaces (GIObjectInfo *info, + const gchar *name, + GIObjectInfo **implementor); + +GI_AVAILABLE_IN_ALL +guint gi_object_info_get_n_constants (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIConstantInfo * gi_object_info_get_constant (GIObjectInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIStructInfo * gi_object_info_get_class_struct (GIObjectInfo *info); + + +GI_AVAILABLE_IN_ALL +const char * gi_object_info_get_ref_function_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIObjectInfoRefFunction gi_object_info_get_ref_function_pointer (GIObjectInfo *info); + + +GI_AVAILABLE_IN_ALL +const char * gi_object_info_get_unref_function_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIObjectInfoUnrefFunction gi_object_info_get_unref_function_pointer (GIObjectInfo *info); + + +GI_AVAILABLE_IN_ALL +const char * gi_object_info_get_set_value_function_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIObjectInfoSetValueFunction gi_object_info_get_set_value_function_pointer (GIObjectInfo *info); + + +GI_AVAILABLE_IN_ALL +const char * gi_object_info_get_get_value_function_name (GIObjectInfo *info); + +GI_AVAILABLE_IN_ALL +GIObjectInfoGetValueFunction gi_object_info_get_get_value_function_pointer (GIObjectInfo *info); + + +G_END_DECLS diff --git a/girepository/gipropertyinfo.c b/girepository/gipropertyinfo.c new file mode 100644 index 0000000..9aaed45 --- /dev/null +++ b/girepository/gipropertyinfo.c @@ -0,0 +1,228 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Property implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gipropertyinfo.h" + +/** + * GIPropertyInfo: + * + * `GIPropertyInfo` represents a property in a [class@GObject.Object]. + * + * A property belongs to either a [class@GIRepository.ObjectInfo] or a + * [class@GIRepository.InterfaceInfo]. + * + * Since: 2.80 + */ + +/** + * gi_property_info_get_flags: + * @info: a #GIPropertyInfo + * + * Obtain the flags for this property info. + * + * See [type@GObject.ParamFlags] for more information about possible flag + * values. + * + * Returns: the flags + * Since: 2.80 + */ +GParamFlags +gi_property_info_get_flags (GIPropertyInfo *info) +{ + GParamFlags flags; + GIRealInfo *rinfo = (GIRealInfo *)info; + PropertyBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), 0); + + blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + + flags = 0; + + if (blob->readable) + flags = flags | G_PARAM_READABLE; + + if (blob->writable) + flags = flags | G_PARAM_WRITABLE; + + if (blob->construct) + flags = flags | G_PARAM_CONSTRUCT; + + if (blob->construct_only) + flags = flags | G_PARAM_CONSTRUCT_ONLY; + + return flags; +} + +/** + * gi_property_info_get_type_info: + * @info: a #GIPropertyInfo + * + * Obtain the type information for the property @info. + * + * Returns: (transfer full): The [class@GIRepository.TypeInfo]. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GITypeInfo * +gi_property_info_get_type_info (GIPropertyInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), NULL); + + return gi_type_info_new ((GIBaseInfo*)info, + rinfo->typelib, + rinfo->offset + G_STRUCT_OFFSET (PropertyBlob, type)); +} + +/** + * gi_property_info_get_ownership_transfer: + * @info: a #GIPropertyInfo + * + * Obtain the ownership transfer for this property. + * + * See [type@GIRepository.Transfer] for more information about transfer values. + * + * Returns: the transfer + * Since: 2.80 + */ +GITransfer +gi_property_info_get_ownership_transfer (GIPropertyInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + PropertyBlob *blob; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), -1); + + blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->transfer_ownership) + return GI_TRANSFER_EVERYTHING; + else if (blob->transfer_container_ownership) + return GI_TRANSFER_CONTAINER; + else + return GI_TRANSFER_NOTHING; +} + +/** + * gi_property_info_get_setter: + * @info: a #GIPropertyInfo + * + * Obtains the setter function associated with this `GIPropertyInfo`. + * + * The setter is only available for `G_PARAM_WRITABLE` properties that + * are also not `G_PARAM_CONSTRUCT_ONLY`. + * + * Returns: (transfer full) (nullable): The function info, or `NULL` if not set. + * Free it with [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_property_info_get_setter (GIPropertyInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + PropertyBlob *blob; + GIBaseInfo *container; + GIInfoType parent_type; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), NULL); + + blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + if (!blob->writable || blob->construct_only) + return NULL; + + if (blob->setter == ACCESSOR_SENTINEL) + return NULL; + + container = rinfo->container; + parent_type = gi_base_info_get_info_type (container); + if (parent_type == GI_INFO_TYPE_OBJECT) + return gi_object_info_get_method ((GIObjectInfo *) container, blob->setter); + else if (parent_type == GI_INFO_TYPE_INTERFACE) + return gi_interface_info_get_method ((GIInterfaceInfo *) container, blob->setter); + else + return NULL; +} + +/** + * gi_property_info_get_getter: + * @info: a #GIPropertyInfo + * + * Obtains the getter function associated with this `GIPropertyInfo`. + * + * The setter is only available for `G_PARAM_READABLE` properties. + * + * Returns: (transfer full) (nullable): The function info, or `NULL` if not set. + * Free it with [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_property_info_get_getter (GIPropertyInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + PropertyBlob *blob; + GIBaseInfo *container; + GIInfoType parent_type; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_PROPERTY_INFO (info), NULL); + + blob = (PropertyBlob *)&rinfo->typelib->data[rinfo->offset]; + if (!blob->readable) + return NULL; + + if (blob->getter == ACCESSOR_SENTINEL) + return NULL; + + container = rinfo->container; + parent_type = gi_base_info_get_info_type (container); + if (parent_type == GI_INFO_TYPE_OBJECT) + return gi_object_info_get_method ((GIObjectInfo *) container, blob->getter); + else if (parent_type == GI_INFO_TYPE_INTERFACE) + return gi_interface_info_get_method ((GIInterfaceInfo *) container, blob->getter); + else + return NULL; +} + +void +gi_property_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_PROPERTY; +} diff --git a/girepository/gipropertyinfo.h b/girepository/gipropertyinfo.h new file mode 100644 index 0000000..cff5faa --- /dev/null +++ b/girepository/gipropertyinfo.h @@ -0,0 +1,62 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Property + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_PROPERTY_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.PropertyInfo]. + * + * Since: 2.80 + */ +#define GI_IS_PROPERTY_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_PROPERTY) + + +GI_AVAILABLE_IN_ALL +GParamFlags gi_property_info_get_flags (GIPropertyInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo *gi_property_info_get_type_info (GIPropertyInfo *info); + +GI_AVAILABLE_IN_ALL +GITransfer gi_property_info_get_ownership_transfer (GIPropertyInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo *gi_property_info_get_setter (GIPropertyInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo *gi_property_info_get_getter (GIPropertyInfo *info); + +G_END_DECLS diff --git a/girepository/giregisteredtypeinfo.c b/girepository/giregisteredtypeinfo.c new file mode 100644 index 0000000..a937736 --- /dev/null +++ b/girepository/giregisteredtypeinfo.c @@ -0,0 +1,165 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Registered Type implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giregisteredtypeinfo.h" + +/** + * GIRegisteredTypeInfo: + * + * `GIRegisteredTypeInfo` represents an entity with a [type@GObject.Type] + * associated. + * + * Could be either a [class@GIRepository.EnumInfo], + * [class@GIRepository.InterfaceInfo], [class@GIRepository.ObjectInfo], + * [class@GIRepository.StructInfo] or a [class@GIRepository.UnionInfo]. + * + * A registered type info struct has a name and a type function. + * + * To get the name call [method@GIRepository.RegisteredTypeInfo.get_type_name]. + * Most users want to call [method@GIRepository.RegisteredTypeInfo.get_g_type] + * and don’t worry about the rest of the details. + * + * Since: 2.80 + */ + +/** + * gi_registered_type_info_get_type_name: + * @info: a #GIRegisteredTypeInfo + * + * Obtain the type name of the struct within the GObject type system. + * + * This type can be passed to [func@GObject.type_name] to get a + * [type@GObject.Type]. + * + * Returns: (nullable): the type name, or `NULL` if unknown + * Since: 2.80 + */ +const gchar * +gi_registered_type_info_get_type_name (GIRegisteredTypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + RegisteredTypeBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_REGISTERED_TYPE_INFO (info), NULL); + + blob = (RegisteredTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->gtype_name) + return gi_typelib_get_string (rinfo->typelib, blob->gtype_name); + + return NULL; +} + +/** + * gi_registered_type_info_get_type_init_function_name: + * @info: a #GIRegisteredTypeInfo + * + * Obtain the type init function for @info. + * + * The type init function is the function which will register the + * [type@GObject.Type] within the GObject type system. Usually this is not + * called by language bindings or applications — use + * [method@GIRepository.RegisteredTypeInfo.get_g_type] directly instead. + * + * Returns: (nullable): the symbol name of the type init function, suitable for + * passing into [method@GModule.Module.symbol], or `NULL` if unknown + * Since: 2.80 + */ +const gchar * +gi_registered_type_info_get_type_init_function_name (GIRegisteredTypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + RegisteredTypeBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_REGISTERED_TYPE_INFO (info), NULL); + + blob = (RegisteredTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->gtype_init) + return gi_typelib_get_string (rinfo->typelib, blob->gtype_init); + + return NULL; +} + +/** + * gi_registered_type_info_get_g_type: + * @info: a #GIRegisteredTypeInfo + * + * Obtain the [type@GObject.Type] for this registered type. + * + * If there is no type information associated with @info, or the shared library + * which provides the `type_init` function for @info cannot be called, then + * `G_TYPE_NONE` is returned. + * + * Returns: the [type@GObject.Type], or `G_TYPE_NONE` if unknown + * Since: 2.80 + */ +GType +gi_registered_type_info_get_g_type (GIRegisteredTypeInfo *info) +{ + const char *type_init; + GType (* get_type_func) (void); + GIRealInfo *rinfo = (GIRealInfo*)info; + + g_return_val_if_fail (info != NULL, G_TYPE_INVALID); + g_return_val_if_fail (GI_IS_REGISTERED_TYPE_INFO (info), G_TYPE_INVALID); + + type_init = gi_registered_type_info_get_type_init_function_name (info); + + if (type_init == NULL) + return G_TYPE_NONE; + else if (!strcmp (type_init, "intern")) + /* The special string "intern" is used for some types exposed by libgobject + (that therefore should be always available) */ + return g_type_from_name (gi_registered_type_info_get_type_name (info)); + + get_type_func = NULL; + if (!gi_typelib_symbol (rinfo->typelib, + type_init, + (void**) &get_type_func)) + return G_TYPE_NONE; + + return (* get_type_func) (); +} + +void +gi_registered_type_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_REGISTERED_TYPE; +} diff --git a/girepository/giregisteredtypeinfo.h b/girepository/giregisteredtypeinfo.h new file mode 100644 index 0000000..45a9100 --- /dev/null +++ b/girepository/giregisteredtypeinfo.h @@ -0,0 +1,64 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Registered Type + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +/** + * GI_IS_REGISTERED_TYPE_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.RegisteredTypeInfo] or derived from + * it. + * + * Since: 2.80 + */ +#define GI_IS_REGISTERED_TYPE_INFO(info) \ + ((gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_BOXED) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_ENUM) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_FLAGS) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_INTERFACE) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_OBJECT) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_STRUCT) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_UNION) || \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_BOXED)) + +GI_AVAILABLE_IN_ALL +const gchar * gi_registered_type_info_get_type_name (GIRegisteredTypeInfo *info); + +GI_AVAILABLE_IN_ALL +const gchar * gi_registered_type_info_get_type_init_function_name (GIRegisteredTypeInfo *info); + +GI_AVAILABLE_IN_ALL +GType gi_registered_type_info_get_g_type (GIRegisteredTypeInfo *info); + +G_END_DECLS diff --git a/girepository/girepository-private.h b/girepository/girepository-private.h new file mode 100644 index 0000000..0146fcd --- /dev/null +++ b/girepository/girepository-private.h @@ -0,0 +1,247 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Private headers + * + * Copyright (C) 2010 Johan Dahlin + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +#define __GIREPOSITORY_H_INSIDE__ + +#include +#include +#include + +/* FIXME: For now, GIRealInfo is a compatibility define. This will eventually + * be removed. */ +typedef struct _GIBaseInfo GIRealInfo; + +/* We changed a gint32 -> gint in the structure below, which should be + * valid everywhere we care about. + */ +G_STATIC_ASSERT (sizeof (int) == sizeof (gint32)); + +/* + * We just use one structure for all of the info object + * types; in general, we should be reading data directly + * from the typelib, and not having computed data in + * per-type structures. + */ +struct _GIBaseInfo +{ + /*< private >*/ + GTypeInstance parent_instance; + gatomicrefcount ref_count; + + GIRepository *repository; + GIBaseInfo *container; + + GITypelib *typelib; + guint32 offset; + + guint32 type_is_embedded : 1; /* Used by GITypeInfo */ +}; + +/* Subtypes */ +struct _GICallableInfo +{ + GIBaseInfo parent; +}; + +void gi_callable_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIFunctionInfo +{ + GIBaseInfo parent; +}; + +void gi_function_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GICallbackInfo +{ + GIBaseInfo parent; +}; + +void gi_callback_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIRegisteredTypeInfo +{ + GIBaseInfo parent; +}; + +void gi_registered_type_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIStructInfo +{ + GIBaseInfo parent; +}; + +void gi_struct_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIUnionInfo +{ + GIBaseInfo parent; +}; + +void gi_union_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIEnumInfo +{ + GIBaseInfo parent; +}; + +void gi_enum_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIObjectInfo +{ + GIBaseInfo parent; +}; + +void gi_object_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIInterfaceInfo +{ + GIBaseInfo parent; +}; + +void gi_interface_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIConstantInfo +{ + GIBaseInfo parent; +}; + +void gi_constant_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIValueInfo +{ + GIBaseInfo parent; +}; + +void gi_value_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GISignalInfo +{ + GIBaseInfo parent; +}; + +void gi_signal_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIVFuncInfo +{ + GIBaseInfo parent; +}; + +void gi_vfunc_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIPropertyInfo +{ + GIBaseInfo parent; +}; + +void gi_property_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIFieldInfo +{ + GIBaseInfo parent; +}; + +void gi_field_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIArgInfo +{ + GIBaseInfo parent; +}; + +void gi_arg_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GITypeInfo +{ + GIBaseInfo parent; +}; + +void gi_type_info_class_init (gpointer g_class, + gpointer class_data); + +struct _GIUnresolvedInfo +{ + GIBaseInfo parent; + + const gchar *name; + const gchar *namespace; +}; + +void gi_unresolved_info_class_init (gpointer g_class, + gpointer class_data); + +void gi_info_init (GIRealInfo *info, + GIInfoType type, + GIRepository *repository, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset); + +GIBaseInfo * gi_info_from_entry (GIRepository *repository, + GITypelib *typelib, + guint16 index); + +GIBaseInfo * gi_info_new_full (GIInfoType type, + GIRepository *repository, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset); + +GITypeInfo * gi_type_info_new (GIBaseInfo *container, + GITypelib *typelib, + guint32 offset); + +void gi_type_info_init (GIBaseInfo *info, + GIBaseInfo *container, + GITypelib *typelib, + guint32 offset); + +GIFunctionInfo * gi_base_info_find_method (GIBaseInfo *base, + guint32 offset, + guint n_methods, + const gchar *name); + +GIVFuncInfo * gi_base_info_find_vfunc (GIRealInfo *rinfo, + guint32 offset, + guint n_vfuncs, + const gchar *name); diff --git a/girepository/girepository.c b/girepository/girepository.c new file mode 100644 index 0000000..206ce17 --- /dev/null +++ b/girepository/girepository.c @@ -0,0 +1,1986 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Repository implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008 Colin Walters + * Copyright (C) 2008 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include +#include + +#include +#include +#include +#include "girepository.h" +#include "gitypelib-internal.h" +#include "girepository-private.h" + +/** + * GIRepository: + * + * `GIRepository` is used to manage repositories of namespaces. Namespaces + * are represented on disk by type libraries (`.typelib` files). + * + * ### Discovery of type libraries + * + * `GIRepository` will typically look for a `girepository-1.0` directory + * under the library directory used when compiling gobject-introspection. On a + * standard Linux system this will end up being `/usr/lib/girepository-1.0`. + * + * It is possible to control the search paths programmatically, using + * [func@GIRepository.Repository.prepend_search_path]. It is also possible to + * modify the search paths by using the `GI_TYPELIB_PATH` environment variable. + * The environment variable takes precedence over the default search path + * and the [func@GIRepository.Repository.prepend_search_path] calls. + * + * Since: 2.80 + */ + +static GIRepository *default_repository = NULL; +static GPtrArray *typelib_search_path = NULL; + +typedef struct { + guint n_interfaces; + GIBaseInfo *interfaces[]; +} GTypeInterfaceCache; + +static void +gtype_interface_cache_free (gpointer data) +{ + GTypeInterfaceCache *cache = data; + guint i; + + for (i = 0; i < cache->n_interfaces; i++) + gi_base_info_unref ((GIBaseInfo*) cache->interfaces[i]); + g_free (cache); +} + +struct _GIRepositoryPrivate +{ + GHashTable *typelibs; /* (string) namespace -> GITypelib */ + GHashTable *lazy_typelibs; /* (string) namespace-version -> GITypelib */ + GHashTable *info_by_gtype; /* GType -> GIBaseInfo */ + GHashTable *info_by_error_domain; /* GQuark -> GIBaseInfo */ + GHashTable *interfaces_for_gtype; /* GType -> GTypeInterfaceCache */ + GHashTable *unknown_gtypes; /* hashset of GType */ +}; + +G_DEFINE_TYPE_WITH_CODE (GIRepository, gi_repository, G_TYPE_OBJECT, G_ADD_PRIVATE (GIRepository)); + +#ifdef G_PLATFORM_WIN32 + +#include + +static HMODULE girepository_dll = NULL; + +#ifdef DLL_EXPORT + +BOOL WINAPI DllMain (HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved); + +BOOL WINAPI +DllMain (HINSTANCE hinstDLL, + DWORD fdwReason, + LPVOID lpvReserved) +{ + if (fdwReason == DLL_PROCESS_ATTACH) + girepository_dll = hinstDLL; + + return TRUE; +} + +#endif + +#undef GOBJECT_INTROSPECTION_LIBDIR + +/* GOBJECT_INTROSPECTION_LIBDIR is used only in code called just once, + * so no problem leaking this + */ +#define GOBJECT_INTROSPECTION_LIBDIR \ + g_build_filename (g_win32_get_package_installation_directory_of_module (girepository_dll), \ + "lib", \ + NULL) + +#endif + +static void +gi_repository_init (GIRepository *repository) +{ + repository->priv = gi_repository_get_instance_private (repository); + repository->priv->typelibs + = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) gi_typelib_free); + repository->priv->lazy_typelibs + = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) NULL); + repository->priv->info_by_gtype + = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) gi_base_info_unref); + repository->priv->info_by_error_domain + = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) gi_base_info_unref); + repository->priv->interfaces_for_gtype + = g_hash_table_new_full (g_direct_hash, g_direct_equal, + (GDestroyNotify) NULL, + (GDestroyNotify) gtype_interface_cache_free); + repository->priv->unknown_gtypes = g_hash_table_new (NULL, NULL); +} + +static void +gi_repository_finalize (GObject *object) +{ + GIRepository *repository = GI_REPOSITORY (object); + + g_hash_table_destroy (repository->priv->typelibs); + g_hash_table_destroy (repository->priv->lazy_typelibs); + g_hash_table_destroy (repository->priv->info_by_gtype); + g_hash_table_destroy (repository->priv->info_by_error_domain); + g_hash_table_destroy (repository->priv->interfaces_for_gtype); + g_hash_table_destroy (repository->priv->unknown_gtypes); + + (* G_OBJECT_CLASS (gi_repository_parent_class)->finalize) (G_OBJECT (repository)); +} + +static void +gi_repository_class_init (GIRepositoryClass *class) +{ + GObjectClass *gobject_class; + + gobject_class = G_OBJECT_CLASS (class); + + gobject_class->finalize = gi_repository_finalize; +} + +static void +init_globals (void) +{ + static gsize initialized = 0; + + if (!g_once_init_enter (&initialized)) + return; + + if (default_repository == NULL) + default_repository = gi_repository_new (); + + if (typelib_search_path == NULL) + { + const char *libdir; + char *typelib_dir; + const gchar *type_lib_path_env; + + /* This variable is intended to take precedence over both: + * - the default search path; + * - all gi_repository_prepend_search_path() calls. + */ + type_lib_path_env = g_getenv ("GI_TYPELIB_PATH"); + + if (type_lib_path_env) + { + gchar **custom_dirs; + + custom_dirs = g_strsplit (type_lib_path_env, G_SEARCHPATH_SEPARATOR_S, 0); + typelib_search_path = + g_ptr_array_new_take_null_terminated ((gpointer) g_steal_pointer (&custom_dirs), g_free); + } + else + { + typelib_search_path = g_ptr_array_new_null_terminated (1, g_free, TRUE); + } + + libdir = GOBJECT_INTROSPECTION_LIBDIR; + + typelib_dir = g_build_filename (libdir, "girepository-1.0", NULL); + + g_ptr_array_add (typelib_search_path, g_steal_pointer (&typelib_dir)); + } + + g_once_init_leave (&initialized, 1); +} + +/** + * gi_repository_prepend_search_path: + * @directory: (type filename): directory name to prepend to the typelib + * search path + * + * Prepends @directory to the typelib search path. + * + * See also: gi_repository_get_search_path(). + * + * Since: 2.80 + */ +void +gi_repository_prepend_search_path (const char *directory) +{ + init_globals (); + g_ptr_array_insert (typelib_search_path, 0, g_strdup (directory)); +} + +/** + * gi_repository_get_search_path: + * @n_paths_out: (optional) (out): The number of search paths returned. + * + * Returns the current search path [class@GIRepository.Repository] will use when + * loading typelib files. + * + * The list is internal to [class@GIRepository.Repository] and should not be + * freed, nor should its string elements. + * + * Returns: (element-type filename) (transfer none) (array length=n_paths_out): list of search paths, most + * important first + * Since: 2.80 + */ +const char * const * +gi_repository_get_search_path (size_t *n_paths_out) +{ + if G_UNLIKELY (!typelib_search_path || !typelib_search_path->pdata) + { + static const char * const empty_search_path[] = {NULL}; + + if (n_paths_out) + *n_paths_out = 0; + + return empty_search_path; + } + + if (n_paths_out) + *n_paths_out = typelib_search_path->len; + + return (const char * const *) typelib_search_path->pdata; +} + +static char * +build_typelib_key (const char *name, const char *source) +{ + GString *str = g_string_new (name); + g_string_append_c (str, '\0'); + g_string_append (str, source); + return g_string_free (str, FALSE); +} + +/* Note: Returns %NULL (not an empty %NULL-terminated array) if there are no + * dependencies. */ +static char ** +get_typelib_dependencies (GITypelib *typelib) +{ + Header *header; + const char *dependencies_glob; + + header = (Header *)typelib->data; + + if (header->dependencies == 0) + return NULL; + + dependencies_glob = gi_typelib_get_string (typelib, header->dependencies); + return g_strsplit (dependencies_glob, "|", 0); +} + +static GIRepository * +get_repository (GIRepository *repository) +{ + init_globals (); + + if (repository != NULL) + return repository; + else + return default_repository; +} + +static GITypelib * +check_version_conflict (GITypelib *typelib, + const gchar *namespace, + const gchar *expected_version, + char **version_conflict) +{ + Header *header; + const char *loaded_version; + + if (expected_version == NULL) + { + if (version_conflict) + *version_conflict = NULL; + return typelib; + } + + header = (Header*)typelib->data; + loaded_version = gi_typelib_get_string (typelib, header->nsversion); + g_assert (loaded_version != NULL); + + if (strcmp (expected_version, loaded_version) != 0) + { + if (version_conflict) + *version_conflict = (char*)loaded_version; + return NULL; + } + if (version_conflict) + *version_conflict = NULL; + return typelib; +} + +static GITypelib * +get_registered_status (GIRepository *repository, + const char *namespace, + const char *version, + gboolean allow_lazy, + gboolean *lazy_status, + char **version_conflict) +{ + GITypelib *typelib; + repository = get_repository (repository); + if (lazy_status) + *lazy_status = FALSE; + typelib = g_hash_table_lookup (repository->priv->typelibs, namespace); + if (typelib) + return check_version_conflict (typelib, namespace, version, version_conflict); + typelib = g_hash_table_lookup (repository->priv->lazy_typelibs, namespace); + if (!typelib) + return NULL; + if (lazy_status) + *lazy_status = TRUE; + if (!allow_lazy) + return NULL; + return check_version_conflict (typelib, namespace, version, version_conflict); +} + +static GITypelib * +get_registered (GIRepository *repository, + const char *namespace, + const char *version) +{ + return get_registered_status (repository, namespace, version, TRUE, NULL, NULL); +} + +static gboolean +load_dependencies_recurse (GIRepository *repository, + GITypelib *typelib, + GError **error) +{ + char **dependencies; + + dependencies = get_typelib_dependencies (typelib); + + if (dependencies != NULL) + { + int i; + + for (i = 0; dependencies[i]; i++) + { + char *dependency = dependencies[i]; + const char *last_dash; + char *dependency_namespace; + const char *dependency_version; + + last_dash = strrchr (dependency, '-'); + dependency_namespace = g_strndup (dependency, last_dash - dependency); + dependency_version = last_dash+1; + + if (!gi_repository_require (repository, dependency_namespace, dependency_version, + 0, error)) + { + g_free (dependency_namespace); + g_strfreev (dependencies); + return FALSE; + } + g_free (dependency_namespace); + } + g_strfreev (dependencies); + } + return TRUE; +} + +static const char * +register_internal (GIRepository *repository, + const char *source, + gboolean lazy, + GITypelib *typelib, + GError **error) +{ + Header *header; + const gchar *namespace; + + g_return_val_if_fail (typelib != NULL, FALSE); + + header = (Header *)typelib->data; + + g_return_val_if_fail (header != NULL, FALSE); + + namespace = gi_typelib_get_string (typelib, header->namespace); + + if (lazy) + { + g_assert (!g_hash_table_lookup (repository->priv->lazy_typelibs, + namespace)); + g_hash_table_insert (repository->priv->lazy_typelibs, + build_typelib_key (namespace, source), (void *)typelib); + } + else + { + gpointer value; + char *key; + + /* First, try loading all the dependencies */ + if (!load_dependencies_recurse (repository, typelib, error)) + return NULL; + + /* Check if we are transitioning from lazily loaded state */ + if (g_hash_table_lookup_extended (repository->priv->lazy_typelibs, + namespace, + (gpointer)&key, &value)) + g_hash_table_remove (repository->priv->lazy_typelibs, key); + else + key = build_typelib_key (namespace, source); + + g_hash_table_insert (repository->priv->typelibs, + g_steal_pointer (&key), + (void *)typelib); + } + + /* These types might be resolved now, clear the cache */ + g_hash_table_remove_all (repository->priv->unknown_gtypes); + + return namespace; +} + +/** + * gi_repository_get_immediate_dependencies: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace of interest + * + * Return an array of the immediate versioned dependencies for @namespace_. + * Returned strings are of the form `namespace-version`. + * + * Note: @namespace_ must have already been loaded using a function + * such as [method@GIRepository.Repository.require] before calling this + * function. + * + * To get the transitive closure of dependencies for @namespace_, use + * [method@GIRepository.Repository.get_dependencies]. + * + * Returns: (transfer full) (array zero-terminated=1): `NULL`-terminated string + * array of immediate versioned dependencies + * Since: 2.80 + */ +char ** +gi_repository_get_immediate_dependencies (GIRepository *repository, + const char *namespace) +{ + GITypelib *typelib; + gchar **deps; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + g_return_val_if_fail (typelib != NULL, NULL); + + /* Ensure we always return a non-%NULL vector. */ + deps = get_typelib_dependencies (typelib); + if (deps == NULL) + deps = g_strsplit ("", "|", 0); + + return deps; +} + +/* Load the transitive closure of dependency namespace-version strings for the + * given @typelib. @repository must be non-%NULL. @transitive_dependencies must + * be a pre-existing GHashTable set for storing the + * dependencies. */ +static void +get_typelib_dependencies_transitive (GIRepository *repository, + GITypelib *typelib, + GHashTable *transitive_dependencies) +{ + gchar **immediate_dependencies; + guint i; + + immediate_dependencies = get_typelib_dependencies (typelib); + + for (i = 0; immediate_dependencies != NULL && immediate_dependencies[i]; i++) + { + gchar *dependency; + const gchar *last_dash; + gchar *dependency_namespace; + + dependency = immediate_dependencies[i]; + + /* Steal from the strv. */ + g_hash_table_add (transitive_dependencies, dependency); + immediate_dependencies[i] = NULL; + + /* Recurse for this namespace. */ + last_dash = strrchr (dependency, '-'); + dependency_namespace = g_strndup (dependency, last_dash - dependency); + + typelib = get_registered (repository, dependency_namespace, NULL); + g_return_if_fail (typelib != NULL); + get_typelib_dependencies_transitive (repository, typelib, + transitive_dependencies); + + g_free (dependency_namespace); + } + + g_free (immediate_dependencies); +} + +/** + * gi_repository_get_dependencies: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace of interest + * + * Retrieves all (transitive) versioned dependencies for + * @namespace_. + * + * The returned strings are of the form `namespace-version`. + * + * Note: @namespace_ must have already been loaded using a function + * such as [method@GIRepository.Repository.require] before calling this + * function. + * + * To get only the immediate dependencies for @namespace_, use + * [method@GIRepository.Repository.get_immediate_dependencies]. + * + * Returns: (transfer full) (array zero-terminated=1): `NULL`-terminated string + * array of all versioned dependencies + * Since: 2.80 + */ +char ** +gi_repository_get_dependencies (GIRepository *repository, + const char *namespace) +{ + GITypelib *typelib; + GHashTable *transitive_dependencies; /* set of owned utf8 */ + GHashTableIter iter; + gchar *dependency; + GPtrArray *out; /* owned utf8 elements */ + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + g_return_val_if_fail (typelib != NULL, NULL); + + /* Load the dependencies. */ + transitive_dependencies = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, NULL); + get_typelib_dependencies_transitive (repository, typelib, + transitive_dependencies); + + /* Convert to a string array. */ + out = g_ptr_array_new_null_terminated (g_hash_table_size (transitive_dependencies), + g_free, TRUE); + g_hash_table_iter_init (&iter, transitive_dependencies); + + while (g_hash_table_iter_next (&iter, (gpointer) &dependency, NULL)) + { + g_ptr_array_add (out, dependency); + g_hash_table_iter_steal (&iter); + } + + g_hash_table_unref (transitive_dependencies); + + return (gchar **) g_ptr_array_free (out, FALSE); +} + +/** + * gi_repository_load_typelib: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @typelib: the typelib to load + * @flags: flags affecting the loading operation + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Load the given @typelib into the repository. + * + * Returns: namespace of the loaded typelib + * Since: 2.80 + */ +const char * +gi_repository_load_typelib (GIRepository *repository, + GITypelib *typelib, + GIRepositoryLoadFlags flags, + GError **error) +{ + Header *header; + const char *namespace; + const char *nsversion; + gboolean allow_lazy = flags & GI_REPOSITORY_LOAD_FLAG_LAZY; + gboolean is_lazy; + char *version_conflict; + + repository = get_repository (repository); + + header = (Header *) typelib->data; + namespace = gi_typelib_get_string (typelib, header->namespace); + nsversion = gi_typelib_get_string (typelib, header->nsversion); + + if (get_registered_status (repository, namespace, nsversion, allow_lazy, + &is_lazy, &version_conflict)) + { + if (version_conflict != NULL) + { + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT, + "Attempting to load namespace '%s', version '%s', but '%s' is already loaded", + namespace, nsversion, version_conflict); + return NULL; + } + return namespace; + } + return register_internal (repository, "", + allow_lazy, typelib, error); +} + +/** + * gi_repository_is_registered: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace of interest + * @version: (nullable): Required version, may be `NULL` for latest + * + * Check whether a particular namespace (and optionally, a specific + * version thereof) is currently loaded. + * + * This function is likely to only be useful in unusual circumstances; in order + * to act upon metadata in the namespace, you should call + * [method@GIRepository.Repository.require] instead which will ensure the + * namespace is loaded, and return as quickly as this function will if it has + * already been loaded. + * + * Returns: `TRUE` if namespace-version is loaded, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_repository_is_registered (GIRepository *repository, + const gchar *namespace, + const gchar *version) +{ + repository = get_repository (repository); + return get_registered (repository, namespace, version) != NULL; +} + +/** + * gi_repository_get_default: + * + * Returns the singleton process-global default #GIRepository. + * + * It is not currently supported to have multiple repositories in a + * particular process, but this function is provided in the unlikely + * eventuality that it would become possible, and as a convenience for + * higher level language bindings to conform to the GObject method + * call conventions. + * + * All methods on #GIRepository also accept `NULL` as an instance + * parameter to mean this default repository, which is usually more + * convenient for C. + * + * Returns: (transfer none): The global singleton [class@GIRepository.Repository] + * Since: 2.80 + */ +GIRepository * +gi_repository_get_default (void) +{ + return get_repository (NULL); +} + +/** + * gi_repository_new: + * + * Create a new (non-singleton) [class@GIRepository.Repository]. + * + * Most callers should use [func@GIRepository.Repository.get_default] instead, + * as a singleton repository is more useful in most situations. + * + * Returns: (transfer full): a new [class@GIRepository.Repository] + * Since: 2.80 + */ +GIRepository * +gi_repository_new (void) +{ + return g_object_new (GI_TYPE_REPOSITORY, NULL); +} + +/** + * gi_repository_get_n_infos: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace to inspect + * + * This function returns the number of metadata entries in + * given namespace @namespace_. + * + * The namespace must have already been loaded before calling this function. + * + * Returns: number of metadata entries + * Since: 2.80 + */ +guint +gi_repository_get_n_infos (GIRepository *repository, + const gchar *namespace) +{ + GITypelib *typelib; + guint n_interfaces = 0; + + g_return_val_if_fail (namespace != NULL, -1); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + + g_return_val_if_fail (typelib != NULL, -1); + + n_interfaces = ((Header *)typelib->data)->n_local_entries; + + return n_interfaces; +} + +/** + * gi_repository_get_info: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace to inspect + * @idx: 0-based offset into namespace metadata for entry + * + * This function returns a particular metadata entry in the + * given namespace @namespace_. + * + * The namespace must have already been loaded before calling this function. + * See [method@GIRepository.Repository.get_n_infos] to find the maximum number + * of entries. + * + * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo] containing + * metadata, or `NULL` if @idx was too high + * Since: 2.80 + */ +GIBaseInfo * +gi_repository_get_info (GIRepository *repository, + const gchar *namespace, + guint idx) +{ + GITypelib *typelib; + DirEntry *entry; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + + g_return_val_if_fail (typelib != NULL, NULL); + + entry = gi_typelib_get_dir_entry (typelib, idx + 1); + if (entry == NULL) + return NULL; + return gi_info_new_full (entry->blob_type, + repository, + NULL, typelib, entry->offset); +} + +typedef struct { + const gchar *gtype_name; + GITypelib *result_typelib; +} FindByGTypeData; + +static DirEntry * +find_by_gtype (GHashTable *table, FindByGTypeData *data, gboolean check_prefix) +{ + GHashTableIter iter; + gpointer key, value; + DirEntry *ret; + + g_hash_table_iter_init (&iter, table); + while (g_hash_table_iter_next (&iter, &key, &value)) + { + GITypelib *typelib = (GITypelib*)value; + if (check_prefix) + { + if (!gi_typelib_matches_gtype_name_prefix (typelib, data->gtype_name)) + continue; + } + + ret = gi_typelib_get_dir_entry_by_gtype_name (typelib, data->gtype_name); + if (ret) + { + data->result_typelib = typelib; + return ret; + } + } + + return NULL; +} + +/** + * gi_repository_find_by_gtype: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @gtype: [type@GObject.Type] to search for + * + * Searches all loaded namespaces for a particular [type@GObject.Type]. + * + * Note that in order to locate the metadata, the namespace corresponding to + * the type must first have been loaded. There is currently no + * mechanism for determining the namespace which corresponds to an + * arbitrary [type@GObject.Type] — thus, this function will operate most + * reliably when you know the [type@GObject.Type] is from a loaded namespace. + * + * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo] + * representing metadata about @type, or `NULL` if none found + * Since: 2.80 + */ +GIBaseInfo * +gi_repository_find_by_gtype (GIRepository *repository, + GType gtype) +{ + FindByGTypeData data; + GIBaseInfo *cached; + DirEntry *entry; + + g_return_val_if_fail (gtype != G_TYPE_INVALID, NULL); + + repository = get_repository (repository); + + cached = g_hash_table_lookup (repository->priv->info_by_gtype, + (gpointer)gtype); + + if (cached != NULL) + return gi_base_info_ref (cached); + + if (g_hash_table_contains (repository->priv->unknown_gtypes, (gpointer)gtype)) + return NULL; + + data.gtype_name = g_type_name (gtype); + data.result_typelib = NULL; + + /* Inside each typelib, we include the "C prefix" which acts as + * a namespace mechanism. For GtkTreeView, the C prefix is Gtk. + * Given the assumption that GTypes for a library also use the + * C prefix, we know we can skip examining a typelib if our + * target type does not have this typelib's C prefix. Use this + * assumption as our first attempt at locating the DirEntry. + */ + entry = find_by_gtype (repository->priv->typelibs, &data, TRUE); + if (entry == NULL) + entry = find_by_gtype (repository->priv->lazy_typelibs, &data, TRUE); + + /* Not ever class library necessarily specifies a correct c_prefix, + * so take a second pass. This time we will try a global lookup, + * ignoring prefixes. + * See http://bugzilla.gnome.org/show_bug.cgi?id=564016 + */ + if (entry == NULL) + entry = find_by_gtype (repository->priv->typelibs, &data, FALSE); + if (entry == NULL) + entry = find_by_gtype (repository->priv->lazy_typelibs, &data, FALSE); + + if (entry != NULL) + { + cached = gi_info_new_full (entry->blob_type, + repository, + NULL, data.result_typelib, entry->offset); + + g_hash_table_insert (repository->priv->info_by_gtype, + (gpointer) gtype, + gi_base_info_ref (cached)); + return cached; + } + else + { + g_hash_table_add (repository->priv->unknown_gtypes, (gpointer) gtype); + return NULL; + } +} + +/** + * gi_repository_find_by_name: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace which will be searched + * @name: Entry name to find + * + * Searches for a particular entry in a namespace. + * + * Before calling this function for a particular namespace, you must call + * [method@GIRepository.Repository.require] to load the namespace, or otherwise + * ensure the namespace has already been loaded. + * + * Returns: (transfer full) (nullable): [class@GIRepository.BaseInfo] + * representing metadata about @name, or `NULL` if none found + * Since: 2.80 + */ +GIBaseInfo * +gi_repository_find_by_name (GIRepository *repository, + const gchar *namespace, + const gchar *name) +{ + GITypelib *typelib; + DirEntry *entry; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + typelib = get_registered (repository, namespace, NULL); + g_return_val_if_fail (typelib != NULL, NULL); + + entry = gi_typelib_get_dir_entry_by_name (typelib, name); + if (entry == NULL) + return NULL; + return gi_info_new_full (entry->blob_type, + repository, + NULL, typelib, entry->offset); +} + +typedef struct { + GIRepository *repository; + GQuark domain; + + GITypelib *result_typelib; + DirEntry *result; +} FindByErrorDomainData; + +static void +find_by_error_domain_foreach (gpointer key, + gpointer value, + gpointer datap) +{ + GITypelib *typelib = (GITypelib*)value; + FindByErrorDomainData *data = datap; + + if (data->result != NULL) + return; + + data->result = gi_typelib_get_dir_entry_by_error_domain (typelib, data->domain); + if (data->result) + data->result_typelib = typelib; +} + +/** + * gi_repository_find_by_error_domain: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @domain: a [type@GLib.Error] domain + * + * Searches for the enum type corresponding to the given [type@GLib.Error] + * domain. + * + * Before calling this function for a particular namespace, you must call + * [method@GIRepository.Repository.require] to load the namespace, or otherwise + * ensure the namespace has already been loaded. + * + * Returns: (transfer full) (nullable): [class@GIRepository.EnumInfo] + * representing metadata about @domain’s enum type, or `NULL` if none found + * Since: 2.80 + */ +GIEnumInfo * +gi_repository_find_by_error_domain (GIRepository *repository, + GQuark domain) +{ + FindByErrorDomainData data; + GIEnumInfo *cached; + + repository = get_repository (repository); + + cached = g_hash_table_lookup (repository->priv->info_by_error_domain, + GUINT_TO_POINTER (domain)); + + if (cached != NULL) + return (GIEnumInfo *) gi_base_info_ref ((GIBaseInfo *)cached); + + data.repository = repository; + data.domain = domain; + data.result_typelib = NULL; + data.result = NULL; + + g_hash_table_foreach (repository->priv->typelibs, find_by_error_domain_foreach, &data); + if (data.result == NULL) + g_hash_table_foreach (repository->priv->lazy_typelibs, find_by_error_domain_foreach, &data); + + if (data.result != NULL) + { + cached = (GIEnumInfo *) gi_info_new_full (data.result->blob_type, + repository, + NULL, data.result_typelib, data.result->offset); + + g_hash_table_insert (repository->priv->info_by_error_domain, + GUINT_TO_POINTER (domain), + gi_base_info_ref ((GIBaseInfo *) cached)); + return cached; + } + return NULL; +} + +/** + * gi_repository_get_object_gtype_interfaces: + * @repository: (nullable): a #GIRepository, or `NULL` for the default repository + * @gtype: a [type@GObject.Type] whose fundamental type is `G_TYPE_OBJECT` + * @n_interfaces_out: (out): Number of interfaces + * @interfaces_out: (out) (transfer none) (array length=n_interfaces_out): Interfaces for @gtype + * + * Look up the implemented interfaces for @gtype. + * + * This function cannot fail per se; but for a totally ‘unknown’ + * [type@GObject.Type], it may return 0 implemented interfaces. + * + * The semantics of this function are designed for a dynamic binding, + * where in certain cases (such as a function which returns an + * interface which may have ‘hidden’ implementation classes), not all + * data may be statically known, and will have to be determined from + * the [type@GObject.Type] of the object. An example is + * [func@Gio.File.new_for_path] returning a concrete class of + * `GLocalFile`, which is a [type@GObject.Type] we see at runtime, but + * not statically. + * + * Since: 2.80 + */ +void +gi_repository_get_object_gtype_interfaces (GIRepository *repository, + GType gtype, + gsize *n_interfaces_out, + GIInterfaceInfo ***interfaces_out) +{ + GTypeInterfaceCache *cache; + + g_return_if_fail (g_type_fundamental (gtype) == G_TYPE_OBJECT); + + repository = get_repository (repository); + + cache = g_hash_table_lookup (repository->priv->interfaces_for_gtype, + (gpointer) gtype); + if (cache == NULL) + { + GType *interfaces; + guint n_interfaces; + guint i; + GList *interface_infos = NULL, *iter; + + interfaces = g_type_interfaces (gtype, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + { + GIBaseInfo *base_info; + + base_info = gi_repository_find_by_gtype (repository, interfaces[i]); + if (base_info == NULL) + continue; + + if (gi_base_info_get_info_type (base_info) != GI_INFO_TYPE_INTERFACE) + { + /* FIXME - could this really happen? */ + gi_base_info_unref (base_info); + continue; + } + + if (!g_list_find (interface_infos, base_info)) + interface_infos = g_list_prepend (interface_infos, base_info); + } + + cache = g_malloc (sizeof (GTypeInterfaceCache) + + sizeof (GIBaseInfo*) * g_list_length (interface_infos)); + cache->n_interfaces = g_list_length (interface_infos); + for (iter = interface_infos, i = 0; iter; iter = iter->next, i++) + cache->interfaces[i] = iter->data; + g_list_free (interface_infos); + + g_hash_table_insert (repository->priv->interfaces_for_gtype, (gpointer) gtype, + cache); + + g_free (interfaces); + } + + *n_interfaces_out = cache->n_interfaces; + *interfaces_out = (GIInterfaceInfo**)&cache->interfaces[0]; +} + +static void +collect_namespaces (gpointer key, + gpointer value, + gpointer data) +{ + GList **list = data; + + *list = g_list_append (*list, key); +} + +/** + * gi_repository_get_loaded_namespaces: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * + * Return the list of currently loaded namespaces. + * + * Returns: (element-type utf8) (transfer full) (array zero-terminated=1): `NULL`-terminated + * list of namespaces + * Since: 2.80 + */ +gchar ** +gi_repository_get_loaded_namespaces (GIRepository *repository) +{ + GList *l, *list = NULL; + gchar **names; + gint i; + + repository = get_repository (repository); + + g_hash_table_foreach (repository->priv->typelibs, collect_namespaces, &list); + g_hash_table_foreach (repository->priv->lazy_typelibs, collect_namespaces, &list); + + names = g_malloc0 (sizeof (gchar *) * (g_list_length (list) + 1)); + i = 0; + for (l = list; l; l = l->next) + names[i++] = g_strdup (l->data); + g_list_free (list); + + return names; +} + +/** + * gi_repository_get_version: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace to inspect + * + * This function returns the loaded version associated with the given + * namespace @namespace_. + * + * Note: The namespace must have already been loaded using a function + * such as [method@GIRepository.Repository.require] before calling this + * function. + * + * Returns: Loaded version + * Since: 2.80 + */ +const gchar * +gi_repository_get_version (GIRepository *repository, + const gchar *namespace) +{ + GITypelib *typelib; + Header *header; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + + g_return_val_if_fail (typelib != NULL, NULL); + + header = (Header *) typelib->data; + return gi_typelib_get_string (typelib, header->nsversion); +} + +/** + * gi_repository_get_shared_library: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace to inspect + * + * This function returns a comma-separated list of paths to the + * shared C libraries associated with the given namespace @namespace_. + * + * There may be no shared library path associated, in which case this + * function will return `NULL`. + * + * Note: The namespace must have already been loaded using a function + * such as [method@GIRepository.Repository.require] before calling this + * function. + * + * Returns: (nullable): Comma-separated list of paths to shared libraries, + * or `NULL` if none are associated + * Since: 2.80 + */ +const gchar * +gi_repository_get_shared_library (GIRepository *repository, + const gchar *namespace) +{ + GITypelib *typelib; + Header *header; + + g_return_val_if_fail (namespace != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace, NULL); + + g_return_val_if_fail (typelib != NULL, NULL); + + header = (Header *) typelib->data; + if (header->shared_library) + return gi_typelib_get_string (typelib, header->shared_library); + else + return NULL; +} + +/** + * gi_repository_get_c_prefix: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: Namespace to inspect + * + * This function returns the ‘C prefix’, or the C level namespace + * associated with the given introspection namespace. + * + * Each C symbol starts with this prefix, as well each [type@GObject.Type] in + * the library. + * + * Note: The namespace must have already been loaded using a function + * such as [method@GIRepository.Repository.require] before calling this + * function. + * + * Returns: (nullable): C namespace prefix, or `NULL` if none associated + * Since: 2.80 + */ +const gchar * +gi_repository_get_c_prefix (GIRepository *repository, + const gchar *namespace_) +{ + GITypelib *typelib; + Header *header; + + g_return_val_if_fail (namespace_ != NULL, NULL); + + repository = get_repository (repository); + + typelib = get_registered (repository, namespace_, NULL); + + g_return_val_if_fail (typelib != NULL, NULL); + + header = (Header *) typelib->data; + if (header->c_prefix) + return gi_typelib_get_string (typelib, header->c_prefix); + else + return NULL; +} + +/** + * gi_repository_get_typelib_path: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: GI namespace to use, e.g. `Gtk` + * + * If namespace @namespace_ is loaded, return the full path to the + * .typelib file it was loaded from. + * + * If the typelib for namespace @namespace_ was included in a shared library, + * return the special string ``. + * + * Returns: (type filename) (nullable): Filesystem path (or ``) if + * successful, `NULL` if namespace is not loaded + * Since: 2.80 + */ +const gchar * +gi_repository_get_typelib_path (GIRepository *repository, + const gchar *namespace) +{ + gpointer orig_key, value; + + repository = get_repository (repository); + + if (!g_hash_table_lookup_extended (repository->priv->typelibs, namespace, + &orig_key, &value)) + { + if (!g_hash_table_lookup_extended (repository->priv->lazy_typelibs, namespace, + &orig_key, &value)) + + return NULL; + } + return ((char*)orig_key) + strlen ((char *) orig_key) + 1; +} + +/* This simple search function looks for a specified namespace-version; + it's faster than the full directory listing required for latest version. */ +static GMappedFile * +find_namespace_version (const char *namespace, + const char *version, + const char * const *search_paths, + size_t n_search_paths, + char **path_ret) +{ + GError *error = NULL; + GMappedFile *mfile = NULL; + char *fname; + + fname = g_strdup_printf ("%s-%s.typelib", namespace, version); + + for (size_t i = 0; i < n_search_paths; ++i) + { + char *path = g_build_filename (search_paths[i], fname, NULL); + + mfile = g_mapped_file_new (path, FALSE, &error); + if (error) + { + g_free (path); + g_clear_error (&error); + continue; + } + *path_ret = path; + break; + } + g_free (fname); + return mfile; +} + +static gboolean +parse_version (const char *version, + int *major, + int *minor) +{ + const char *dot; + char *end; + + *major = strtol (version, &end, 10); + dot = strchr (version, '.'); + if (dot == NULL) + { + *minor = 0; + return TRUE; + } + if (dot != end) + return FALSE; + *minor = strtol (dot+1, &end, 10); + if (end != (version + strlen (version))) + return FALSE; + return TRUE; +} + +static int +compare_version (const char *v1, + const char *v2) +{ + gboolean success; + int v1_major, v1_minor; + int v2_major, v2_minor; + + success = parse_version (v1, &v1_major, &v1_minor); + g_assert (success); + + success = parse_version (v2, &v2_major, &v2_minor); + g_assert (success); + + /* Avoid a compiler warning about `success` being unused with G_DISABLE_ASSERT */ + (void) success; + + if (v1_major > v2_major) + return 1; + else if (v2_major > v1_major) + return -1; + else if (v1_minor > v2_minor) + return 1; + else if (v2_minor > v1_minor) + return -1; + return 0; +} + +struct NamespaceVersionCandidadate +{ + GMappedFile *mfile; + int path_index; + char *path; + char *version; +}; + +static int +compare_candidate_reverse (struct NamespaceVersionCandidadate *c1, + struct NamespaceVersionCandidadate *c2) +{ + int result = compare_version (c1->version, c2->version); + /* First, check the version */ + if (result > 0) + return -1; + else if (result < 0) + return 1; + else + { + /* Now check the path index, which says how early in the search path + * we found it. This ensures that of equal version targets, we + * pick the earlier one. + */ + if (c1->path_index == c2->path_index) + return 0; + else if (c1->path_index > c2->path_index) + return 1; + else + return -1; + } +} + +static void +free_candidate (struct NamespaceVersionCandidadate *candidate) +{ + g_mapped_file_unref (candidate->mfile); + g_free (candidate->path); + g_free (candidate->version); + g_slice_free (struct NamespaceVersionCandidadate, candidate); +} + +static GSList * +enumerate_namespace_versions (const char *namespace, + const char * const *search_paths, + size_t n_search_paths) +{ + GSList *candidates = NULL; + GHashTable *found_versions = g_hash_table_new (g_str_hash, g_str_equal); + char *namespace_dash; + char *namespace_typelib; + GError *error = NULL; + int index; + + namespace_dash = g_strdup_printf ("%s-", namespace); + namespace_typelib = g_strdup_printf ("%s.typelib", namespace); + + index = 0; + for (size_t i = 0; i < n_search_paths; ++i) + { + GDir *dir; + const char *dirname; + const char *entry; + + dirname = search_paths[i]; + dir = g_dir_open (dirname, 0, NULL); + if (dir == NULL) + continue; + while ((entry = g_dir_read_name (dir)) != NULL) + { + GMappedFile *mfile; + char *path, *version; + struct NamespaceVersionCandidadate *candidate; + + if (!g_str_has_suffix (entry, ".typelib")) + continue; + + if (g_str_has_prefix (entry, namespace_dash)) + { + const char *last_dash; + const char *name_end; + int major, minor; + + name_end = strrchr (entry, '.'); + last_dash = strrchr (entry, '-'); + version = g_strndup (last_dash+1, name_end-(last_dash+1)); + if (!parse_version (version, &major, &minor)) + { + g_free (version); + continue; + } + } + else + continue; + + if (g_hash_table_lookup (found_versions, version) != NULL) + { + g_free (version); + continue; + } + + path = g_build_filename (dirname, entry, NULL); + mfile = g_mapped_file_new (path, FALSE, &error); + if (mfile == NULL) + { + g_free (path); + g_free (version); + g_clear_error (&error); + continue; + } + candidate = g_slice_new0 (struct NamespaceVersionCandidadate); + candidate->mfile = mfile; + candidate->path_index = index; + candidate->path = path; + candidate->version = version; + candidates = g_slist_prepend (candidates, candidate); + g_hash_table_add (found_versions, version); + } + g_dir_close (dir); + index++; + } + + g_free (namespace_dash); + g_free (namespace_typelib); + g_hash_table_destroy (found_versions); + + return candidates; +} + +static GMappedFile * +find_namespace_latest (const char *namespace, + const char * const *search_paths, + size_t n_search_paths, + char **version_ret, + char **path_ret) +{ + GSList *candidates; + GMappedFile *result = NULL; + + *version_ret = NULL; + *path_ret = NULL; + + candidates = enumerate_namespace_versions (namespace, search_paths, n_search_paths); + + if (candidates != NULL) + { + struct NamespaceVersionCandidadate *elected; + candidates = g_slist_sort (candidates, (GCompareFunc) compare_candidate_reverse); + + elected = (struct NamespaceVersionCandidadate *) candidates->data; + /* Remove the elected one so we don't try to free its contents */ + candidates = g_slist_delete_link (candidates, candidates); + + result = elected->mfile; + *path_ret = elected->path; + *version_ret = elected->version; + g_slice_free (struct NamespaceVersionCandidadate, elected); /* just free the container */ + g_slist_foreach (candidates, (GFunc) (void *) free_candidate, NULL); + g_slist_free (candidates); + } + return result; +} + +/** + * gi_repository_enumerate_versions: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: GI namespace, e.g. `Gtk` + * @n_versions_out: (optional) (out): The number of versions returned. + * + * Obtain an unordered list of versions (either currently loaded or + * available) for @namespace_ in this @repository. + * + * Returns: (element-type utf8) (transfer full) (array length=n_versions_out): the array of versions. + * Since: 2.80 + */ +char ** +gi_repository_enumerate_versions (GIRepository *repository, + const gchar *namespace_, + size_t *n_versions_out) +{ + GPtrArray *versions; + GSList *candidates, *link; + const gchar *loaded_version; + char **ret; + + init_globals (); + candidates = enumerate_namespace_versions (namespace_, + (const char * const *) typelib_search_path->pdata, + typelib_search_path->len); + + if (!candidates) + { + if (n_versions_out) + *n_versions_out = 0; + return g_strdupv ((char *[]) {NULL}); + } + + versions = g_ptr_array_new_null_terminated (1, g_free, TRUE); + for (link = candidates; link; link = link->next) + { + struct NamespaceVersionCandidadate *candidate = link->data; + g_ptr_array_add (versions, g_steal_pointer (&candidate->version)); + free_candidate (candidate); + } + g_slist_free (candidates); + + /* The currently loaded version of a namespace is also part of the + * available versions, as it could have been loaded using + * require_private(). + */ + if (gi_repository_is_registered (repository, namespace_, NULL)) + { + loaded_version = gi_repository_get_version (repository, namespace_); + if (loaded_version && + !g_ptr_array_find_with_equal_func (versions, loaded_version, g_str_equal, NULL)) + g_ptr_array_add (versions, g_strdup (loaded_version)); + } + + ret = (char **) g_ptr_array_steal (versions, n_versions_out); + g_ptr_array_unref (g_steal_pointer (&versions)); + + return ret; +} + +static GITypelib * +require_internal (GIRepository *repository, + const char *namespace, + const char *version, + GIRepositoryLoadFlags flags, + const char * const *search_paths, + size_t n_search_paths, + GError **error) +{ + GMappedFile *mfile; + GITypelib *ret = NULL; + Header *header; + GITypelib *typelib = NULL; + const gchar *typelib_namespace, *typelib_version; + gboolean allow_lazy = (flags & GI_REPOSITORY_LOAD_FLAG_LAZY) > 0; + gboolean is_lazy; + char *version_conflict = NULL; + char *path = NULL; + char *tmp_version = NULL; + + g_return_val_if_fail (namespace != NULL, FALSE); + + repository = get_repository (repository); + + typelib = get_registered_status (repository, namespace, version, allow_lazy, + &is_lazy, &version_conflict); + if (typelib) + return typelib; + + if (version_conflict != NULL) + { + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT, + "Requiring namespace '%s' version '%s', but '%s' is already loaded", + namespace, version, version_conflict); + return NULL; + } + + if (version != NULL) + { + mfile = find_namespace_version (namespace, version, search_paths, + n_search_paths, &path); + tmp_version = g_strdup (version); + } + else + { + mfile = find_namespace_latest (namespace, search_paths, n_search_paths, + &tmp_version, &path); + } + + if (mfile == NULL) + { + if (version != NULL) + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND, + "Typelib file for namespace '%s', version '%s' not found", + namespace, version); + else + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND, + "Typelib file for namespace '%s' (any version) not found", + namespace); + goto out; + } + + { + GError *temp_error = NULL; + typelib = gi_typelib_new_from_mapped_file (mfile, &temp_error); + if (!typelib) + { + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND, + "Failed to load typelib file '%s' for namespace '%s': %s", + path, namespace, temp_error->message); + g_clear_error (&temp_error); + goto out; + } + } + header = (Header *) typelib->data; + typelib_namespace = gi_typelib_get_string (typelib, header->namespace); + typelib_version = gi_typelib_get_string (typelib, header->nsversion); + + if (strcmp (typelib_namespace, namespace) != 0) + { + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH, + "Typelib file %s for namespace '%s' contains " + "namespace '%s' which doesn't match the file name", + path, namespace, typelib_namespace); + gi_typelib_free (typelib); + goto out; + } + if (version != NULL && strcmp (typelib_version, version) != 0) + { + g_set_error (error, GI_REPOSITORY_ERROR, + GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH, + "Typelib file %s for namespace '%s' contains " + "version '%s' which doesn't match the expected version '%s'", + path, namespace, typelib_version, version); + gi_typelib_free (typelib); + goto out; + } + + if (!register_internal (repository, path, allow_lazy, + typelib, error)) + { + gi_typelib_free (typelib); + goto out; + } + ret = typelib; + out: + g_free (tmp_version); + g_free (path); + return ret; +} + +/** + * gi_repository_require: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @namespace_: GI namespace to use, e.g. `Gtk` + * @version: (nullable): Version of namespace, may be `NULL` for latest + * @flags: Set of [flags@GIRepository.RepositoryLoadFlags], may be 0 + * @error: a [type@GLib.Error]. + * + * Force the namespace @namespace_ to be loaded if it isn’t already. + * + * If @namespace_ is not loaded, this function will search for a + * `.typelib` file using the repository search path. In addition, a + * version @version of namespace may be specified. If @version is + * not specified, the latest will be used. + * + * Returns: (transfer none): a pointer to the [type@GIRepository.Typelib] if + * successful, `NULL` otherwise + * Since: 2.80 + */ +GITypelib * +gi_repository_require (GIRepository *repository, + const gchar *namespace, + const gchar *version, + GIRepositoryLoadFlags flags, + GError **error) +{ + GITypelib *typelib; + + init_globals (); + typelib = require_internal (repository, namespace, version, flags, + (const char * const *) typelib_search_path->pdata, + typelib_search_path->len, error); + + return typelib; +} + +/** + * gi_repository_require_private: + * @repository: (nullable): A #GIRepository, or `NULL` for the singleton + * process-global default #GIRepository + * @typelib_dir: (type filename): Private directory where to find the requested + * typelib + * @namespace_: GI namespace to use, e.g. `Gtk` + * @version: (nullable): Version of namespace, may be `NULL` for latest + * @flags: Set of [flags@GIRepository.RepositoryLoadFlags], may be 0 + * @error: a [type@GLib.Error]. + * + * Force the namespace @namespace_ to be loaded if it isn’t already. + * + * If @namespace_ is not loaded, this function will search for a + * `.typelib` file within the private directory only. In addition, a + * version @version of namespace should be specified. If @version is + * not specified, the latest will be used. + * + * Returns: (transfer none): a pointer to the [type@GIRepository.Typelib] if + * successful, `NULL` otherwise + * Since: 2.80 + */ +GITypelib * +gi_repository_require_private (GIRepository *repository, + const gchar *typelib_dir, + const gchar *namespace, + const gchar *version, + GIRepositoryLoadFlags flags, + GError **error) +{ + const char * const search_path[] = { typelib_dir, NULL }; + + return require_internal (repository, namespace, version, flags, + search_path, 1, error); +} + +static gboolean +gi_repository_introspect_cb (const char *option_name, + const char *value, + gpointer data, + GError **error) +{ + GError *tmp_error = NULL; + char **args; + + args = g_strsplit (value, ",", 2); + + if (!gi_repository_dump (args[0], args[1], &tmp_error)) + { + g_error ("Failed to extract GType data: %s", + tmp_error->message); + exit (1); + } + exit (0); +} + +static const GOptionEntry introspection_args[] = { + { "introspect-dump", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, + gi_repository_introspect_cb, "Dump introspection information", + "infile.txt,outfile.xml" }, + G_OPTION_ENTRY_NULL +}; + +/** + * gi_repository_get_option_group: + * + * Obtain the option group for girepository. + * + * It’s used by the dumper and for programs that want to provide introspection + * information + * + * Returns: (transfer full): the option group + * Since: 2.80 + */ +GOptionGroup * +gi_repository_get_option_group (void) +{ + GOptionGroup *group; + group = g_option_group_new ("girepository", "Introspection Options", "Show Introspection Options", NULL, NULL); + + g_option_group_add_entries (group, introspection_args); + return group; +} + +GQuark +gi_repository_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("g-irepository-error-quark"); + return quark; +} + +/** + * gi_type_tag_to_string: + * @type: the type_tag + * + * Obtain a string representation of @type + * + * Returns: the string + * Since: 2.80 + */ +const gchar* +gi_type_tag_to_string (GITypeTag type) +{ + switch (type) + { + case GI_TYPE_TAG_VOID: + return "void"; + case GI_TYPE_TAG_BOOLEAN: + return "gboolean"; + case GI_TYPE_TAG_INT8: + return "gint8"; + case GI_TYPE_TAG_UINT8: + return "guint8"; + case GI_TYPE_TAG_INT16: + return "gint16"; + case GI_TYPE_TAG_UINT16: + return "guint16"; + case GI_TYPE_TAG_INT32: + return "gint32"; + case GI_TYPE_TAG_UINT32: + return "guint32"; + case GI_TYPE_TAG_INT64: + return "gint64"; + case GI_TYPE_TAG_UINT64: + return "guint64"; + case GI_TYPE_TAG_FLOAT: + return "gfloat"; + case GI_TYPE_TAG_DOUBLE: + return "gdouble"; + case GI_TYPE_TAG_UNICHAR: + return "gunichar"; + case GI_TYPE_TAG_GTYPE: + return "GType"; + case GI_TYPE_TAG_UTF8: + return "utf8"; + case GI_TYPE_TAG_FILENAME: + return "filename"; + case GI_TYPE_TAG_ARRAY: + return "array"; + case GI_TYPE_TAG_INTERFACE: + return "interface"; + case GI_TYPE_TAG_GLIST: + return "glist"; + case GI_TYPE_TAG_GSLIST: + return "gslist"; + case GI_TYPE_TAG_GHASH: + return "ghash"; + case GI_TYPE_TAG_ERROR: + return "error"; + default: + return "unknown"; + } +} + +/** + * gi_info_type_to_string: + * @type: the info type + * + * Obtain a string representation of @type + * + * Returns: the string + * Since: 2.80 + */ +const gchar* +gi_info_type_to_string (GIInfoType type) +{ + switch (type) + { + case GI_INFO_TYPE_INVALID: + return "invalid"; + case GI_INFO_TYPE_FUNCTION: + return "function"; + case GI_INFO_TYPE_CALLBACK: + return "callback"; + case GI_INFO_TYPE_STRUCT: + return "struct"; + case GI_INFO_TYPE_BOXED: + return "boxed"; + case GI_INFO_TYPE_ENUM: + return "enum"; + case GI_INFO_TYPE_FLAGS: + return "flags"; + case GI_INFO_TYPE_OBJECT: + return "object"; + case GI_INFO_TYPE_INTERFACE: + return "interface"; + case GI_INFO_TYPE_CONSTANT: + return "constant"; + case GI_INFO_TYPE_UNION: + return "union"; + case GI_INFO_TYPE_VALUE: + return "value"; + case GI_INFO_TYPE_SIGNAL: + return "signal"; + case GI_INFO_TYPE_VFUNC: + return "vfunc"; + case GI_INFO_TYPE_PROPERTY: + return "property"; + case GI_INFO_TYPE_FIELD: + return "field"; + case GI_INFO_TYPE_ARG: + return "arg"; + case GI_INFO_TYPE_TYPE: + return "type"; + case GI_INFO_TYPE_UNRESOLVED: + return "unresolved"; + default: + return "unknown"; + } +} diff --git a/girepository/girepository.h b/girepository/girepository.h new file mode 100644 index 0000000..05d7cf8 --- /dev/null +++ b/girepository/girepository.h @@ -0,0 +1,256 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Repository + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include + +#include + +#define __GIREPOSITORY_H_INSIDE__ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +G_BEGIN_DECLS + +#define GI_TYPE_REPOSITORY (gi_repository_get_type ()) +#define GI_REPOSITORY(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), GI_TYPE_REPOSITORY, GIRepository)) +#define GI_REPOSITORY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GI_TYPE_REPOSITORY, GIRepositoryClass)) +#define GI_IS_REPOSITORY(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), GI_TYPE_REPOSITORY)) +#define GI_IS_REPOSITORY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GI_TYPE_REPOSITORY)) +#define GI_REPOSITORY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GI_TYPE_REPOSITORY, GIRepositoryClass)) + +typedef struct _GIRepository GIRepository; +typedef struct _GIRepositoryClass GIRepositoryClass; +typedef struct _GIRepositoryPrivate GIRepositoryPrivate; + +struct _GIRepository +{ + /*< private >*/ + GObject parent; + GIRepositoryPrivate *priv; +}; + +struct _GIRepositoryClass +{ + /*< private >*/ + GObjectClass parent; +}; + +/** + * GIRepositoryLoadFlags: + * @GI_REPOSITORY_LOAD_FLAG_LAZY: Lazily load the typelib. + * + * Flags that control how a typelib is loaded. + * + * Since: 2.80 + */ +typedef enum +{ + GI_REPOSITORY_LOAD_FLAG_LAZY = 1 << 0 +} GIRepositoryLoadFlags; + +/* Repository */ + +GI_AVAILABLE_IN_ALL +GType gi_repository_get_type (void) G_GNUC_CONST; + +GI_AVAILABLE_IN_ALL +GIRepository *gi_repository_get_default (void); + +GI_AVAILABLE_IN_ALL +GIRepository *gi_repository_new (void); + +GI_AVAILABLE_IN_ALL +void gi_repository_prepend_search_path (const char *directory); + +GI_AVAILABLE_IN_ALL +void gi_repository_prepend_library_path (const char *directory); + +GI_AVAILABLE_IN_ALL +const char * const * gi_repository_get_search_path (size_t *n_paths_out); + +GI_AVAILABLE_IN_ALL +const char * gi_repository_load_typelib (GIRepository *repository, + GITypelib *typelib, + GIRepositoryLoadFlags flags, + GError **error); + +GI_AVAILABLE_IN_ALL +gboolean gi_repository_is_registered (GIRepository *repository, + const gchar *namespace_, + const gchar *version); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_repository_find_by_name (GIRepository *repository, + const gchar *namespace_, + const gchar *name); + +GI_AVAILABLE_IN_ALL +char ** gi_repository_enumerate_versions (GIRepository *repository, + const gchar *namespace_, + size_t *n_versions_out); + +GI_AVAILABLE_IN_ALL +GITypelib * gi_repository_require (GIRepository *repository, + const gchar *namespace_, + const gchar *version, + GIRepositoryLoadFlags flags, + GError **error); + +GI_AVAILABLE_IN_ALL +GITypelib * gi_repository_require_private (GIRepository *repository, + const gchar *typelib_dir, + const gchar *namespace_, + const gchar *version, + GIRepositoryLoadFlags flags, + GError **error); + +GI_AVAILABLE_IN_ALL +gchar ** gi_repository_get_immediate_dependencies (GIRepository *repository, + const gchar *namespace_); + +GI_AVAILABLE_IN_ALL +gchar ** gi_repository_get_dependencies (GIRepository *repository, + const gchar *namespace_); + +GI_AVAILABLE_IN_ALL +gchar ** gi_repository_get_loaded_namespaces (GIRepository *repository); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_repository_find_by_gtype (GIRepository *repository, + GType gtype); + +GI_AVAILABLE_IN_ALL +void gi_repository_get_object_gtype_interfaces (GIRepository *repository, + GType gtype, + gsize *n_interfaces_out, + GIInterfaceInfo ***interfaces_out); + +GI_AVAILABLE_IN_ALL +guint gi_repository_get_n_infos (GIRepository *repository, + const gchar *namespace_); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_repository_get_info (GIRepository *repository, + const gchar *namespace_, + guint idx); + +GI_AVAILABLE_IN_ALL +GIEnumInfo * gi_repository_find_by_error_domain (GIRepository *repository, + GQuark domain); + +GI_AVAILABLE_IN_ALL +const gchar * gi_repository_get_typelib_path (GIRepository *repository, + const gchar *namespace_); +GI_AVAILABLE_IN_ALL +const gchar * gi_repository_get_shared_library (GIRepository *repository, + const gchar *namespace_); +GI_AVAILABLE_IN_ALL +const gchar * gi_repository_get_c_prefix (GIRepository *repository, + const gchar *namespace_); +GI_AVAILABLE_IN_ALL +const gchar * gi_repository_get_version (GIRepository *repository, + const gchar *namespace_); + + +GI_AVAILABLE_IN_ALL +GOptionGroup * gi_repository_get_option_group (void); + + +GI_AVAILABLE_IN_ALL +gboolean gi_repository_dump (const char *input_filename, + const char *output_filename, + GError **error); + +/** + * GIRepositoryError: + * @GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND: the typelib could not be found. + * @GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH: the namespace does not match the + * requested namespace. + * @GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT: the version of the + * typelib does not match the requested version. + * @GI_REPOSITORY_ERROR_LIBRARY_NOT_FOUND: the library used by the typelib + * could not be found. + * + * An error code used with `GI_REPOSITORY_ERROR` in a [type@GLib.Error] + * returned from a [class@GIRepository.Repository] routine. + * + * Since: 2.80 + */ +typedef enum +{ + GI_REPOSITORY_ERROR_TYPELIB_NOT_FOUND, + GI_REPOSITORY_ERROR_NAMESPACE_MISMATCH, + GI_REPOSITORY_ERROR_NAMESPACE_VERSION_CONFLICT, + GI_REPOSITORY_ERROR_LIBRARY_NOT_FOUND +} GIRepositoryError; + +/** + * GI_REPOSITORY_ERROR: + * + * Error domain for [class@GIRepository.Repository]. + * + * Errors in this domain will be from the [enum@GIRepository.Error] enumeration. + * See [type@GLib.Error] for more information on error domains. + * + * Since: 2.80 + */ +#define GI_REPOSITORY_ERROR (gi_repository_error_quark ()) + +GI_AVAILABLE_IN_ALL +GQuark gi_repository_error_quark (void); + + +/* Global utility functions */ + +GI_AVAILABLE_IN_ALL +void gi_cclosure_marshal_generic (GClosure *closure, + GValue *return_gvalue, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data); + +G_END_DECLS diff --git a/girepository/girffi.c b/girepository/girffi.c new file mode 100644 index 0000000..aed8e81 --- /dev/null +++ b/girepository/girffi.c @@ -0,0 +1,460 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Helper functions for ffi integration + * + * Copyright (C) 2008 Red Hat, Inc + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include +#ifdef HAVE_UNISTD_H +#include +#endif +#include "girffi.h" +#include "girepository.h" +#include "girepository-private.h" + +static ffi_type * +gi_type_tag_get_ffi_type_internal (GITypeTag tag, + gboolean is_pointer, + gboolean is_enum) +{ + switch (tag) + { + case GI_TYPE_TAG_BOOLEAN: + return &ffi_type_uint; + case GI_TYPE_TAG_INT8: + return &ffi_type_sint8; + case GI_TYPE_TAG_UINT8: + return &ffi_type_uint8; + case GI_TYPE_TAG_INT16: + return &ffi_type_sint16; + case GI_TYPE_TAG_UINT16: + return &ffi_type_uint16; + case GI_TYPE_TAG_INT32: + return &ffi_type_sint32; + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UNICHAR: + return &ffi_type_uint32; + case GI_TYPE_TAG_INT64: + return &ffi_type_sint64; + case GI_TYPE_TAG_UINT64: + return &ffi_type_uint64; + case GI_TYPE_TAG_GTYPE: +#if GLIB_SIZEOF_SIZE_T == 4 + return &ffi_type_uint32; +#elif GLIB_SIZEOF_SIZE_T == 8 + return &ffi_type_uint64; +#else +# error "Unexpected size for size_t: not 4 or 8" +#endif + case GI_TYPE_TAG_FLOAT: + return &ffi_type_float; + case GI_TYPE_TAG_DOUBLE: + return &ffi_type_double; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + return &ffi_type_pointer; + case GI_TYPE_TAG_INTERFACE: + { + /* We need to handle enums specially: + * https://bugzilla.gnome.org/show_bug.cgi?id=665150 + */ + if (!is_enum) + return &ffi_type_pointer; + else + return &ffi_type_sint32; + } + case GI_TYPE_TAG_VOID: + if (is_pointer) + return &ffi_type_pointer; + else + return &ffi_type_void; + default: + break; + } + + g_assert_not_reached (); + + return NULL; +} + +/** + * gi_type_tag_get_ffi_type: + * @type_tag: a #GITypeTag + * @is_pointer: whether this is a pointer type + * + * Get the `ffi_type` corresponding to @type_tag. + * + * Returns: (transfer none): an `ffi_type` corresponding to the platform default + * C ABI for @tag and @is_pointer. + * Since: 2.80 + */ +ffi_type * +gi_type_tag_get_ffi_type (GITypeTag type_tag, + gboolean is_pointer) +{ + return gi_type_tag_get_ffi_type_internal (type_tag, is_pointer, FALSE); +} + +/** + * gi_type_info_get_ffi_type: + * @info: a #GITypeInfo + * + * Get the `ffi_type` corresponding to @info. + * + * Returns: (transfer none): a `ffi_type` corresponding to the platform default + * C ABI for @info. + * Since: 2.80 + */ +ffi_type * +gi_type_info_get_ffi_type (GITypeInfo *info) +{ + gboolean is_enum = FALSE; + GIBaseInfo *iinfo; + + if (gi_type_info_get_tag (info) == GI_TYPE_TAG_INTERFACE) + { + iinfo = gi_type_info_get_interface (info); + switch (gi_base_info_get_info_type (iinfo)) + { + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + is_enum = TRUE; + break; + default: + break; + } + gi_base_info_unref (iinfo); + } + + return gi_type_tag_get_ffi_type_internal (gi_type_info_get_tag (info), gi_type_info_is_pointer (info), is_enum); +} + +/** + * gi_callable_info_get_ffi_arg_types: + * @callable_info: a callable info from a typelib + * @n_args_p: (out) (optional): the number of arguments returned + * + * Get the `ffi_type`s for the arguments of @callable_info. + * + * Returns: (transfer container) (array length=n_args_p): an array of + * `ffi_type*`. The array itself should be freed using [func@GLib.free] after + * use. + * Since: 2.80 + */ +static ffi_type ** +gi_callable_info_get_ffi_arg_types (GICallableInfo *callable_info, + int *n_args_p) +{ + ffi_type **arg_types; + gboolean is_method, throws; + gint n_args, n_invoke_args, i, offset; + + g_return_val_if_fail (callable_info != NULL, NULL); + + n_args = gi_callable_info_get_n_args (callable_info); + is_method = gi_callable_info_is_method (callable_info); + throws = gi_callable_info_can_throw_gerror (callable_info); + offset = is_method ? 1 : 0; + + n_invoke_args = n_args; + + if (is_method) + n_invoke_args++; + if (throws) + n_invoke_args++; + + if (n_args_p) + *n_args_p = n_invoke_args; + + arg_types = (ffi_type **) g_new0 (ffi_type *, n_invoke_args + 1); + + if (is_method) + arg_types[0] = &ffi_type_pointer; + if (throws) + arg_types[n_invoke_args - 1] = &ffi_type_pointer; + + for (i = 0; i < n_args; ++i) + { + GIArgInfo arg_info; + GITypeInfo arg_type; + + gi_callable_info_load_arg (callable_info, i, &arg_info); + gi_arg_info_load_type (&arg_info, &arg_type); + switch (gi_arg_info_get_direction (&arg_info)) + { + case GI_DIRECTION_IN: + arg_types[i + offset] = gi_type_info_get_ffi_type (&arg_type); + break; + case GI_DIRECTION_OUT: + case GI_DIRECTION_INOUT: + arg_types[i + offset] = &ffi_type_pointer; + break; + default: + g_assert_not_reached (); + } + } + + arg_types[n_invoke_args] = NULL; + + return arg_types; +} + +/** + * gi_callable_info_get_ffi_return_type: + * @callable_info: a callable info from a typelib + * + * Fetches the `ffi_type` for a corresponding return value of + * a [class@GIRepository.CallableInfo]. + * + * Returns: (transfer none): the `ffi_type` for the return value + * Since: 2.80 + */ +static ffi_type * +gi_callable_info_get_ffi_return_type (GICallableInfo *callable_info) +{ + GITypeInfo *return_type; + ffi_type *return_ffi_type; + + g_return_val_if_fail (callable_info != NULL, NULL); + + return_type = gi_callable_info_get_return_type (callable_info); + return_ffi_type = gi_type_info_get_ffi_type (return_type); + gi_base_info_unref((GIBaseInfo*)return_type); + + return return_ffi_type; +} + +/** + * gi_function_info_prep_invoker: + * @info: A #GIFunctionInfo + * @invoker: (out caller-allocates): Output invoker structure + * @error: A #GError + * + * Initialize the caller-allocated @invoker structure with a cache + * of information needed to invoke the C function corresponding to + * @info with the platform’s default ABI. + * + * A primary intent of this function is that a dynamic structure allocated + * by a language binding could contain a [type@GIRepository.FunctionInvoker] + * structure inside the binding’s function mapping. + * + * Returns: `TRUE` on success, `FALSE` otherwise with @error set. + * Since: 2.80 + */ +gboolean +gi_function_info_prep_invoker (GIFunctionInfo *info, + GIFunctionInvoker *invoker, + GError **error) +{ + const char *symbol; + gpointer addr; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (invoker != NULL, FALSE); + + symbol = gi_function_info_get_symbol ((GIFunctionInfo*) info); + + if (!gi_typelib_symbol (gi_base_info_get_typelib ((GIBaseInfo *) info), + symbol, &addr)) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Could not locate %s: %s", symbol, g_module_error ()); + + return FALSE; + } + + return gi_function_invoker_new_for_address (addr, (GICallableInfo *) info, invoker, error); +} + +/** + * gi_function_invoker_new_for_address: + * @addr: The address + * @info: A #GICallableInfo + * @invoker: (out caller-allocates): Output invoker structure + * @error: A #GError + * + * Initialize the caller-allocated @invoker structure with a cache + * of information needed to invoke the C function corresponding to + * @info with the platform’s default ABI. + * + * A primary intent of this function is that a dynamic structure allocated + * by a language binding could contain a [type@GIRepository.FunctionInvoker] + * structure inside the binding’s function mapping. + * + * Returns: `TRUE` on success, `FALSE` otherwise with @error set. + * Since: 2.80 + */ +gboolean +gi_function_invoker_new_for_address (gpointer addr, + GICallableInfo *info, + GIFunctionInvoker *invoker, + GError **error) +{ + ffi_type **atypes; + gint n_args; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (invoker != NULL, FALSE); + + invoker->native_address = addr; + + atypes = gi_callable_info_get_ffi_arg_types (info, &n_args); + + return ffi_prep_cif (&(invoker->cif), FFI_DEFAULT_ABI, n_args, + gi_callable_info_get_ffi_return_type (info), + atypes) == FFI_OK; +} + +/** + * gi_function_invoker_destroy: + * @invoker: (transfer none): A #GIFunctionInvoker + * + * Release all resources allocated for the internals of @invoker. + * + * Callers are responsible for freeing any resources allocated for the structure + * itself however. + * + * Since: 2.80 + */ +void +gi_function_invoker_destroy (GIFunctionInvoker *invoker) +{ + g_free (invoker->cif.arg_types); +} + +typedef struct { + ffi_closure ffi_closure; + gpointer writable_self; + gpointer native_address; +} GIClosureWrapper; + +/** + * gi_callable_info_create_closure: + * @callable_info: a callable info from a typelib + * @cif: a `ffi_cif` structure + * @callback: the ffi callback + * @user_data: data to be passed into the callback + * + * Prepares a callback for ffi invocation. + * + * Returns: (transfer full) (nullable): the `ffi_closure`, or `NULL` on error. + * The return value should be freed by calling + * [method@GIRepository.CallableInfo.destroy_closure]. + * Since: 2.80 + */ +ffi_closure * +gi_callable_info_create_closure (GICallableInfo *callable_info, + ffi_cif *cif, + GIFFIClosureCallback callback, + gpointer user_data) +{ + gpointer exec_ptr; + int n_args; + ffi_type **atypes; + GIClosureWrapper *closure; + ffi_status status; + + g_return_val_if_fail (callable_info != NULL, FALSE); + g_return_val_if_fail (cif != NULL, FALSE); + g_return_val_if_fail (callback != NULL, FALSE); + + closure = ffi_closure_alloc (sizeof (GIClosureWrapper), &exec_ptr); + if (!closure) + { + g_warning ("could not allocate closure\n"); + return NULL; + } + closure->writable_self = closure; + closure->native_address = exec_ptr; + + + atypes = gi_callable_info_get_ffi_arg_types (callable_info, &n_args); + status = ffi_prep_cif (cif, FFI_DEFAULT_ABI, n_args, + gi_callable_info_get_ffi_return_type (callable_info), + atypes); + if (status != FFI_OK) + { + g_warning ("ffi_prep_cif failed: %d\n", status); + ffi_closure_free (closure); + return NULL; + } + + status = ffi_prep_closure_loc (&closure->ffi_closure, cif, callback, user_data, exec_ptr); + if (status != FFI_OK) + { + g_warning ("ffi_prep_closure failed: %d\n", status); + ffi_closure_free (closure); + return NULL; + } + + return &closure->ffi_closure; +} + +/** + * gi_callable_info_get_closure_native_address: + * @callable_info: a callable info from a typelib + * @closure: ffi closure + * + * Gets callable code from `ffi_closure` prepared by + * [method@GIRepository.CallableInfo.create_closure]. + * + * Returns: (transfer none): native address + * Since: 2.80 + */ +gpointer * +gi_callable_info_get_closure_native_address (GICallableInfo *callable_info, + ffi_closure *closure) +{ + GIClosureWrapper *wrapper = (GIClosureWrapper *)closure; + return wrapper->native_address; +} + +/** + * gi_callable_info_destroy_closure: + * @callable_info: a callable info from a typelib + * @closure: (transfer full): ffi closure + * + * Frees a `ffi_closure` returned from + * [method@GIRepository.CallableInfo.create_closure]. + * + * Since: 2.80 + */ +void +gi_callable_info_destroy_closure (GICallableInfo *callable_info, + ffi_closure *closure) +{ + GIClosureWrapper *wrapper = (GIClosureWrapper *)closure; + + g_free (wrapper->ffi_closure.cif->arg_types); + ffi_closure_free (wrapper->writable_self); +} diff --git a/girepository/girffi.h b/girepository/girffi.h new file mode 100644 index 0000000..4125011 --- /dev/null +++ b/girepository/girffi.h @@ -0,0 +1,128 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Helper functions for ffi integration + * + * Copyright (C) 2008 Red Hat, Inc + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include "girepository.h" + +G_BEGIN_DECLS + +/** + * GIFFIClosureCallback: + * @cif: the `ffi_cif` passed to + * [method@GIRepository.CallableInfo.create_closure] + * @ret: (out caller-allocates): a pointer to the memory used for the function’s + * return value + * @args: a vector of pointers to memory holding the arguments to the function + * @user_data: the user data passed to + * [method@GIRepository.CallableInfo.create_closure] + * + * The function which will be called when a closure created with + * [method@GIRepository.CallableInfo.create_closure] is invoked. + * + * The value of @ret is undefined if the function returns `void`. + * + * Since: 2.80 + */ +typedef void (*GIFFIClosureCallback) (ffi_cif *cif, + void *ret, + void **args, + void *user_data); + +/** + * GIFunctionInvoker: + * @cif: the cif + * @native_address: the native address + * + * Structure containing the data necessary to invoke a callable function. + * + * Since: 2.80 + */ +typedef struct { + ffi_cif cif; + gpointer native_address; + /*< private >*/ + gpointer padding[3]; +} GIFunctionInvoker; + +/** + * GIFFIReturnValue: + * + * The type of a return value from a callable invocation closure. + * + * Since: 2.80 + */ +typedef GIArgument GIFFIReturnValue; + +GI_AVAILABLE_IN_ALL +ffi_type * gi_type_tag_get_ffi_type (GITypeTag type_tag, gboolean is_pointer); + +GI_AVAILABLE_IN_ALL +ffi_type * gi_type_info_get_ffi_type (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_type_info_extract_ffi_return_value (GITypeInfo *return_info, + GIFFIReturnValue *ffi_value, + GIArgument *arg); + +GI_AVAILABLE_IN_ALL +void gi_type_tag_extract_ffi_return_value (GITypeTag return_tag, + GIInfoType interface_type, + GIFFIReturnValue *ffi_value, + GIArgument *arg); + +GI_AVAILABLE_IN_ALL +gboolean gi_function_info_prep_invoker (GIFunctionInfo *info, + GIFunctionInvoker *invoker, + GError **error); + +GI_AVAILABLE_IN_ALL +gboolean gi_function_invoker_new_for_address (gpointer addr, + GICallableInfo *info, + GIFunctionInvoker *invoker, + GError **error); + +GI_AVAILABLE_IN_ALL +void gi_function_invoker_destroy (GIFunctionInvoker *invoker); + + +GI_AVAILABLE_IN_ALL +ffi_closure * gi_callable_info_create_closure (GICallableInfo *callable_info, + ffi_cif *cif, + GIFFIClosureCallback callback, + gpointer user_data); + +GI_AVAILABLE_IN_ALL +gpointer * gi_callable_info_get_closure_native_address (GICallableInfo *callable_info, + ffi_closure *closure); + +GI_AVAILABLE_IN_ALL +void gi_callable_info_destroy_closure (GICallableInfo *callable_info, + ffi_closure *closure); + +G_END_DECLS diff --git a/girepository/girmodule-private.h b/girepository/girmodule-private.h new file mode 100644 index 0000000..ef38663 --- /dev/null +++ b/girepository/girmodule-private.h @@ -0,0 +1,85 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Parsed IDL + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include "gitypelib-internal.h" + +G_BEGIN_DECLS + +typedef struct _GIIrTypelibBuild GIIrTypelibBuild; +typedef struct _GIIrModule GIIrModule; + +struct _GIIrTypelibBuild { + GIIrModule *module; + GHashTable *strings; + GHashTable *types; + GList *nodes_with_attributes; + guint32 n_attributes; + guchar *data; + GList *stack; +}; + +struct _GIIrModule +{ + gchar *name; + gchar *version; + gchar *shared_library; + gchar *c_prefix; + GList *dependencies; + GList *entries; + + /* All modules that are included directly or indirectly */ + GList *include_modules; + + /* Aliases defined in the module or in included modules */ + GHashTable *aliases; + + /* Structures with the 'pointer' flag (typedef struct _X *X) + * in the module or in included modules + */ + GHashTable *pointer_structures; + /* Same as 'pointer' structures, but with the deprecated + * 'disguised' flag + */ + GHashTable *disguised_structures; +}; + +GIIrModule *gi_ir_module_new (const gchar *name, + const gchar *nsversion, + const gchar *module_filename, + const gchar *c_prefix); +void gi_ir_module_free (GIIrModule *module); + +void gi_ir_module_add_include_module (GIIrModule *module, + GIIrModule *include_module); + +GITypelib * gi_ir_module_build_typelib (GIIrModule *module); + +void gi_ir_module_fatal (GIIrTypelibBuild *build, guint line, const char *msg, ...) G_GNUC_PRINTF (3, 4) G_GNUC_NORETURN; + +void gi_ir_node_init_stats (void); +void gi_ir_node_dump_stats (void); + +G_END_DECLS diff --git a/girepository/girmodule.c b/girepository/girmodule.c new file mode 100644 index 0000000..f81bc76 --- /dev/null +++ b/girepository/girmodule.c @@ -0,0 +1,584 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Typelib creation + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "girmodule-private.h" + +#include "girnode-private.h" +#include "gitypelib-internal.h" + +#include +#include +#include + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + +#define NUM_SECTIONS 2 + +GIIrModule * +gi_ir_module_new (const gchar *name, + const gchar *version, + const gchar *shared_library, + const gchar *c_prefix) +{ + GIIrModule *module; + + module = g_slice_new0 (GIIrModule); + + module->name = g_strdup (name); + module->version = g_strdup (version); + if (shared_library) + module->shared_library = g_strdup (shared_library); + else + module->shared_library = NULL; + module->c_prefix = g_strdup (c_prefix); + module->dependencies = NULL; + module->entries = NULL; + + module->include_modules = NULL; + module->aliases = NULL; + + return module; +} + +void +gi_ir_module_free (GIIrModule *module) +{ + GList *e; + + g_free (module->name); + + for (e = module->entries; e; e = e->next) + gi_ir_node_free ((GIIrNode *)e->data); + + g_list_free (module->entries); + /* Don't free dependencies, we inherit that from the parser */ + + g_list_free (module->include_modules); + + g_hash_table_destroy (module->aliases); + g_hash_table_destroy (module->pointer_structures); + g_hash_table_destroy (module->disguised_structures); + + g_slice_free (GIIrModule, module); +} + +/** + * gi_ir_module_fatal: + * @build: Current build + * @line: Origin line number, or 0 if unknown + * @msg: printf-format string + * @args: Remaining arguments + * + * Report a fatal error, then exit. + * + * Since: 2.80 + */ +void +gi_ir_module_fatal (GIIrTypelibBuild *build, + guint line, + const char *msg, + ...) +{ + GString *context; + char *formatted; + GList *link; + + va_list args; + + va_start (args, msg); + + formatted = g_strdup_vprintf (msg, args); + + context = g_string_new (""); + if (line > 0) + g_string_append_printf (context, "%d: ", line); + if (build->stack) + g_string_append (context, "In "); + for (link = g_list_last (build->stack); link; link = link->prev) + { + GIIrNode *node = link->data; + const char *name = node->name; + if (name) + g_string_append (context, name); + if (link->prev) + g_string_append (context, "."); + } + if (build->stack) + g_string_append (context, ": "); + + g_printerr ("%s-%s.gir:%serror: %s\n", build->module->name, + build->module->version, + context->str, formatted); + g_string_free (context, TRUE); + + exit (1); + + va_end (args); +} + +static void +add_alias_foreach (gpointer key, + gpointer value, + gpointer data) +{ + GIIrModule *module = data; + + g_hash_table_replace (module->aliases, g_strdup (key), g_strdup (value)); +} + +static void +add_pointer_structure_foreach (gpointer key, + gpointer value, + gpointer data) +{ + GIIrModule *module = data; + + g_hash_table_replace (module->pointer_structures, g_strdup (key), value); +} + +static void +add_disguised_structure_foreach (gpointer key, + gpointer value, + gpointer data) +{ + GIIrModule *module = data; + + g_hash_table_replace (module->disguised_structures, g_strdup (key), value); +} + +void +gi_ir_module_add_include_module (GIIrModule *module, + GIIrModule *include_module) +{ + module->include_modules = g_list_prepend (module->include_modules, + include_module); + + g_hash_table_foreach (include_module->aliases, + add_alias_foreach, + module); + + g_hash_table_foreach (include_module->pointer_structures, + add_pointer_structure_foreach, + module); + g_hash_table_foreach (include_module->disguised_structures, + add_disguised_structure_foreach, + module); +} + +struct AttributeWriteData +{ + guint count; + guchar *databuf; + GIIrNode *node; + GHashTable *strings; + guint32 *offset; + guint32 *offset2; +}; + +static void +write_attribute (gpointer key, gpointer value, gpointer datap) +{ + struct AttributeWriteData *data = datap; + guint32 old_offset = *(data->offset); + AttributeBlob *blob = (AttributeBlob*)&(data->databuf[old_offset]); + + *(data->offset) += sizeof (AttributeBlob); + + blob->offset = data->node->offset; + blob->name = gi_ir_write_string ((const char*) key, data->strings, data->databuf, data->offset2); + blob->value = gi_ir_write_string ((const char*) value, data->strings, data->databuf, data->offset2); + + data->count++; +} + +static guint +write_attributes (GIIrModule *module, + GIIrNode *node, + GHashTable *strings, + guchar *data, + guint32 *offset, + guint32 *offset2) +{ + struct AttributeWriteData wdata; + wdata.count = 0; + wdata.databuf = data; + wdata.node = node; + wdata.offset = offset; + wdata.offset2 = offset2; + wdata.strings = strings; + + g_hash_table_foreach (node->attributes, write_attribute, &wdata); + + return wdata.count; +} + +static gint +node_cmp_offset_func (gconstpointer a, + gconstpointer b) +{ + const GIIrNode *na = a; + const GIIrNode *nb = b; + return na->offset - nb->offset; +} + +static void +alloc_section (guint8 *data, SectionType section_id, guint32 offset) +{ + int i; + Header *header = (Header*)data; + Section *section_data = (Section*)&data[header->sections]; + + g_assert (section_id != GI_SECTION_END); + + for (i = 0; i < NUM_SECTIONS; i++) + { + if (section_data->id == GI_SECTION_END) + { + section_data->id = section_id; + section_data->offset = offset; + return; + } + section_data++; + } + g_assert_not_reached (); +} + +static guint8* +add_directory_index_section (guint8 *data, GIIrModule *module, guint32 *offset2) +{ + DirEntry *entry; + Header *header = (Header*)data; + GITypelibHashBuilder *dirindex_builder; + guint i, n_interfaces; + guint16 required_size; + guint32 new_offset; + + dirindex_builder = gi_typelib_hash_builder_new (); + + n_interfaces = ((Header *)data)->n_local_entries; + + for (i = 0; i < n_interfaces; i++) + { + const char *str; + entry = (DirEntry *)&data[header->directory + (i * header->entry_blob_size)]; + str = (const char *) (&data[entry->name]); + gi_typelib_hash_builder_add_string (dirindex_builder, str, i); + } + + if (!gi_typelib_hash_builder_prepare (dirindex_builder)) + { + /* This happens if CMPH couldn't create a perfect hash. So + * we just punt and leave no directory index section. + */ + gi_typelib_hash_builder_destroy (dirindex_builder); + return data; + } + + alloc_section (data, GI_SECTION_DIRECTORY_INDEX, *offset2); + + required_size = gi_typelib_hash_builder_get_buffer_size (dirindex_builder); + required_size = ALIGN_VALUE (required_size, 4); + + new_offset = *offset2 + required_size; + + data = g_realloc (data, new_offset); + + gi_typelib_hash_builder_pack (dirindex_builder, ((guint8*)data) + *offset2, required_size); + + *offset2 = new_offset; + + gi_typelib_hash_builder_destroy (dirindex_builder); + return data; +} + +GITypelib * +gi_ir_module_build_typelib (GIIrModule *module) +{ + GError *error = NULL; + GITypelib *typelib; + gsize length; + guint i; + GList *e; + Header *header; + DirEntry *entry; + guint32 header_size; + guint32 dir_size; + guint32 n_entries; + guint32 n_local_entries; + guint32 size, offset, offset2, old_offset; + GHashTable *strings; + GHashTable *types; + GList *nodes_with_attributes; + char *dependencies; + guchar *data; + Section *section; + + header_size = ALIGN_VALUE (sizeof (Header), 4); + n_local_entries = g_list_length (module->entries); + + /* Serialize dependencies into one string; this is convenient + * and not a major change to the typelib format. */ + { + GString *dependencies_str = g_string_new (""); + GList *link; + for (link = module->dependencies; link; link = link->next) + { + const char *dependency = link->data; + if (!strcmp (dependency, module->name)) + continue; + g_string_append (dependencies_str, dependency); + if (link->next) + g_string_append_c (dependencies_str, '|'); + } + dependencies = g_string_free (dependencies_str, FALSE); + if (!dependencies[0]) + { + g_free (dependencies); + dependencies = NULL; + } + } + + restart: + gi_ir_node_init_stats (); + strings = g_hash_table_new (g_str_hash, g_str_equal); + types = g_hash_table_new (g_str_hash, g_str_equal); + nodes_with_attributes = NULL; + n_entries = g_list_length (module->entries); + + g_message ("%d entries (%d local), %d dependencies\n", n_entries, n_local_entries, + g_list_length (module->dependencies)); + + dir_size = n_entries * sizeof (DirEntry); + size = header_size + dir_size; + + size += ALIGN_VALUE (strlen (module->name) + 1, 4); + + for (e = module->entries; e; e = e->next) + { + GIIrNode *node = e->data; + + size += gi_ir_node_get_full_size (node); + + /* Also reset the offset here */ + node->offset = 0; + } + + /* Adjust size for strings allocated in header below specially */ + size += ALIGN_VALUE (strlen (module->name) + 1, 4); + if (module->shared_library) + size += ALIGN_VALUE (strlen (module->shared_library) + 1, 4); + if (dependencies != NULL) + size += ALIGN_VALUE (strlen (dependencies) + 1, 4); + if (module->c_prefix != NULL) + size += ALIGN_VALUE (strlen (module->c_prefix) + 1, 4); + + size += sizeof (Section) * NUM_SECTIONS; + + g_message ("allocating %d bytes (%d header, %d directory, %d entries)\n", + size, header_size, dir_size, size - header_size - dir_size); + + data = g_malloc0 (size); + + /* fill in header */ + header = (Header *)data; + memcpy (header, GI_IR_MAGIC, 16); + header->major_version = 4; + header->minor_version = 0; + header->reserved = 0; + header->n_entries = n_entries; + header->n_local_entries = n_local_entries; + header->n_attributes = 0; + header->attributes = 0; /* filled in later */ + /* NOTE: When writing strings to the typelib here, you should also update + * the size calculations above. + */ + if (dependencies != NULL) + header->dependencies = gi_ir_write_string (dependencies, strings, data, &header_size); + else + header->dependencies = 0; + header->size = 0; /* filled in later */ + header->namespace = gi_ir_write_string (module->name, strings, data, &header_size); + header->nsversion = gi_ir_write_string (module->version, strings, data, &header_size); + header->shared_library = (module->shared_library? + gi_ir_write_string (module->shared_library, strings, data, &header_size) + : 0); + if (module->c_prefix != NULL) + header->c_prefix = gi_ir_write_string (module->c_prefix, strings, data, &header_size); + else + header->c_prefix = 0; + header->entry_blob_size = sizeof (DirEntry); + header->function_blob_size = sizeof (FunctionBlob); + header->callback_blob_size = sizeof (CallbackBlob); + header->signal_blob_size = sizeof (SignalBlob); + header->vfunc_blob_size = sizeof (VFuncBlob); + header->arg_blob_size = sizeof (ArgBlob); + header->property_blob_size = sizeof (PropertyBlob); + header->field_blob_size = sizeof (FieldBlob); + header->value_blob_size = sizeof (ValueBlob); + header->constant_blob_size = sizeof (ConstantBlob); + header->error_domain_blob_size = 16; /* No longer used */ + header->attribute_blob_size = sizeof (AttributeBlob); + header->signature_blob_size = sizeof (SignatureBlob); + header->enum_blob_size = sizeof (EnumBlob); + header->struct_blob_size = sizeof (StructBlob); + header->object_blob_size = sizeof(ObjectBlob); + header->interface_blob_size = sizeof (InterfaceBlob); + header->union_blob_size = sizeof (UnionBlob); + + offset2 = ALIGN_VALUE (header_size, 4); + header->sections = offset2; + + /* Initialize all the sections to _END/0; we fill them in later using + * alloc_section(). (Right now there's just the directory index + * though, note) + */ + for (i = 0; i < NUM_SECTIONS; i++) + { + section = (Section*) &data[offset2]; + section->id = GI_SECTION_END; + section->offset = 0; + offset2 += sizeof(Section); + } + header->directory = offset2; + + /* fill in directory and content */ + entry = (DirEntry *)&data[header->directory]; + + offset2 += dir_size; + + for (e = module->entries, i = 0; e; e = e->next, i++) + { + GIIrTypelibBuild build; + GIIrNode *node = e->data; + + if (strchr (node->name, '.')) + { + g_error ("Names may not contain '.'"); + } + + /* we picked up implicit xref nodes, start over */ + if (i == n_entries) + { + GList *link; + g_message ("Found implicit cross references, starting over"); + + g_hash_table_destroy (strings); + g_hash_table_destroy (types); + + /* Reset the cached offsets */ + for (link = nodes_with_attributes; link; link = link->next) + ((GIIrNode *) link->data)->offset = 0; + + g_list_free (nodes_with_attributes); + strings = NULL; + + g_free (data); + data = NULL; + + goto restart; + } + + offset = offset2; + + if (node->type == GI_IR_NODE_XREF) + { + const char *namespace = ((GIIrNodeXRef*)node)->namespace; + + entry->blob_type = 0; + entry->local = FALSE; + entry->offset = gi_ir_write_string (namespace, strings, data, &offset2); + entry->name = gi_ir_write_string (node->name, strings, data, &offset2); + } + else + { + old_offset = offset; + offset2 = offset + gi_ir_node_get_size (node); + + entry->blob_type = node->type; + entry->local = TRUE; + entry->offset = offset; + entry->name = gi_ir_write_string (node->name, strings, data, &offset2); + + memset (&build, 0, sizeof (build)); + build.module = module; + build.strings = strings; + build.types = types; + build.nodes_with_attributes = nodes_with_attributes; + build.n_attributes = header->n_attributes; + build.data = data; + gi_ir_node_build_typelib (node, NULL, &build, &offset, &offset2, NULL); + + nodes_with_attributes = build.nodes_with_attributes; + header->n_attributes = build.n_attributes; + + if (offset2 > old_offset + gi_ir_node_get_full_size (node)) + g_error ("left a hole of %d bytes\n", offset2 - old_offset - gi_ir_node_get_full_size (node)); + } + + entry++; + } + + /* GIBaseInfo expects the AttributeBlob array to be sorted on the field (offset) */ + nodes_with_attributes = g_list_sort (nodes_with_attributes, node_cmp_offset_func); + + g_message ("header: %d entries, %d attributes", header->n_entries, header->n_attributes); + + gi_ir_node_dump_stats (); + + /* Write attributes after the blobs */ + offset = offset2; + header->attributes = offset; + offset2 = offset + header->n_attributes * header->attribute_blob_size; + + for (e = nodes_with_attributes; e; e = e->next) + { + GIIrNode *node = e->data; + write_attributes (module, node, strings, data, &offset, &offset2); + } + + g_message ("reallocating to %d bytes", offset2); + + data = g_realloc (data, offset2); + header = (Header*) data; + + data = add_directory_index_section (data, module, &offset2); + header = (Header *)data; + + length = header->size = offset2; + typelib = gi_typelib_new_from_memory (data, length, &error); + if (!typelib) + { + g_error ("error building typelib: %s", + error->message); + } + + g_hash_table_destroy (strings); + g_hash_table_destroy (types); + g_list_free (nodes_with_attributes); + + return typelib; +} + diff --git a/girepository/girnode-private.h b/girepository/girnode-private.h new file mode 100644 index 0000000..61a3794 --- /dev/null +++ b/girepository/girnode-private.h @@ -0,0 +1,400 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Parsed GIR + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +#include "girmodule-private.h" + +G_BEGIN_DECLS + +typedef struct _GIIrNode GIIrNode; +typedef struct _GIIrNodeFunction GIIrNodeFunction; +typedef struct _GIIrNodeParam GIIrNodeParam; +typedef struct _GIIrNodeType GIIrNodeType; +typedef struct _GIIrNodeInterface GIIrNodeInterface; +typedef struct _GIIrNodeSignal GIIrNodeSignal; +typedef struct _GIIrNodeProperty GIIrNodeProperty; +typedef struct _GIIrNodeVFunc GIIrNodeVFunc; +typedef struct _GIIrNodeField GIIrNodeField; +typedef struct _GIIrNodeValue GIIrNodeValue; +typedef struct _GIIrNodeEnum GIIrNodeEnum; +typedef struct _GIIrNodeBoxed GIIrNodeBoxed; +typedef struct _GIIrNodeStruct GIIrNodeStruct; +typedef struct _GIIrNodeConstant GIIrNodeConstant; +typedef struct _GIIrNodeXRef GIIrNodeXRef; +typedef struct _GIIrNodeUnion GIIrNodeUnion; + +typedef enum +{ + GI_IR_NODE_INVALID = 0, + GI_IR_NODE_FUNCTION = 1, + GI_IR_NODE_CALLBACK = 2, + GI_IR_NODE_STRUCT = 3, + GI_IR_NODE_BOXED = 4, + GI_IR_NODE_ENUM = 5, + GI_IR_NODE_FLAGS = 6, + GI_IR_NODE_OBJECT = 7, + GI_IR_NODE_INTERFACE = 8, + GI_IR_NODE_CONSTANT = 9, + GI_IR_NODE_INVALID_0 = 10, /* DELETED - used to be ERROR_DOMAIN */ + GI_IR_NODE_UNION = 11, + GI_IR_NODE_PARAM = 12, + GI_IR_NODE_TYPE = 13, + GI_IR_NODE_PROPERTY = 14, + GI_IR_NODE_SIGNAL = 15, + GI_IR_NODE_VALUE = 16, + GI_IR_NODE_VFUNC = 17, + GI_IR_NODE_FIELD = 18, + GI_IR_NODE_XREF = 19 +} GIIrNodeTypeId; + +struct _GIIrNode +{ + GIIrNodeTypeId type; + gchar *name; + GIIrModule *module; + + guint32 offset; /* Assigned as we build the typelib */ + + GHashTable *attributes; +}; + +struct _GIIrNodeXRef +{ + GIIrNode node; + + gchar *namespace; +}; + +struct _GIIrNodeFunction +{ + GIIrNode node; + + gboolean deprecated; + gboolean is_varargs; /* Not in typelib yet */ + + gboolean is_method; + gboolean is_setter; + gboolean is_getter; + gboolean is_constructor; + gboolean wraps_vfunc; + gboolean throws; + gboolean instance_transfer_full; + + gchar *symbol; + char *property; + + GIIrNodeParam *result; + GList *parameters; +}; + +struct _GIIrNodeType +{ + GIIrNode node; + + gboolean is_pointer; + gboolean is_basic; + gboolean is_array; + gboolean is_glist; + gboolean is_gslist; + gboolean is_ghashtable; + gboolean is_interface; + gboolean is_error; + gint tag; + + gchar *unparsed; + + gboolean zero_terminated; + gboolean has_length; + gint length; + gboolean has_size; + gint size; + gint array_type; + + GIIrNodeType *parameter_type1; + GIIrNodeType *parameter_type2; + + gchar *giinterface; + gchar **errors; +}; + +struct _GIIrNodeParam +{ + GIIrNode node; + + gboolean in; + gboolean out; + gboolean caller_allocates; + gboolean optional; + gboolean retval; + gboolean nullable; + gboolean skip; + gboolean transfer; + gboolean shallow_transfer; + GIScopeType scope; + + gint8 closure; + gint8 destroy; + + GIIrNodeType *type; +}; + +struct _GIIrNodeProperty +{ + GIIrNode node; + + gboolean deprecated; + + gchar *name; + gboolean readable; + gboolean writable; + gboolean construct; + gboolean construct_only; + gboolean transfer; + gboolean shallow_transfer; + + char *setter; + char *getter; + + GIIrNodeType *type; +}; + +struct _GIIrNodeSignal +{ + GIIrNode node; + + gboolean deprecated; + + gboolean run_first; + gboolean run_last; + gboolean run_cleanup; + gboolean no_recurse; + gboolean detailed; + gboolean action; + gboolean no_hooks; + gboolean instance_transfer_full; + + gboolean has_class_closure; + gboolean true_stops_emit; + + gint class_closure; + + GList *parameters; + GIIrNodeParam *result; +}; + +struct _GIIrNodeVFunc +{ + GIIrNode node; + + gboolean is_varargs; /* Not in typelib yet */ + gboolean must_chain_up; + gboolean must_be_implemented; + gboolean must_not_be_implemented; + gboolean is_class_closure; + gboolean throws; + gboolean instance_transfer_full; + + char *invoker; + + GList *parameters; + GIIrNodeParam *result; + + gint offset; +}; + +struct _GIIrNodeField +{ + GIIrNode node; + + gboolean readable; + gboolean writable; + gint bits; + gint offset; + GIIrNodeFunction *callback; + + GIIrNodeType *type; +}; + +struct _GIIrNodeInterface +{ + GIIrNode node; + + gboolean abstract; + gboolean deprecated; + gboolean fundamental; + gboolean final_; + + gchar *gtype_name; + gchar *gtype_init; + + gchar *ref_func; + gchar *unref_func; + gchar *set_value_func; + gchar *get_value_func; + + gchar *parent; + gchar *glib_type_struct; + + GList *interfaces; + GList *prerequisites; + + gint alignment; + gint size; + + GList *members; +}; + +struct _GIIrNodeValue +{ + GIIrNode node; + + gboolean deprecated; + + gint64 value; +}; + +struct _GIIrNodeConstant +{ + GIIrNode node; + + gboolean deprecated; + + GIIrNodeType *type; + + gchar *value; +}; + +struct _GIIrNodeEnum +{ + GIIrNode node; + + gboolean deprecated; + gint storage_type; + + gchar *gtype_name; + gchar *gtype_init; + gchar *error_domain; + + GList *values; + GList *methods; +}; + +struct _GIIrNodeBoxed +{ + GIIrNode node; + + gboolean deprecated; + + gchar *gtype_name; + gchar *gtype_init; + + gint alignment; + gint size; + + GList *members; +}; + +struct _GIIrNodeStruct +{ + GIIrNode node; + + gboolean deprecated; + gboolean disguised; + gboolean opaque; + gboolean pointer; + gboolean is_gtype_struct; + gboolean foreign; + + gchar *gtype_name; + gchar *gtype_init; + + gchar *copy_func; + gchar *free_func; + + gint alignment; + gint size; + + GList *members; +}; + +struct _GIIrNodeUnion +{ + GIIrNode node; + + gboolean deprecated; + + GList *members; + GList *discriminators; + + gchar *gtype_name; + gchar *gtype_init; + + gchar *copy_func; + gchar *free_func; + + gint alignment; + gint size; + + gint discriminator_offset; + GIIrNodeType *discriminator_type; +}; + + +GIIrNode *gi_ir_node_new (GIIrNodeTypeId type, + GIIrModule *module); +void gi_ir_node_free (GIIrNode *node); +guint32 gi_ir_node_get_size (GIIrNode *node); +guint32 gi_ir_node_get_full_size (GIIrNode *node); +void gi_ir_node_build_typelib (GIIrNode *node, + GIIrNode *parent, + GIIrTypelibBuild *build, + guint32 *offset, + guint32 *offset2, + guint16 *count2); +int gi_ir_node_cmp (GIIrNode *node, + GIIrNode *other); +gboolean gi_ir_node_can_have_member (GIIrNode *node); +void gi_ir_node_add_member (GIIrNode *node, + GIIrNodeFunction *member); +guint32 gi_ir_write_string (const gchar *str, + GHashTable *strings, + guchar *data, + guint32 *offset); + +const gchar * gi_ir_node_param_direction_string (GIIrNodeParam * node); +const gchar * gi_ir_node_type_to_string (GIIrNodeTypeId type); + +GIIrNode *gi_ir_find_node (GIIrTypelibBuild *build, + GIIrModule *module, + const char *name); + +/* In giroffsets.c */ + +void gi_ir_node_compute_offsets (GIIrTypelibBuild *build, + GIIrNode *node); + + +G_END_DECLS diff --git a/girepository/girnode.c b/girepository/girnode.c new file mode 100644 index 0000000..004d670 --- /dev/null +++ b/girepository/girnode.c @@ -0,0 +1,2444 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Typelib creation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "girnode-private.h" + +#include "gitypelib-internal.h" + +#include +#include +#include + +#ifdef _MSC_VER +#define strtoll _strtoi64 +#define strtoull _strtoui64 +#endif + +static gulong string_count = 0; +static gulong unique_string_count = 0; +static gulong string_size = 0; +static gulong unique_string_size = 0; +static gulong types_count = 0; +static gulong unique_types_count = 0; + +void +gi_ir_node_init_stats (void) +{ + string_count = 0; + unique_string_count = 0; + string_size = 0; + unique_string_size = 0; + types_count = 0; + unique_types_count = 0; +} + +void +gi_ir_node_dump_stats (void) +{ + g_message ("%lu strings (%lu before sharing), %lu bytes (%lu before sharing)", + unique_string_count, string_count, unique_string_size, string_size); + g_message ("%lu types (%lu before sharing)", unique_types_count, types_count); +} + +#define DO_ALIGNED_COPY(dest_addr, value, type) \ +do { \ + type tmp_var; \ + tmp_var = value; \ + memcpy(dest_addr, &tmp_var, sizeof(type)); \ +} while(0) + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + + +const gchar * +gi_ir_node_type_to_string (GIIrNodeTypeId type) +{ + switch (type) + { + case GI_IR_NODE_FUNCTION: + return "function"; + case GI_IR_NODE_CALLBACK: + return "callback"; + case GI_IR_NODE_PARAM: + return "param"; + case GI_IR_NODE_TYPE: + return "type"; + case GI_IR_NODE_OBJECT: + return "object"; + case GI_IR_NODE_INTERFACE: + return "interface"; + case GI_IR_NODE_SIGNAL: + return "signal"; + case GI_IR_NODE_PROPERTY: + return "property"; + case GI_IR_NODE_VFUNC: + return "vfunc"; + case GI_IR_NODE_FIELD: + return "field"; + case GI_IR_NODE_ENUM: + return "enum"; + case GI_IR_NODE_FLAGS: + return "flags"; + case GI_IR_NODE_BOXED: + return "boxed"; + case GI_IR_NODE_STRUCT: + return "struct"; + case GI_IR_NODE_VALUE: + return "value"; + case GI_IR_NODE_CONSTANT: + return "constant"; + case GI_IR_NODE_XREF: + return "xref"; + case GI_IR_NODE_UNION: + return "union"; + default: + return "unknown"; + } +} + +GIIrNode * +gi_ir_node_new (GIIrNodeTypeId type, + GIIrModule *module) +{ + GIIrNode *node = NULL; + + switch (type) + { + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + node = g_malloc0 (sizeof (GIIrNodeFunction)); + break; + + case GI_IR_NODE_PARAM: + node = g_malloc0 (sizeof (GIIrNodeParam)); + break; + + case GI_IR_NODE_TYPE: + node = g_malloc0 (sizeof (GIIrNodeType)); + break; + + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + node = g_malloc0 (sizeof (GIIrNodeInterface)); + break; + + case GI_IR_NODE_SIGNAL: + node = g_malloc0 (sizeof (GIIrNodeSignal)); + break; + + case GI_IR_NODE_PROPERTY: + node = g_malloc0 (sizeof (GIIrNodeProperty)); + break; + + case GI_IR_NODE_VFUNC: + node = g_malloc0 (sizeof (GIIrNodeFunction)); + break; + + case GI_IR_NODE_FIELD: + node = g_malloc0 (sizeof (GIIrNodeField)); + break; + + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + node = g_malloc0 (sizeof (GIIrNodeEnum)); + break; + + case GI_IR_NODE_BOXED: + node = g_malloc0 (sizeof (GIIrNodeBoxed)); + break; + + case GI_IR_NODE_STRUCT: + node = g_malloc0 (sizeof (GIIrNodeStruct)); + break; + + case GI_IR_NODE_VALUE: + node = g_malloc0 (sizeof (GIIrNodeValue)); + break; + + case GI_IR_NODE_CONSTANT: + node = g_malloc0 (sizeof (GIIrNodeConstant)); + break; + + case GI_IR_NODE_XREF: + node = g_malloc0 (sizeof (GIIrNodeXRef)); + break; + + case GI_IR_NODE_UNION: + node = g_malloc0 (sizeof (GIIrNodeUnion)); + break; + + default: + g_error ("Unhandled node type %d\n", type); + break; + } + + node->type = type; + node->module = module; + node->offset = 0; + node->attributes = g_hash_table_new_full (g_str_hash, g_str_equal, + g_free, g_free); + + return node; +} + +void +gi_ir_node_free (GIIrNode *node) +{ + GList *l; + + if (node == NULL) + return; + + switch (node->type) + { + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + { + GIIrNodeFunction *function = (GIIrNodeFunction *)node; + + g_free (node->name); + g_free (function->symbol); + g_free (function->property); + gi_ir_node_free ((GIIrNode *)function->result); + for (l = function->parameters; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (function->parameters); + } + break; + + case GI_IR_NODE_TYPE: + { + GIIrNodeType *type = (GIIrNodeType *)node; + + g_free (node->name); + gi_ir_node_free ((GIIrNode *)type->parameter_type1); + gi_ir_node_free ((GIIrNode *)type->parameter_type2); + + g_free (type->giinterface); + g_strfreev (type->errors); + + } + break; + + case GI_IR_NODE_PARAM: + { + GIIrNodeParam *param = (GIIrNodeParam *)node; + + g_free (node->name); + gi_ir_node_free ((GIIrNode *)param->type); + } + break; + + case GI_IR_NODE_PROPERTY: + { + GIIrNodeProperty *property = (GIIrNodeProperty *)node; + + g_free (node->name); + g_free (property->setter); + g_free (property->getter); + gi_ir_node_free ((GIIrNode *)property->type); + } + break; + + case GI_IR_NODE_SIGNAL: + { + GIIrNodeSignal *signal = (GIIrNodeSignal *)node; + + g_free (node->name); + for (l = signal->parameters; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (signal->parameters); + gi_ir_node_free ((GIIrNode *)signal->result); + } + break; + + case GI_IR_NODE_VFUNC: + { + GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; + + g_free (node->name); + g_free (vfunc->invoker); + for (l = vfunc->parameters; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (vfunc->parameters); + gi_ir_node_free ((GIIrNode *)vfunc->result); + } + break; + + case GI_IR_NODE_FIELD: + { + GIIrNodeField *field = (GIIrNodeField *)node; + + g_free (node->name); + gi_ir_node_free ((GIIrNode *)field->type); + gi_ir_node_free ((GIIrNode *)field->callback); + } + break; + + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + g_free (node->name); + g_free (iface->gtype_name); + g_free (iface->gtype_init); + g_free (iface->ref_func); + g_free (iface->unref_func); + g_free (iface->set_value_func); + g_free (iface->get_value_func); + + + g_free (iface->glib_type_struct); + g_free (iface->parent); + + for (l = iface->interfaces; l; l = l->next) + g_free ((GIIrNode *)l->data); + g_list_free (iface->interfaces); + + for (l = iface->members; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (iface->members); + + } + break; + + case GI_IR_NODE_VALUE: + { + g_free (node->name); + } + break; + + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; + + g_free (node->name); + g_free (enum_->gtype_name); + g_free (enum_->gtype_init); + g_free (enum_->error_domain); + + for (l = enum_->values; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (enum_->values); + + for (l = enum_->methods; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (enum_->methods); + } + break; + + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + + g_free (node->name); + g_free (boxed->gtype_name); + g_free (boxed->gtype_init); + + for (l = boxed->members; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (boxed->members); + } + break; + + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + + g_free (node->name); + g_free (struct_->gtype_name); + g_free (struct_->gtype_init); + g_free (struct_->copy_func); + g_free (struct_->free_func); + + for (l = struct_->members; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + g_list_free (struct_->members); + } + break; + + case GI_IR_NODE_CONSTANT: + { + GIIrNodeConstant *constant = (GIIrNodeConstant *)node; + + g_free (node->name); + g_free (constant->value); + gi_ir_node_free ((GIIrNode *)constant->type); + } + break; + + case GI_IR_NODE_XREF: + { + GIIrNodeXRef *xref = (GIIrNodeXRef *)node; + + g_free (node->name); + g_free (xref->namespace); + } + break; + + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + + g_free (node->name); + g_free (union_->gtype_name); + g_free (union_->gtype_init); + g_free (union_->copy_func); + g_free (union_->free_func); + + gi_ir_node_free ((GIIrNode *)union_->discriminator_type); + for (l = union_->members; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + gi_ir_node_free ((GIIrNode *)l->data); + } + break; + + default: + g_error ("Unhandled node type %d\n", node->type); + break; + } + + g_hash_table_destroy (node->attributes); + + g_free (node); +} + +/* returns the fixed size of the blob */ +guint32 +gi_ir_node_get_size (GIIrNode *node) +{ + GList *l; + gint size, n; + + switch (node->type) + { + case GI_IR_NODE_CALLBACK: + size = sizeof (CallbackBlob); + break; + + case GI_IR_NODE_FUNCTION: + size = sizeof (FunctionBlob); + break; + + case GI_IR_NODE_PARAM: + /* See the comment in the GI_IR_NODE_PARAM/ArgBlob writing below */ + size = sizeof (ArgBlob) - sizeof (SimpleTypeBlob); + break; + + case GI_IR_NODE_TYPE: + size = sizeof (SimpleTypeBlob); + break; + + case GI_IR_NODE_OBJECT: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + n = g_list_length (iface->interfaces); + size = sizeof (ObjectBlob) + 2 * (n + (n % 2)); + + for (l = iface->members; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + n = g_list_length (iface->prerequisites); + size = sizeof (InterfaceBlob) + 2 * (n + (n % 2)); + + for (l = iface->members; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; + + size = sizeof (EnumBlob); + for (l = enum_->values; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + for (l = enum_->methods; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_VALUE: + size = sizeof (ValueBlob); + break; + + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + + size = sizeof (StructBlob); + for (l = struct_->members; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + + size = sizeof (StructBlob); + for (l = boxed->members; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_PROPERTY: + size = sizeof (PropertyBlob); + break; + + case GI_IR_NODE_SIGNAL: + size = sizeof (SignalBlob); + break; + + case GI_IR_NODE_VFUNC: + size = sizeof (VFuncBlob); + break; + + case GI_IR_NODE_FIELD: + { + GIIrNodeField *field = (GIIrNodeField *)node; + + size = sizeof (FieldBlob); + if (field->callback) + size += gi_ir_node_get_size ((GIIrNode *)field->callback); + } + break; + + case GI_IR_NODE_CONSTANT: + size = sizeof (ConstantBlob); + break; + + case GI_IR_NODE_XREF: + size = 0; + break; + + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + + size = sizeof (UnionBlob); + for (l = union_->members; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + size += gi_ir_node_get_size ((GIIrNode *)l->data); + } + break; + + default: + g_error ("Unhandled node type '%s'\n", + gi_ir_node_type_to_string (node->type)); + size = 0; + } + + g_debug ("node %p type '%s' size %d", node, + gi_ir_node_type_to_string (node->type), size); + + return size; +} + +static void +add_attribute_size (gpointer key, gpointer value, gpointer data) +{ + const gchar *key_str = key; + const gchar *value_str = value; + gint *size_p = data; + + *size_p += sizeof (AttributeBlob); + *size_p += ALIGN_VALUE (strlen (key_str) + 1, 4); + *size_p += ALIGN_VALUE (strlen (value_str) + 1, 4); +} + +/* returns the full size of the blob including variable-size parts (including attributes) */ +static guint32 +gi_ir_node_get_full_size_internal (GIIrNode *parent, + GIIrNode *node) +{ + GList *l; + gint size, n; + + if (node == NULL && parent != NULL) + g_error ("Caught NULL node, parent=%s", parent->name); + + g_debug ("node %p type '%s'", node, + gi_ir_node_type_to_string (node->type)); + + switch (node->type) + { + case GI_IR_NODE_CALLBACK: + { + GIIrNodeFunction *function = (GIIrNodeFunction *)node; + size = sizeof (CallbackBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + for (l = function->parameters; l; l = l->next) + { + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)function->result); + } + break; + + case GI_IR_NODE_FUNCTION: + { + GIIrNodeFunction *function = (GIIrNodeFunction *)node; + size = sizeof (FunctionBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += ALIGN_VALUE (strlen (function->symbol) + 1, 4); + for (l = function->parameters; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)function->result); + } + break; + + case GI_IR_NODE_PARAM: + { + GIIrNodeParam *param = (GIIrNodeParam *)node; + + /* See the comment in the GI_IR_NODE_PARAM/ArgBlob writing below */ + size = sizeof (ArgBlob) - sizeof (SimpleTypeBlob); + if (node->name) + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)param->type); + } + break; + + case GI_IR_NODE_TYPE: + { + GIIrNodeType *type = (GIIrNodeType *)node; + size = sizeof (SimpleTypeBlob); + if (!GI_TYPE_TAG_IS_BASIC (type->tag)) + { + g_debug ("node %p type tag '%s'", node, + gi_type_tag_to_string (type->tag)); + + switch (type->tag) + { + case GI_TYPE_TAG_ARRAY: + size = sizeof (ArrayTypeBlob); + if (type->parameter_type1) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); + break; + case GI_TYPE_TAG_INTERFACE: + size += sizeof (InterfaceTypeBlob); + break; + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + size += sizeof (ParamTypeBlob); + if (type->parameter_type1) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); + break; + case GI_TYPE_TAG_GHASH: + size += sizeof (ParamTypeBlob) * 2; + if (type->parameter_type1) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type1); + if (type->parameter_type2) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)type->parameter_type2); + break; + case GI_TYPE_TAG_ERROR: + size += sizeof (ErrorTypeBlob); + break; + default: + g_error ("Unknown type tag %d\n", type->tag); + break; + } + } + } + break; + + case GI_IR_NODE_OBJECT: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + n = g_list_length (iface->interfaces); + size = sizeof(ObjectBlob); + if (iface->parent) + size += ALIGN_VALUE (strlen (iface->parent) + 1, 4); + if (iface->glib_type_struct) + size += ALIGN_VALUE (strlen (iface->glib_type_struct) + 1, 4); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4); + if (iface->gtype_init) + size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4); + if (iface->ref_func) + size += ALIGN_VALUE (strlen (iface->ref_func) + 1, 4); + if (iface->unref_func) + size += ALIGN_VALUE (strlen (iface->unref_func) + 1, 4); + if (iface->set_value_func) + size += ALIGN_VALUE (strlen (iface->set_value_func) + 1, 4); + if (iface->get_value_func) + size += ALIGN_VALUE (strlen (iface->get_value_func) + 1, 4); + size += 2 * (n + (n % 2)); + + for (l = iface->members; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + n = g_list_length (iface->prerequisites); + size = sizeof (InterfaceBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += ALIGN_VALUE (strlen (iface->gtype_name) + 1, 4); + size += ALIGN_VALUE (strlen (iface->gtype_init) + 1, 4); + size += 2 * (n + (n % 2)); + + for (l = iface->members; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; + + size = sizeof (EnumBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + if (enum_->gtype_name) + { + size += ALIGN_VALUE (strlen (enum_->gtype_name) + 1, 4); + size += ALIGN_VALUE (strlen (enum_->gtype_init) + 1, 4); + } + if (enum_->error_domain) + size += ALIGN_VALUE (strlen (enum_->error_domain) + 1, 4); + + for (l = enum_->values; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + for (l = enum_->methods; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_VALUE: + { + size = sizeof (ValueBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + } + break; + + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + + size = sizeof (StructBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + if (struct_->gtype_name) + size += ALIGN_VALUE (strlen (struct_->gtype_name) + 1, 4); + if (struct_->gtype_init) + size += ALIGN_VALUE (strlen (struct_->gtype_init) + 1, 4); + if (struct_->copy_func) + size += ALIGN_VALUE (strlen (struct_->copy_func) + 1, 4); + if (struct_->free_func) + size += ALIGN_VALUE (strlen (struct_->free_func) + 1, 4); + for (l = struct_->members; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + + size = sizeof (StructBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + if (boxed->gtype_name) + { + size += ALIGN_VALUE (strlen (boxed->gtype_name) + 1, 4); + size += ALIGN_VALUE (strlen (boxed->gtype_init) + 1, 4); + } + for (l = boxed->members; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + case GI_IR_NODE_PROPERTY: + { + GIIrNodeProperty *prop = (GIIrNodeProperty *)node; + + size = sizeof (PropertyBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)prop->type); + } + break; + + case GI_IR_NODE_SIGNAL: + { + GIIrNodeSignal *signal = (GIIrNodeSignal *)node; + + size = sizeof (SignalBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + for (l = signal->parameters; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)signal->result); + } + break; + + case GI_IR_NODE_VFUNC: + { + GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; + + size = sizeof (VFuncBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + for (l = vfunc->parameters; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)vfunc->result); + } + break; + + case GI_IR_NODE_FIELD: + { + GIIrNodeField *field = (GIIrNodeField *)node; + + size = sizeof (FieldBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + if (field->callback) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)field->callback); + else + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)field->type); + } + break; + + case GI_IR_NODE_CONSTANT: + { + GIIrNodeConstant *constant = (GIIrNodeConstant *)node; + + size = sizeof (ConstantBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + /* FIXME non-string values */ + size += ALIGN_VALUE (strlen (constant->value) + 1, 4); + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)constant->type); + } + break; + + case GI_IR_NODE_XREF: + { + GIIrNodeXRef *xref = (GIIrNodeXRef *)node; + + size = 0; + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + size += ALIGN_VALUE (strlen (xref->namespace) + 1, 4); + } + break; + + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + + size = sizeof (UnionBlob); + size += ALIGN_VALUE (strlen (node->name) + 1, 4); + if (union_->gtype_name) + size += ALIGN_VALUE (strlen (union_->gtype_name) + 1, 4); + if (union_->gtype_init) + size += ALIGN_VALUE (strlen (union_->gtype_init) + 1, 4); + if (union_->copy_func) + size += ALIGN_VALUE (strlen (union_->copy_func) + 1, 4); + if (union_->free_func) + size += ALIGN_VALUE (strlen (union_->free_func) + 1, 4); + for (l = union_->members; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + for (l = union_->discriminators; l; l = l->next) + size += gi_ir_node_get_full_size_internal (node, (GIIrNode *)l->data); + } + break; + + default: + g_error ("Unknown type tag %d\n", node->type); + size = 0; + } + + g_debug ("node %s%s%s%p type '%s' full size %d", + node->name ? "'" : "", + node->name ? node->name : "", + node->name ? "' " : "", + node, gi_ir_node_type_to_string (node->type), size); + + g_hash_table_foreach (node->attributes, add_attribute_size, &size); + + return size; +} + +guint32 +gi_ir_node_get_full_size (GIIrNode *node) +{ + return gi_ir_node_get_full_size_internal (NULL, node); +} + +int +gi_ir_node_cmp (GIIrNode *node, + GIIrNode *other) +{ + if (node->type < other->type) + return -1; + else if (node->type > other->type) + return 1; + else + return strcmp (node->name, other->name); +} + +gboolean +gi_ir_node_can_have_member (GIIrNode *node) +{ + switch (node->type) + { + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + case GI_IR_NODE_BOXED: + case GI_IR_NODE_STRUCT: + case GI_IR_NODE_UNION: + return TRUE; + /* list others individually rather than with default: so that compiler + * warns if new node types are added without adding them to the switch + */ + case GI_IR_NODE_INVALID: + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + case GI_IR_NODE_CONSTANT: + case GI_IR_NODE_INVALID_0: + case GI_IR_NODE_PARAM: + case GI_IR_NODE_TYPE: + case GI_IR_NODE_PROPERTY: + case GI_IR_NODE_SIGNAL: + case GI_IR_NODE_VALUE: + case GI_IR_NODE_VFUNC: + case GI_IR_NODE_FIELD: + case GI_IR_NODE_XREF: + return FALSE; + default: + g_assert_not_reached (); + }; + return FALSE; +} + +void +gi_ir_node_add_member (GIIrNode *node, + GIIrNodeFunction *member) +{ + g_return_if_fail (node != NULL); + g_return_if_fail (member != NULL); + + switch (node->type) + { + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + iface->members = + g_list_insert_sorted (iface->members, member, + (GCompareFunc) gi_ir_node_cmp); + break; + } + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + boxed->members = + g_list_insert_sorted (boxed->members, member, + (GCompareFunc) gi_ir_node_cmp); + break; + } + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + struct_->members = + g_list_insert_sorted (struct_->members, member, + (GCompareFunc) gi_ir_node_cmp); + break; + } + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + union_->members = + g_list_insert_sorted (union_->members, member, + (GCompareFunc) gi_ir_node_cmp); + break; + } + default: + g_error ("Cannot add a member to unknown type tag type %d\n", + node->type); + break; + } +} + +const gchar * +gi_ir_node_param_direction_string (GIIrNodeParam * node) +{ + if (node->out) + { + if (node->in) + return "in-out"; + else + return "out"; + } + return "in"; +} + +static gint64 +parse_int_value (const gchar *str) +{ + return g_ascii_strtoll (str, NULL, 0); +} + +static guint64 +parse_uint_value (const gchar *str) +{ + return g_ascii_strtoull (str, NULL, 0); +} + +static gdouble +parse_float_value (const gchar *str) +{ + return g_ascii_strtod (str, NULL); +} + +static gboolean +parse_boolean_value (const gchar *str) +{ + if (g_ascii_strcasecmp (str, "TRUE") == 0) + return TRUE; + + if (g_ascii_strcasecmp (str, "FALSE") == 0) + return FALSE; + + return parse_int_value (str) ? TRUE : FALSE; +} + +static GIIrNode * +find_entry_node (GIIrTypelibBuild *build, + const gchar *name, + guint16 *idx) + +{ + GIIrModule *module = build->module; + GList *l; + gint i; + gchar **names; + gint n_names; + GIIrNode *result = NULL; + + g_assert (name != NULL); + g_assert (strlen (name) > 0); + + names = g_strsplit (name, ".", 0); + n_names = g_strv_length (names); + if (n_names > 2) + g_error ("Too many name parts"); + + for (l = module->entries, i = 1; l; l = l->next, i++) + { + GIIrNode *node = (GIIrNode *)l->data; + + if (n_names > 1) + { + if (node->type != GI_IR_NODE_XREF) + continue; + + if (((GIIrNodeXRef *)node)->namespace == NULL || + strcmp (((GIIrNodeXRef *)node)->namespace, names[0]) != 0) + continue; + } + + if (strcmp (node->name, names[n_names - 1]) == 0) + { + if (idx) + *idx = i; + + result = node; + goto out; + } + } + + if (n_names > 1) + { + GIIrNode *node = gi_ir_node_new (GI_IR_NODE_XREF, module); + + ((GIIrNodeXRef *)node)->namespace = g_strdup (names[0]); + node->name = g_strdup (names[1]); + + module->entries = g_list_append (module->entries, node); + + if (idx) + *idx = g_list_length (module->entries); + + result = node; + + g_debug ("Creating XREF: %s %s", names[0], names[1]); + + goto out; + } + + + gi_ir_module_fatal (build, -1, "type reference '%s' not found", name); + out: + + g_strfreev (names); + + return result; +} + +static guint16 +find_entry (GIIrTypelibBuild *build, + const gchar *name) +{ + guint16 idx = 0; + + find_entry_node (build, name, &idx); + + return idx; +} + +static GIIrModule * +find_namespace (GIIrModule *module, + const char *name) +{ + GIIrModule *target; + GList *l; + + if (strcmp (module->name, name) == 0) + return module; + + for (l = module->include_modules; l; l = l->next) + { + GIIrModule *submodule = l->data; + + if (strcmp (submodule->name, name) == 0) + return submodule; + + target = find_namespace (submodule, name); + if (target) + return target; + } + return NULL; +} + +GIIrNode * +gi_ir_find_node (GIIrTypelibBuild *build, + GIIrModule *src_module, + const char *name) +{ + GList *l; + GIIrNode *return_node = NULL; + char **names = g_strsplit (name, ".", 0); + gint n_names = g_strv_length (names); + const char *target_name; + GIIrModule *target_module; + + if (n_names == 1) + { + target_module = src_module; + target_name = name; + } + else + { + target_module = find_namespace (build->module, names[0]); + target_name = names[1]; + } + + /* find_namespace() may return NULL. */ + if (target_module == NULL) + goto done; + + for (l = target_module->entries; l; l = l->next) + { + GIIrNode *node = (GIIrNode *)l->data; + + if (strcmp (node->name, target_name) == 0) + { + return_node = node; + break; + } + } + +done: + g_strfreev (names); + + return return_node; +} + +static int +get_index_of_member_type (GIIrNodeInterface *node, + GIIrNodeTypeId type, + const char *name) +{ + guint index = -1; + GList *l; + + for (l = node->members; l; l = l->next) + { + GIIrNode *member_node = l->data; + + if (member_node->type != type) + continue; + + index++; + + if (strcmp (member_node->name, name) == 0) + break; + } + + return index; +} + +static void +serialize_type (GIIrTypelibBuild *build, + GIIrNodeType *node, + GString *str) +{ + gint i; + + if (GI_TYPE_TAG_IS_BASIC (node->tag)) + { + g_string_append_printf (str, "%s%s", gi_type_tag_to_string (node->tag), + node->is_pointer ? "*" : ""); + } + else if (node->tag == GI_TYPE_TAG_ARRAY) + { + if (node->array_type == GI_ARRAY_TYPE_C) + { + serialize_type (build, node->parameter_type1, str); + g_string_append (str, "["); + + if (node->has_length) + g_string_append_printf (str, "length=%d", node->length); + else if (node->has_size) + g_string_append_printf (str, "fixed-size=%d", node->size); + + if (node->zero_terminated) + g_string_append_printf (str, "%szero-terminated=1", + node->has_length ? "," : ""); + + g_string_append (str, "]"); + if (node->is_pointer) + g_string_append (str, "*"); + } + else if (node->array_type == GI_ARRAY_TYPE_BYTE_ARRAY) + { + /* We on purpose skip serializing parameter_type1, which should + always be void* + */ + g_string_append (str, "GByteArray"); + } + else + { + if (node->array_type == GI_ARRAY_TYPE_ARRAY) + g_string_append (str, "GArray"); + else + g_string_append (str, "GPtrArray"); + if (node->parameter_type1) + { + g_string_append (str, "<"); + serialize_type (build, node->parameter_type1, str); + g_string_append (str, ">"); + } + } + } + else if (node->tag == GI_TYPE_TAG_INTERFACE) + { + GIIrNode *iface; + gchar *name; + + iface = find_entry_node (build, node->giinterface, NULL); + if (iface) + { + if (iface->type == GI_IR_NODE_XREF) + g_string_append_printf (str, "%s.", ((GIIrNodeXRef *)iface)->namespace); + name = iface->name; + } + else + { + g_warning ("Interface for type reference %s not found", node->giinterface); + name = node->giinterface; + } + + g_string_append_printf (str, "%s%s", name, + node->is_pointer ? "*" : ""); + } + else if (node->tag == GI_TYPE_TAG_GLIST) + { + g_string_append (str, "GList"); + if (node->parameter_type1) + { + g_string_append (str, "<"); + serialize_type (build, node->parameter_type1, str); + g_string_append (str, ">"); + } + } + else if (node->tag == GI_TYPE_TAG_GSLIST) + { + g_string_append (str, "GSList"); + if (node->parameter_type1) + { + g_string_append (str, "<"); + serialize_type (build, node->parameter_type1, str); + g_string_append (str, ">"); + } + } + else if (node->tag == GI_TYPE_TAG_GHASH) + { + g_string_append (str, "GHashTable"); + if (node->parameter_type1) + { + g_string_append (str, "<"); + serialize_type (build, node->parameter_type1, str); + g_string_append (str, ","); + serialize_type (build, node->parameter_type2, str); + g_string_append (str, ">"); + } + } + else if (node->tag == GI_TYPE_TAG_ERROR) + { + g_string_append (str, "GError"); + if (node->errors) + { + g_string_append (str, "<"); + for (i = 0; node->errors[i]; i++) + { + if (i > 0) + g_string_append (str, ","); + g_string_append (str, node->errors[i]); + } + g_string_append (str, ">"); + } + } +} + +static void +gi_ir_node_build_members (GList **members, + GIIrNodeTypeId type, + guint16 *count, + GIIrNode *parent, + GIIrTypelibBuild *build, + guint32 *offset, + guint32 *offset2, + guint16 *count2) +{ + GList *l = *members; + + while (l) + { + GIIrNode *member = (GIIrNode *)l->data; + GList *next = l->next; + + if (member->type == type) + { + (*count)++; + gi_ir_node_build_typelib (member, parent, build, offset, offset2, count2); + *members = g_list_delete_link (*members, l); + } + l = next; + } +} + +static void +gi_ir_node_check_unhandled_members (GList **members, + GIIrNodeTypeId container_type) +{ +#if 0 + if (*members) + { + GList *l; + + for (l = *members; l; l = l->next) + { + GIIrNode *member = (GIIrNode *)l->data; + g_printerr ("Unhandled '%s' member '%s' type '%s'\n", + gi_ir_node_type_to_string (container_type), + member->name, + gi_ir_node_type_to_string (member->type)); + } + + g_list_free (*members); + *members = NULL; + + g_error ("Unhandled members. Aborting."); + } +#else + g_list_free (*members); + *members = NULL; +#endif +} + +void +gi_ir_node_build_typelib (GIIrNode *node, + GIIrNode *parent, + GIIrTypelibBuild *build, + guint32 *offset, + guint32 *offset2, + guint16 *count2) +{ + gboolean appended_stack; + GHashTable *strings = build->strings; + GHashTable *types = build->types; + guchar *data = build->data; + GList *l; + guint32 old_offset = *offset; + guint32 old_offset2 = *offset2; + + g_assert (node != NULL); + + g_debug ("build_typelib: %s%s(%s)", + node->name ? node->name : "", + node->name ? " " : "", + gi_ir_node_type_to_string (node->type)); + + if (build->stack) + appended_stack = node != (GIIrNode*)build->stack->data; + else + appended_stack = TRUE; + if (appended_stack) + build->stack = g_list_prepend (build->stack, node); + + gi_ir_node_compute_offsets (build, node); + + /* We should only be building each node once. If we do a typelib expansion, we also + * reset the offset in girmodule.c. + */ + g_assert (node->offset == 0); + node->offset = *offset; + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, node); + + build->n_attributes += g_hash_table_size (node->attributes); + + switch (node->type) + { + case GI_IR_NODE_TYPE: + { + GIIrNodeType *type = (GIIrNodeType *)node; + SimpleTypeBlob *blob = (SimpleTypeBlob *)&data[*offset]; + + *offset += sizeof (SimpleTypeBlob); + + if (GI_TYPE_TAG_IS_BASIC (type->tag)) + { + blob->flags.reserved = 0; + blob->flags.reserved2 = 0; + blob->flags.pointer = type->is_pointer; + blob->flags.reserved3 = 0; + blob->flags.tag = type->tag; + } + else + { + GString *str; + gchar *s; + gpointer value; + + str = g_string_new (0); + serialize_type (build, type, str); + s = g_string_free (str, FALSE); + + types_count += 1; + value = g_hash_table_lookup (types, s); + if (value) + { + blob->offset = GPOINTER_TO_UINT (value); + g_free (s); + } + else + { + unique_types_count += 1; + g_hash_table_insert (types, s, GUINT_TO_POINTER(*offset2)); + + blob->offset = *offset2; + switch (type->tag) + { + case GI_TYPE_TAG_ARRAY: + { + ArrayTypeBlob *array = (ArrayTypeBlob *)&data[*offset2]; + guint32 pos; + + array->pointer = type->is_pointer; + array->reserved = 0; + array->tag = type->tag; + array->zero_terminated = type->zero_terminated; + array->has_length = type->has_length; + array->has_size = type->has_size; + array->array_type = type->array_type; + array->reserved2 = 0; + if (array->has_length) + array->dimensions.length = type->length; + else if (array->has_size) + array->dimensions.size = type->size; + else + array->dimensions.length = -1; + + pos = *offset2 + G_STRUCT_OFFSET (ArrayTypeBlob, type); + *offset2 += sizeof (ArrayTypeBlob); + + gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, + node, build, &pos, offset2, NULL); + } + break; + + case GI_TYPE_TAG_INTERFACE: + { + InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&data[*offset2]; + *offset2 += sizeof (InterfaceTypeBlob); + + iface->pointer = type->is_pointer; + iface->reserved = 0; + iface->tag = type->tag; + iface->reserved2 = 0; + iface->interface = find_entry (build, type->giinterface); + + } + break; + + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + { + ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2]; + guint32 pos; + + param->pointer = 1; + param->reserved = 0; + param->tag = type->tag; + param->reserved2 = 0; + param->n_types = 1; + + pos = *offset2 + G_STRUCT_OFFSET (ParamTypeBlob, type); + *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob); + + gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, + node, build, &pos, offset2, NULL); + } + break; + + case GI_TYPE_TAG_GHASH: + { + ParamTypeBlob *param = (ParamTypeBlob *)&data[*offset2]; + guint32 pos; + + param->pointer = 1; + param->reserved = 0; + param->tag = type->tag; + param->reserved2 = 0; + param->n_types = 2; + + pos = *offset2 + G_STRUCT_OFFSET (ParamTypeBlob, type); + *offset2 += sizeof (ParamTypeBlob) + sizeof (SimpleTypeBlob)*2; + + gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type1, + node, build, &pos, offset2, NULL); + gi_ir_node_build_typelib ((GIIrNode *)type->parameter_type2, + node, build, &pos, offset2, NULL); + } + break; + + case GI_TYPE_TAG_ERROR: + { + ErrorTypeBlob *error_blob = (ErrorTypeBlob *)&data[*offset2]; + + error_blob->pointer = 1; + error_blob->reserved = 0; + error_blob->tag = type->tag; + error_blob->reserved2 = 0; + error_blob->n_domains = 0; + + *offset2 += sizeof (ErrorTypeBlob); + } + break; + + default: + g_error ("Unknown type tag %d\n", type->tag); + break; + } + } + } + } + break; + + case GI_IR_NODE_FIELD: + { + GIIrNodeField *field = (GIIrNodeField *)node; + FieldBlob *blob; + + blob = (FieldBlob *)&data[*offset]; + + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->readable = field->readable; + blob->writable = field->writable; + blob->reserved = 0; + blob->bits = 0; + if (field->offset >= 0) + blob->struct_offset = field->offset; + else + blob->struct_offset = 0xFFFF; /* mark as unknown */ + + if (field->callback) + { + blob->has_embedded_type = TRUE; + blob->type.offset = GI_INFO_TYPE_CALLBACK; + *offset += sizeof (FieldBlob); + gi_ir_node_build_typelib ((GIIrNode *)field->callback, + node, build, offset, offset2, NULL); + /* Fields with callbacks are bigger than normal, update count2 + * as an extra hint which represents the number of fields which are + * callbacks. This allows us to gain constant time performance in the + * repository for skipping over the fields section. + */ + if (count2) + (*count2)++; + } + else + { + blob->has_embedded_type = FALSE; + /* We handle the size member specially below, so subtract it */ + *offset += sizeof (FieldBlob) - sizeof (SimpleTypeBlob); + gi_ir_node_build_typelib ((GIIrNode *)field->type, + node, build, offset, offset2, NULL); + } + } + break; + + case GI_IR_NODE_PROPERTY: + { + GIIrNodeProperty *prop = (GIIrNodeProperty *)node; + PropertyBlob *blob = (PropertyBlob *)&data[*offset]; + /* We handle the size member specially below, so subtract it */ + *offset += sizeof (PropertyBlob) - sizeof (SimpleTypeBlob); + + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->deprecated = prop->deprecated; + blob->readable = prop->readable; + blob->writable = prop->writable; + blob->construct = prop->construct; + blob->construct_only = prop->construct_only; + blob->transfer_ownership = prop->transfer; + blob->transfer_container_ownership = prop->shallow_transfer; + blob->reserved = 0; + + if (prop->setter != NULL) + { + int index = get_index_of_member_type ((GIIrNodeInterface*)parent, + GI_IR_NODE_FUNCTION, + prop->setter); + if (index == -1) + { + g_error ("Unknown setter %s for property %s:%s", prop->setter, parent->name, node->name); + } + + blob->setter = (guint) index; + } + else + blob->setter = ACCESSOR_SENTINEL; + + if (prop->getter != NULL) + { + int index = get_index_of_member_type ((GIIrNodeInterface*)parent, + GI_IR_NODE_FUNCTION, + prop->getter); + if (index == -1) + { + g_error ("Unknown getter %s for property %s:%s", prop->getter, parent->name, node->name); + } + + blob->getter = (guint) index; + } + else + blob->getter = ACCESSOR_SENTINEL; + + gi_ir_node_build_typelib ((GIIrNode *)prop->type, + node, build, offset, offset2, NULL); + } + break; + + case GI_IR_NODE_FUNCTION: + { + FunctionBlob *blob = (FunctionBlob *)&data[*offset]; + SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; + GIIrNodeFunction *function = (GIIrNodeFunction *)node; + guint32 signature; + gint n; + + signature = *offset2; + n = g_list_length (function->parameters); + + *offset += sizeof (FunctionBlob); + *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); + + blob->blob_type = BLOB_TYPE_FUNCTION; + blob->deprecated = function->deprecated; + blob->is_static = !function->is_method; + blob->setter = FALSE; + blob->getter = FALSE; + blob->constructor = function->is_constructor; + blob->wraps_vfunc = function->wraps_vfunc; + blob->throws = function->throws; /* Deprecated. Also stored in SignatureBlob. */ + blob->index = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->symbol = gi_ir_write_string (function->symbol, strings, data, offset2); + blob->signature = signature; + + if (function->is_setter || function->is_getter) + { + int index = get_index_of_member_type ((GIIrNodeInterface*)parent, + GI_IR_NODE_PROPERTY, + function->property); + if (index == -1) + { + g_error ("Unknown property %s:%s for accessor %s", parent->name, function->property, function->symbol); + } + + blob->setter = function->is_setter; + blob->getter = function->is_getter; + blob->index = (guint) index; + } + + /* function->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, function->result); + build->n_attributes += g_hash_table_size (((GIIrNode *) function->result)->attributes); + g_assert (((GIIrNode *) function->result)->offset == 0); + ((GIIrNode *) function->result)->offset = signature; + + g_debug ("building function '%s'", function->symbol); + + gi_ir_node_build_typelib ((GIIrNode *)function->result->type, + node, build, &signature, offset2, NULL); + + blob2->may_return_null = function->result->nullable; + blob2->caller_owns_return_value = function->result->transfer; + blob2->caller_owns_return_container = function->result->shallow_transfer; + blob2->skip_return = function->result->skip; + blob2->instance_transfer_ownership = function->instance_transfer_full; + blob2->reserved = 0; + blob2->n_arguments = n; + blob2->throws = function->throws; + + signature += 4; + + for (l = function->parameters; l; l = l->next) + { + GIIrNode *param = (GIIrNode *)l->data; + + gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); + } + + } + break; + + case GI_IR_NODE_CALLBACK: + { + CallbackBlob *blob = (CallbackBlob *)&data[*offset]; + SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; + GIIrNodeFunction *function = (GIIrNodeFunction *)node; + guint32 signature; + gint n; + + signature = *offset2; + n = g_list_length (function->parameters); + + *offset += sizeof (CallbackBlob); + *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); + + blob->blob_type = BLOB_TYPE_CALLBACK; + blob->deprecated = function->deprecated; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->signature = signature; + + gi_ir_node_build_typelib ((GIIrNode *)function->result->type, + node, build, &signature, offset2, NULL); + + blob2->may_return_null = function->result->nullable; + blob2->caller_owns_return_value = function->result->transfer; + blob2->caller_owns_return_container = function->result->shallow_transfer; + blob2->reserved = 0; + blob2->n_arguments = n; + blob2->throws = function->throws; + + signature += 4; + + for (l = function->parameters; l; l = l->next) + { + GIIrNode *param = (GIIrNode *)l->data; + + gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); + } + } + break; + + case GI_IR_NODE_SIGNAL: + { + SignalBlob *blob = (SignalBlob *)&data[*offset]; + SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; + GIIrNodeSignal *signal = (GIIrNodeSignal *)node; + guint32 signature; + gint n; + + signature = *offset2; + n = g_list_length (signal->parameters); + + *offset += sizeof (SignalBlob); + *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); + + blob->deprecated = signal->deprecated; + blob->run_first = signal->run_first; + blob->run_last = signal->run_last; + blob->run_cleanup = signal->run_cleanup; + blob->no_recurse = signal->no_recurse; + blob->detailed = signal->detailed; + blob->action = signal->action; + blob->no_hooks = signal->no_hooks; + blob->has_class_closure = 0; /* FIXME */ + blob->true_stops_emit = 0; /* FIXME */ + blob->reserved = 0; + blob->class_closure = 0; /* FIXME */ + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->signature = signature; + + /* signal->result is special since it doesn't appear in the serialized format but + * we do want the attributes for it to appear + */ + build->nodes_with_attributes = g_list_prepend (build->nodes_with_attributes, signal->result); + build->n_attributes += g_hash_table_size (((GIIrNode *) signal->result)->attributes); + g_assert (((GIIrNode *) signal->result)->offset == 0); + ((GIIrNode *) signal->result)->offset = signature; + + gi_ir_node_build_typelib ((GIIrNode *)signal->result->type, + node, build, &signature, offset2, NULL); + + blob2->may_return_null = signal->result->nullable; + blob2->caller_owns_return_value = signal->result->transfer; + blob2->caller_owns_return_container = signal->result->shallow_transfer; + blob2->instance_transfer_ownership = signal->instance_transfer_full; + blob2->reserved = 0; + blob2->n_arguments = n; + + signature += 4; + + for (l = signal->parameters; l; l = l->next) + { + GIIrNode *param = (GIIrNode *)l->data; + + gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); + } + } + break; + + case GI_IR_NODE_VFUNC: + { + VFuncBlob *blob = (VFuncBlob *)&data[*offset]; + SignatureBlob *blob2 = (SignatureBlob *)&data[*offset2]; + GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)node; + guint32 signature; + gint n; + + signature = *offset2; + n = g_list_length (vfunc->parameters); + + *offset += sizeof (VFuncBlob); + *offset2 += sizeof (SignatureBlob) + n * sizeof (ArgBlob); + + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->must_chain_up = 0; /* FIXME */ + blob->must_be_implemented = 0; /* FIXME */ + blob->must_not_be_implemented = 0; /* FIXME */ + blob->class_closure = 0; /* FIXME */ + blob->throws = vfunc->throws; /* Deprecated. Also stored in SignatureBlob. */ + blob->reserved = 0; + + if (vfunc->invoker) + { + int index = get_index_of_member_type ((GIIrNodeInterface*)parent, GI_IR_NODE_FUNCTION, vfunc->invoker); + if (index == -1) + { + g_error ("Unknown member function %s for vfunc %s", vfunc->invoker, node->name); + } + blob->invoker = (guint) index; + } + else + blob->invoker = 0x3ff; /* max of 10 bits */ + + blob->struct_offset = vfunc->offset; + blob->reserved2 = 0; + blob->signature = signature; + + gi_ir_node_build_typelib ((GIIrNode *)vfunc->result->type, + node, build, &signature, offset2, NULL); + + blob2->may_return_null = vfunc->result->nullable; + blob2->caller_owns_return_value = vfunc->result->transfer; + blob2->caller_owns_return_container = vfunc->result->shallow_transfer; + blob2->instance_transfer_ownership = vfunc->instance_transfer_full; + blob2->reserved = 0; + blob2->n_arguments = n; + blob2->throws = vfunc->throws; + + signature += 4; + + for (l = vfunc->parameters; l; l = l->next) + { + GIIrNode *param = (GIIrNode *)l->data; + + gi_ir_node_build_typelib (param, node, build, &signature, offset2, NULL); + } + } + break; + + case GI_IR_NODE_PARAM: + { + ArgBlob *blob = (ArgBlob *)&data[*offset]; + GIIrNodeParam *param = (GIIrNodeParam *)node; + + /* The offset for this one is smaller than the struct because + * we recursively build the simple type inline here below. + */ + *offset += sizeof (ArgBlob) - sizeof (SimpleTypeBlob); + + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->in = param->in; + blob->out = param->out; + blob->caller_allocates = param->caller_allocates; + blob->nullable = param->nullable; + blob->skip = param->skip; + blob->optional = param->optional; + blob->transfer_ownership = param->transfer; + blob->transfer_container_ownership = param->shallow_transfer; + blob->return_value = param->retval; + blob->scope = param->scope; + blob->reserved = 0; + blob->closure = param->closure; + blob->destroy = param->destroy; + + gi_ir_node_build_typelib ((GIIrNode *)param->type, node, build, offset, offset2, NULL); + } + break; + + case GI_IR_NODE_STRUCT: + { + StructBlob *blob = (StructBlob *)&data[*offset]; + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + GList *members; + + blob->blob_type = BLOB_TYPE_STRUCT; + blob->foreign = struct_->foreign; + blob->deprecated = struct_->deprecated; + blob->is_gtype_struct = struct_->is_gtype_struct; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->alignment = struct_->alignment; + blob->size = struct_->size; + + if (struct_->gtype_name) + { + blob->unregistered = FALSE; + blob->gtype_name = gi_ir_write_string (struct_->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (struct_->gtype_init, strings, data, offset2); + } + else + { + blob->unregistered = TRUE; + blob->gtype_name = 0; + blob->gtype_init = 0; + } + + if (struct_->copy_func) + blob->copy_func = gi_ir_write_string (struct_->copy_func, strings, data, offset2); + if (struct_->free_func) + blob->free_func = gi_ir_write_string (struct_->free_func, strings, data, offset2); + + blob->n_fields = 0; + blob->n_methods = 0; + + *offset += sizeof (StructBlob); + + members = g_list_copy (struct_->members); + + gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, + node, build, offset, offset2, NULL); + + gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, + node, build, offset, offset2, NULL); + + gi_ir_node_check_unhandled_members (&members, node->type); + + g_assert (members == NULL); + } + break; + + case GI_IR_NODE_BOXED: + { + StructBlob *blob = (StructBlob *)&data[*offset]; + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + GList *members; + + blob->blob_type = BLOB_TYPE_BOXED; + blob->deprecated = boxed->deprecated; + blob->unregistered = FALSE; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->gtype_name = gi_ir_write_string (boxed->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (boxed->gtype_init, strings, data, offset2); + blob->alignment = boxed->alignment; + blob->size = boxed->size; + + blob->n_fields = 0; + blob->n_methods = 0; + + *offset += sizeof (StructBlob); + + members = g_list_copy (boxed->members); + + gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, + node, build, offset, offset2, NULL); + + gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, + node, build, offset, offset2, NULL); + + gi_ir_node_check_unhandled_members (&members, node->type); + + g_assert (members == NULL); + } + break; + + case GI_IR_NODE_UNION: + { + UnionBlob *blob = (UnionBlob *)&data[*offset]; + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + GList *members; + + blob->blob_type = BLOB_TYPE_UNION; + blob->deprecated = union_->deprecated; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->alignment = union_->alignment; + blob->size = union_->size; + if (union_->gtype_name) + { + blob->unregistered = FALSE; + blob->gtype_name = gi_ir_write_string (union_->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (union_->gtype_init, strings, data, offset2); + } + else + { + blob->unregistered = TRUE; + blob->gtype_name = 0; + blob->gtype_init = 0; + } + + blob->n_fields = 0; + blob->n_functions = 0; + + blob->discriminator_offset = union_->discriminator_offset; + + if (union_->copy_func) + blob->copy_func = gi_ir_write_string (union_->copy_func, strings, data, offset2); + if (union_->free_func) + blob->free_func = gi_ir_write_string (union_->free_func, strings, data, offset2); + + /* We don't support Union discriminators right now. */ + /* + if (union_->discriminator_type) + { + *offset += 28; + blob->discriminated = TRUE; + gi_ir_node_build_typelib ((GIIrNode *)union_->discriminator_type, + build, offset, offset2, NULL); + } + else + { + */ + *offset += sizeof (UnionBlob); + blob->discriminated = FALSE; + blob->discriminator_type.offset = 0; + + members = g_list_copy (union_->members); + + gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, + node, build, offset, offset2, NULL); + + gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_functions, + node, build, offset, offset2, NULL); + + gi_ir_node_check_unhandled_members (&members, node->type); + + g_assert (members == NULL); + + if (union_->discriminator_type) + { + for (l = union_->discriminators; l; l = l->next) + { + GIIrNode *member = (GIIrNode *)l->data; + + gi_ir_node_build_typelib (member, node, build, offset, offset2, NULL); + } + } + } + break; + + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + EnumBlob *blob = (EnumBlob *)&data[*offset]; + GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; + + *offset += sizeof (EnumBlob); + + if (node->type == GI_IR_NODE_ENUM) + blob->blob_type = BLOB_TYPE_ENUM; + else + blob->blob_type = BLOB_TYPE_FLAGS; + + blob->deprecated = enum_->deprecated; + blob->reserved = 0; + blob->storage_type = enum_->storage_type; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + if (enum_->gtype_name) + { + blob->unregistered = FALSE; + blob->gtype_name = gi_ir_write_string (enum_->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (enum_->gtype_init, strings, data, offset2); + } + else + { + blob->unregistered = TRUE; + blob->gtype_name = 0; + blob->gtype_init = 0; + } + if (enum_->error_domain) + blob->error_domain = gi_ir_write_string (enum_->error_domain, strings, data, offset2); + else + blob->error_domain = 0; + + blob->n_values = 0; + blob->n_methods = 0; + + for (l = enum_->values; l; l = l->next) + { + GIIrNode *value = (GIIrNode *)l->data; + + blob->n_values++; + gi_ir_node_build_typelib (value, node, build, offset, offset2, NULL); + } + + for (l = enum_->methods; l; l = l->next) + { + GIIrNode *method = (GIIrNode *)l->data; + + blob->n_methods++; + gi_ir_node_build_typelib (method, node, build, offset, offset2, NULL); + } + } + break; + + case GI_IR_NODE_OBJECT: + { + ObjectBlob *blob = (ObjectBlob *)&data[*offset]; + GIIrNodeInterface *object = (GIIrNodeInterface *)node; + GList *members; + + blob->blob_type = BLOB_TYPE_OBJECT; + blob->abstract = object->abstract; + blob->fundamental = object->fundamental; + blob->final_ = object->final_; + blob->deprecated = object->deprecated; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->gtype_name = gi_ir_write_string (object->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (object->gtype_init, strings, data, offset2); + if (object->ref_func) + blob->ref_func = gi_ir_write_string (object->ref_func, strings, data, offset2); + if (object->unref_func) + blob->unref_func = gi_ir_write_string (object->unref_func, strings, data, offset2); + if (object->set_value_func) + blob->set_value_func = gi_ir_write_string (object->set_value_func, strings, data, offset2); + if (object->get_value_func) + blob->get_value_func = gi_ir_write_string (object->get_value_func, strings, data, offset2); + if (object->parent) + blob->parent = find_entry (build, object->parent); + else + blob->parent = 0; + if (object->glib_type_struct) + blob->gtype_struct = find_entry (build, object->glib_type_struct); + else + blob->gtype_struct = 0; + + blob->n_interfaces = 0; + blob->n_fields = 0; + blob->n_properties = 0; + blob->n_methods = 0; + blob->n_signals = 0; + blob->n_vfuncs = 0; + blob->n_constants = 0; + blob->n_field_callbacks = 0; + + *offset += sizeof(ObjectBlob); + for (l = object->interfaces; l; l = l->next) + { + blob->n_interfaces++; + *(guint16*)&data[*offset] = find_entry (build, (gchar *)l->data); + *offset += 2; + } + + members = g_list_copy (object->members); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_FIELD, &blob->n_fields, + node, build, offset, offset2, &blob->n_field_callbacks); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_PROPERTY, &blob->n_properties, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_SIGNAL, &blob->n_signals, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_VFUNC, &blob->n_vfuncs, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_CONSTANT, &blob->n_constants, + node, build, offset, offset2, NULL); + + gi_ir_node_check_unhandled_members (&members, node->type); + + g_assert (members == NULL); + } + break; + + case GI_IR_NODE_INTERFACE: + { + InterfaceBlob *blob = (InterfaceBlob *)&data[*offset]; + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + GList *members; + + blob->blob_type = BLOB_TYPE_INTERFACE; + blob->deprecated = iface->deprecated; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->gtype_name = gi_ir_write_string (iface->gtype_name, strings, data, offset2); + blob->gtype_init = gi_ir_write_string (iface->gtype_init, strings, data, offset2); + if (iface->glib_type_struct) + blob->gtype_struct = find_entry (build, iface->glib_type_struct); + else + blob->gtype_struct = 0; + blob->n_prerequisites = 0; + blob->n_properties = 0; + blob->n_methods = 0; + blob->n_signals = 0; + blob->n_vfuncs = 0; + blob->n_constants = 0; + + *offset += sizeof (InterfaceBlob); + for (l = iface->prerequisites; l; l = l->next) + { + blob->n_prerequisites++; + *(guint16*)&data[*offset] = find_entry (build, (gchar *)l->data); + *offset += 2; + } + + members = g_list_copy (iface->members); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_PROPERTY, &blob->n_properties, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_FUNCTION, &blob->n_methods, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_SIGNAL, &blob->n_signals, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_VFUNC, &blob->n_vfuncs, + node, build, offset, offset2, NULL); + + *offset = ALIGN_VALUE (*offset, 4); + gi_ir_node_build_members (&members, GI_IR_NODE_CONSTANT, &blob->n_constants, + node, build, offset, offset2, NULL); + + gi_ir_node_check_unhandled_members (&members, node->type); + + g_assert (members == NULL); + } + break; + + + case GI_IR_NODE_VALUE: + { + GIIrNodeValue *value = (GIIrNodeValue *)node; + ValueBlob *blob = (ValueBlob *)&data[*offset]; + *offset += sizeof (ValueBlob); + + blob->deprecated = value->deprecated; + blob->reserved = 0; + blob->unsigned_value = value->value >= 0 ? 1 : 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + blob->value = (gint32)value->value; + } + break; + + case GI_IR_NODE_CONSTANT: + { + GIIrNodeConstant *constant = (GIIrNodeConstant *)node; + ConstantBlob *blob = (ConstantBlob *)&data[*offset]; + guint32 pos; + + pos = *offset + G_STRUCT_OFFSET (ConstantBlob, type); + *offset += sizeof (ConstantBlob); + + blob->blob_type = BLOB_TYPE_CONSTANT; + blob->deprecated = constant->deprecated; + blob->reserved = 0; + blob->name = gi_ir_write_string (node->name, strings, data, offset2); + + blob->offset = *offset2; + switch (constant->type->tag) + { + case GI_TYPE_TAG_BOOLEAN: + blob->size = 4; + *(gboolean*)&data[blob->offset] = parse_boolean_value (constant->value); + break; + case GI_TYPE_TAG_INT8: + blob->size = 1; + *(gint8*)&data[blob->offset] = (gint8) parse_int_value (constant->value); + break; + case GI_TYPE_TAG_UINT8: + blob->size = 1; + *(guint8*)&data[blob->offset] = (guint8) parse_uint_value (constant->value); + break; + case GI_TYPE_TAG_INT16: + blob->size = 2; + *(gint16*)&data[blob->offset] = (gint16) parse_int_value (constant->value); + break; + case GI_TYPE_TAG_UINT16: + blob->size = 2; + *(guint16*)&data[blob->offset] = (guint16) parse_uint_value (constant->value); + break; + case GI_TYPE_TAG_INT32: + blob->size = 4; + *(gint32*)&data[blob->offset] = (gint32) parse_int_value (constant->value); + break; + case GI_TYPE_TAG_UINT32: + blob->size = 4; + *(guint32*)&data[blob->offset] = (guint32) parse_uint_value (constant->value); + break; + case GI_TYPE_TAG_INT64: + blob->size = 8; + DO_ALIGNED_COPY(&data[blob->offset], parse_int_value (constant->value), gint64); + break; + case GI_TYPE_TAG_UINT64: + blob->size = 8; + DO_ALIGNED_COPY(&data[blob->offset], parse_uint_value (constant->value), guint64); + break; + case GI_TYPE_TAG_FLOAT: + blob->size = sizeof (gfloat); + DO_ALIGNED_COPY(&data[blob->offset], parse_float_value (constant->value), gfloat); + break; + case GI_TYPE_TAG_DOUBLE: + blob->size = sizeof (gdouble); + DO_ALIGNED_COPY(&data[blob->offset], parse_float_value (constant->value), gdouble); + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + blob->size = strlen (constant->value) + 1; + memcpy (&data[blob->offset], constant->value, blob->size); + break; + default: + break; + } + *offset2 += ALIGN_VALUE (blob->size, 4); + + gi_ir_node_build_typelib ((GIIrNode *)constant->type, node, build, &pos, offset2, NULL); + } + break; + default: + g_assert_not_reached (); + } + + g_debug ("node %s%s%s%p type '%s', offset %d -> %d, offset2 %d -> %d", + node->name ? "'" : "", + node->name ? node->name : "", + node->name ? "' " : "", + node, gi_ir_node_type_to_string (node->type), + old_offset, *offset, old_offset2, *offset2); + + if (*offset2 - old_offset2 + *offset - old_offset > gi_ir_node_get_full_size (node)) + g_error ("exceeding space reservation; offset: %d (prev %d) offset2: %d (prev %d) nodesize: %d", + *offset, old_offset, *offset2, old_offset2, gi_ir_node_get_full_size (node)); + + if (appended_stack) + build->stack = g_list_delete_link (build->stack, build->stack); +} + +/* if str is already in the pool, return previous location, otherwise write str + * to the typelib at offset, put it in the pool and update offset. If the + * typelib is not large enough to hold the string, reallocate it. + */ +guint32 +gi_ir_write_string (const gchar *str, + GHashTable *strings, + guchar *data, + guint32 *offset) +{ + gpointer value; + guint32 start; + + string_count += 1; + string_size += strlen (str); + + value = g_hash_table_lookup (strings, str); + + if (value) + return GPOINTER_TO_UINT (value); + + unique_string_count += 1; + unique_string_size += strlen (str); + + g_hash_table_insert (strings, (gpointer)str, GUINT_TO_POINTER (*offset)); + + start = *offset; + *offset = ALIGN_VALUE (start + strlen (str) + 1, 4); + + strcpy ((gchar*)&data[start], str); + + return start; +} + diff --git a/girepository/giroffsets.c b/girepository/giroffsets.c new file mode 100644 index 0000000..32bf684 --- /dev/null +++ b/girepository/giroffsets.c @@ -0,0 +1,593 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Compute structure offsets + * + * Copyright (C) 2008 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "girffi.h" + +#include "girnode-private.h" + +#include + +/* The C standard specifies that an enumeration can be any char or any signed + * or unsigned integer type capable of representing all the values of the + * enumeration. We use test enumerations to figure out what choices the + * compiler makes. (Ignoring > 32 bit enumerations) + */ + +typedef enum { + ENUM_1 = 1 /* compiler could use int8, uint8, int16, uint16, int32, uint32 */ +} Enum1; + +typedef enum { + ENUM_2 = 128 /* compiler could use uint8, int16, uint16, int32, uint32 */ +} Enum2; + +typedef enum { + ENUM_3 = 257 /* compiler could use int16, uint16, int32, uint32 */ +} Enum3; + +typedef enum { + ENUM_4 = G_MAXSHORT + 1 /* compiler could use uint16, int32, uint32 */ +} Enum4; + +typedef enum { + ENUM_5 = G_MAXUSHORT + 1 /* compiler could use int32, uint32 */ +} Enum5; + +typedef enum { + ENUM_6 = ((guint)G_MAXINT) + 1 /* compiler could use uint32 */ +} Enum6; + +typedef enum { + ENUM_7 = -1 /* compiler could use int8, int16, int32 */ +} Enum7; + +typedef enum { + ENUM_8 = -129 /* compiler could use int16, int32 */ +} Enum8; + +typedef enum { + ENUM_9 = G_MINSHORT - 1 /* compiler could use int32 */ +} Enum9; + +static void +compute_enum_storage_type (GIIrNodeEnum *enum_node) +{ + GList *l; + gint64 max_value = 0; + gint64 min_value = 0; + int width; + gboolean signed_type; + + if (enum_node->storage_type != GI_TYPE_TAG_VOID) /* already done */ + return; + + for (l = enum_node->values; l; l = l->next) + { + GIIrNodeValue *value = l->data; + if (value->value > max_value) + max_value = value->value; + if (value->value < min_value) + min_value = value->value; + } + + if (min_value < 0) + { + signed_type = TRUE; + + if (min_value > -128 && max_value <= 127) + width = sizeof(Enum7); + else if (min_value >= G_MINSHORT && max_value <= G_MAXSHORT) + width = sizeof(Enum8); + else + width = sizeof(Enum9); + } + else + { + if (max_value <= 127) + { + width = sizeof (Enum1); + signed_type = (gint64)(Enum1)(-1) < 0; + } + else if (max_value <= 255) + { + width = sizeof (Enum2); + signed_type = (gint64)(Enum2)(-1) < 0; + } + else if (max_value <= G_MAXSHORT) + { + width = sizeof (Enum3); + signed_type = (gint64)(Enum3)(-1) < 0; + } + else if (max_value <= G_MAXUSHORT) + { + width = sizeof (Enum4); + signed_type = (gint64)(Enum4)(-1) < 0; + } + else if (max_value <= G_MAXINT) + { + width = sizeof (Enum5); + signed_type = (gint64)(Enum5)(-1) < 0; + } + else + { + width = sizeof (Enum6); + signed_type = (gint64)(Enum6)(-1) < 0; + } + } + + if (width == 1) + enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT8 : GI_TYPE_TAG_UINT8; + else if (width == 2) + enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT16 : GI_TYPE_TAG_UINT16; + else if (width == 4) + enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT32 : GI_TYPE_TAG_UINT32; + else if (width == 8) + enum_node->storage_type = signed_type ? GI_TYPE_TAG_INT64 : GI_TYPE_TAG_UINT64; + else + g_error ("Unexpected enum width %d", width); +} + +static gboolean +get_enum_size_alignment (GIIrNodeEnum *enum_node, + gint *size, + gint *alignment) +{ + ffi_type *type_ffi; + + compute_enum_storage_type (enum_node); + + switch (enum_node->storage_type) + { + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + type_ffi = &ffi_type_uint8; + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + type_ffi = &ffi_type_uint16; + break; + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + type_ffi = &ffi_type_uint32; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + type_ffi = &ffi_type_uint64; + break; + default: + g_error ("Unexpected enum storage type %s", + gi_type_tag_to_string (enum_node->storage_type)); + } + + *size = type_ffi->size; + *alignment = type_ffi->alignment; + + return TRUE; +} + +static gboolean +get_interface_size_alignment (GIIrTypelibBuild *build, + GIIrNodeType *type, + gint *size, + gint *alignment, + const char *who) +{ + GIIrNode *iface; + + iface = gi_ir_find_node (build, ((GIIrNode*)type)->module, type->giinterface); + if (!iface) + { + gi_ir_module_fatal (build, 0, "Can't resolve type '%s' for %s", type->giinterface, who); + *size = -1; + *alignment = -1; + return FALSE; + } + + gi_ir_node_compute_offsets (build, iface); + + switch (iface->type) + { + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)iface; + *size = boxed->size; + *alignment = boxed->alignment; + break; + } + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)iface; + *size = struct_->size; + *alignment = struct_->alignment; + break; + } + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *interface = (GIIrNodeInterface *)iface; + *size = interface->size; + *alignment = interface->alignment; + break; + } + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)iface; + *size = union_->size; + *alignment = union_->alignment; + break; + } + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + return get_enum_size_alignment ((GIIrNodeEnum *)iface, + size, alignment); + } + case GI_IR_NODE_CALLBACK: + { + *size = ffi_type_pointer.size; + *alignment = ffi_type_pointer.alignment; + break; + } + default: + { + g_warning ("%s has is not a pointer and is of type %s", + who, + gi_ir_node_type_to_string (iface->type)); + *size = -1; + *alignment = -1; + break; + } + } + + return *alignment > 0; +} + +static gboolean +get_type_size_alignment (GIIrTypelibBuild *build, + GIIrNodeType *type, + gint *size, + gint *alignment, + const char *who) +{ + ffi_type *type_ffi; + + if (type->is_pointer) + { + type_ffi = &ffi_type_pointer; + } + else if (type->tag == GI_TYPE_TAG_ARRAY) + { + gint elt_size, elt_alignment; + + if (!type->has_size + || !get_type_size_alignment(build, type->parameter_type1, + &elt_size, &elt_alignment, who)) + { + *size = -1; + *alignment = -1; + return FALSE; + } + + *size = type->size * elt_size; + *alignment = elt_alignment; + + return TRUE; + } + else + { + if (type->tag == GI_TYPE_TAG_INTERFACE) + { + return get_interface_size_alignment (build, type, size, alignment, who); + } + else + { + type_ffi = gi_type_tag_get_ffi_type (type->tag, type->is_pointer); + + if (type_ffi == &ffi_type_void) + { + g_warning ("%s has void type", who); + *size = -1; + *alignment = -1; + return FALSE; + } + else if (type_ffi == &ffi_type_pointer) + { + g_warning ("%s has is not a pointer and is of type %s", + who, + gi_type_tag_to_string (type->tag)); + *size = -1; + *alignment = -1; + return FALSE; + } + } + } + + g_assert (type_ffi); + *size = type_ffi->size; + *alignment = type_ffi->alignment; + + return TRUE; +} + +static gboolean +get_field_size_alignment (GIIrTypelibBuild *build, + GIIrNodeField *field, + GIIrNode *parent_node, + gint *size, + gint *alignment) +{ + GIIrModule *module = build->module; + gchar *who; + gboolean success; + + who = g_strdup_printf ("field %s.%s.%s", module->name, parent_node->name, ((GIIrNode *)field)->name); + + if (field->callback) + { + *size = ffi_type_pointer.size; + *alignment = ffi_type_pointer.alignment; + success = TRUE; + } + else + success = get_type_size_alignment (build, field->type, size, alignment, who); + g_free (who); + + return success; +} + +#define GI_ALIGN(n, align) (((n) + (align) - 1) & ~((align) - 1)) + +static gboolean +compute_struct_field_offsets (GIIrTypelibBuild *build, + GIIrNode *node, + GList *members, + gint *size_out, + gint *alignment_out) +{ + int size = 0; + int alignment = 1; + GList *l; + gboolean have_error = FALSE; + + *alignment_out = -2; /* mark to detect recursion */ + + for (l = members; l; l = l->next) + { + GIIrNode *member = (GIIrNode *)l->data; + + if (member->type == GI_IR_NODE_FIELD) + { + GIIrNodeField *field = (GIIrNodeField *)member; + + if (!have_error) + { + int member_size; + int member_alignment; + + if (get_field_size_alignment (build, field, node, + &member_size, &member_alignment)) + { + size = GI_ALIGN (size, member_alignment); + alignment = MAX (alignment, member_alignment); + field->offset = size; + size += member_size; + } + else + have_error = TRUE; + } + + if (have_error) + field->offset = -1; + } + else if (member->type == GI_IR_NODE_CALLBACK) + { + size = GI_ALIGN (size, ffi_type_pointer.alignment); + alignment = MAX (alignment, ffi_type_pointer.alignment); + size += ffi_type_pointer.size; + } + } + + /* Structs are tail-padded out to a multiple of their alignment */ + size = GI_ALIGN (size, alignment); + + if (!have_error) + { + *size_out = size; + *alignment_out = alignment; + } + else + { + *size_out = -1; + *alignment_out = -1; + } + + return !have_error; +} + +static gboolean +compute_union_field_offsets (GIIrTypelibBuild *build, + GIIrNode *node, + GList *members, + gint *size_out, + gint *alignment_out) +{ + int size = 0; + int alignment = 1; + GList *l; + gboolean have_error = FALSE; + + *alignment_out = -2; /* mark to detect recursion */ + + for (l = members; l; l = l->next) + { + GIIrNode *member = (GIIrNode *)l->data; + + if (member->type == GI_IR_NODE_FIELD) + { + GIIrNodeField *field = (GIIrNodeField *)member; + + if (!have_error) + { + int member_size; + int member_alignment; + + if (get_field_size_alignment (build,field, node, + &member_size, &member_alignment)) + { + size = MAX (size, member_size); + alignment = MAX (alignment, member_alignment); + } + else + have_error = TRUE; + } + } + } + + /* Unions are tail-padded out to a multiple of their alignment */ + size = GI_ALIGN (size, alignment); + + if (!have_error) + { + *size_out = size; + *alignment_out = alignment; + } + else + { + *size_out = -1; + *alignment_out = -1; + } + + return !have_error; +} + +static gboolean +check_needs_computation (GIIrTypelibBuild *build, + GIIrNode *node, + gint alignment) +{ + GIIrModule *module = build->module; + /* + * 0: Not yet computed + * >0: Previously succeeded + * -1: Previously failed + * -2: In progress + */ + if (alignment == -2) + { + g_warning ("Recursion encountered when computing the size of %s.%s", + module->name, node->name); + } + + return alignment == 0; +} + +/* + * gi_ir_node_compute_offsets: + * @build: Current typelib build + * @node: a #GIIrNode + * + * If a node is a a structure or union, makes sure that the field + * offsets have been computed, and also computes the overall size and + * alignment for the type. + * + * Since: 2.80 + */ +void +gi_ir_node_compute_offsets (GIIrTypelibBuild *build, + GIIrNode *node) +{ + gboolean appended_stack; + + if (build->stack) + appended_stack = node != (GIIrNode*)build->stack->data; + else + appended_stack = TRUE; + if (appended_stack) + build->stack = g_list_prepend (build->stack, node); + + switch (node->type) + { + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed = (GIIrNodeBoxed *)node; + + if (!check_needs_computation (build, node, boxed->alignment)) + return; + + compute_struct_field_offsets (build, node, boxed->members, + &boxed->size, &boxed->alignment); + break; + } + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_ = (GIIrNodeStruct *)node; + + if (!check_needs_computation (build, node, struct_->alignment)) + return; + + compute_struct_field_offsets (build, node, struct_->members, + &struct_->size, &struct_->alignment); + break; + } + case GI_IR_NODE_OBJECT: + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)node; + + if (!check_needs_computation (build, node, iface->alignment)) + return; + + compute_struct_field_offsets (build, node, iface->members, + &iface->size, &iface->alignment); + break; + } + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_ = (GIIrNodeUnion *)node; + + if (!check_needs_computation (build, node, union_->alignment)) + return; + + compute_union_field_offsets (build, (GIIrNode*)union_, union_->members, + &union_->size, &union_->alignment); + break; + } + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + GIIrNodeEnum *enum_ = (GIIrNodeEnum *)node; + + if (enum_->storage_type != GI_TYPE_TAG_VOID) /* already done */ + return; + + compute_enum_storage_type (enum_); + + break; + } + default: + break; + } + + if (appended_stack) + build->stack = g_list_delete_link (build->stack, build->stack); +} diff --git a/girepository/girparser-private.h b/girepository/girparser-private.h new file mode 100644 index 0000000..a2dcb6a --- /dev/null +++ b/girepository/girparser-private.h @@ -0,0 +1,49 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: A parser for the XML GIR format + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +#include "girmodule-private.h" + +typedef struct _GIIrParser GIIrParser; + +GIIrParser *gi_ir_parser_new (void); +void gi_ir_parser_free (GIIrParser *parser); +void gi_ir_parser_set_includes (GIIrParser *parser, + const gchar *const *includes); + +GIIrModule *gi_ir_parser_parse_string (GIIrParser *parser, + const gchar *namespace, + const gchar *filename, + const gchar *buffer, + gssize length, + GError **error); +GIIrModule *gi_ir_parser_parse_file (GIIrParser *parser, + const gchar *filename, + GError **error); + +G_END_DECLS diff --git a/girepository/girparser.c b/girepository/girparser.c new file mode 100644 index 0000000..f6f6593 --- /dev/null +++ b/girepository/girparser.c @@ -0,0 +1,3820 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: A parser for the XML GIR format + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008 Philip Van Hoof + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "girparser-private.h" + +#include "girnode-private.h" +#include "gitypelib-internal.h" + +#include +#include +#include + +/* This is a "major" version in the sense that it's only bumped + * for incompatible changes. + */ +#define SUPPORTED_GIR_VERSION "1.2" + +#ifdef G_OS_WIN32 + +#include + +#ifdef GIR_DIR +#undef GIR_DIR +#endif + +/* GIR_DIR is used only in code called just once, + * so no problem leaking this + */ +#define GIR_DIR \ + g_build_filename (g_win32_get_package_installation_directory_of_module(NULL), \ + "share", \ + GIR_SUFFIX, \ + NULL) +#endif + +struct _GIIrParser +{ + gchar **includes; + gchar **gi_gir_path; + GList *parsed_modules; /* All previously parsed modules */ +}; + +typedef enum +{ + STATE_NONE = 0, + STATE_START, + STATE_END, + STATE_REPOSITORY, + STATE_INCLUDE, + STATE_C_INCLUDE, /* 5 */ + STATE_PACKAGE, + STATE_NAMESPACE, + STATE_ENUM, + STATE_BITFIELD, + STATE_FUNCTION, /* 10 */ + STATE_FUNCTION_RETURN, + STATE_FUNCTION_PARAMETERS, + STATE_FUNCTION_PARAMETER, + STATE_CLASS, + STATE_CLASS_FIELD, /* 15 */ + STATE_CLASS_PROPERTY, + STATE_INTERFACE, + STATE_INTERFACE_PROPERTY, + STATE_INTERFACE_FIELD, + STATE_IMPLEMENTS, /* 20 */ + STATE_PREREQUISITE, + STATE_BOXED, + STATE_BOXED_FIELD, + STATE_STRUCT, + STATE_STRUCT_FIELD, /* 25 */ + STATE_UNION, + STATE_UNION_FIELD, + STATE_NAMESPACE_CONSTANT, + STATE_CLASS_CONSTANT, + STATE_INTERFACE_CONSTANT, /* 30 */ + STATE_ALIAS, + STATE_TYPE, + STATE_ATTRIBUTE, + STATE_PASSTHROUGH +} ParseState; + +typedef struct _ParseContext ParseContext; +struct _ParseContext +{ + GIIrParser *parser; + + ParseState state; + int unknown_depth; + ParseState prev_state; + + GList *modules; + GList *include_modules; + GList *dependencies; + GHashTable *aliases; + GHashTable *disguised_structures; + GHashTable *pointer_structures; + + const char *file_path; + const char *namespace; + const char *c_prefix; + GIIrModule *current_module; + GSList *node_stack; + char *current_alias; + GIIrNode *current_typed; + GList *type_stack; + GList *type_parameters; + int type_depth; + ParseState in_embedded_state; +}; +#define CURRENT_NODE(ctx) ((GIIrNode *)((ctx)->node_stack->data)) + +static void start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error); +static void end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error); +static void text_handler (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error); +static void cleanup (GMarkupParseContext *context, + GError *error, + gpointer user_data); +static void state_switch (ParseContext *ctx, ParseState newstate); + + +static GMarkupParser markup_parser = +{ + start_element_handler, + end_element_handler, + text_handler, + NULL, + cleanup +}; + +static gboolean +start_alias (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error); +static gboolean +start_type (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error); + +static const gchar *find_attribute (const gchar *name, + const gchar **attribute_names, + const gchar **attribute_values); + + +GIIrParser * +gi_ir_parser_new (void) +{ + GIIrParser *parser = g_slice_new0 (GIIrParser); + const char *gi_gir_path = g_getenv ("GI_GIR_PATH"); + + if (gi_gir_path != NULL) + parser->gi_gir_path = g_strsplit (gi_gir_path, G_SEARCHPATH_SEPARATOR_S, 0); + + return parser; +} + +void +gi_ir_parser_free (GIIrParser *parser) +{ + GList *l; + + g_strfreev (parser->includes); + g_strfreev (parser->gi_gir_path); + + for (l = parser->parsed_modules; l; l = l->next) + gi_ir_module_free (l->data); + + g_slice_free (GIIrParser, parser); +} + +void +gi_ir_parser_set_includes (GIIrParser *parser, + const gchar *const *includes) +{ + g_strfreev (parser->includes); + + parser->includes = g_strdupv ((char **)includes); +} + +static void +firstpass_start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + + if (strcmp (element_name, "alias") == 0) + { + start_alias (context, element_name, attribute_names, attribute_values, + ctx, error); + } + else if (ctx->state == STATE_ALIAS && strcmp (element_name, "type") == 0) + { + start_type (context, element_name, attribute_names, attribute_values, + ctx, error); + } + else if (strcmp (element_name, "record") == 0) + { + const gchar *name; + const gchar *disguised; + const gchar *pointer; + + name = find_attribute ("name", attribute_names, attribute_values); + disguised = find_attribute ("disguised", attribute_names, attribute_values); + pointer = find_attribute ("pointer", attribute_names, attribute_values); + + if (g_strcmp0 (pointer, "1") == 0) + { + char *key; + + key = g_strdup_printf ("%s.%s", ctx->namespace, name); + g_hash_table_replace (ctx->pointer_structures, key, GINT_TO_POINTER (1)); + } + else if (g_strcmp0 (disguised, "1") == 0) + { + char *key; + + key = g_strdup_printf ("%s.%s", ctx->namespace, name); + g_hash_table_replace (ctx->disguised_structures, key, GINT_TO_POINTER (1)); + } + } +} + +static void +firstpass_end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + if (strcmp (element_name, "alias") == 0) + { + state_switch (ctx, STATE_NAMESPACE); + g_free (ctx->current_alias); + ctx->current_alias = NULL; + } + else if (strcmp (element_name, "type") == 0 && ctx->state == STATE_TYPE) + state_switch (ctx, ctx->prev_state); +} + +static GMarkupParser firstpass_parser = +{ + firstpass_start_element_handler, + firstpass_end_element_handler, + NULL, + NULL, + NULL, +}; + +static char * +locate_gir (GIIrParser *parser, + const char *girname) +{ + const gchar *const *datadirs; + const gchar *const *dir; + char *path = NULL; + + g_debug ("Looking for %s", girname); + datadirs = g_get_system_data_dirs (); + + if (parser->includes != NULL) + { + for (dir = (const gchar *const *)parser->includes; *dir; dir++) + { + path = g_build_filename (*dir, girname, NULL); + g_debug ("Trying %s from includes", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + } + } + + if (parser->gi_gir_path != NULL) + { + for (dir = (const gchar *const *) parser->gi_gir_path; *dir; dir++) + { + if (**dir == '\0') + continue; + + path = g_build_filename (*dir, girname, NULL); + g_debug ("Trying %s from GI_GIR_PATH", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + } + } + + path = g_build_filename (g_get_user_data_dir (), GIR_SUFFIX, girname, NULL); + g_debug ("Trying %s from user data dir", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + + for (dir = datadirs; *dir; dir++) + { + path = g_build_filename (*dir, GIR_SUFFIX, girname, NULL); + g_debug ("Trying %s from system data dirs", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + } + + path = g_build_filename (GIR_DIR, girname, NULL); + g_debug ("Trying %s from GIR_DIR", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + + path = g_build_filename (GOBJECT_INTROSPECTION_DATADIR, GIR_SUFFIX, girname, NULL); + g_debug ("Trying %s from DATADIR", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); + +#ifdef G_OS_UNIX + path = g_build_filename ("/usr/share", GIR_SUFFIX, girname, NULL); + g_debug ("Trying %s", path); + if (g_file_test (path, G_FILE_TEST_EXISTS | G_FILE_TEST_IS_REGULAR)) + return g_steal_pointer (&path); + g_clear_pointer (&path, g_free); +#endif + + g_debug ("Did not find %s", girname); + return NULL; +} + +#define MISSING_ATTRIBUTE(context,error,element,attribute) \ + do { \ + int line_number, char_number; \ + g_markup_parse_context_get_position (context, &line_number, &char_number); \ + g_set_error (error, \ + G_MARKUP_ERROR, \ + G_MARKUP_ERROR_INVALID_CONTENT, \ + "Line %d, character %d: The attribute '%s' on the element '%s' must be specified", \ + line_number, char_number, attribute, element); \ + } while (0) + +static const gchar * +find_attribute (const gchar *name, + const gchar **attribute_names, + const gchar **attribute_values) +{ + gint i; + + for (i = 0; attribute_names[i] != NULL; i++) + if (strcmp (attribute_names[i], name) == 0) + return attribute_values[i]; + + return 0; +} + +static void +state_switch (ParseContext *ctx, ParseState newstate) +{ + g_assert (ctx->state != newstate); + ctx->prev_state = ctx->state; + ctx->state = newstate; + + if (ctx->state == STATE_PASSTHROUGH) + ctx->unknown_depth = 1; +} + +static GIIrNode * +pop_node (ParseContext *ctx) +{ + GSList *top; + GIIrNode *node; + g_assert (ctx->node_stack != 0); + + top = ctx->node_stack; + node = top->data; + + g_debug ("popping node %d %s", node->type, node->name); + ctx->node_stack = top->next; + g_slist_free_1 (top); + return node; +} + +static void +push_node (ParseContext *ctx, GIIrNode *node) +{ + g_assert (node != NULL); + g_debug ("pushing node %d %s", node->type, node->name); + ctx->node_stack = g_slist_prepend (ctx->node_stack, node); +} + +static GIIrNodeType * parse_type_internal (GIIrModule *module, + const gchar *str, gchar **next, gboolean in_glib, + gboolean in_gobject); + +typedef struct { + const gchar *str; + guint size; + guint is_signed : 1; +} IntegerAliasInfo; + +static IntegerAliasInfo integer_aliases[] = { + { "gchar", SIZEOF_CHAR, 1 }, + { "guchar", SIZEOF_CHAR, 0 }, + { "gshort", SIZEOF_SHORT, 1 }, + { "gushort", SIZEOF_SHORT, 0 }, + { "gint", SIZEOF_INT, 1 }, + { "guint", SIZEOF_INT, 0 }, + { "glong", SIZEOF_LONG, 1 }, + { "gulong", SIZEOF_LONG, 0 }, + { "gssize", GLIB_SIZEOF_SIZE_T, 1 }, + { "gsize", GLIB_SIZEOF_SIZE_T, 0 }, + { "gintptr", GLIB_SIZEOF_SIZE_T, 1 }, + { "guintptr", GLIB_SIZEOF_SIZE_T, 0 }, +}; + +typedef struct { + const gchar *str; + gint tag; + gboolean pointer; +} BasicTypeInfo; + +#define BASIC_TYPE_FIXED_OFFSET 3 + +static BasicTypeInfo basic_types[] = { + { "none", GI_TYPE_TAG_VOID, 0 }, + { "gpointer", GI_TYPE_TAG_VOID, 1 }, + + { "gboolean", GI_TYPE_TAG_BOOLEAN, 0 }, + { "gint8", GI_TYPE_TAG_INT8, 0 }, /* Start of BASIC_TYPE_FIXED_OFFSET */ + { "guint8", GI_TYPE_TAG_UINT8, 0 }, + { "gint16", GI_TYPE_TAG_INT16, 0 }, + { "guint16", GI_TYPE_TAG_UINT16, 0 }, + { "gint32", GI_TYPE_TAG_INT32, 0 }, + { "guint32", GI_TYPE_TAG_UINT32, 0 }, + { "gint64", GI_TYPE_TAG_INT64, 0 }, + { "guint64", GI_TYPE_TAG_UINT64, 0 }, + { "gfloat", GI_TYPE_TAG_FLOAT, 0 }, + { "gdouble", GI_TYPE_TAG_DOUBLE, 0 }, + { "GType", GI_TYPE_TAG_GTYPE, 0 }, + { "utf8", GI_TYPE_TAG_UTF8, 1 }, + { "filename", GI_TYPE_TAG_FILENAME,1 }, + { "gunichar", GI_TYPE_TAG_UNICHAR, 0 }, +}; + +static const BasicTypeInfo * +parse_basic (const char *str) +{ + guint i; + guint n_basic = G_N_ELEMENTS (basic_types); + + for (i = 0; i < n_basic; i++) + { + if (strcmp (str, basic_types[i].str) == 0) + return &(basic_types[i]); + } + for (i = 0; i < G_N_ELEMENTS (integer_aliases); i++) + { + if (strcmp (str, integer_aliases[i].str) == 0) + { + switch (integer_aliases[i].size) + { + case sizeof(guint8): + if (integer_aliases[i].is_signed) + return &basic_types[BASIC_TYPE_FIXED_OFFSET]; + else + return &basic_types[BASIC_TYPE_FIXED_OFFSET+1]; + break; + case sizeof(guint16): + if (integer_aliases[i].is_signed) + return &basic_types[BASIC_TYPE_FIXED_OFFSET+2]; + else + return &basic_types[BASIC_TYPE_FIXED_OFFSET+3]; + break; + case sizeof(guint32): + if (integer_aliases[i].is_signed) + return &basic_types[BASIC_TYPE_FIXED_OFFSET+4]; + else + return &basic_types[BASIC_TYPE_FIXED_OFFSET+5]; + break; + case sizeof(guint64): + if (integer_aliases[i].is_signed) + return &basic_types[BASIC_TYPE_FIXED_OFFSET+6]; + else + return &basic_types[BASIC_TYPE_FIXED_OFFSET+7]; + break; + default: + g_assert_not_reached (); + } + } + } + return NULL; +} + +static GIIrNodeType * +parse_type_internal (GIIrModule *module, + const gchar *str, + char **next, + gboolean in_glib, + gboolean in_gobject) +{ + const BasicTypeInfo *basic; + GIIrNodeType *type; + char *temporary_type = NULL; + + type = (GIIrNodeType *)gi_ir_node_new (GI_IR_NODE_TYPE, module); + + type->unparsed = g_strdup (str); + + /* See comment below on GLib.List handling */ + if (in_gobject && strcmp (str, "Type") == 0) + { + temporary_type = g_strdup ("GLib.Type"); + str = temporary_type; + } + + basic = parse_basic (str); + if (basic != NULL) + { + type->is_basic = TRUE; + type->tag = basic->tag; + type->is_pointer = basic->pointer; + + str += strlen(basic->str); + } + else if (in_glib) + { + /* If we're inside GLib, handle "List" etc. by prefixing with + * "GLib." so the parsing code below doesn't have to get more + * special. + */ + if (g_str_has_prefix (str, "List<") || + strcmp (str, "List") == 0) + { + temporary_type = g_strdup_printf ("GLib.List%s", str + 4); + str = temporary_type; + } + else if (g_str_has_prefix (str, "SList<") || + strcmp (str, "SList") == 0) + { + temporary_type = g_strdup_printf ("GLib.SList%s", str + 5); + str = temporary_type; + } + else if (g_str_has_prefix (str, "HashTable<") || + strcmp (str, "HashTable") == 0) + { + temporary_type = g_strdup_printf ("GLib.HashTable%s", str + 9); + str = temporary_type; + } + else if (g_str_has_prefix (str, "Error<") || + strcmp (str, "Error") == 0) + { + temporary_type = g_strdup_printf ("GLib.Error%s", str + 5); + str = temporary_type; + } + } + + if (basic != NULL) + /* found a basic type */; + else if (g_str_has_prefix (str, "GLib.List") || + g_str_has_prefix (str, "GLib.SList")) + { + str += strlen ("GLib."); + if (g_str_has_prefix (str, "List")) + { + type->tag = GI_TYPE_TAG_GLIST; + type->is_glist = TRUE; + type->is_pointer = TRUE; + str += strlen ("List"); + } + else + { + type->tag = GI_TYPE_TAG_GSLIST; + type->is_gslist = TRUE; + type->is_pointer = TRUE; + str += strlen ("SList"); + } + } + else if (g_str_has_prefix (str, "GLib.HashTable")) + { + str += strlen ("GLib."); + + type->tag = GI_TYPE_TAG_GHASH; + type->is_ghashtable = TRUE; + type->is_pointer = TRUE; + str += strlen ("HashTable"); + } + else if (g_str_has_prefix (str, "GLib.Error")) + { + str += strlen ("GLib."); + + type->tag = GI_TYPE_TAG_ERROR; + type->is_error = TRUE; + type->is_pointer = TRUE; + str += strlen ("Error"); + + if (*str == '<') + { + char *tmp, *end; + (str)++; + + end = strchr (str, '>'); + tmp = g_strndup (str, end - str); + type->errors = g_strsplit (tmp, ",", 0); + g_free (tmp); + + str = end; + } + } + else + { + const char *start; + type->tag = GI_TYPE_TAG_INTERFACE; + type->is_interface = TRUE; + start = str; + + /* must be an interface type */ + while (g_ascii_isalnum (*str) || + *str == '.' || + *str == '-' || + *str == '_' || + *str == ':') + (str)++; + + type->giinterface = g_strndup (start, str - start); + } + + if (next) + *next = (char*)str; + g_assert (type->tag >= 0 && type->tag < GI_TYPE_TAG_N_TYPES); + g_free (temporary_type); + return type; + +/* error: */ + gi_ir_node_free ((GIIrNode *)type); + g_free (temporary_type); + return NULL; +} + +static const char * +resolve_aliases (ParseContext *ctx, const gchar *type) +{ + gpointer orig; + gpointer value; + GSList *seen_values = NULL; + const gchar *lookup; + gchar *prefixed; + + if (strchr (type, '.') == NULL) + { + prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type); + lookup = prefixed; + } + else + { + lookup = type; + prefixed = NULL; + } + + seen_values = g_slist_prepend (seen_values, (char*)lookup); + while (g_hash_table_lookup_extended (ctx->current_module->aliases, lookup, &orig, &value)) + { + g_debug ("Resolved: %s => %s\n", lookup, (char*)value); + lookup = value; + if (g_slist_find_custom (seen_values, lookup, + (GCompareFunc)strcmp) != NULL) + break; + seen_values = g_slist_prepend (seen_values, (gchar*)lookup); + } + g_slist_free (seen_values); + + if (lookup == prefixed) + lookup = type; + + g_free (prefixed); + + return lookup; +} + +static void +is_pointer_or_disguised_structure (ParseContext *ctx, + const gchar *type, + gboolean *is_pointer, + gboolean *is_disguised) +{ + const gchar *lookup; + gchar *prefixed; + + if (strchr (type, '.') == NULL) + { + prefixed = g_strdup_printf ("%s.%s", ctx->namespace, type); + lookup = prefixed; + } + else + { + lookup = type; + prefixed = NULL; + } + + if (is_pointer != NULL) + *is_pointer = g_hash_table_lookup (ctx->current_module->pointer_structures, lookup) != NULL; + if (is_disguised != NULL) + *is_disguised = g_hash_table_lookup (ctx->current_module->disguised_structures, lookup) != NULL; + + g_free (prefixed); +} + +static GIIrNodeType * +parse_type (ParseContext *ctx, const gchar *type) +{ + GIIrNodeType *node; + const BasicTypeInfo *basic; + gboolean in_glib, in_gobject; + + in_glib = strcmp (ctx->namespace, "GLib") == 0; + in_gobject = strcmp (ctx->namespace, "GObject") == 0; + + /* Do not search aliases for basic types */ + basic = parse_basic (type); + if (basic == NULL) + type = resolve_aliases (ctx, type); + + node = parse_type_internal (ctx->current_module, type, NULL, in_glib, in_gobject); + if (node) + g_debug ("Parsed type: %s => %d", type, node->tag); + else + g_critical ("Failed to parse type: '%s'", type); + + return node; +} + +static gboolean +introspectable_prelude (GMarkupParseContext *context, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + ParseState new_state) +{ + const gchar *introspectable_arg; + const gchar *shadowed_by; + gboolean introspectable; + + g_assert (ctx->state != STATE_PASSTHROUGH); + + introspectable_arg = find_attribute ("introspectable", attribute_names, attribute_values); + shadowed_by = find_attribute ("shadowed-by", attribute_names, attribute_values); + + introspectable = !(introspectable_arg && atoi (introspectable_arg) == 0) && shadowed_by == NULL; + + if (introspectable) + state_switch (ctx, new_state); + else + state_switch (ctx, STATE_PASSTHROUGH); + + return introspectable; +} + +static gboolean +start_glib_boxed (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + GIIrNodeBoxed *boxed; + + if (!(strcmp (element_name, "glib:boxed") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_BOXED)) + return TRUE; + + name = find_attribute ("glib:name", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:name"); + return FALSE; + } + else if (typename == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + else if (typeinit == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } + + boxed = (GIIrNodeBoxed *) gi_ir_node_new (GI_IR_NODE_BOXED, + ctx->current_module); + + ((GIIrNode *)boxed)->name = g_strdup (name); + boxed->gtype_name = g_strdup (typename); + boxed->gtype_init = g_strdup (typeinit); + if (deprecated) + boxed->deprecated = TRUE; + else + boxed->deprecated = FALSE; + + push_node (ctx, (GIIrNode *)boxed); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, boxed); + + return TRUE; +} + +static gboolean +start_function (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *shadows; + const gchar *symbol; + const gchar *deprecated; + const gchar *throws; + const gchar *set_property; + const gchar *get_property; + GIIrNodeFunction *function; + gboolean found = FALSE; + ParseState in_embedded_state = STATE_NONE; + + switch (ctx->state) + { + case STATE_NAMESPACE: + found = (strcmp (element_name, "function") == 0 || + strcmp (element_name, "callback") == 0); + break; + case STATE_CLASS: + case STATE_BOXED: + case STATE_STRUCT: + case STATE_UNION: + found = strcmp (element_name, "constructor") == 0; + /* fallthrough */ + G_GNUC_FALLTHROUGH; + case STATE_INTERFACE: + found = (found || + strcmp (element_name, "function") == 0 || + strcmp (element_name, "method") == 0 || + strcmp (element_name, "callback") == 0); + break; + case STATE_ENUM: + found = strcmp (element_name, "function") == 0; + break; + case STATE_CLASS_FIELD: + case STATE_STRUCT_FIELD: + found = (found || strcmp (element_name, "callback") == 0); + in_embedded_state = ctx->state; + break; + default: + break; + } + + if (!found) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; + + ctx->in_embedded_state = in_embedded_state; + + name = find_attribute ("name", attribute_names, attribute_values); + shadows = find_attribute ("shadows", attribute_names, attribute_values); + symbol = find_attribute ("c:identifier", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + throws = find_attribute ("throws", attribute_names, attribute_values); + set_property = find_attribute ("glib:set-property", attribute_names, attribute_values); + get_property = find_attribute ("glib:get-property", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (strcmp (element_name, "callback") != 0 && symbol == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "c:identifier"); + return FALSE; + } + + if (shadows) + name = shadows; + + function = (GIIrNodeFunction *) gi_ir_node_new (GI_IR_NODE_FUNCTION, + ctx->current_module); + + ((GIIrNode *)function)->name = g_strdup (name); + function->symbol = g_strdup (symbol); + function->parameters = NULL; + if (deprecated) + function->deprecated = TRUE; + else + function->deprecated = FALSE; + + if (strcmp (element_name, "method") == 0 || + strcmp (element_name, "constructor") == 0) + { + function->is_method = TRUE; + + if (strcmp (element_name, "constructor") == 0) + function->is_constructor = TRUE; + else + function->is_constructor = FALSE; + + if (set_property != NULL) + { + function->is_setter = TRUE; + function->is_getter = FALSE; + function->property = g_strdup (set_property); + } + else if (get_property != NULL) + { + function->is_setter = FALSE; + function->is_getter = TRUE; + function->property = g_strdup (get_property); + } + else + { + function->is_setter = FALSE; + function->is_getter = FALSE; + function->property = NULL; + } + } + else + { + function->is_method = FALSE; + function->is_setter = FALSE; + function->is_getter = FALSE; + function->is_constructor = FALSE; + if (strcmp (element_name, "callback") == 0) + ((GIIrNode *)function)->type = GI_IR_NODE_CALLBACK; + } + + if (throws && strcmp (throws, "1") == 0) + function->throws = TRUE; + else + function->throws = FALSE; + + if (ctx->node_stack == NULL) + { + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, function); + } + else if (ctx->current_typed) + { + GIIrNodeField *field; + + field = (GIIrNodeField *)ctx->current_typed; + field->callback = function; + } + else + switch (CURRENT_NODE (ctx)->type) + { + case GI_IR_NODE_INTERFACE: + case GI_IR_NODE_OBJECT: + { + GIIrNodeInterface *iface; + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, function); + } + break; + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed; + + boxed = (GIIrNodeBoxed *)CURRENT_NODE (ctx); + boxed->members = g_list_append (boxed->members, function); + } + break; + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_; + + struct_ = (GIIrNodeStruct *)CURRENT_NODE (ctx); + struct_->members = g_list_append (struct_->members, function); } + break; + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_; + + union_ = (GIIrNodeUnion *)CURRENT_NODE (ctx); + union_->members = g_list_append (union_->members, function); + } + break; + case GI_IR_NODE_ENUM: + case GI_IR_NODE_FLAGS: + { + GIIrNodeEnum *enum_; + + enum_ = (GIIrNodeEnum *)CURRENT_NODE (ctx); + enum_->methods = g_list_append (enum_->methods, function); + } + break; + default: + g_assert_not_reached (); + } + + push_node(ctx, (GIIrNode *)function); + + return TRUE; +} + +static void +parse_property_transfer (GIIrNodeProperty *property, + const gchar *transfer, + ParseContext *ctx) +{ + if (transfer == NULL) + { +#if 0 + GIIrNodeInterface *iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + + g_debug ("required attribute 'transfer-ownership' is missing from " + "property '%s' in type '%s.%s'. Assuming 'none'\n", + property->node.name, ctx->namespace, iface->node.name); +#endif + transfer = "none"; + } + if (strcmp (transfer, "none") == 0) + { + property->transfer = FALSE; + property->shallow_transfer = FALSE; + } + else if (strcmp (transfer, "container") == 0) + { + property->transfer = FALSE; + property->shallow_transfer = TRUE; + } + else if (strcmp (transfer, "full") == 0) + { + property->transfer = TRUE; + property->shallow_transfer = FALSE; + } + else + { + GIIrNodeInterface *iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + + g_warning ("Unknown transfer-ownership value: '%s' for property '%s' in " + "type '%s.%s'", transfer, property->node.name, ctx->namespace, + iface->node.name); + } +} + +static gboolean +parse_param_transfer (GIIrNodeParam *param, const gchar *transfer, const gchar *name, + GError **error) +{ + if (transfer == NULL) + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "required attribute 'transfer-ownership' missing"); + return FALSE; + } + else if (strcmp (transfer, "none") == 0) + { + param->transfer = FALSE; + param->shallow_transfer = FALSE; + } + else if (strcmp (transfer, "container") == 0) + { + param->transfer = FALSE; + param->shallow_transfer = TRUE; + } + else if (strcmp (transfer, "full") == 0) + { + param->transfer = TRUE; + param->shallow_transfer = FALSE; + } + else + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "invalid value for 'transfer-ownership': %s", transfer); + return FALSE; + } + return TRUE; +} + +static gboolean +start_instance_parameter (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *transfer; + gboolean transfer_full; + + if (!(strcmp (element_name, "instance-parameter") == 0 && + ctx->state == STATE_FUNCTION_PARAMETERS)) + return FALSE; + + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + + state_switch (ctx, STATE_PASSTHROUGH); + + if (g_strcmp0 (transfer, "full") == 0) + transfer_full = TRUE; + else if (g_strcmp0 (transfer, "none") == 0) + transfer_full = FALSE; + else + { + g_set_error (error, G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "invalid value for 'transfer-ownership' for instance parameter: %s", transfer); + return FALSE; + } + + switch (CURRENT_NODE (ctx)->type) + { + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + { + GIIrNodeFunction *func; + + func = (GIIrNodeFunction *)CURRENT_NODE (ctx); + func->instance_transfer_full = transfer_full; + } + break; + case GI_IR_NODE_SIGNAL: + { + GIIrNodeSignal *signal; + + signal = (GIIrNodeSignal *)CURRENT_NODE (ctx); + signal->instance_transfer_full = transfer_full; + } + break; + case GI_IR_NODE_VFUNC: + { + GIIrNodeVFunc *vfunc; + + vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx); + vfunc->instance_transfer_full = transfer_full; + } + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +start_parameter (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *direction; + const gchar *retval; + const gchar *optional; + const gchar *caller_allocates; + const gchar *allow_none; + const gchar *transfer; + const gchar *scope; + const gchar *closure; + const gchar *destroy; + const gchar *skip; + const gchar *nullable; + GIIrNodeParam *param; + + if (!(strcmp (element_name, "parameter") == 0 && + ctx->state == STATE_FUNCTION_PARAMETERS)) + return FALSE; + + name = find_attribute ("name", attribute_names, attribute_values); + direction = find_attribute ("direction", attribute_names, attribute_values); + retval = find_attribute ("retval", attribute_names, attribute_values); + optional = find_attribute ("optional", attribute_names, attribute_values); + allow_none = find_attribute ("allow-none", attribute_names, attribute_values); + caller_allocates = find_attribute ("caller-allocates", attribute_names, attribute_values); + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + scope = find_attribute ("scope", attribute_names, attribute_values); + closure = find_attribute ("closure", attribute_names, attribute_values); + destroy = find_attribute ("destroy", attribute_names, attribute_values); + skip = find_attribute ("skip", attribute_names, attribute_values); + nullable = find_attribute ("nullable", attribute_names, attribute_values); + + if (name == NULL) + name = "unknown"; + + param = (GIIrNodeParam *)gi_ir_node_new (GI_IR_NODE_PARAM, + ctx->current_module); + + ctx->current_typed = (GIIrNode*) param; + ctx->current_typed->name = g_strdup (name); + + state_switch (ctx, STATE_FUNCTION_PARAMETER); + + if (direction && strcmp (direction, "out") == 0) + { + param->in = FALSE; + param->out = TRUE; + if (caller_allocates == NULL) + param->caller_allocates = FALSE; + else + param->caller_allocates = strcmp (caller_allocates, "1") == 0; + } + else if (direction && strcmp (direction, "inout") == 0) + { + param->in = TRUE; + param->out = TRUE; + param->caller_allocates = FALSE; + } + else + { + param->in = TRUE; + param->out = FALSE; + param->caller_allocates = FALSE; + } + + if (retval && strcmp (retval, "1") == 0) + param->retval = TRUE; + else + param->retval = FALSE; + + if (optional && strcmp (optional, "1") == 0) + param->optional = TRUE; + else + param->optional = FALSE; + + if (nullable && strcmp (nullable, "1") == 0) + param->nullable = TRUE; + else + param->nullable = FALSE; + + if (allow_none && strcmp (allow_none, "1") == 0) + { + if (param->out) + param->optional = TRUE; + else + param->nullable = TRUE; + } + + if (skip && strcmp (skip, "1") == 0) + param->skip = TRUE; + else + param->skip = FALSE; + + if (!parse_param_transfer (param, transfer, name, error)) + return FALSE; + + if (scope && strcmp (scope, "call") == 0) + param->scope = GI_SCOPE_TYPE_CALL; + else if (scope && strcmp (scope, "async") == 0) + param->scope = GI_SCOPE_TYPE_ASYNC; + else if (scope && strcmp (scope, "notified") == 0) + param->scope = GI_SCOPE_TYPE_NOTIFIED; + else if (scope && strcmp (scope, "forever") == 0) + param->scope = GI_SCOPE_TYPE_FOREVER; + else + param->scope = GI_SCOPE_TYPE_INVALID; + + param->closure = closure ? atoi (closure) : -1; + param->destroy = destroy ? atoi (destroy) : -1; + + ((GIIrNode *)param)->name = g_strdup (name); + + switch (CURRENT_NODE (ctx)->type) + { + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + { + GIIrNodeFunction *func; + + func = (GIIrNodeFunction *)CURRENT_NODE (ctx); + func->parameters = g_list_append (func->parameters, param); + } + break; + case GI_IR_NODE_SIGNAL: + { + GIIrNodeSignal *signal; + + signal = (GIIrNodeSignal *)CURRENT_NODE (ctx); + signal->parameters = g_list_append (signal->parameters, param); + } + break; + case GI_IR_NODE_VFUNC: + { + GIIrNodeVFunc *vfunc; + + vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx); + vfunc->parameters = g_list_append (vfunc->parameters, param); + } + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +start_field (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *readable; + const gchar *writable; + const gchar *bits; + const gchar *branch; + GIIrNodeField *field; + ParseState target_state; + gboolean introspectable; + + switch (ctx->state) + { + case STATE_CLASS: + target_state = STATE_CLASS_FIELD; + break; + case STATE_BOXED: + target_state = STATE_BOXED_FIELD; + break; + case STATE_STRUCT: + target_state = STATE_STRUCT_FIELD; + break; + case STATE_UNION: + target_state = STATE_UNION_FIELD; + break; + case STATE_INTERFACE: + target_state = STATE_INTERFACE_FIELD; + break; + default: + return FALSE; + } + + if (strcmp (element_name, "field") != 0) + return FALSE; + + g_assert (ctx->state != STATE_PASSTHROUGH); + + /* We handle introspectability specially here; we replace with just gpointer + * for the type. + */ + introspectable = introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state); + + name = find_attribute ("name", attribute_names, attribute_values); + readable = find_attribute ("readable", attribute_names, attribute_values); + writable = find_attribute ("writable", attribute_names, attribute_values); + bits = find_attribute ("bits", attribute_names, attribute_values); + branch = find_attribute ("branch", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + field = (GIIrNodeField *)gi_ir_node_new (GI_IR_NODE_FIELD, + ctx->current_module); + if (introspectable) + { + ctx->current_typed = (GIIrNode*) field; + } + else + { + field->type = parse_type (ctx, "gpointer"); + } + + ((GIIrNode *)field)->name = g_strdup (name); + /* Fields are assumed to be read-only. + * (see also girwriter.py and generate.c) + */ + field->readable = readable == NULL || strcmp (readable, "0") == 0; + field->writable = writable != NULL && strcmp (writable, "1") == 0; + + if (bits) + field->bits = atoi (bits); + else + field->bits = 0; + + switch (CURRENT_NODE (ctx)->type) + { + case GI_IR_NODE_OBJECT: + { + GIIrNodeInterface *iface; + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, field); + } + break; + case GI_IR_NODE_INTERFACE: + { + GIIrNodeInterface *iface; + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, field); + } + break; + case GI_IR_NODE_BOXED: + { + GIIrNodeBoxed *boxed; + + boxed = (GIIrNodeBoxed *)CURRENT_NODE (ctx); + boxed->members = g_list_append (boxed->members, field); + } + break; + case GI_IR_NODE_STRUCT: + { + GIIrNodeStruct *struct_; + + struct_ = (GIIrNodeStruct *)CURRENT_NODE (ctx); + struct_->members = g_list_append (struct_->members, field); + } + break; + case GI_IR_NODE_UNION: + { + GIIrNodeUnion *union_; + + union_ = (GIIrNodeUnion *)CURRENT_NODE (ctx); + union_->members = g_list_append (union_->members, field); + if (branch) + { + GIIrNodeConstant *constant; + + constant = (GIIrNodeConstant *) gi_ir_node_new (GI_IR_NODE_CONSTANT, + ctx->current_module); + ((GIIrNode *)constant)->name = g_strdup (name); + constant->value = g_strdup (branch); + constant->type = union_->discriminator_type; + constant->deprecated = FALSE; + + union_->discriminators = g_list_append (union_->discriminators, constant); + } + } + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +start_alias (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + + name = find_attribute ("name", attribute_names, attribute_values); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + ctx->current_alias = g_strdup (name); + state_switch (ctx, STATE_ALIAS); + + return TRUE; +} + +static gboolean +start_enum (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + const gchar *error_domain; + GIIrNodeEnum *enum_; + + if (!((strcmp (element_name, "enumeration") == 0 && ctx->state == STATE_NAMESPACE) || + (strcmp (element_name, "bitfield") == 0 && ctx->state == STATE_NAMESPACE))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_ENUM)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + error_domain = find_attribute ("glib:error-domain", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + if (strcmp (element_name, "enumeration") == 0) + enum_ = (GIIrNodeEnum *) gi_ir_node_new (GI_IR_NODE_ENUM, + ctx->current_module); + else + enum_ = (GIIrNodeEnum *) gi_ir_node_new (GI_IR_NODE_FLAGS, + ctx->current_module); + ((GIIrNode *)enum_)->name = g_strdup (name); + enum_->gtype_name = g_strdup (typename); + enum_->gtype_init = g_strdup (typeinit); + enum_->error_domain = g_strdup (error_domain); + + if (deprecated) + enum_->deprecated = TRUE; + else + enum_->deprecated = FALSE; + + push_node (ctx, (GIIrNode *) enum_); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, enum_); + + return TRUE; +} + +static gboolean +start_property (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + ParseState target_state; + const gchar *name; + const gchar *readable; + const gchar *writable; + const gchar *construct; + const gchar *construct_only; + const gchar *transfer; + const gchar *setter; + const gchar *getter; + GIIrNodeProperty *property; + GIIrNodeInterface *iface; + + if (!(strcmp (element_name, "property") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; + + if (ctx->state == STATE_CLASS) + target_state = STATE_CLASS_PROPERTY; + else if (ctx->state == STATE_INTERFACE) + target_state = STATE_INTERFACE_PROPERTY; + else + g_assert_not_reached (); + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state)) + return TRUE; + + + name = find_attribute ("name", attribute_names, attribute_values); + readable = find_attribute ("readable", attribute_names, attribute_values); + writable = find_attribute ("writable", attribute_names, attribute_values); + construct = find_attribute ("construct", attribute_names, attribute_values); + construct_only = find_attribute ("construct-only", attribute_names, attribute_values); + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + setter = find_attribute ("setter", attribute_names, attribute_values); + getter = find_attribute ("getter", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + property = (GIIrNodeProperty *) gi_ir_node_new (GI_IR_NODE_PROPERTY, + ctx->current_module); + ctx->current_typed = (GIIrNode*) property; + + ((GIIrNode *)property)->name = g_strdup (name); + + /* Assume properties are readable */ + if (readable == NULL || strcmp (readable, "1") == 0) + property->readable = TRUE; + else + property->readable = FALSE; + if (writable && strcmp (writable, "1") == 0) + property->writable = TRUE; + else + property->writable = FALSE; + if (construct && strcmp (construct, "1") == 0) + property->construct = TRUE; + else + property->construct = FALSE; + if (construct_only && strcmp (construct_only, "1") == 0) + property->construct_only = TRUE; + else + property->construct_only = FALSE; + + property->setter = g_strdup (setter); + property->getter = g_strdup (getter); + + parse_property_transfer (property, transfer, ctx); + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, property); + + return TRUE; +} + +static gint64 +parse_value (const gchar *str) +{ + gchar *shift_op; + + /* FIXME just a quick hack */ + shift_op = strstr (str, "<<"); + + if (shift_op) + { + gint64 base, shift; + + base = g_ascii_strtoll (str, NULL, 10); + shift = g_ascii_strtoll (shift_op + 3, NULL, 10); + + return base << shift; + } + else + return g_ascii_strtoll (str, NULL, 10); + + return 0; +} + +static gboolean +start_member (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *value; + const gchar *deprecated; + const gchar *c_identifier; + GIIrNodeEnum *enum_; + GIIrNodeValue *value_; + + if (!(strcmp (element_name, "member") == 0 && + ctx->state == STATE_ENUM)) + return FALSE; + + name = find_attribute ("name", attribute_names, attribute_values); + value = find_attribute ("value", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + c_identifier = find_attribute ("c:identifier", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + value_ = (GIIrNodeValue *) gi_ir_node_new (GI_IR_NODE_VALUE, + ctx->current_module); + + ((GIIrNode *)value_)->name = g_strdup (name); + + value_->value = parse_value (value); + + if (deprecated) + value_->deprecated = TRUE; + else + value_->deprecated = FALSE; + + g_hash_table_insert (((GIIrNode *)value_)->attributes, + g_strdup ("c:identifier"), + g_strdup (c_identifier)); + + enum_ = (GIIrNodeEnum *)CURRENT_NODE (ctx); + enum_->values = g_list_append (enum_->values, value_); + + return TRUE; +} + +static gboolean +start_constant (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + ParseState prev_state; + ParseState target_state; + const gchar *name; + const gchar *value; + const gchar *deprecated; + GIIrNodeConstant *constant; + + if (!(strcmp (element_name, "constant") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; + + switch (ctx->state) + { + case STATE_NAMESPACE: + target_state = STATE_NAMESPACE_CONSTANT; + break; + case STATE_CLASS: + target_state = STATE_CLASS_CONSTANT; + break; + case STATE_INTERFACE: + target_state = STATE_INTERFACE_CONSTANT; + break; + default: + g_assert_not_reached (); + } + + prev_state = ctx->state; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, target_state)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + value = find_attribute ("value", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (value == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "value"); + return FALSE; + } + + constant = (GIIrNodeConstant *) gi_ir_node_new (GI_IR_NODE_CONSTANT, + ctx->current_module); + + ((GIIrNode *)constant)->name = g_strdup (name); + constant->value = g_strdup (value); + + ctx->current_typed = (GIIrNode*) constant; + + if (deprecated) + constant->deprecated = TRUE; + else + constant->deprecated = FALSE; + + if (prev_state == STATE_NAMESPACE) + { + push_node (ctx, (GIIrNode *) constant); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, constant); + } + else + { + GIIrNodeInterface *iface; + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, constant); + } + + return TRUE; +} + +static gboolean +start_interface (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + const gchar *glib_type_struct; + GIIrNodeInterface *iface; + + if (!(strcmp (element_name, "interface") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_INTERFACE)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (typename == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + else if (typeinit == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } + + iface = (GIIrNodeInterface *) gi_ir_node_new (GI_IR_NODE_INTERFACE, + ctx->current_module); + ((GIIrNode *)iface)->name = g_strdup (name); + iface->gtype_name = g_strdup (typename); + iface->gtype_init = g_strdup (typeinit); + iface->glib_type_struct = g_strdup (glib_type_struct); + if (deprecated) + iface->deprecated = TRUE; + else + iface->deprecated = FALSE; + + push_node (ctx, (GIIrNode *) iface); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, iface); + + return TRUE; +} + +static gboolean +start_class (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *parent; + const gchar *glib_type_struct; + const gchar *typename; + const gchar *typeinit; + const gchar *deprecated; + const gchar *abstract; + const gchar *fundamental; + const gchar *final; + const gchar *ref_func; + const gchar *unref_func; + const gchar *set_value_func; + const gchar *get_value_func; + GIIrNodeInterface *iface; + + if (!(strcmp (element_name, "class") == 0 && + ctx->state == STATE_NAMESPACE)) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_CLASS)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + parent = find_attribute ("parent", attribute_names, attribute_values); + glib_type_struct = find_attribute ("glib:type-struct", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + abstract = find_attribute ("abstract", attribute_names, attribute_values); + final = find_attribute ("final", attribute_names, attribute_values); + fundamental = find_attribute ("glib:fundamental", attribute_names, attribute_values); + ref_func = find_attribute ("glib:ref-func", attribute_names, attribute_values); + unref_func = find_attribute ("glib:unref-func", attribute_names, attribute_values); + set_value_func = find_attribute ("glib:set-value-func", attribute_names, attribute_values); + get_value_func = find_attribute ("glib:get-value-func", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + else if (typename == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + else if (typeinit == NULL && strcmp (typename, "GObject")) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } + + iface = (GIIrNodeInterface *) gi_ir_node_new (GI_IR_NODE_OBJECT, + ctx->current_module); + ((GIIrNode *)iface)->name = g_strdup (name); + iface->gtype_name = g_strdup (typename); + iface->gtype_init = g_strdup (typeinit); + iface->parent = g_strdup (parent); + iface->glib_type_struct = g_strdup (glib_type_struct); + if (deprecated) + iface->deprecated = TRUE; + else + iface->deprecated = FALSE; + + iface->abstract = abstract && strcmp (abstract, "1") == 0; + iface->final_ = final && strcmp (final, "1") == 0; + + if (fundamental) + iface->fundamental = TRUE; + if (ref_func) + iface->ref_func = g_strdup (ref_func); + if (unref_func) + iface->unref_func = g_strdup (unref_func); + if (set_value_func) + iface->set_value_func = g_strdup (set_value_func); + if (get_value_func) + iface->get_value_func = g_strdup (get_value_func); + + push_node (ctx, (GIIrNode *) iface); + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, iface); + + return TRUE; +} + +static gboolean +start_type (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *ctype; + gboolean in_alias = FALSE; + gboolean is_array; + gboolean is_varargs; + GIIrNodeType *typenode; + + is_array = strcmp (element_name, "array") == 0; + is_varargs = strcmp (element_name, "varargs") == 0; + + if (!(is_array || is_varargs || (strcmp (element_name, "type") == 0))) + return FALSE; + + if (ctx->state == STATE_TYPE) + { + ctx->type_depth++; + ctx->type_stack = g_list_prepend (ctx->type_stack, ctx->type_parameters); + ctx->type_parameters = NULL; + } + else if (ctx->state == STATE_FUNCTION_PARAMETER || + ctx->state == STATE_FUNCTION_RETURN || + ctx->state == STATE_STRUCT_FIELD || + ctx->state == STATE_UNION_FIELD || + ctx->state == STATE_CLASS_PROPERTY || + ctx->state == STATE_CLASS_FIELD || + ctx->state == STATE_INTERFACE_FIELD || + ctx->state == STATE_INTERFACE_PROPERTY || + ctx->state == STATE_BOXED_FIELD || + ctx->state == STATE_NAMESPACE_CONSTANT || + ctx->state == STATE_CLASS_CONSTANT || + ctx->state == STATE_INTERFACE_CONSTANT || + ctx->state == STATE_ALIAS + ) + { + if (ctx->state == STATE_ALIAS) + in_alias = TRUE; + state_switch (ctx, STATE_TYPE); + ctx->type_depth = 1; + ctx->type_stack = NULL; + ctx->type_parameters = NULL; + } + + name = find_attribute ("name", attribute_names, attribute_values); + + if (in_alias && ctx->current_alias) + { + char *key; + char *value; + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + key = g_strdup_printf ("%s.%s", ctx->namespace, ctx->current_alias); + if (!strchr (name, '.')) + { + const BasicTypeInfo *basic = parse_basic (name); + if (!basic) + { + /* For non-basic types, re-qualify the interface */ + value = g_strdup_printf ("%s.%s", ctx->namespace, name); + } + else + { + value = g_strdup (name); + } + } + else + value = g_strdup (name); + + g_hash_table_replace (ctx->aliases, key, value); + + return TRUE; + } + else if (!ctx->current_module || in_alias) + return TRUE; + + if (!ctx->current_typed) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "The element is invalid here"); + return FALSE; + } + + if (is_varargs) + return TRUE; + + if (is_array) + { + const char *zero; + const char *len; + const char *size; + + typenode = (GIIrNodeType *)gi_ir_node_new (GI_IR_NODE_TYPE, + ctx->current_module); + + typenode->tag = GI_TYPE_TAG_ARRAY; + typenode->is_pointer = TRUE; + typenode->is_array = TRUE; + + if (name && strcmp (name, "GLib.Array") == 0) { + typenode->array_type = GI_ARRAY_TYPE_ARRAY; + } else if (name && strcmp (name, "GLib.ByteArray") == 0) { + typenode->array_type = GI_ARRAY_TYPE_BYTE_ARRAY; + } else if (name && strcmp (name, "GLib.PtrArray") == 0) { + typenode->array_type = GI_ARRAY_TYPE_PTR_ARRAY; + } else { + typenode->array_type = GI_ARRAY_TYPE_C; + } + + if (typenode->array_type == GI_ARRAY_TYPE_C) { + zero = find_attribute ("zero-terminated", attribute_names, attribute_values); + len = find_attribute ("length", attribute_names, attribute_values); + size = find_attribute ("fixed-size", attribute_names, attribute_values); + + typenode->has_length = len != NULL; + typenode->length = typenode->has_length ? atoi (len) : -1; + + typenode->has_size = size != NULL; + typenode->size = typenode->has_size ? atoi (size) : -1; + + if (zero) + typenode->zero_terminated = strcmp(zero, "1") == 0; + else + /* If neither zero-terminated nor length nor fixed-size is given, assume zero-terminated. */ + typenode->zero_terminated = !(typenode->has_length || typenode->has_size); + + if (typenode->has_size && ctx->current_typed->type == GI_IR_NODE_FIELD) + typenode->is_pointer = FALSE; + } else { + typenode->zero_terminated = FALSE; + typenode->has_length = FALSE; + typenode->length = -1; + typenode->has_size = FALSE; + typenode->size = -1; + } + } + else + { + int pointer_depth; + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + pointer_depth = 0; + ctype = find_attribute ("c:type", attribute_names, attribute_values); + if (ctype != NULL) + { + const char *cp = ctype + strlen(ctype) - 1; + while (cp > ctype && *cp-- == '*') + pointer_depth++; + + if (g_str_has_prefix (ctype, "gpointer") + || g_str_has_prefix (ctype, "gconstpointer")) + pointer_depth++; + } + + if (ctx->current_typed->type == GI_IR_NODE_PARAM && + ((GIIrNodeParam *)ctx->current_typed)->out && + pointer_depth > 0) + pointer_depth--; + + typenode = parse_type (ctx, name); + + /* A "pointer" structure is one where the c:type is a typedef that + * to a pointer to a structure; we used to call them "disguised" + * structures as well. + */ + if (typenode->tag == GI_TYPE_TAG_INTERFACE) + { + gboolean is_pointer = FALSE; + gboolean is_disguised = FALSE; + + is_pointer_or_disguised_structure (ctx, typenode->giinterface, + &is_pointer, + &is_disguised); + + if (is_pointer || is_disguised) + pointer_depth++; + } + + if (pointer_depth > 0) + typenode->is_pointer = TRUE; + } + + ctx->type_parameters = g_list_append (ctx->type_parameters, typenode); + + return TRUE; +} + +static void +end_type_top (ParseContext *ctx) +{ + GIIrNodeType *typenode; + + if (!ctx->type_parameters) + goto out; + + typenode = (GIIrNodeType*)ctx->type_parameters->data; + + /* Default to pointer for unspecified containers */ + if (typenode->tag == GI_TYPE_TAG_ARRAY || + typenode->tag == GI_TYPE_TAG_GLIST || + typenode->tag == GI_TYPE_TAG_GSLIST) + { + if (typenode->parameter_type1 == NULL) + typenode->parameter_type1 = parse_type (ctx, "gpointer"); + } + else if (typenode->tag == GI_TYPE_TAG_GHASH) + { + if (typenode->parameter_type1 == NULL) + { + typenode->parameter_type1 = parse_type (ctx, "gpointer"); + typenode->parameter_type2 = parse_type (ctx, "gpointer"); + } + } + + switch (ctx->current_typed->type) + { + case GI_IR_NODE_PARAM: + { + GIIrNodeParam *param = (GIIrNodeParam *)ctx->current_typed; + param->type = typenode; + } + break; + case GI_IR_NODE_FIELD: + { + GIIrNodeField *field = (GIIrNodeField *)ctx->current_typed; + field->type = typenode; + } + break; + case GI_IR_NODE_PROPERTY: + { + GIIrNodeProperty *property = (GIIrNodeProperty *) ctx->current_typed; + property->type = typenode; + } + break; + case GI_IR_NODE_CONSTANT: + { + GIIrNodeConstant *constant = (GIIrNodeConstant *)ctx->current_typed; + constant->type = typenode; + } + break; + default: + g_printerr("current node is %d\n", CURRENT_NODE (ctx)->type); + g_assert_not_reached (); + } + g_list_free (ctx->type_parameters); + + out: + ctx->type_depth = 0; + ctx->type_parameters = NULL; + ctx->current_typed = NULL; +} + +static void +end_type_recurse (ParseContext *ctx) +{ + GIIrNodeType *parent; + GIIrNodeType *param = NULL; + + parent = (GIIrNodeType *) ((GList*)ctx->type_stack->data)->data; + if (ctx->type_parameters) + param = (GIIrNodeType *) ctx->type_parameters->data; + + if (parent->tag == GI_TYPE_TAG_ARRAY || + parent->tag == GI_TYPE_TAG_GLIST || + parent->tag == GI_TYPE_TAG_GSLIST) + { + g_assert (param != NULL); + + if (parent->parameter_type1 == NULL) + parent->parameter_type1 = param; + else + g_assert_not_reached (); + } + else if (parent->tag == GI_TYPE_TAG_GHASH) + { + g_assert (param != NULL); + + if (parent->parameter_type1 == NULL) + parent->parameter_type1 = param; + else if (parent->parameter_type2 == NULL) + parent->parameter_type2 = param; + else + g_assert_not_reached (); + } + g_list_free (ctx->type_parameters); + ctx->type_parameters = (GList *)ctx->type_stack->data; + ctx->type_stack = g_list_delete_link (ctx->type_stack, ctx->type_stack); +} + +static void +end_type (ParseContext *ctx) +{ + if (ctx->type_depth == 1) + { + end_type_top (ctx); + state_switch (ctx, ctx->prev_state); + } + else + { + end_type_recurse (ctx); + ctx->type_depth--; + } +} + +static gboolean +start_attribute (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *value; + GIIrNode *curnode; + + if (strcmp (element_name, "attribute") != 0 || ctx->node_stack == NULL) + return FALSE; + + name = find_attribute ("name", attribute_names, attribute_values); + value = find_attribute ("value", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + if (value == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "value"); + return FALSE; + } + + state_switch (ctx, STATE_ATTRIBUTE); + + curnode = CURRENT_NODE (ctx); + + if (ctx->current_typed && ctx->current_typed->type == GI_IR_NODE_PARAM) + { + g_hash_table_insert (ctx->current_typed->attributes, g_strdup (name), g_strdup (value)); + } + else + { + g_hash_table_insert (curnode->attributes, g_strdup (name), g_strdup (value)); + } + + return TRUE; +} + +static gboolean +start_return_value (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + GIIrNodeParam *param; + const gchar *transfer; + const gchar *skip; + const gchar *nullable; + + if (!(strcmp (element_name, "return-value") == 0 && + ctx->state == STATE_FUNCTION)) + return FALSE; + + param = (GIIrNodeParam *)gi_ir_node_new (GI_IR_NODE_PARAM, + ctx->current_module); + param->in = FALSE; + param->out = FALSE; + param->retval = TRUE; + + ctx->current_typed = (GIIrNode*) param; + + state_switch (ctx, STATE_FUNCTION_RETURN); + + skip = find_attribute ("skip", attribute_names, attribute_values); + if (skip && strcmp (skip, "1") == 0) + param->skip = TRUE; + else + param->skip = FALSE; + + transfer = find_attribute ("transfer-ownership", attribute_names, attribute_values); + if (!parse_param_transfer (param, transfer, NULL, error)) + return FALSE; + + nullable = find_attribute ("nullable", attribute_names, attribute_values); + if (nullable && g_str_equal (nullable, "1")) + param->nullable = TRUE; + + switch (CURRENT_NODE (ctx)->type) + { + case GI_IR_NODE_FUNCTION: + case GI_IR_NODE_CALLBACK: + { + GIIrNodeFunction *func = (GIIrNodeFunction *)CURRENT_NODE (ctx); + func->result = param; + } + break; + case GI_IR_NODE_SIGNAL: + { + GIIrNodeSignal *signal = (GIIrNodeSignal *)CURRENT_NODE (ctx); + signal->result = param; + } + break; + case GI_IR_NODE_VFUNC: + { + GIIrNodeVFunc *vfunc = (GIIrNodeVFunc *)CURRENT_NODE (ctx); + vfunc->result = param; + } + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +static gboolean +start_implements (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + GIIrNodeInterface *iface; + const char *name; + + if (strcmp (element_name, "implements") != 0 || + !(ctx->state == STATE_CLASS)) + return FALSE; + + state_switch (ctx, STATE_IMPLEMENTS); + + name = find_attribute ("name", attribute_names, attribute_values); + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->interfaces = g_list_append (iface->interfaces, g_strdup (name)); + + return TRUE; +} + +static gboolean +start_glib_signal (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *when; + const gchar *no_recurse; + const gchar *detailed; + const gchar *action; + const gchar *no_hooks; + const gchar *has_class_closure; + GIIrNodeInterface *iface; + GIIrNodeSignal *signal; + + if (!(strcmp (element_name, "glib:signal") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + when = find_attribute ("when", attribute_names, attribute_values); + no_recurse = find_attribute ("no-recurse", attribute_names, attribute_values); + detailed = find_attribute ("detailed", attribute_names, attribute_values); + action = find_attribute ("action", attribute_names, attribute_values); + no_hooks = find_attribute ("no-hooks", attribute_names, attribute_values); + has_class_closure = find_attribute ("has-class-closure", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + signal = (GIIrNodeSignal *)gi_ir_node_new (GI_IR_NODE_SIGNAL, + ctx->current_module); + + ((GIIrNode *)signal)->name = g_strdup (name); + + signal->run_first = FALSE; + signal->run_last = FALSE; + signal->run_cleanup = FALSE; + if (when == NULL || g_ascii_strcasecmp (when, "LAST") == 0) + signal->run_last = TRUE; + else if (g_ascii_strcasecmp (when, "FIRST") == 0) + signal->run_first = TRUE; + else + signal->run_cleanup = TRUE; + + if (no_recurse && strcmp (no_recurse, "1") == 0) + signal->no_recurse = TRUE; + else + signal->no_recurse = FALSE; + if (detailed && strcmp (detailed, "1") == 0) + signal->detailed = TRUE; + else + signal->detailed = FALSE; + if (action && strcmp (action, "1") == 0) + signal->action = TRUE; + else + signal->action = FALSE; + if (no_hooks && strcmp (no_hooks, "1") == 0) + signal->no_hooks = TRUE; + else + signal->no_hooks = FALSE; + if (has_class_closure && strcmp (has_class_closure, "1") == 0) + signal->has_class_closure = TRUE; + else + signal->has_class_closure = FALSE; + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, signal); + + push_node (ctx, (GIIrNode *)signal); + + return TRUE; +} + +static gboolean +start_vfunc (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *must_chain_up; + const gchar *override; + const gchar *is_class_closure; + const gchar *offset; + const gchar *invoker; + const gchar *throws; + GIIrNodeInterface *iface; + GIIrNodeVFunc *vfunc; + + if (!(strcmp (element_name, "virtual-method") == 0 && + (ctx->state == STATE_CLASS || + ctx->state == STATE_INTERFACE))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_FUNCTION)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + must_chain_up = find_attribute ("must-chain-up", attribute_names, attribute_values); + override = find_attribute ("override", attribute_names, attribute_values); + is_class_closure = find_attribute ("is-class-closure", attribute_names, attribute_values); + offset = find_attribute ("offset", attribute_names, attribute_values); + invoker = find_attribute ("invoker", attribute_names, attribute_values); + throws = find_attribute ("throws", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + vfunc = (GIIrNodeVFunc *)gi_ir_node_new (GI_IR_NODE_VFUNC, + ctx->current_module); + + ((GIIrNode *)vfunc)->name = g_strdup (name); + + if (must_chain_up && strcmp (must_chain_up, "1") == 0) + vfunc->must_chain_up = TRUE; + else + vfunc->must_chain_up = FALSE; + + if (override && strcmp (override, "always") == 0) + { + vfunc->must_be_implemented = TRUE; + vfunc->must_not_be_implemented = FALSE; + } + else if (override && strcmp (override, "never") == 0) + { + vfunc->must_be_implemented = FALSE; + vfunc->must_not_be_implemented = TRUE; + } + else + { + vfunc->must_be_implemented = FALSE; + vfunc->must_not_be_implemented = FALSE; + } + + if (is_class_closure && strcmp (is_class_closure, "1") == 0) + vfunc->is_class_closure = TRUE; + else + vfunc->is_class_closure = FALSE; + + if (throws && strcmp (throws, "1") == 0) + vfunc->throws = TRUE; + else + vfunc->throws = FALSE; + + if (offset) + vfunc->offset = atoi (offset); + else + vfunc->offset = 0xFFFF; + + vfunc->invoker = g_strdup (invoker); + + iface = (GIIrNodeInterface *)CURRENT_NODE (ctx); + iface->members = g_list_append (iface->members, vfunc); + + push_node (ctx, (GIIrNode *)vfunc); + + return TRUE; +} + +static gboolean +start_struct (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *deprecated; + const gchar *disguised; + const gchar *opaque; + const gchar *pointer; + const gchar *gtype_name; + const gchar *gtype_init; + const gchar *gtype_struct; + const gchar *foreign; + const gchar *copy_func; + const gchar *free_func; + GIIrNodeStruct *struct_; + + if (!(strcmp (element_name, "record") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_UNION || + ctx->state == STATE_STRUCT || + ctx->state == STATE_CLASS))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_STRUCT)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + disguised = find_attribute ("disguised", attribute_names, attribute_values); + pointer = find_attribute ("pointer", attribute_names, attribute_values); + opaque = find_attribute ("opaque", attribute_names, attribute_values); + gtype_name = find_attribute ("glib:type-name", attribute_names, attribute_values); + gtype_init = find_attribute ("glib:get-type", attribute_names, attribute_values); + gtype_struct = find_attribute ("glib:is-gtype-struct-for", attribute_names, attribute_values); + foreign = find_attribute ("foreign", attribute_names, attribute_values); + copy_func = find_attribute ("copy-function", attribute_names, attribute_values); + free_func = find_attribute ("free-function", attribute_names, attribute_values); + + if (name == NULL && ctx->node_stack == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + if ((gtype_name == NULL && gtype_init != NULL)) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:type-name"); + return FALSE; + } + if ((gtype_name != NULL && gtype_init == NULL)) + { + MISSING_ATTRIBUTE (context, error, element_name, "glib:get-type"); + return FALSE; + } + + struct_ = (GIIrNodeStruct *) gi_ir_node_new (GI_IR_NODE_STRUCT, + ctx->current_module); + + ((GIIrNode *)struct_)->name = g_strdup (name ? name : ""); + if (deprecated) + struct_->deprecated = TRUE; + else + struct_->deprecated = FALSE; + + if (g_strcmp0 (disguised, "1") == 0) + struct_->disguised = TRUE; + + if (g_strcmp0 (pointer, "1") == 0) + struct_->pointer = TRUE; + + if (g_strcmp0 (opaque, "1") == 0) + struct_->opaque = TRUE; + + struct_->is_gtype_struct = gtype_struct != NULL; + + struct_->gtype_name = g_strdup (gtype_name); + struct_->gtype_init = g_strdup (gtype_init); + + struct_->foreign = (g_strcmp0 (foreign, "1") == 0); + + struct_->copy_func = g_strdup (copy_func); + struct_->free_func = g_strdup (free_func); + + if (ctx->node_stack == NULL) + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, struct_); + push_node (ctx, (GIIrNode *)struct_); + return TRUE; +} + +static gboolean +start_union (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *name; + const gchar *deprecated; + const gchar *typename; + const gchar *typeinit; + const gchar *copy_func; + const gchar *free_func; + GIIrNodeUnion *union_; + + if (!(strcmp (element_name, "union") == 0 && + (ctx->state == STATE_NAMESPACE || + ctx->state == STATE_UNION || + ctx->state == STATE_STRUCT || + ctx->state == STATE_CLASS))) + return FALSE; + + if (!introspectable_prelude (context, attribute_names, attribute_values, ctx, STATE_UNION)) + return TRUE; + + name = find_attribute ("name", attribute_names, attribute_values); + deprecated = find_attribute ("deprecated", attribute_names, attribute_values); + typename = find_attribute ("glib:type-name", attribute_names, attribute_values); + typeinit = find_attribute ("glib:get-type", attribute_names, attribute_values); + copy_func = find_attribute ("copy-function", attribute_names, attribute_values); + free_func = find_attribute ("free-function", attribute_names, attribute_values); + + if (name == NULL && ctx->node_stack == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + return FALSE; + } + + union_ = (GIIrNodeUnion *) gi_ir_node_new (GI_IR_NODE_UNION, + ctx->current_module); + + ((GIIrNode *)union_)->name = g_strdup (name ? name : ""); + union_->gtype_name = g_strdup (typename); + union_->gtype_init = g_strdup (typeinit); + union_->copy_func = g_strdup (copy_func); + union_->free_func = g_strdup (free_func); + if (deprecated) + union_->deprecated = TRUE; + else + union_->deprecated = FALSE; + + if (ctx->node_stack == NULL) + ctx->current_module->entries = + g_list_append (ctx->current_module->entries, union_); + push_node (ctx, (GIIrNode *)union_); + return TRUE; +} + +static gboolean +start_discriminator (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + ParseContext *ctx, + GError **error) +{ + const gchar *type; + const gchar *offset; + if (!(strcmp (element_name, "discriminator") == 0 && + ctx->state == STATE_UNION)) + return FALSE; + + type = find_attribute ("type", attribute_names, attribute_values); + offset = find_attribute ("offset", attribute_names, attribute_values); + if (type == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "type"); + return FALSE; + } + else if (offset == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "offset"); + return FALSE; + } + + ((GIIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_type + = parse_type (ctx, type); + ((GIIrNodeUnion *)CURRENT_NODE (ctx))->discriminator_offset + = atoi (offset); + + return TRUE; +} + +static gboolean +parse_include (GMarkupParseContext *context, + ParseContext *ctx, + const char *name, + const char *version) +{ + GError *error = NULL; + gchar *buffer; + gsize length; + gchar *girpath, *girname; + GIIrModule *module; + GList *l; + + for (l = ctx->parser->parsed_modules; l; l = l->next) + { + GIIrModule *m = l->data; + + if (strcmp (m->name, name) == 0) + { + if (strcmp (m->version, version) == 0) + { + ctx->include_modules = g_list_prepend (ctx->include_modules, m); + + return TRUE; + } + else + { + g_printerr ("Module '%s' imported with conflicting versions '%s' and '%s'\n", + name, m->version, version); + return FALSE; + } + } + } + + girname = g_strdup_printf ("%s-%s.gir", name, version); + girpath = locate_gir (ctx->parser, girname); + + if (girpath == NULL) + { + g_printerr ("Could not find GIR file '%s'; check XDG_DATA_DIRS or use --includedir\n", + girname); + g_free (girname); + return FALSE; + } + g_free (girname); + + g_debug ("Parsing include %s\n", girpath); + + if (!g_file_get_contents (girpath, &buffer, &length, &error)) + { + g_printerr ("%s: %s\n", girpath, error->message); + g_clear_error (&error); + g_free (girpath); + return FALSE; + } + + module = gi_ir_parser_parse_string (ctx->parser, name, girpath, buffer, length, &error); + g_free (buffer); + if (error != NULL) + { + int line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + g_printerr ("%s:%d:%d: error: %s\n", girpath, line_number, char_number, error->message); + g_clear_error (&error); + g_free (girpath); + return FALSE; + } + g_free (girpath); + + ctx->include_modules = g_list_append (ctx->include_modules, + module); + + return TRUE; +} + +extern GLogLevelFlags logged_levels; + +static void +start_element_handler (GMarkupParseContext *context, + const gchar *element_name, + const gchar **attribute_names, + const gchar **attribute_values, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + + if (logged_levels & G_LOG_LEVEL_DEBUG) + { + GString *tags = g_string_new (""); + int i; + for (i = 0; attribute_names[i]; i++) + g_string_append_printf (tags, "%s=\"%s\" ", + attribute_names[i], + attribute_values[i]); + + if (i) + { + g_string_insert_c (tags, 0, ' '); + g_string_truncate (tags, tags->len - 1); + } + g_debug ("<%s%s>", element_name, tags->str); + g_string_free (tags, TRUE); + } + + if (ctx->state == STATE_PASSTHROUGH) + { + ctx->unknown_depth += 1; + return; + } + + switch (element_name[0]) + { + case 'a': + if (ctx->state == STATE_NAMESPACE && strcmp (element_name, "alias") == 0) + { + state_switch (ctx, STATE_ALIAS); + goto out; + } + if (start_type (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_attribute (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + case 'b': + if (start_enum (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + case 'c': + if (start_function (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_constant (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_class (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'd': + if (start_discriminator (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + if (strcmp ("doc", element_name) == 0 || strcmp ("doc-deprecated", element_name) == 0 || + strcmp ("doc-stability", element_name) == 0 || strcmp ("doc-version", element_name) == 0 || + strcmp ("docsection", element_name) == 0) + { + state_switch (ctx, STATE_PASSTHROUGH); + goto out; + } + break; + + case 'e': + if (start_enum (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'f': + if (strcmp ("function-macro", element_name) == 0) + { + state_switch (ctx, STATE_PASSTHROUGH); + goto out; + } + else if (start_function (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_field (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'g': + if (start_glib_boxed (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_glib_signal (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'i': + if (strcmp (element_name, "include") == 0 && + ctx->state == STATE_REPOSITORY) + { + const gchar *name; + const gchar *version; + + name = find_attribute ("name", attribute_names, attribute_values); + version = find_attribute ("version", attribute_names, attribute_values); + + if (name == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "name"); + break; + } + if (version == NULL) + { + MISSING_ATTRIBUTE (context, error, element_name, "version"); + break; + } + + if (!parse_include (context, ctx, name, version)) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Failed to parse included gir %s-%s", + name, + version); + return; + } + + ctx->dependencies = g_list_prepend (ctx->dependencies, + g_strdup_printf ("%s-%s", name, version)); + + + state_switch (ctx, STATE_INCLUDE); + goto out; + } + if (start_interface (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_implements (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_instance_parameter (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (strcmp (element_name, "c:include") == 0) + { + state_switch (ctx, STATE_C_INCLUDE); + goto out; + } + break; + + case 'm': + if (start_function (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_member (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'n': + if (strcmp (element_name, "namespace") == 0 && ctx->state == STATE_REPOSITORY) + { + const gchar *name, *version, *shared_library, *cprefix; + + if (ctx->current_module != NULL) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Only one element is currently allowed per "); + goto out; + } + + name = find_attribute ("name", attribute_names, attribute_values); + version = find_attribute ("version", attribute_names, attribute_values); + shared_library = find_attribute ("shared-library", attribute_names, attribute_values); + cprefix = find_attribute ("c:identifier-prefixes", attribute_names, attribute_values); + /* Backwards compatibility; vala currently still generates this */ + if (cprefix == NULL) + cprefix = find_attribute ("c:prefix", attribute_names, attribute_values); + + if (name == NULL) + MISSING_ATTRIBUTE (context, error, element_name, "name"); + else if (version == NULL) + MISSING_ATTRIBUTE (context, error, element_name, "version"); + else + { + GList *l; + + if (strcmp (name, ctx->namespace) != 0) + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + " name element '%s' doesn't match file name '%s'", + name, ctx->namespace); + + ctx->current_module = gi_ir_module_new (name, version, shared_library, cprefix); + + ctx->current_module->aliases = ctx->aliases; + ctx->aliases = NULL; + ctx->current_module->disguised_structures = ctx->disguised_structures; + ctx->current_module->pointer_structures = ctx->pointer_structures; + ctx->disguised_structures = NULL; + ctx->pointer_structures = NULL; + + for (l = ctx->include_modules; l; l = l->next) + gi_ir_module_add_include_module (ctx->current_module, l->data); + + g_list_free (ctx->include_modules); + ctx->include_modules = NULL; + + ctx->modules = g_list_append (ctx->modules, ctx->current_module); + ctx->current_module->dependencies = ctx->dependencies; + + state_switch (ctx, STATE_NAMESPACE); + goto out; + } + } + break; + + case 'p': + if (start_property (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (strcmp (element_name, "parameters") == 0 && + ctx->state == STATE_FUNCTION) + { + state_switch (ctx, STATE_FUNCTION_PARAMETERS); + + goto out; + } + else if (start_parameter (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (strcmp (element_name, "prerequisite") == 0 && + ctx->state == STATE_INTERFACE) + { + const gchar *name; + + name = find_attribute ("name", attribute_names, attribute_values); + + state_switch (ctx, STATE_PREREQUISITE); + + if (name == NULL) + MISSING_ATTRIBUTE (context, error, element_name, "name"); + else + { + GIIrNodeInterface *iface; + + iface = (GIIrNodeInterface *)CURRENT_NODE(ctx); + iface->prerequisites = g_list_append (iface->prerequisites, g_strdup (name)); + } + goto out; + } + else if (strcmp (element_name, "package") == 0 && + ctx->state == STATE_REPOSITORY) + { + state_switch (ctx, STATE_PACKAGE); + goto out; + } + break; + + case 'r': + if (strcmp (element_name, "repository") == 0 && ctx->state == STATE_START) + { + const gchar *version; + + version = find_attribute ("version", attribute_names, attribute_values); + + if (version == NULL) + MISSING_ATTRIBUTE (context, error, element_name, "version"); + else if (strcmp (version, SUPPORTED_GIR_VERSION) != 0) + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Unsupported version '%s'", + version); + else + state_switch (ctx, STATE_REPOSITORY); + + goto out; + } + else if (start_return_value (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + else if (start_struct (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 's': + if (strcmp ("source-position", element_name) == 0) + { + state_switch (ctx, STATE_PASSTHROUGH); + goto out; + } + break; + case 'u': + if (start_union (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 't': + if (start_type (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + + case 'v': + if (start_vfunc (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + if (start_type (context, element_name, + attribute_names, attribute_values, + ctx, error)) + goto out; + break; + default: + break; + } + + if (*error == NULL && ctx->state != STATE_PASSTHROUGH) + { + gint line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + if (!g_str_has_prefix (element_name, "c:")) + g_printerr ("%s:%d:%d: warning: element %s from state %d is unknown, ignoring\n", + ctx->file_path, line_number, char_number, element_name, + ctx->state); + state_switch (ctx, STATE_PASSTHROUGH); + } + + out: + if (*error) + { + gint line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + + g_printerr ("%s:%d:%d: error: %s\n", ctx->file_path, line_number, char_number, (*error)->message); + } +} + +static gboolean +require_one_of_end_elements (GMarkupParseContext *context, + ParseContext *ctx, + const char *actual_name, + GError **error, + ...) +{ + va_list args; + int line_number, char_number; + const char *expected; + gboolean matched = FALSE; + + va_start (args, error); + + while ((expected = va_arg (args, const char*)) != NULL) + { + if (strcmp (expected, actual_name) == 0) + { + matched = TRUE; + break; + } + } + + va_end (args); + + if (matched) + return TRUE; + + g_markup_parse_context_get_position (context, &line_number, &char_number); + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Unexpected end tag '%s' on line %d char %d; current state=%d (prev=%d)", + actual_name, + line_number, char_number, ctx->state, ctx->prev_state); + return FALSE; +} + +static gboolean +state_switch_end_struct_or_union (GMarkupParseContext *context, + ParseContext *ctx, + const gchar *element_name, + GError **error) +{ + pop_node (ctx); + if (ctx->node_stack == NULL) + { + state_switch (ctx, STATE_NAMESPACE); + } + else + { + if (CURRENT_NODE (ctx)->type == GI_IR_NODE_STRUCT) + state_switch (ctx, STATE_STRUCT); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_UNION) + state_switch (ctx, STATE_UNION); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_OBJECT) + state_switch (ctx, STATE_CLASS); + else + { + int line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Unexpected end tag '%s' on line %d char %d", + element_name, + line_number, char_number); + return FALSE; + } + } + return TRUE; +} + +static gboolean +require_end_element (GMarkupParseContext *context, + ParseContext *ctx, + const char *expected_name, + const char *actual_name, + GError **error) +{ + return require_one_of_end_elements (context, ctx, actual_name, error, expected_name, NULL); +} + +static void +end_element_handler (GMarkupParseContext *context, + const gchar *element_name, + gpointer user_data, + GError **error) +{ + ParseContext *ctx = user_data; + + g_debug ("", element_name); + + switch (ctx->state) + { + case STATE_START: + case STATE_END: + /* no need to GError here, GMarkup already catches this */ + break; + + case STATE_REPOSITORY: + state_switch (ctx, STATE_END); + break; + + case STATE_INCLUDE: + if (require_end_element (context, ctx, "include", element_name, error)) + { + state_switch (ctx, STATE_REPOSITORY); + } + break; + + case STATE_C_INCLUDE: + if (require_end_element (context, ctx, "c:include", element_name, error)) + { + state_switch (ctx, STATE_REPOSITORY); + } + break; + + case STATE_PACKAGE: + if (require_end_element (context, ctx, "package", element_name, error)) + { + state_switch (ctx, STATE_REPOSITORY); + } + break; + + case STATE_NAMESPACE: + if (require_end_element (context, ctx, "namespace", element_name, error)) + { + ctx->current_module = NULL; + state_switch (ctx, STATE_REPOSITORY); + } + break; + + case STATE_ALIAS: + if (require_end_element (context, ctx, "alias", element_name, error)) + { + g_free (ctx->current_alias); + ctx->current_alias = NULL; + state_switch (ctx, STATE_NAMESPACE); + } + break; + + case STATE_FUNCTION_RETURN: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "return-value", element_name, error)) + { + state_switch (ctx, STATE_FUNCTION); + } + break; + + case STATE_FUNCTION_PARAMETERS: + if (require_end_element (context, ctx, "parameters", element_name, error)) + { + state_switch (ctx, STATE_FUNCTION); + } + break; + + case STATE_FUNCTION_PARAMETER: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "parameter", element_name, error)) + { + state_switch (ctx, STATE_FUNCTION_PARAMETERS); + } + break; + + case STATE_FUNCTION: + { + pop_node (ctx); + if (ctx->node_stack == NULL) + { + state_switch (ctx, STATE_NAMESPACE); + } + else + { + g_debug("case STATE_FUNCTION %d", CURRENT_NODE (ctx)->type); + if (ctx->in_embedded_state != STATE_NONE) + { + state_switch (ctx, ctx->in_embedded_state); + ctx->in_embedded_state = STATE_NONE; + } + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_INTERFACE) + state_switch (ctx, STATE_INTERFACE); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_OBJECT) + state_switch (ctx, STATE_CLASS); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_BOXED) + state_switch (ctx, STATE_BOXED); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_STRUCT) + state_switch (ctx, STATE_STRUCT); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_UNION) + state_switch (ctx, STATE_UNION); + else if (CURRENT_NODE (ctx)->type == GI_IR_NODE_ENUM || + CURRENT_NODE (ctx)->type == GI_IR_NODE_FLAGS) + state_switch (ctx, STATE_ENUM); + else + { + int line_number, char_number; + g_markup_parse_context_get_position (context, &line_number, &char_number); + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Unexpected end tag '%s' on line %d char %d", + element_name, + line_number, char_number); + } + } + } + break; + + case STATE_CLASS_FIELD: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "field", element_name, error)) + { + state_switch (ctx, STATE_CLASS); + } + break; + + case STATE_CLASS_PROPERTY: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "property", element_name, error)) + { + state_switch (ctx, STATE_CLASS); + } + break; + + case STATE_CLASS: + if (require_end_element (context, ctx, "class", element_name, error)) + { + pop_node (ctx); + state_switch (ctx, STATE_NAMESPACE); + } + break; + + case STATE_INTERFACE_PROPERTY: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "property", element_name, error)) + { + state_switch (ctx, STATE_INTERFACE); + } + break; + + case STATE_INTERFACE_FIELD: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "field", element_name, error)) + { + state_switch (ctx, STATE_INTERFACE); + } + break; + + case STATE_INTERFACE: + if (require_end_element (context, ctx, "interface", element_name, error)) + { + pop_node (ctx); + state_switch (ctx, STATE_NAMESPACE); + } + break; + + case STATE_ENUM: + if (strcmp ("member", element_name) == 0) + break; + else if (strcmp ("function", element_name) == 0) + break; + else if (require_one_of_end_elements (context, ctx, + element_name, error, "enumeration", + "bitfield", NULL)) + { + pop_node (ctx); + state_switch (ctx, STATE_NAMESPACE); + } + break; + + case STATE_BOXED: + if (require_end_element (context, ctx, "glib:boxed", element_name, error)) + { + pop_node (ctx); + state_switch (ctx, STATE_NAMESPACE); + } + break; + + case STATE_BOXED_FIELD: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "field", element_name, error)) + { + state_switch (ctx, STATE_BOXED); + } + break; + + case STATE_STRUCT_FIELD: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "field", element_name, error)) + { + state_switch (ctx, STATE_STRUCT); + } + break; + + case STATE_STRUCT: + if (require_end_element (context, ctx, "record", element_name, error)) + { + state_switch_end_struct_or_union (context, ctx, element_name, error); + } + break; + + case STATE_UNION_FIELD: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "field", element_name, error)) + { + state_switch (ctx, STATE_UNION); + } + break; + + case STATE_UNION: + if (require_end_element (context, ctx, "union", element_name, error)) + { + state_switch_end_struct_or_union (context, ctx, element_name, error); + } + break; + case STATE_IMPLEMENTS: + if (strcmp ("interface", element_name) == 0) + break; + if (require_end_element (context, ctx, "implements", element_name, error)) + state_switch (ctx, STATE_CLASS); + break; + case STATE_PREREQUISITE: + if (require_end_element (context, ctx, "prerequisite", element_name, error)) + state_switch (ctx, STATE_INTERFACE); + break; + case STATE_NAMESPACE_CONSTANT: + case STATE_CLASS_CONSTANT: + case STATE_INTERFACE_CONSTANT: + if (strcmp ("type", element_name) == 0) + break; + if (require_end_element (context, ctx, "constant", element_name, error)) + { + switch (ctx->state) + { + case STATE_NAMESPACE_CONSTANT: + pop_node (ctx); + state_switch (ctx, STATE_NAMESPACE); + break; + case STATE_CLASS_CONSTANT: + state_switch (ctx, STATE_CLASS); + break; + case STATE_INTERFACE_CONSTANT: + state_switch (ctx, STATE_INTERFACE); + break; + default: + g_assert_not_reached (); + break; + } + } + break; + case STATE_TYPE: + if ((strcmp ("type", element_name) == 0) || (strcmp ("array", element_name) == 0) || + (strcmp ("varargs", element_name) == 0)) + { + end_type (ctx); + } + break; + case STATE_ATTRIBUTE: + if (strcmp ("attribute", element_name) == 0) + { + state_switch (ctx, ctx->prev_state); + } + break; + + case STATE_PASSTHROUGH: + ctx->unknown_depth -= 1; + g_assert (ctx->unknown_depth >= 0); + if (ctx->unknown_depth == 0) + state_switch (ctx, ctx->prev_state); + break; + default: + g_error ("Unhandled state %d in end_element_handler\n", ctx->state); + } +} + +static void +text_handler (GMarkupParseContext *context, + const gchar *text, + gsize text_len, + gpointer user_data, + GError **error) +{ + /* FIXME warn about non-whitespace text */ +} + +static void +cleanup (GMarkupParseContext *context, + GError *error, + gpointer user_data) +{ + ParseContext *ctx = user_data; + GList *m; + + for (m = ctx->modules; m; m = m->next) + gi_ir_module_free (m->data); + g_list_free (ctx->modules); + ctx->modules = NULL; + + ctx->current_module = NULL; +} + +/** + * gi_ir_parser_parse_string: + * @parser: a #GIIrParser + * @namespace: the namespace of the string + * @filename: (nullable) (type filename): Path to parsed file, or `NULL` + * @buffer: (array length=length): the data containing the XML + * @length: length of the data, in bytes + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Parse a string that holds a complete GIR XML file, and return a list of a + * a [class@GIRepository.IrModule] for each `` element within the + * file. + * + * Returns: (transfer none): a new [class@GIRepository.IrModule] + * Since: 2.80 + */ +GIIrModule * +gi_ir_parser_parse_string (GIIrParser *parser, + const gchar *namespace, + const gchar *filename, + const gchar *buffer, + gssize length, + GError **error) +{ + ParseContext ctx = { 0 }; + GMarkupParseContext *context; + + ctx.parser = parser; + ctx.state = STATE_START; + ctx.file_path = filename; + ctx.namespace = namespace; + ctx.include_modules = NULL; + ctx.aliases = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + ctx.disguised_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + ctx.pointer_structures = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + ctx.type_depth = 0; + ctx.dependencies = NULL; + ctx.current_module = NULL; + + context = g_markup_parse_context_new (&firstpass_parser, 0, &ctx, NULL); + + if (!g_markup_parse_context_parse (context, buffer, length, error)) + goto out; + + if (!g_markup_parse_context_end_parse (context, error)) + goto out; + + g_markup_parse_context_free (context); + + ctx.state = STATE_START; + context = g_markup_parse_context_new (&markup_parser, 0, &ctx, NULL); + if (!g_markup_parse_context_parse (context, buffer, length, error)) + goto out; + + if (!g_markup_parse_context_end_parse (context, error)) + goto out; + + parser->parsed_modules = g_list_concat (g_list_copy (ctx.modules), + parser->parsed_modules); + + out: + + if (ctx.modules == NULL) + { + /* An error occurred before we created a module, so we haven't + * transferred ownership of these hash tables to the module. + */ + g_clear_pointer (&ctx.aliases, g_hash_table_unref); + g_clear_pointer (&ctx.disguised_structures, g_hash_table_unref); + g_clear_pointer (&ctx.pointer_structures, g_hash_table_unref); + g_list_free (ctx.include_modules); + } + + g_markup_parse_context_free (context); + + if (ctx.modules) + return ctx.modules->data; + + if (error && *error == NULL) + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Expected namespace element in the gir file"); + return NULL; +} + +/** + * gi_ir_parser_parse_file: + * @parser: a #GIIrParser + * @filename: (type filename): filename to parse + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Parse the given GIR XML file, and return a list of a + * [class@GIRepository.IrModule] for each `` element within the + * file. + * + * Returns: (transfer container): a newly allocated list of + * [class@GIRepository.IrModule]s. The modules themselves + * are owned by the `GIIrParser` and will be freed along with the parser. + * Since: 2.80 + */ +GIIrModule * +gi_ir_parser_parse_file (GIIrParser *parser, + const gchar *filename, + GError **error) +{ + gchar *buffer; + gsize length; + GIIrModule *module; + char *dash; + char *namespace; + + if (!g_str_has_suffix (filename, ".gir")) + { + g_set_error (error, + G_MARKUP_ERROR, + G_MARKUP_ERROR_INVALID_CONTENT, + "Expected filename to end with '.gir'"); + return NULL; + } + + g_debug ("[parsing] filename %s", filename); + + namespace = g_path_get_basename (filename); + namespace[strlen(namespace)-4] = '\0'; + + /* Remove version */ + dash = strstr (namespace, "-"); + if (dash != NULL) + *dash = '\0'; + + if (!g_file_get_contents (filename, &buffer, &length, error)) + { + g_free (namespace); + + return NULL; + } + + module = gi_ir_parser_parse_string (parser, namespace, filename, buffer, length, error); + + g_free (namespace); + + g_free (buffer); + + return module; +} + + diff --git a/girepository/girwriter-private.h b/girepository/girwriter-private.h new file mode 100644 index 0000000..3d060ef --- /dev/null +++ b/girepository/girwriter-private.h @@ -0,0 +1,35 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: IDL writer + * + * Copyright (C) 2007 Johan Dahlin + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +void gi_ir_writer_write (const char *filename, + const char *ns, + gboolean needs_prefix, + gboolean show_all); + +G_END_DECLS diff --git a/girepository/girwriter.c b/girepository/girwriter.c new file mode 100644 index 0000000..1d307ee --- /dev/null +++ b/girepository/girwriter.c @@ -0,0 +1,1463 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: IDL generator + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include "girwriter-private.h" + +#include "girepository.h" +#include "gitypelib-internal.h" + +#include +#include +#include + +#include +#include +#include + +typedef struct { + FILE *file; + GSList *stack; + gboolean show_all; +} Xml; + +typedef struct { + char *name; + guint has_children : 1; +} XmlElement; + +static XmlElement * +xml_element_new (const char *name) +{ + XmlElement *elem; + + elem = g_slice_new (XmlElement); + elem->name = g_strdup (name); + elem->has_children = FALSE; + return elem; +} + +static void +xml_element_free (XmlElement *elem) +{ + g_free (elem->name); + g_slice_free (XmlElement, elem); +} + +static void +xml_printf (Xml *xml, const char *fmt, ...) G_GNUC_PRINTF (2, 3); + +static void +xml_printf (Xml *xml, const char *fmt, ...) +{ + va_list ap; + char *s; + + va_start (ap, fmt); + s = g_markup_vprintf_escaped (fmt, ap); + fputs (s, xml->file); + g_free (s); + va_end (ap); +} + +static void +xml_start_element (Xml *xml, const char *element_name) +{ + XmlElement *parent = NULL; + + if (xml->stack) + { + parent = xml->stack->data; + + if (!parent->has_children) + xml_printf (xml, ">\n"); + + parent->has_children = TRUE; + } + + xml_printf (xml, "%*s<%s", g_slist_length(xml->stack)*2, "", element_name); + + xml->stack = g_slist_prepend (xml->stack, xml_element_new (element_name)); +} + +static void +xml_end_element (Xml *xml, const char *name) +{ + XmlElement *elem; + + g_assert (xml->stack != NULL); + + elem = xml->stack->data; + xml->stack = g_slist_delete_link (xml->stack, xml->stack); + + if (name != NULL) + g_assert_cmpstr (name, ==, elem->name); + + if (elem->has_children) + xml_printf (xml, "%*s\n", g_slist_length (xml->stack)*2, "", elem->name); + else + xml_printf (xml, "/>\n"); + + xml_element_free (elem); +} + +static void +xml_end_element_unchecked (Xml *xml) +{ + xml_end_element (xml, NULL); +} + +static Xml * +xml_open (FILE *file) +{ + Xml *xml; + + xml = g_slice_new (Xml); + xml->file = file; + xml->stack = NULL; + + return xml; +} + +static void +xml_close (Xml *xml) +{ + g_assert (xml->stack == NULL); + if (xml->file != NULL) + { + fflush (xml->file); + if (xml->file != stdout) + fclose (xml->file); + xml->file = NULL; + } +} + +static void +xml_free (Xml *xml) +{ + xml_close (xml); + g_slice_free (Xml, xml); +} + + +static void +check_unresolved (GIBaseInfo *info) +{ + if (gi_base_info_get_info_type (info) != GI_INFO_TYPE_UNRESOLVED) + return; + + g_critical ("Found unresolved type '%s' '%s'\n", + gi_base_info_get_name (info), gi_base_info_get_namespace (info)); +} + +static void +write_type_name (const gchar *ns, + GIBaseInfo *info, + Xml *file) +{ + if (strcmp (ns, gi_base_info_get_namespace (info)) != 0) + xml_printf (file, "%s.", gi_base_info_get_namespace (info)); + + xml_printf (file, "%s", gi_base_info_get_name (info)); +} + +static void +write_type_name_attribute (const gchar *ns, + GIBaseInfo *info, + const char *attr_name, + Xml *file) +{ + xml_printf (file, " %s=\"", attr_name); + write_type_name (ns, info, file); + xml_printf (file, "\""); +} + + static void +write_ownership_transfer (GITransfer transfer, + Xml *file) +{ + switch (transfer) + { + case GI_TRANSFER_NOTHING: + xml_printf (file, " transfer-ownership=\"none\""); + break; + case GI_TRANSFER_CONTAINER: + xml_printf (file, " transfer-ownership=\"container\""); + break; + case GI_TRANSFER_EVERYTHING: + xml_printf (file, " transfer-ownership=\"full\""); + break; + default: + g_assert_not_reached (); + } +} + +static void +write_type_info (const gchar *ns, + GITypeInfo *info, + Xml *file) +{ + gint tag; + GITypeInfo *type; + gboolean is_pointer; + + check_unresolved ((GIBaseInfo*)info); + + tag = gi_type_info_get_tag (info); + is_pointer = gi_type_info_is_pointer (info); + + if (tag == GI_TYPE_TAG_VOID) + { + xml_start_element (file, "type"); + + xml_printf (file, " name=\"%s\"", is_pointer ? "any" : "none"); + + xml_end_element (file, "type"); + } + else if (GI_TYPE_TAG_IS_BASIC (tag)) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"%s\"", gi_type_tag_to_string (tag)); + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_ARRAY) + { + gint length; + gssize size; + const char *name = NULL; + + xml_start_element (file, "array"); + + switch (gi_type_info_get_array_type (info)) { + case GI_ARRAY_TYPE_C: + break; + case GI_ARRAY_TYPE_ARRAY: + name = "GLib.Array"; + break; + case GI_ARRAY_TYPE_PTR_ARRAY: + name = "GLib.PtrArray"; + break; + case GI_ARRAY_TYPE_BYTE_ARRAY: + name = "GLib.ByteArray"; + break; + default: + break; + } + + if (name) + xml_printf (file, " name=\"%s\"", name); + + type = gi_type_info_get_param_type (info, 0); + + length = gi_type_info_get_array_length_index (info); + if (length >= 0) + xml_printf (file, " length=\"%d\"", length); + + size = gi_type_info_get_array_fixed_size (info); + if (size >= 0) + xml_printf (file, " fixed-size=\"%" G_GSSIZE_FORMAT "\"", size); + + if (gi_type_info_is_zero_terminated (info)) + xml_printf (file, " zero-terminated=\"1\""); + + write_type_info (ns, type, file); + + gi_base_info_unref ((GIBaseInfo *)type); + + xml_end_element (file, "array"); + } + else if (tag == GI_TYPE_TAG_INTERFACE) + { + GIBaseInfo *iface = gi_type_info_get_interface (info); + xml_start_element (file, "type"); + write_type_name_attribute (ns, iface, "name", file); + xml_end_element (file, "type"); + gi_base_info_unref (iface); + } + else if (tag == GI_TYPE_TAG_GLIST) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.List\""); + type = gi_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (ns, type, file); + gi_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_GSLIST) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.SList\""); + type = gi_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (ns, type, file); + gi_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_GHASH) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.HashTable\""); + type = gi_type_info_get_param_type (info, 0); + if (type) + { + write_type_info (ns, type, file); + gi_base_info_unref ((GIBaseInfo *)type); + type = gi_type_info_get_param_type (info, 1); + write_type_info (ns, type, file); + gi_base_info_unref ((GIBaseInfo *)type); + } + xml_end_element (file, "type"); + } + else if (tag == GI_TYPE_TAG_ERROR) + { + xml_start_element (file, "type"); + xml_printf (file, " name=\"GLib.Error\""); + xml_end_element (file, "type"); + } + else + { + g_printerr ("Unhandled type tag %d\n", tag); + g_assert_not_reached (); + } +} + +static void +write_attributes (Xml *file, + GIBaseInfo *info) +{ + GIAttributeIter iter = { 0, }; + const char *name, *value; + + while (gi_base_info_iterate_attributes (info, &iter, &name, &value)) + { + xml_start_element (file, "attribute"); + xml_printf (file, " name=\"%s\" value=\"%s\"", name, value); + xml_end_element (file, "attribute"); + } +} + +static void +write_return_value_attributes (Xml *file, + GICallableInfo *info) +{ + GIAttributeIter iter = { 0, }; + const char *name, *value; + + while (gi_callable_info_iterate_return_attributes (info, &iter, &name, &value)) + { + xml_start_element (file, "attribute"); + xml_printf (file, " name=\"%s\" value=\"%s\"", name, value); + xml_end_element (file, "attribute"); + } +} + +static void +write_constant_value (const gchar *ns, + GITypeInfo *info, + GIArgument *argument, + Xml *file); + +static void +write_callback_info (const gchar *ns, + GICallbackInfo *info, + Xml *file); + +static void +write_field_info (const gchar *ns, + GIFieldInfo *info, + GIConstantInfo *branch, + Xml *file) +{ + const gchar *name; + GIFieldInfoFlags flags; + gint size; + gint offset; + GITypeInfo *type; + GIBaseInfo *interface; + GIArgument value; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + flags = gi_field_info_get_flags (info); + size = gi_field_info_get_size (info); + offset = gi_field_info_get_offset (info); + + xml_start_element (file, "field"); + xml_printf (file, " name=\"%s\"", name); + + /* Fields are assumed to be read-only + * (see also girwriter.py and girparser.c) + */ + if (!(flags & GI_FIELD_IS_READABLE)) + xml_printf (file, " readable=\"0\""); + if (flags & GI_FIELD_IS_WRITABLE) + xml_printf (file, " writable=\"1\""); + + if (size) + xml_printf (file, " bits=\"%d\"", size); + + write_attributes (file, (GIBaseInfo*) info); + + type = gi_field_info_get_type_info (info); + + if (branch) + { + xml_printf (file, " branch=\""); + gi_base_info_unref ((GIBaseInfo *)type); + type = gi_constant_info_get_type_info (branch); + gi_constant_info_get_value (branch, &value); + write_constant_value (ns, type, &value, file); + xml_printf (file, "\""); + } + + if (file->show_all) + { + if (offset >= 0) + xml_printf (file, "offset=\"%d\"", offset); + } + + interface = gi_type_info_get_interface (type); + if (interface && gi_base_info_get_info_type (interface) == GI_INFO_TYPE_CALLBACK) + write_callback_info (ns, (GICallbackInfo *)interface, file); + else + write_type_info (ns, type, file); + + if (interface) + gi_base_info_unref (interface); + + gi_base_info_unref ((GIBaseInfo *)type); + + xml_end_element (file, "field"); +} + +static void +write_callable_info (const gchar *ns, + GICallableInfo *info, + Xml *file) +{ + GITypeInfo *type; + + if (gi_callable_info_can_throw_gerror (info)) + xml_printf (file, " throws=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + type = gi_callable_info_get_return_type (info); + + xml_start_element (file, "return-value"); + + write_ownership_transfer (gi_callable_info_get_caller_owns (info), file); + + if (gi_callable_info_may_return_null (info)) + xml_printf (file, " allow-none=\"1\""); + + if (gi_callable_info_skip_return (info)) + xml_printf (file, " skip=\"1\""); + + write_return_value_attributes (file, info); + + write_type_info (ns, type, file); + + xml_end_element (file, "return-value"); + + if (gi_callable_info_get_n_args (info) <= 0) + return; + + xml_start_element (file, "parameters"); + for (guint i = 0; i < gi_callable_info_get_n_args (info); i++) + { + GIArgInfo *arg = gi_callable_info_get_arg (info, i); + + xml_start_element (file, "parameter"); + xml_printf (file, " name=\"%s\"", + gi_base_info_get_name ((GIBaseInfo *) arg)); + + write_ownership_transfer (gi_arg_info_get_ownership_transfer (arg), file); + + switch (gi_arg_info_get_direction (arg)) + { + case GI_DIRECTION_IN: + break; + case GI_DIRECTION_OUT: + xml_printf (file, " direction=\"out\" caller-allocates=\"%s\"", + gi_arg_info_is_caller_allocates (arg) ? "1" : "0"); + break; + case GI_DIRECTION_INOUT: + xml_printf (file, " direction=\"inout\""); + break; + default: + g_assert_not_reached (); + } + + if (gi_arg_info_may_be_null (arg)) + xml_printf (file, " allow-none=\"1\""); + + if (gi_arg_info_is_return_value (arg)) + xml_printf (file, " retval=\"1\""); + + if (gi_arg_info_is_optional (arg)) + xml_printf (file, " optional=\"1\""); + + switch (gi_arg_info_get_scope (arg)) + { + case GI_SCOPE_TYPE_INVALID: + break; + case GI_SCOPE_TYPE_CALL: + xml_printf (file, " scope=\"call\""); + break; + case GI_SCOPE_TYPE_ASYNC: + xml_printf (file, " scope=\"async\""); + break; + case GI_SCOPE_TYPE_NOTIFIED: + xml_printf (file, " scope=\"notified\""); + break; + case GI_SCOPE_TYPE_FOREVER: + xml_printf (file, " scope=\"forever\""); + break; + default: + g_assert_not_reached (); + } + + if (gi_arg_info_get_closure_index (arg) >= 0) + xml_printf (file, " closure=\"%d\"", gi_arg_info_get_closure_index (arg)); + + if (gi_arg_info_get_destroy_index (arg) >= 0) + xml_printf (file, " destroy=\"%d\"", gi_arg_info_get_destroy_index (arg)); + + if (gi_arg_info_is_skip (arg)) + xml_printf (file, " skip=\"1\""); + + write_attributes (file, (GIBaseInfo*) arg); + + type = gi_arg_info_get_type_info (arg); + write_type_info (ns, type, file); + + xml_end_element (file, "parameter"); + + gi_base_info_unref ((GIBaseInfo *)arg); + } + + xml_end_element (file, "parameters"); + gi_base_info_unref ((GIBaseInfo *)type); +} + +static void +write_function_info (const gchar *ns, + GIFunctionInfo *info, + Xml *file) +{ + GIFunctionInfoFlags flags; + const gchar *tag; + const gchar *name; + const gchar *symbol; + gboolean deprecated; + + flags = gi_function_info_get_flags (info); + name = gi_base_info_get_name ((GIBaseInfo *)info); + symbol = gi_function_info_get_symbol (info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + if (flags & GI_FUNCTION_IS_CONSTRUCTOR) + tag = "constructor"; + else if (flags & GI_FUNCTION_IS_METHOD) + tag = "method"; + else + tag = "function"; + + xml_start_element (file, tag); + xml_printf (file, " name=\"%s\" c:identifier=\"%s\"", + name, symbol); + + if ((flags & GI_FUNCTION_IS_SETTER) || (flags & GI_FUNCTION_IS_GETTER)) + { + GIPropertyInfo *property = gi_function_info_get_property (info); + + if (property != NULL) + { + const char *property_name = gi_base_info_get_name ((GIBaseInfo *)property); + + if (flags & GI_FUNCTION_IS_SETTER) + xml_printf (file, " glib:set-property=\"%s\"", property_name); + else if (flags & GI_FUNCTION_IS_GETTER) + xml_printf (file, " glib:get-property=\"%s\"", property_name); + + gi_base_info_unref ((GIBaseInfo *) property); + } + } + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_callable_info (ns, (GICallableInfo*)info, file); + xml_end_element (file, tag); +} + +static void +write_callback_info (const gchar *ns, + GICallbackInfo *info, + Xml *file) +{ + const gchar *name; + gboolean deprecated; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "callback"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_callable_info (ns, (GICallableInfo*)info, file); + xml_end_element (file, "callback"); +} + +static void +write_struct_info (const gchar *ns, + GIStructInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + const gchar *func; + gboolean deprecated; + gboolean is_gtype_struct; + gboolean foreign; + gint size; + guint n_elts; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info); + + if (gi_base_info_get_info_type ((GIBaseInfo *) info) == GI_INFO_TYPE_BOXED) + { + xml_start_element (file, "glib:boxed"); + xml_printf (file, " glib:name=\"%s\"", name); + } + else + { + xml_start_element (file, "record"); + xml_printf (file, " name=\"%s\"", name); + } + + if (type_name != NULL) + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + is_gtype_struct = gi_struct_info_is_gtype_struct (info); + if (is_gtype_struct) + xml_printf (file, " glib:is-gtype-struct=\"1\""); + + func = gi_struct_info_get_copy_function_name (info); + if (func) + xml_printf (file, " copy-function=\"%s\"", func); + + func = gi_struct_info_get_free_function_name (info); + if (func) + xml_printf (file, " free-function=\"%s\"", func); + + write_attributes (file, (GIBaseInfo*) info); + + size = gi_struct_info_get_size (info); + if (file->show_all && size >= 0) + xml_printf (file, " size=\"%d\"", size); + + foreign = gi_struct_info_is_foreign (info); + if (foreign) + xml_printf (file, " foreign=\"1\""); + + n_elts = gi_struct_info_get_n_fields (info) + gi_struct_info_get_n_methods (info); + if (n_elts > 0) + { + for (guint i = 0; i < gi_struct_info_get_n_fields (info); i++) + { + GIFieldInfo *field = gi_struct_info_get_field (info, i); + write_field_info (ns, field, NULL, file); + gi_base_info_unref ((GIBaseInfo *)field); + } + + for (guint i = 0; i < gi_struct_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = gi_struct_info_get_method (info, i); + write_function_info (ns, function, file); + gi_base_info_unref ((GIBaseInfo *)function); + } + + } + + xml_end_element_unchecked (file); +} + +static void +write_value_info (const gchar *ns, + GIValueInfo *info, + Xml *file) +{ + const gchar *name; + gint64 value; + gchar *value_str; + gboolean deprecated; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + value = gi_value_info_get_value (info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "member"); + value_str = g_strdup_printf ("%" G_GINT64_FORMAT, value); + xml_printf (file, " name=\"%s\" value=\"%s\"", name, value_str); + g_free (value_str); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + xml_end_element (file, "member"); +} + +static void +write_constant_value (const gchar *ns, + GITypeInfo *type, + GIArgument *value, + Xml *file) +{ + switch (gi_type_info_get_tag (type)) + { + case GI_TYPE_TAG_BOOLEAN: + xml_printf (file, "%d", value->v_boolean); + break; + case GI_TYPE_TAG_INT8: + xml_printf (file, "%d", value->v_int8); + break; + case GI_TYPE_TAG_UINT8: + xml_printf (file, "%d", value->v_uint8); + break; + case GI_TYPE_TAG_INT16: + xml_printf (file, "%" G_GINT16_FORMAT, value->v_int16); + break; + case GI_TYPE_TAG_UINT16: + xml_printf (file, "%" G_GUINT16_FORMAT, value->v_uint16); + break; + case GI_TYPE_TAG_INT32: + xml_printf (file, "%" G_GINT32_FORMAT, value->v_int32); + break; + case GI_TYPE_TAG_UINT32: + xml_printf (file, "%" G_GUINT32_FORMAT, value->v_uint32); + break; + case GI_TYPE_TAG_INT64: + xml_printf (file, "%" G_GINT64_FORMAT, value->v_int64); + break; + case GI_TYPE_TAG_UINT64: + xml_printf (file, "%" G_GUINT64_FORMAT, value->v_uint64); + break; + case GI_TYPE_TAG_FLOAT: + xml_printf (file, "%f", (double)value->v_float); + break; + case GI_TYPE_TAG_DOUBLE: + xml_printf (file, "%f", value->v_double); + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + xml_printf (file, "%s", value->v_string); + break; + default: + g_assert_not_reached (); + } +} + +static void +write_constant_info (const gchar *ns, + GIConstantInfo *info, + Xml *file) +{ + GITypeInfo *type; + const gchar *name; + GIArgument value; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + + xml_start_element (file, "constant"); + xml_printf (file, " name=\"%s\"", name); + + type = gi_constant_info_get_type_info (info); + xml_printf (file, " value=\""); + + gi_constant_info_get_value (info, &value); + write_constant_value (ns, type, &value, file); + xml_printf (file, "\""); + + write_type_info (ns, type, file); + + write_attributes (file, (GIBaseInfo*) info); + + xml_end_element (file, "constant"); + + gi_base_info_unref ((GIBaseInfo *)type); +} + + +static void +write_enum_info (const gchar *ns, + GIEnumInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + const gchar *error_domain; + gboolean deprecated; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info); + error_domain = gi_enum_info_get_error_domain (info); + + if (gi_base_info_get_info_type ((GIBaseInfo *) info) == GI_INFO_TYPE_ENUM) + xml_start_element (file, "enumeration"); + else + xml_start_element (file, "bitfield"); + xml_printf (file, " name=\"%s\"", name); + + if (type_init) + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + if (error_domain) + xml_printf (file, " glib:error-domain=\"%s\"", error_domain); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + for (guint i = 0; i < gi_enum_info_get_n_values (info); i++) + { + GIValueInfo *value = gi_enum_info_get_value (info, i); + write_value_info (ns, value, file); + gi_base_info_unref ((GIBaseInfo *)value); + } + + xml_end_element_unchecked (file); +} + +static void +write_signal_info (const gchar *ns, + GISignalInfo *info, + Xml *file) +{ + GSignalFlags flags; + const gchar *name; + gboolean deprecated; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + flags = gi_signal_info_get_flags (info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "glib:signal"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + if (flags & G_SIGNAL_RUN_FIRST) + xml_printf (file, " when=\"FIRST\""); + else if (flags & G_SIGNAL_RUN_LAST) + xml_printf (file, " when=\"LAST\""); + else if (flags & G_SIGNAL_RUN_CLEANUP) + xml_printf (file, " when=\"CLEANUP\""); + + if (flags & G_SIGNAL_NO_RECURSE) + xml_printf (file, " no-recurse=\"1\""); + + if (flags & G_SIGNAL_DETAILED) + xml_printf (file, " detailed=\"1\""); + + if (flags & G_SIGNAL_ACTION) + xml_printf (file, " action=\"1\""); + + if (flags & G_SIGNAL_NO_HOOKS) + xml_printf (file, " no-hooks=\"1\""); + + write_callable_info (ns, (GICallableInfo*)info, file); + + xml_end_element (file, "glib:signal"); +} + +static void +write_vfunc_info (const gchar *ns, + GIVFuncInfo *info, + Xml *file) +{ + GIVFuncInfoFlags flags; + const gchar *name; + GIFunctionInfo *invoker; + gboolean deprecated; + gint offset; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + flags = gi_vfunc_info_get_flags (info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + offset = gi_vfunc_info_get_offset (info); + invoker = gi_vfunc_info_get_invoker (info); + + xml_start_element (file, "virtual-method"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + if (flags & GI_VFUNC_MUST_CHAIN_UP) + xml_printf (file, " must-chain-up=\"1\""); + + if (flags & GI_VFUNC_MUST_OVERRIDE) + xml_printf (file, " override=\"always\""); + else if (flags & GI_VFUNC_MUST_NOT_OVERRIDE) + xml_printf (file, " override=\"never\""); + + xml_printf (file, " offset=\"%d\"", offset); + + if (invoker) + { + xml_printf (file, " invoker=\"%s\"", gi_base_info_get_name ((GIBaseInfo*)invoker)); + gi_base_info_unref ((GIBaseInfo *)invoker); + } + + write_callable_info (ns, (GICallableInfo*)info, file); + + xml_end_element (file, "virtual-method"); +} + +static void +write_property_info (const gchar *ns, + GIPropertyInfo *info, + Xml *file) +{ + GParamFlags flags; + const gchar *name; + gboolean deprecated; + GITypeInfo *type; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + flags = gi_property_info_get_flags (info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + xml_start_element (file, "property"); + xml_printf (file, " name=\"%s\"", name); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + /* Properties are assumed to be read-only (see also girwriter.py) */ + if (!(flags & G_PARAM_READABLE)) + xml_printf (file, " readable=\"0\""); + if (flags & G_PARAM_WRITABLE) + xml_printf (file, " writable=\"1\""); + + if (flags & G_PARAM_CONSTRUCT) + xml_printf (file, " construct=\"1\""); + + if (flags & G_PARAM_CONSTRUCT_ONLY) + xml_printf (file, " construct-only=\"1\""); + + if (flags & G_PARAM_READABLE) + { + GIFunctionInfo *getter = gi_property_info_get_getter (info); + + if (getter != NULL) + { + xml_printf (file, " getter=\"%s\"", gi_base_info_get_name ((GIBaseInfo *) getter)); + gi_base_info_unref ((GIBaseInfo *) getter); + } + } + + if (flags & G_PARAM_WRITABLE) + { + GIFunctionInfo *setter = gi_property_info_get_setter (info); + + if (setter != NULL) + { + xml_printf (file, " setter=\"%s\"", gi_base_info_get_name ((GIBaseInfo *) setter)); + gi_base_info_unref ((GIBaseInfo *) setter); + } + } + + write_ownership_transfer (gi_property_info_get_ownership_transfer (info), file); + + write_attributes (file, (GIBaseInfo*) info); + + type = gi_property_info_get_type_info (info); + + write_type_info (ns, type, file); + + xml_end_element (file, "property"); +} + +static void +write_object_info (const gchar *ns, + GIObjectInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + const gchar *func; + gboolean deprecated; + gboolean is_abstract; + gboolean is_fundamental; + gboolean is_final; + GIObjectInfo *pnode; + GIStructInfo *class_struct; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + is_abstract = gi_object_info_get_abstract (info); + is_fundamental = gi_object_info_get_fundamental (info); + is_final = gi_object_info_get_final (info); + + type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info); + xml_start_element (file, "class"); + xml_printf (file, " name=\"%s\"", name); + + pnode = gi_object_info_get_parent (info); + if (pnode) + { + write_type_name_attribute (ns, (GIBaseInfo *)pnode, "parent", file); + gi_base_info_unref ((GIBaseInfo *)pnode); + } + + class_struct = gi_object_info_get_class_struct (info); + if (class_struct) + { + write_type_name_attribute (ns, (GIBaseInfo*) class_struct, "glib:type-struct", file); + gi_base_info_unref ((GIBaseInfo*)class_struct); + } + + if (is_abstract) + xml_printf (file, " abstract=\"1\""); + + if (is_final) + xml_printf (file, " final=\"1\""); + + xml_printf (file, " glib:type-name=\"%s\" glib:get-type=\"%s\"", type_name, type_init); + + if (is_fundamental) + xml_printf (file, " glib:fundamental=\"1\""); + + func = gi_object_info_get_unref_function_name (info); + if (func) + xml_printf (file, " glib:unref-function=\"%s\"", func); + + func = gi_object_info_get_ref_function_name (info); + if (func) + xml_printf (file, " glib:ref-function=\"%s\"", func); + + func = gi_object_info_get_set_value_function_name (info); + if (func) + xml_printf (file, " glib:set-value-function=\"%s\"", func); + + func = gi_object_info_get_get_value_function_name (info); + if (func) + xml_printf (file, " glib:get-value-function=\"%s\"", func); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + if (gi_object_info_get_n_interfaces (info) > 0) + { + for (guint i = 0; i < gi_object_info_get_n_interfaces (info); i++) + { + GIInterfaceInfo *imp = gi_object_info_get_interface (info, i); + xml_start_element (file, "implements"); + write_type_name_attribute (ns, (GIBaseInfo *)imp, "name", file); + xml_end_element (file, "implements"); + gi_base_info_unref ((GIBaseInfo*)imp); + } + } + + for (guint i = 0; i < gi_object_info_get_n_fields (info); i++) + { + GIFieldInfo *field = gi_object_info_get_field (info, i); + write_field_info (ns, field, NULL, file); + gi_base_info_unref ((GIBaseInfo *)field); + } + + for (guint i = 0; i < gi_object_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = gi_object_info_get_method (info, i); + write_function_info (ns, function, file); + gi_base_info_unref ((GIBaseInfo *)function); + } + + for (guint i = 0; i < gi_object_info_get_n_properties (info); i++) + { + GIPropertyInfo *prop = gi_object_info_get_property (info, i); + write_property_info (ns, prop, file); + gi_base_info_unref ((GIBaseInfo *)prop); + } + + for (guint i = 0; i < gi_object_info_get_n_signals (info); i++) + { + GISignalInfo *signal = gi_object_info_get_signal (info, i); + write_signal_info (ns, signal, file); + gi_base_info_unref ((GIBaseInfo *)signal); + } + + for (guint i = 0; i < gi_object_info_get_n_vfuncs (info); i++) + { + GIVFuncInfo *vfunc = gi_object_info_get_vfunc (info, i); + write_vfunc_info (ns, vfunc, file); + gi_base_info_unref ((GIBaseInfo *)vfunc); + } + + for (guint i = 0; i < gi_object_info_get_n_constants (info); i++) + { + GIConstantInfo *constant = gi_object_info_get_constant (info, i); + write_constant_info (ns, constant, file); + gi_base_info_unref ((GIBaseInfo *)constant); + } + + xml_end_element (file, "class"); +} + +static void +write_interface_info (const gchar *ns, + GIInterfaceInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + GIStructInfo *class_struct; + gboolean deprecated; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info); + xml_start_element (file, "interface"); + xml_printf (file, " name=\"%s\" glib:type-name=\"%s\" glib:get-type=\"%s\"", + name, type_name, type_init); + + class_struct = gi_interface_info_get_iface_struct (info); + if (class_struct) + { + write_type_name_attribute (ns, (GIBaseInfo*) class_struct, "glib:type-struct", file); + gi_base_info_unref ((GIBaseInfo*)class_struct); + } + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + write_attributes (file, (GIBaseInfo*) info); + + if (gi_interface_info_get_n_prerequisites (info) > 0) + { + for (guint i = 0; i < gi_interface_info_get_n_prerequisites (info); i++) + { + GIBaseInfo *req = gi_interface_info_get_prerequisite (info, i); + + xml_start_element (file, "prerequisite"); + write_type_name_attribute (ns, req, "name", file); + + xml_end_element_unchecked (file); + gi_base_info_unref (req); + } + } + + for (guint i = 0; i < gi_interface_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = gi_interface_info_get_method (info, i); + write_function_info (ns, function, file); + gi_base_info_unref ((GIBaseInfo *)function); + } + + for (guint i = 0; i < gi_interface_info_get_n_properties (info); i++) + { + GIPropertyInfo *prop = gi_interface_info_get_property (info, i); + write_property_info (ns, prop, file); + gi_base_info_unref ((GIBaseInfo *)prop); + } + + for (guint i = 0; i < gi_interface_info_get_n_signals (info); i++) + { + GISignalInfo *signal = gi_interface_info_get_signal (info, i); + write_signal_info (ns, signal, file); + gi_base_info_unref ((GIBaseInfo *)signal); + } + + for (guint i = 0; i < gi_interface_info_get_n_vfuncs (info); i++) + { + GIVFuncInfo *vfunc = gi_interface_info_get_vfunc (info, i); + write_vfunc_info (ns, vfunc, file); + gi_base_info_unref ((GIBaseInfo *)vfunc); + } + + for (guint i = 0; i < gi_interface_info_get_n_constants (info); i++) + { + GIConstantInfo *constant = gi_interface_info_get_constant (info, i); + write_constant_info (ns, constant, file); + gi_base_info_unref ((GIBaseInfo *)constant); + } + + xml_end_element (file, "interface"); +} + +static void +write_union_info (const gchar *ns, + GIUnionInfo *info, + Xml *file) +{ + const gchar *name; + const gchar *type_name; + const gchar *type_init; + const gchar *func; + gboolean deprecated; + gsize size; + + name = gi_base_info_get_name ((GIBaseInfo *)info); + deprecated = gi_base_info_is_deprecated ((GIBaseInfo *)info); + + type_name = gi_registered_type_info_get_type_name ((GIRegisteredTypeInfo*)info); + type_init = gi_registered_type_info_get_type_init_function_name ((GIRegisteredTypeInfo*)info); + + xml_start_element (file, "union"); + xml_printf (file, " name=\"%s\"", name); + + if (type_name) + xml_printf (file, " type-name=\"%s\" get-type=\"%s\"", type_name, type_init); + + if (deprecated) + xml_printf (file, " deprecated=\"1\""); + + size = gi_union_info_get_size (info); + if (file->show_all) + xml_printf (file, " size=\"%" G_GSIZE_FORMAT "\"", size); + + func = gi_union_info_get_copy_function_name (info); + if (func) + xml_printf (file, " copy-function=\"%s\"", func); + + func = gi_union_info_get_free_function_name (info); + if (func) + xml_printf (file, " free-function=\"%s\"", func); + + write_attributes (file, (GIBaseInfo*) info); + + if (gi_union_info_is_discriminated (info)) + { + guint offset; + GITypeInfo *type; + + offset = gi_union_info_get_discriminator_offset (info); + type = gi_union_info_get_discriminator_type (info); + + xml_start_element (file, "discriminator"); + xml_printf (file, " offset=\"%d\" type=\"", offset); + write_type_info (ns, type, file); + xml_end_element (file, "discriminator"); + gi_base_info_unref ((GIBaseInfo *)type); + } + + for (guint i = 0; i < gi_union_info_get_n_fields (info); i++) + { + GIFieldInfo *field = gi_union_info_get_field (info, i); + GIConstantInfo *constant = gi_union_info_get_discriminator (info, i); + write_field_info (ns, field, constant, file); + gi_base_info_unref ((GIBaseInfo *)field); + if (constant) + gi_base_info_unref ((GIBaseInfo *)constant); + } + + for (guint i = 0; i < gi_union_info_get_n_methods (info); i++) + { + GIFunctionInfo *function = gi_union_info_get_method (info, i); + write_function_info (ns, function, file); + gi_base_info_unref ((GIBaseInfo *)function); + } + + xml_end_element (file, "union"); +} + + +/** + * gi_ir_writer_write: + * @filename: (type filename): filename to write to + * @ns: GIR namespace to write + * @needs_prefix: if the filename needs prefixing + * @show_all: if field size calculations should be included + * + * Writes the output of a typelib represented by @ns + * into a GIR xml file named @filename. + * + * Since: 2.80 + */ +void +gi_ir_writer_write (const char *filename, + const char *ns, + gboolean needs_prefix, + gboolean show_all) +{ + FILE *ofile; + gint i, j; + char **dependencies; + GIRepository *repository; + Xml *xml; + + repository = gi_repository_get_default (); + + if (filename == NULL) + ofile = stdout; + else + { + gchar *full_filename; + + if (needs_prefix) + full_filename = g_strdup_printf ("%s-%s", ns, filename); + else + full_filename = g_strdup (filename); + ofile = g_fopen (filename, "w"); + + if (ofile == NULL) + { + g_fprintf (stderr, "failed to open '%s': %s\n", + full_filename, g_strerror (errno)); + g_free (full_filename); + + return; + } + + g_free (full_filename); + } + + xml = xml_open (ofile); + xml->show_all = show_all; + xml_printf (xml, "\n"); + xml_start_element (xml, "repository"); + xml_printf (xml, " version=\"1.0\"\n" + " xmlns=\"http://www.gtk.org/introspection/core/1.0\"\n" + " xmlns:c=\"http://www.gtk.org/introspection/c/1.0\"\n" + " xmlns:glib=\"http://www.gtk.org/introspection/glib/1.0\""); + + dependencies = gi_repository_get_immediate_dependencies (repository, ns); + if (dependencies != NULL) + { + for (i = 0; dependencies[i]; i++) + { + char **parts = g_strsplit (dependencies[i], "-", 2); + xml_start_element (xml, "include"); + xml_printf (xml, " name=\"%s\" version=\"%s\"", parts[0], parts[1]); + xml_end_element (xml, "include"); + g_strfreev (parts); + } + } + + if (TRUE) + { + const gchar *shared_library; + const gchar *c_prefix; + const char *cur_ns = ns; + const char *cur_version; + gint n_infos; + + cur_version = gi_repository_get_version (repository, cur_ns); + + shared_library = gi_repository_get_shared_library (repository, cur_ns); + c_prefix = gi_repository_get_c_prefix (repository, cur_ns); + xml_start_element (xml, "namespace"); + xml_printf (xml, " name=\"%s\" version=\"%s\"", cur_ns, cur_version); + if (shared_library) + xml_printf (xml, " shared-library=\"%s\"", shared_library); + if (c_prefix) + xml_printf (xml, " c:prefix=\"%s\"", c_prefix); + + n_infos = gi_repository_get_n_infos (repository, cur_ns); + for (j = 0; j < n_infos; j++) + { + GIBaseInfo *info = gi_repository_get_info (repository, cur_ns, j); + switch (gi_base_info_get_info_type (info)) + { + case GI_INFO_TYPE_FUNCTION: + write_function_info (ns, (GIFunctionInfo *)info, xml); + break; + + case GI_INFO_TYPE_CALLBACK: + write_callback_info (ns, (GICallbackInfo *)info, xml); + break; + + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_BOXED: + write_struct_info (ns, (GIStructInfo *)info, xml); + break; + + case GI_INFO_TYPE_UNION: + write_union_info (ns, (GIUnionInfo *)info, xml); + break; + + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + write_enum_info (ns, (GIEnumInfo *)info, xml); + break; + + case GI_INFO_TYPE_CONSTANT: + write_constant_info (ns, (GIConstantInfo *)info, xml); + break; + + case GI_INFO_TYPE_OBJECT: + write_object_info (ns, (GIObjectInfo *)info, xml); + break; + + case GI_INFO_TYPE_INTERFACE: + write_interface_info (ns, (GIInterfaceInfo *)info, xml); + break; + + default: + g_error ("unknown info type %d\n", gi_base_info_get_info_type (info)); + } + + gi_base_info_unref (info); + } + + xml_end_element (xml, "namespace"); + } + + xml_end_element (xml, "repository"); + + xml_free (xml); +} diff --git a/girepository/gisignalinfo.c b/girepository/gisignalinfo.c new file mode 100644 index 0000000..3a1b80c --- /dev/null +++ b/girepository/gisignalinfo.c @@ -0,0 +1,159 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Signal implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gisignalinfo.h" + +/** + * GISignalInfo: + * + * `GISignalInfo` represents a signal. + * + * It’s a sub-struct of [class@GIRepository.CallableInfo] and contains a set of + * flags and a class closure. + * + * See [class@GIRepository.CallableInfo] for information on how to retrieve + * arguments and other metadata from the signal. + * + * Since: 2.80 + */ + +/** + * gi_signal_info_get_flags: + * @info: a #GISignalInfo + * + * Obtain the flags for this signal info. + * + * See [flags@GObject.SignalFlags] for more information about possible flag + * values. + * + * Returns: the flags + * Since: 2.80 + */ +GSignalFlags +gi_signal_info_get_flags (GISignalInfo *info) +{ + GSignalFlags flags; + GIRealInfo *rinfo = (GIRealInfo *)info; + SignalBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_SIGNAL_INFO (info), 0); + + blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; + flags = 0; + + if (blob->run_first) + flags = flags | G_SIGNAL_RUN_FIRST; + + if (blob->run_last) + flags = flags | G_SIGNAL_RUN_LAST; + + if (blob->run_cleanup) + flags = flags | G_SIGNAL_RUN_CLEANUP; + + if (blob->no_recurse) + flags = flags | G_SIGNAL_NO_RECURSE; + + if (blob->detailed) + flags = flags | G_SIGNAL_DETAILED; + + if (blob->action) + flags = flags | G_SIGNAL_ACTION; + + if (blob->no_hooks) + flags = flags | G_SIGNAL_NO_HOOKS; + + return flags; +} + +/** + * gi_signal_info_get_class_closure: + * @info: a #GISignalInfo + * + * Obtain the class closure for this signal if one is set. + * + * The class closure is a virtual function on the type that the signal belongs + * to. If the signal lacks a closure, `NULL` will be returned. + * + * Returns: (transfer full) (nullable): the class closure, or `NULL` if none is + * set + * Since: 2.80 + */ +GIVFuncInfo * +gi_signal_info_get_class_closure (GISignalInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SignalBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_SIGNAL_INFO (info), 0); + + blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->has_class_closure) + return gi_interface_info_get_vfunc ((GIInterfaceInfo *)rinfo->container, blob->class_closure); + + return NULL; +} + +/** + * gi_signal_info_true_stops_emit: + * @info: a #GISignalInfo + * + * Obtain if the returning `TRUE` in the signal handler will stop the emission + * of the signal. + * + * Returns: `TRUE` if returning `TRUE` stops the signal emission + * Since: 2.80 + */ +gboolean +gi_signal_info_true_stops_emit (GISignalInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SignalBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_SIGNAL_INFO (info), 0); + + blob = (SignalBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->true_stops_emit; +} + +void +gi_signal_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_SIGNAL; +} diff --git a/girepository/gisignalinfo.h b/girepository/gisignalinfo.h new file mode 100644 index 0000000..705cc68 --- /dev/null +++ b/girepository/gisignalinfo.h @@ -0,0 +1,57 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Signal + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +G_BEGIN_DECLS + +/** + * GI_IS_SIGNAL_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.SignalInfo]. + * + * Since: 2.80 + */ +#define GI_IS_SIGNAL_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_SIGNAL) + + +GI_AVAILABLE_IN_ALL +GSignalFlags gi_signal_info_get_flags (GISignalInfo *info); + +GI_AVAILABLE_IN_ALL +GIVFuncInfo * gi_signal_info_get_class_closure (GISignalInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_signal_info_true_stops_emit (GISignalInfo *info); + +G_END_DECLS diff --git a/girepository/gistructinfo.c b/girepository/gistructinfo.c new file mode 100644 index 0000000..5955a08 --- /dev/null +++ b/girepository/gistructinfo.c @@ -0,0 +1,364 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Struct implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gistructinfo.h" + +/** + * GIStructInfo: + * + * `GIStructInfo` represents a generic C structure type. + * + * A structure has methods and fields. + * + * Since: 2.80 + */ + +/** + * gi_struct_info_get_n_fields: + * @info: a #GIStructInfo + * + * Obtain the number of fields this structure has. + * + * Returns: number of fields + * Since: 2.80 + */ +guint +gi_struct_info_get_n_fields (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_fields; +} + +/** + * gi_struct_info_get_field_offset: + * @info: a #GIStructInfo + * @n: index of queried field + * + * Obtain the offset of the specified field. + * + * Returns: field offset, in bytes + * Since: 2.80 + */ +static gint32 +gi_struct_get_field_offset (GIStructInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + guint32 offset = rinfo->offset + header->struct_blob_size; + FieldBlob *field_blob; + + for (guint i = 0; i < n; i++) + { + field_blob = (FieldBlob *)&rinfo->typelib->data[offset]; + offset += header->field_blob_size; + if (field_blob->has_embedded_type) + offset += header->callback_blob_size; + } + + return offset; +} + +/** + * gi_struct_info_get_field: + * @info: a #GIStructInfo + * @n: a field index + * + * Obtain the type information for field with specified index. + * + * Returns: (transfer full): The [class@GIRepository.FieldInfo]. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFieldInfo * +gi_struct_info_get_field (GIStructInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + return (GIFieldInfo *) gi_info_new (GI_INFO_TYPE_FIELD, (GIBaseInfo*)info, rinfo->typelib, + gi_struct_get_field_offset (info, n)); +} + +/** + * gi_struct_info_find_field: + * @info: a #GIStructInfo + * @name: a field name + * + * Obtain the type information for field named @name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.FieldInfo], or + * `NULL` if not found. Free it with [method@GIRepository.BaseInfo.unref] when + * done. + * Since: 2.80 + */ +GIFieldInfo * +gi_struct_info_find_field (GIStructInfo *info, + const gchar *name) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + Header *header = (Header *)rinfo->typelib->data; + guint32 offset = rinfo->offset + header->struct_blob_size; + gint i; + + for (i = 0; i < blob->n_fields; i++) + { + FieldBlob *field_blob = (FieldBlob *)&rinfo->typelib->data[offset]; + const gchar *fname = (const gchar *)&rinfo->typelib->data[field_blob->name]; + + if (strcmp (name, fname) == 0) + { + return (GIFieldInfo *) gi_info_new (GI_INFO_TYPE_FIELD, + (GIBaseInfo* )info, + rinfo->typelib, + offset); + } + + offset += header->field_blob_size; + if (field_blob->has_embedded_type) + offset += header->callback_blob_size; + } + + return NULL; +} + +/** + * gi_struct_info_get_n_methods: + * @info: a #GIStructInfo + * + * Obtain the number of methods this structure has. + * + * Returns: number of methods + * Since: 2.80 + */ +guint +gi_struct_info_get_n_methods (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_methods; +} + +/** + * gi_struct_info_get_method: + * @info: a #GIStructInfo + * @n: a method index + * + * Obtain the type information for method with specified index. + * + * Returns: (transfer full): The [class@GIRepository.FunctionInfo]. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_struct_info_get_method (GIStructInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + Header *header = (Header *)rinfo->typelib->data; + gint offset; + + offset = gi_struct_get_field_offset (info, blob->n_fields) + n * header->function_blob_size; + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_struct_info_find_method: + * @info: a #GIStructInfo + * @name: a method name + * + * Obtain the type information for method named @name. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.FunctionInfo], + * or `NULL` if none was found. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_struct_info_find_method (GIStructInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = gi_struct_get_field_offset (info, blob->n_fields); + return gi_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_methods, name); +} + +/** + * gi_struct_info_get_size: + * @info: a #GIStructInfo + * + * Obtain the total size of the structure. + * + * Returns: size of the structure, in bytes + * Since: 2.80 + */ +gsize +gi_struct_info_get_size (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->size; +} + +/** + * gi_struct_info_get_alignment: + * @info: a #GIStructInfo + * + * Obtain the required alignment of the structure. + * + * Returns: required alignment, in bytes + * Since: 2.80 + */ +gsize +gi_struct_info_get_alignment (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->alignment; +} + +/** + * gi_struct_info_is_foreign: + * @info: a #GIStructInfo + * + * Gets whether the structure is foreign, i.e. if it’s expected to be overridden + * by a native language binding instead of relying of introspected bindings. + * + * Returns: `TRUE` if the structure is foreign + * Since: 2.80 + */ +gboolean +gi_struct_info_is_foreign (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->foreign; +} + +/** + * gi_struct_info_is_gtype_struct: + * @info: a #GIStructInfo + * + * Return true if this structure represents the ‘class structure’ for some + * [class@GObject.Object] or `GInterface`. + * + * This function is mainly useful to hide this kind of structure from generated + * public APIs. + * + * Returns: `TRUE` if this is a class struct, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_struct_info_is_gtype_struct (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->is_gtype_struct; +} + +/** + * gi_struct_info_get_copy_function_name: + * @info: a struct information blob + * + * Retrieves the name of the copy function for @info, if any is set. + * + * Returns: (transfer none) (nullable): the name of the copy function, or `NULL` + * if the structure has no copy function + * Since: 2.80 + */ +const char * +gi_struct_info_get_copy_function_name (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_STRUCT_INFO (info), NULL); + + blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->copy_func) + return gi_typelib_get_string (rinfo->typelib, blob->copy_func); + + return NULL; +} + +/** + * gi_struct_info_get_free_function_name: + * @info: a struct information blob + * + * Retrieves the name of the free function for @info, if any is set. + * + * Returns: (transfer none) (nullable): the name of the free function, or `NULL` + * if the structure has no free function + * Since: 2.80 + */ +const char * +gi_struct_info_get_free_function_name (GIStructInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + StructBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_STRUCT_INFO (info), NULL); + + blob = (StructBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->free_func) + return gi_typelib_get_string (rinfo->typelib, blob->free_func); + + return NULL; +} + +void +gi_struct_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_STRUCT; +} diff --git a/girepository/gistructinfo.h b/girepository/gistructinfo.h new file mode 100644 index 0000000..21c8532 --- /dev/null +++ b/girepository/gistructinfo.h @@ -0,0 +1,87 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Struct + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_STRUCT_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.StructInfo]. + * + * Since: 2.80 + */ +#define GI_IS_STRUCT_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_STRUCT) + + +GI_AVAILABLE_IN_ALL +guint gi_struct_info_get_n_fields (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +GIFieldInfo * gi_struct_info_get_field (GIStructInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIFieldInfo * gi_struct_info_find_field (GIStructInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +guint gi_struct_info_get_n_methods (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_struct_info_get_method (GIStructInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_struct_info_find_method (GIStructInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +gsize gi_struct_info_get_size (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +gsize gi_struct_info_get_alignment (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_struct_info_is_gtype_struct (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_struct_info_is_foreign (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +const char * gi_struct_info_get_copy_function_name (GIStructInfo *info); + +GI_AVAILABLE_IN_ALL +const char * gi_struct_info_get_free_function_name (GIStructInfo *info); + +G_END_DECLS diff --git a/girepository/gitypeinfo.c b/girepository/gitypeinfo.c new file mode 100644 index 0000000..9ecdfa2 --- /dev/null +++ b/girepository/gitypeinfo.c @@ -0,0 +1,623 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Type implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "gitypeinfo.h" + +/** + * GITypeInfo: + * + * `GITypeInfo` represents a type, including information about direction and + * transfer. + * + * You can retrieve a type info from an argument (see + * [class@GIRepository.ArgInfo]), a function’s return value (see + * [class@GIRepository.FunctionInfo]), a field (see + * [class@GIRepository.FieldInfo]), a property (see + * [class@GIRepository.PropertyInfo]), a constant (see + * [class@GIRepository.ConstantInfo]) or for a union discriminator (see + * [class@GIRepository.UnionInfo]). + * + * A type can either be a of a basic type which is a standard C primitive + * type or an interface type. For interface types you need to call + * [method@GIRepository.TypeInfo.get_interface] to get a reference to the base + * info for that interface. + * + * Since: 2.80 + */ + +/** + * gi_type_info_is_pointer: + * @info: a #GITypeInfo + * + * Obtain if the type is passed as a reference. + * + * Note that the types of `GI_DIRECTION_OUT` and `GI_DIRECTION_INOUT` parameters + * will only be pointers if the underlying type being transferred is a pointer + * (i.e. only if the type of the C function’s formal parameter is a pointer to a + * pointer). + * + * Returns: `TRUE` if it is a pointer + * Since: 2.80 + */ +gboolean +gi_type_info_is_pointer (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), FALSE); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (type->flags.reserved == 0 && type->flags.reserved2 == 0) + return type->flags.pointer; + else + { + InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + return iface->pointer; + } +} + +/** + * gi_type_info_get_tag: + * @info: a #GITypeInfo + * + * Obtain the type tag for the type. + * + * See [type@GIRepository.TypeTag] for a list of type tags. + * + * Returns: the type tag + * Since: 2.80 + */ +GITypeTag +gi_type_info_get_tag (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, GI_TYPE_TAG_BOOLEAN); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), GI_TYPE_TAG_BOOLEAN); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (rinfo->type_is_embedded) + return GI_TYPE_TAG_INTERFACE; + else if (type->flags.reserved == 0 && type->flags.reserved2 == 0) + return type->flags.tag; + else + { + InterfaceTypeBlob *iface = (InterfaceTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + return iface->tag; + } +} + +/** + * gi_type_info_get_param_type: + * @info: a #GITypeInfo + * @n: index of the parameter + * + * Obtain the parameter type @n, or `NULL` if the type is not an array. + * + * Returns: (transfer full) (nullable): the param type info, or `NULL` if the + * type is not an array + * Since: 2.80 + */ +GITypeInfo * +gi_type_info_get_param_type (GITypeInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), NULL); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + ParamTypeBlob *param = (ParamTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + switch (param->tag) + { + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, + rinfo->offset + sizeof (ParamTypeBlob) + + sizeof (SimpleTypeBlob) * n); + break; + default: + break; + } + } + + return NULL; +} + +/** + * gi_type_info_get_interface: + * @info: a #GITypeInfo + * + * For types which have `GI_TYPE_TAG_INTERFACE` such as [class@GObject.Object]s + * and boxed values, this function returns full information about the referenced + * type. + * + * You can then inspect the type of the returned [class@GIRepository.BaseInfo] + * to further query whether it is a concrete [class@GObject.Object], an + * interface, a structure, etc., using + * [method@GIRepository.BaseInfo.get_info_type]. + * + * Returns: (transfer full) (nullable): The [class@GIRepository.BaseInfo], or + * `NULL`. Free it with gi_base_info_unref() when done. + * Since: 2.80 + */ +GIBaseInfo * +gi_type_info_get_interface (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), NULL); + + /* For embedded types, the given offset is a pointer to the actual blob, + * after the end of the field. In that case we know it's a "subclass" of + * CommonBlob, so use that to determine the info type. + */ + if (rinfo->type_is_embedded) + { + CommonBlob *common = (CommonBlob *)&rinfo->typelib->data[rinfo->offset]; + GIInfoType info_type; + + switch (common->blob_type) + { + case BLOB_TYPE_CALLBACK: + info_type = GI_INFO_TYPE_CALLBACK; + break; + default: + g_assert_not_reached (); + return NULL; + } + return (GIBaseInfo *) gi_info_new (info_type, (GIBaseInfo*)info, rinfo->typelib, + rinfo->offset); + } + else + { + SimpleTypeBlob *type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + InterfaceTypeBlob *blob = (InterfaceTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->tag == GI_TYPE_TAG_INTERFACE) + return gi_info_from_entry (rinfo->repository, rinfo->typelib, blob->interface); + } + } + + return NULL; +} + +/** + * gi_type_info_get_array_length_index: + * @info: a #GITypeInfo + * + * Obtain the position of the argument which gives the array length of the type. + * + * The type tag must be a `GI_TYPE_TAG_ARRAY` or `-1` will be returned. + * + * Returns: the array length argument index, or `-1` if the type is not an array + * or it has no length argument + * Since: 2.80 + */ +gint +gi_type_info_get_array_length_index (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), -1); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->tag == GI_TYPE_TAG_ARRAY) + { + if (blob->has_length) + return blob->dimensions.length; + } + } + + return -1; +} + +/** + * gi_type_info_get_array_fixed_size: + * @info: a #GITypeInfo + * + * Obtain the fixed array size of the type, in number of elements (not bytes). + * + * The type tag must be a `GI_TYPE_TAG_ARRAY` or `-1` will be returned. + * + * Returns: the size or `-1` if the type is not an array or it has no fixed size + * Since: 2.80 + */ +gssize +gi_type_info_get_array_fixed_size (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), -1); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->tag == GI_TYPE_TAG_ARRAY) + { + if (blob->has_size) + return blob->dimensions.size; + } + } + + return -1; +} + +/** + * gi_type_info_is_zero_terminated: + * @info: a #GITypeInfo + * + * Obtain if the last element of the array is `NULL`. + * + * The type tag must be a `GI_TYPE_TAG_ARRAY` or `FALSE` will be returned. + * + * Returns: `TRUE` if zero terminated + * Since: 2.80 + */ +gboolean +gi_type_info_is_zero_terminated (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), FALSE); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->tag == GI_TYPE_TAG_ARRAY) + return blob->zero_terminated; + } + + return FALSE; +} + +/** + * gi_type_info_get_array_type: + * @info: a #GITypeInfo + * + * Obtain the array type for this type. + * + * See [enum@GIRepository.ArrayType] for a list of possible values. If the type + * tag of this type is not array, `-1` will be returned. + * + * Returns: the array type or `-1` + * Since: 2.80 + */ +GIArrayType +gi_type_info_get_array_type (GITypeInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + SimpleTypeBlob *type; + + g_return_val_if_fail (info != NULL, -1); + g_return_val_if_fail (GI_IS_TYPE_INFO (info), -1); + + type = (SimpleTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (!(type->flags.reserved == 0 && type->flags.reserved2 == 0)) + { + ArrayTypeBlob *blob = (ArrayTypeBlob *)&rinfo->typelib->data[rinfo->offset]; + g_return_val_if_fail (blob->tag == GI_TYPE_TAG_ARRAY, -1); + + return blob->array_type; + } + + return -1; +} + +/** + * gi_type_info_get_storage_type: + * @info: a #GITypeInfo + * + * Obtain the type tag corresponding to the underlying storage type in C for + * the type. + * + * See [type@GIRepository.TypeTag] for a list of type tags. + * + * Returns: the type tag + * Since: 2.80 + */ +GITypeTag +gi_type_info_get_storage_type (GITypeInfo *info) +{ + GITypeTag type_tag = gi_type_info_get_tag (info); + + if (type_tag == GI_TYPE_TAG_INTERFACE) + { + GIBaseInfo *interface = gi_type_info_get_interface (info); + GIInfoType info_type = gi_base_info_get_info_type (interface); + if (info_type == GI_INFO_TYPE_ENUM || info_type == GI_INFO_TYPE_FLAGS) + type_tag = gi_enum_info_get_storage_type ((GIEnumInfo *) interface); + gi_base_info_unref (interface); + } + + return type_tag; +} + +/** + * gi_type_tag_argument_from_hash_pointer: + * @storage_type: a [type@GIRepository.TypeTag] obtained from + * [method@GIRepository.TypeInfo.get_storage_type] + * @hash_pointer: a pointer, such as a [struct@GLib.HashTable] data pointer + * @arg: (out caller-allocates) (not nullable): a [type@GIRepository.Argument] + * to fill in + * + * Convert a data pointer from a GLib data structure to a + * [type@GIRepository.Argument]. + * + * GLib data structures, such as [type@GLib.List], [type@GLib.SList], and + * [type@GLib.HashTable], all store data pointers. + * + * In the case where the list or hash table is storing single types rather than + * structs, these data pointers may have values stuffed into them via macros + * such as `GPOINTER_TO_INT`. + * + * Use this function to ensure that all values are correctly extracted from + * stuffed pointers, regardless of the machine’s architecture or endianness. + * + * This function fills in the appropriate field of @arg with the value extracted + * from @hash_pointer, depending on @storage_type. + * + * Since: 2.80 + */ +void +gi_type_tag_argument_from_hash_pointer (GITypeTag storage_type, + gpointer hash_pointer, + GIArgument *arg) +{ + switch (storage_type) + { + case GI_TYPE_TAG_BOOLEAN: + arg->v_boolean = !!GPOINTER_TO_INT (hash_pointer); + break; + case GI_TYPE_TAG_INT8: + arg->v_int8 = (gint8)GPOINTER_TO_INT (hash_pointer); + break; + case GI_TYPE_TAG_UINT8: + arg->v_uint8 = (guint8)GPOINTER_TO_UINT (hash_pointer); + break; + case GI_TYPE_TAG_INT16: + arg->v_int16 = (gint16)GPOINTER_TO_INT (hash_pointer); + break; + case GI_TYPE_TAG_UINT16: + arg->v_uint16 = (guint16)GPOINTER_TO_UINT (hash_pointer); + break; + case GI_TYPE_TAG_INT32: + arg->v_int32 = (gint32)GPOINTER_TO_INT (hash_pointer); + break; + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UNICHAR: + arg->v_uint32 = (guint32)GPOINTER_TO_UINT (hash_pointer); + break; + case GI_TYPE_TAG_GTYPE: + arg->v_size = GPOINTER_TO_SIZE (hash_pointer); + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + arg->v_pointer = hash_pointer; + break; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + default: + g_critical ("Unsupported storage type for pointer-stuffing: %s", + gi_type_tag_to_string (storage_type)); + arg->v_pointer = hash_pointer; + } +} + +/** + * gi_type_info_argument_from_hash_pointer: + * @info: a #GITypeInfo + * @hash_pointer: a pointer, such as a [struct@GLib.HashTable] data pointer + * @arg: (out caller-allocates): a [type@GIRepository.Argument] to fill in + * + * Convert a data pointer from a GLib data structure to a + * [type@GIRepository.Argument]. + * + * GLib data structures, such as [type@GLib.List], [type@GLib.SList], and + * [type@GLib.HashTable], all store data pointers. + * + * In the case where the list or hash table is storing single types rather than + * structs, these data pointers may have values stuffed into them via macros + * such as `GPOINTER_TO_INT`. + * + * Use this function to ensure that all values are correctly extracted from + * stuffed pointers, regardless of the machine’s architecture or endianness. + * + * This function fills in the appropriate field of @arg with the value extracted + * from @hash_pointer, depending on the storage type of @info. + * + * Since: 2.80 + */ +void +gi_type_info_argument_from_hash_pointer (GITypeInfo *info, + gpointer hash_pointer, + GIArgument *arg) +{ + GITypeTag storage_type = gi_type_info_get_storage_type (info); + gi_type_tag_argument_from_hash_pointer (storage_type, hash_pointer, + arg); +} + +/** + * gi_type_tag_hash_pointer_from_argument: + * @storage_type: a [type@GIRepository.TypeTag] obtained from + * [method@GIRepository.TypeInfo.get_storage_type] + * @arg: a [type@GIRepository.Argument] with the value to stuff into a pointer + * + * Convert a [type@GIRepository.Argument] to data pointer for use in a GLib + * data structure. + * + * GLib data structures, such as [type@GLib.List], [type@GLib.SList], and + * [type@GLib.HashTable], all store data pointers. + * + * In the case where the list or hash table is storing single types rather than + * structs, these data pointers may have values stuffed into them via macros + * such as `GPOINTER_TO_INT`. + * + * Use this function to ensure that all values are correctly stuffed into + * pointers, regardless of the machine’s architecture or endianness. + * + * This function returns a pointer stuffed with the appropriate field of @arg, + * depending on @storage_type. + * + * Returns: A stuffed pointer, that can be stored in a [struct@GLib.HashTable], + * for example + * Since: 2.80 + */ +gpointer +gi_type_tag_hash_pointer_from_argument (GITypeTag storage_type, + GIArgument *arg) +{ + switch (storage_type) + { + case GI_TYPE_TAG_BOOLEAN: + return GINT_TO_POINTER (arg->v_boolean); + case GI_TYPE_TAG_INT8: + return GINT_TO_POINTER (arg->v_int8); + case GI_TYPE_TAG_UINT8: + return GUINT_TO_POINTER (arg->v_uint8); + case GI_TYPE_TAG_INT16: + return GINT_TO_POINTER (arg->v_int16); + case GI_TYPE_TAG_UINT16: + return GUINT_TO_POINTER (arg->v_uint16); + case GI_TYPE_TAG_INT32: + return GINT_TO_POINTER (arg->v_int32); + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_UNICHAR: + return GUINT_TO_POINTER (arg->v_uint32); + case GI_TYPE_TAG_GTYPE: + return GSIZE_TO_POINTER (arg->v_size); + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + return arg->v_pointer; + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + default: + g_critical ("Unsupported storage type for pointer-stuffing: %s", + gi_type_tag_to_string (storage_type)); + return arg->v_pointer; + } +} + +/** + * gi_type_info_hash_pointer_from_argument: + * @info: a #GITypeInfo + * @arg: a [struct@GIRepository.Argument] with the value to stuff into a pointer + * + * Convert a [type@GIRepository.Argument] to data pointer for use in a GLib + * data structure. + * + * GLib data structures, such as [type@GLib.List], [type@GLib.SList], and + * [type@GLib.HashTable], all store data pointers. + * + * In the case where the list or hash table is storing single types rather than + * structs, these data pointers may have values stuffed into them via macros + * such as `GPOINTER_TO_INT`. + * + * Use this function to ensure that all values are correctly stuffed into + * pointers, regardless of the machine’s architecture or endianness. + * + * This function returns a pointer stuffed with the appropriate field of @arg, + * depending on the storage type of @info. + * + * Returns: A stuffed pointer, that can be stored in a [struct@GLib.HashTable], + * for example + * Since: 2.80 + */ +gpointer +gi_type_info_hash_pointer_from_argument (GITypeInfo *info, + GIArgument *arg) +{ + GITypeTag storage_type = gi_type_info_get_storage_type (info); + return gi_type_tag_hash_pointer_from_argument (storage_type, arg); +} + +void +gi_type_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_TYPE; +} diff --git a/girepository/gitypeinfo.h b/girepository/gitypeinfo.h new file mode 100644 index 0000000..7076fdf --- /dev/null +++ b/girepository/gitypeinfo.h @@ -0,0 +1,131 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Type + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_TYPE_INFO: + * @info: an info structure + * + * Checks if @info is a [alias@GIRepository.TypeInfo]. + * + * Since: 2.80 + */ +#define GI_IS_TYPE_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_TYPE) + +/** + * GI_TYPE_TAG_IS_BASIC: + * @tag: a type tag + * + * Checks if @tag is a basic type. + * + * Since: 2.80 + */ +#define GI_TYPE_TAG_IS_BASIC(tag) ((tag) < GI_TYPE_TAG_ARRAY || (tag) == GI_TYPE_TAG_UNICHAR) + +/** + * GI_TYPE_TAG_IS_NUMERIC: + * @tag: a type tag + * + * Checks if @tag is a numeric type. That is, integer or floating point. + * + * Since: 2.80 + */ +#define GI_TYPE_TAG_IS_NUMERIC(tag) ((tag) >= GI_TYPE_TAG_INT8 && (tag) <= GI_TYPE_TAG_DOUBLE) + +/** + * GI_TYPE_TAG_IS_CONTAINER: + * @tag: a type tag + * + * Checks if @tag is a container type. That is, a type which may have a nonnull + * return from [method@GIRepository.TypeInfo.get_param_type]. + * + * Since: 2.80 + */ + #define GI_TYPE_TAG_IS_CONTAINER(tag) ((tag) == GI_TYPE_TAG_ARRAY || \ + ((tag) >= GI_TYPE_TAG_GLIST && (tag) <= GI_TYPE_TAG_GHASH)) + +GI_AVAILABLE_IN_ALL +const gchar* gi_type_tag_to_string (GITypeTag type); + +GI_AVAILABLE_IN_ALL +const gchar* gi_info_type_to_string (GIInfoType type); + + +GI_AVAILABLE_IN_ALL +gboolean gi_type_info_is_pointer (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeTag gi_type_info_get_tag (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_type_info_get_param_type (GITypeInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIBaseInfo * gi_type_info_get_interface (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +gint gi_type_info_get_array_length_index (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +gssize gi_type_info_get_array_fixed_size (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +gboolean gi_type_info_is_zero_terminated (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +GIArrayType gi_type_info_get_array_type (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeTag gi_type_info_get_storage_type (GITypeInfo *info); + +GI_AVAILABLE_IN_ALL +void gi_type_info_argument_from_hash_pointer (GITypeInfo *info, + gpointer hash_pointer, + GIArgument *arg); + +GI_AVAILABLE_IN_ALL +gpointer gi_type_info_hash_pointer_from_argument (GITypeInfo *info, + GIArgument *arg); + +GI_AVAILABLE_IN_ALL +void gi_type_tag_argument_from_hash_pointer (GITypeTag storage_type, + gpointer hash_pointer, + GIArgument *arg); + +GI_AVAILABLE_IN_ALL +gpointer gi_type_tag_hash_pointer_from_argument (GITypeTag storage_type, + GIArgument *arg); + +G_END_DECLS diff --git a/girepository/gitypelib-internal.h b/girepository/gitypelib-internal.h new file mode 100644 index 0000000..a83f1ae --- /dev/null +++ b/girepository/gitypelib-internal.h @@ -0,0 +1,1422 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: struct definitions for the binary + * typelib format, validation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#include +#include "girepository.h" + +G_BEGIN_DECLS + +/** + * SECTION:gitypelib-internal + * @title: GITypelib Internals + * @short_description: Layout and accessors for typelib + * @stability: Stable + * + * The ‘typelib’ is a binary, readonly, memory-mappable database + * containing reflective information about a GObject library. + * + * What the typelib describes and the types used are the same for every + * platform so, apart the endianness of its scalar values, the typelib + * database must be considered architecture-independent. + * + * The format of GObject typelib is strongly influenced by the Mozilla XPCOM + * format. + * + * Some of the differences to XPCOM include: + * + * - Type information is stored not quite as compactly (XPCOM stores it inline + * in function descriptions in variable-sized blobs of 1 to n bytes. We store + * 16 bits of type information for each parameter, which is enough to encode + * simple types inline. Complex (e.g. recursive) types are stored out of line + * in a separate list of types. + * - String and complex type data is stored outside of typelib entry blobs, + * references are stored as offsets relative to the start of the typelib. + * One possibility is to store the strings and types in a pools at the end + * of the typelib. + * + * The typelib has the following general format: + * + * ``` + * typelib ::= header, section-index, directory, blobs, attributes, attributedata + * + * directory ::= list of entries + * + * entry ::= blob type, name, namespace, offset + * blob ::= function|callback|struct|boxed|enum|flags|object|interface|constant|union + * attribute ::= offset, key, value + * attributedata ::= string data for attributes + * ``` + * + * ## Details + * + * We describe the fragments that make up the typelib in the form of C structs + * (although some fall short of being valid C structs since they contain + * multiple flexible arrays). + * + * Since: 2.80 + */ + +/* +TYPELIB HISTORY +----- + +Version 1.1 +- Add ref/unref/set-value/get-value functions to Object, to be able + to support instantiatable fundamental types which are not GObject based. + +Version 1.0 +- Rename class_struct to gtype_struct, add to interfaces + +Changes since 0.9: +- Add padding to structures + +Changes since 0.8: +- Add class struct concept to ObjectBlob +- Add is_class_struct bit to StructBlob + +Changes since 0.7: +- Add dependencies + +Changes since 0.6: +- rename metadata to typelib, to follow xpcom terminology + +Changes since 0.5: +- basic type cleanup: + + remove GString + + add [u]int, [u]long, [s]size_t + + rename string to utf8, add filename +- allow blob_type to be zero for non-local entries + +Changes since 0.4: +- add a UnionBlob + +Changes since 0.3: +- drop short_name for ValueBlob + +Changes since 0.2: +- make inline types 4 bytes after all, remove header->types and allow + types to appear anywhere +- allow error domains in the directory + +Changes since 0.1: + +- drop comments about _GOBJ_METADATA +- drop string pool, strings can appear anywhere +- use 'blob' as collective name for the various blob types +- rename 'type' field in blobs to 'blob_type' +- rename 'type_name' and 'type_init' fields to 'gtype_name', 'gtype_init' +- shrink directory entries to 12 bytes +- merge struct and boxed blobs +- split interface blobs into enum, object and interface blobs +- add an 'unregistered' flag to struct and enum blobs +- add a 'wraps_vfunc' flag to function blobs and link them to + the vfuncs they wrap +- restrict value blobs to only occur inside enums and flags again +- add constant blobs, allow them toplevel, in interfaces and in objects +- rename 'receiver_owns_value' and 'receiver_owns_container' to + 'transfer_ownership' and 'transfer_container_ownership' +- add a 'struct_offset' field to virtual function and field blobs +- add 'dipper' and 'optional' flags to arg blobs +- add a 'true_stops_emit' flag to signal blobs +- add variable blob sizes to header +- store offsets to signature blobs instead of including them directly +- change the type offset to be measured in words rather than bytes +*/ + +/** + * GI_IR_MAGIC: + * + * Identifying prefix for the typelib. + * + * This was inspired by XPCOM, which in turn borrowed from PNG. + * + * Since: 2.80 + */ +#define GI_IR_MAGIC "GOBJ\nMETADATA\r\n\032" + +/** + * GITypelibBlobType: + * @BLOB_TYPE_INVALID: Should not appear in code + * @BLOB_TYPE_FUNCTION: A #FunctionBlob + * @BLOB_TYPE_CALLBACK: A #CallbackBlob + * @BLOB_TYPE_STRUCT: A #StructBlob + * @BLOB_TYPE_BOXED: Can be either a #StructBlob or #UnionBlob + * @BLOB_TYPE_ENUM: An #EnumBlob + * @BLOB_TYPE_FLAGS: An #EnumBlob + * @BLOB_TYPE_OBJECT: An #ObjectBlob + * @BLOB_TYPE_INTERFACE: An #InterfaceBlob + * @BLOB_TYPE_CONSTANT: A #ConstantBlob + * @BLOB_TYPE_INVALID_0: Deleted, used to be ErrorDomain. + * @BLOB_TYPE_UNION: A #UnionBlob + * + * The integral value of this enumeration appears in each "Blob" component of + * a typelib to identify its type. + * + * Since: 2.80 + */ +typedef enum { + BLOB_TYPE_INVALID, + BLOB_TYPE_FUNCTION, + BLOB_TYPE_CALLBACK, + BLOB_TYPE_STRUCT, + BLOB_TYPE_BOXED, + BLOB_TYPE_ENUM, + BLOB_TYPE_FLAGS, + BLOB_TYPE_OBJECT, + BLOB_TYPE_INTERFACE, + BLOB_TYPE_CONSTANT, + BLOB_TYPE_INVALID_0, + BLOB_TYPE_UNION +} GITypelibBlobType; + + +#if defined (G_CAN_INLINE) && defined (G_ALWAYS_INLINE) + +G_ALWAYS_INLINE +inline gboolean +_blob_is_registered_type (GITypelibBlobType blob_type) +{ + switch (blob_type) + { + case BLOB_TYPE_STRUCT: + case BLOB_TYPE_UNION: + case BLOB_TYPE_ENUM: + case BLOB_TYPE_FLAGS: + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + return TRUE; + default: + return FALSE; + } +} + +#define BLOB_IS_REGISTERED_TYPE(blob) \ + _blob_is_registered_type ((GITypelibBlobType) (blob)->blob_type) + +#else + +#define BLOB_IS_REGISTERED_TYPE(blob) \ + ((blob)->blob_type == BLOB_TYPE_STRUCT || \ + (blob)->blob_type == BLOB_TYPE_UNION || \ + (blob)->blob_type == BLOB_TYPE_ENUM || \ + (blob)->blob_type == BLOB_TYPE_FLAGS || \ + (blob)->blob_type == BLOB_TYPE_OBJECT || \ + (blob)->blob_type == BLOB_TYPE_INTERFACE) + +#endif /* defined (G_CAN_INLINE) && defined (G_ALWAYS_INLINE) */ + +/** + * Header: + * @magic: See #GI_IR_MAGIC. + * @major_version: The major version number of the typelib format. Major version + * number changes indicate incompatible changes to the tyeplib format. + * @minor_version: The minor version number of the typelib format. Minor version + * number changes indicate compatible changes and should still allow the + * typelib to be parsed by a parser designed for the same @major_version. + * @reserved: Reserved for future use. + * @n_entries: The number of entries in the directory. + * @n_local_entries: The number of entries referring to blobs in this typelib. + * The local entries must occur before the unresolved entries. + * @directory: Offset of the directory in the typelib. + * @n_attributes: Number of attribute blocks + * @attributes: Offset of the list of attributes in the typelib. + * @dependencies: Offset of a single string, which is the list of immediate + * dependencies, separated by the '|' character. The dependencies are + * required in order to avoid having programs consuming a typelib check for + * an "Unresolved" type return from every API call. + * @size: The size in bytes of the typelib. + * @namespace: Offset of the namespace string in the typelib. + * @nsversion: Offset of the namespace version string in the typelib. + * @shared_library: This field is the set of shared libraries associated with + * the typelib. The entries are separated by the '|' (pipe) character. + * @c_prefix: The prefix for the function names of the library + * @entry_blob_size: The sizes of fixed-size blobs. Recording this information + * here allows to write parser which continue to work if the format is + * extended by adding new fields to the end of the fixed-size blobs. + * @function_blob_size: See @entry_blob_size. + * @callback_blob_size: See @entry_blob_size. + * @signal_blob_size: See @entry_blob_size. + * @vfunc_blob_size: See @entry_blob_size. + * @arg_blob_size: See @entry_blob_size. + * @property_blob_size: See @entry_blob_size. + * @field_blob_size: See @entry_blob_size. + * @value_blob_size: See @entry_blob_size. + * @attribute_blob_size: See @entry_blob_size. + * @constant_blob_size: See @entry_blob_size. + * @error_domain_blob_size: See @entry_blob_size. + * @signature_blob_size: See @entry_blob_size. + * @enum_blob_size: See @entry_blob_size. + * @struct_blob_size: See @entry_blob_size. + * @object_blob_size: See @entry_blob_size. + * @interface_blob_size: For variable-size blobs, the size of the struct up to + * the first flexible array member. Recording this information here allows + * to write parser which continue to work if the format is extended by + * adding new fields before the first flexible array member in + * variable-size blobs. + * @union_blob_size: See @entry_blob_size. + * @sections: Offset of section blob array + * @padding: TODO + * + * The header structure appears exactly once at the beginning of a typelib. It is a + * collection of meta-information, such as the number of entries and dependencies. + * + * Since: 2.80 + */ +typedef struct { + gchar magic[16]; + guint8 major_version; + guint8 minor_version; + guint16 reserved; + guint16 n_entries; + guint16 n_local_entries; + guint32 directory; + guint32 n_attributes; + guint32 attributes; + + guint32 dependencies; + + guint32 size; + guint32 namespace; + guint32 nsversion; + guint32 shared_library; + guint32 c_prefix; + + guint16 entry_blob_size; + guint16 function_blob_size; + guint16 callback_blob_size; + guint16 signal_blob_size; + guint16 vfunc_blob_size; + guint16 arg_blob_size; + guint16 property_blob_size; + guint16 field_blob_size; + guint16 value_blob_size; + guint16 attribute_blob_size; + guint16 constant_blob_size; + guint16 error_domain_blob_size; + + guint16 signature_blob_size; + guint16 enum_blob_size; + guint16 struct_blob_size; + guint16 object_blob_size; + guint16 interface_blob_size; + guint16 union_blob_size; + + guint32 sections; + + guint16 padding[6]; +} Header; + +/** + * SectionType: + * @GI_SECTION_END: TODO + * @GI_SECTION_DIRECTORY_INDEX: TODO + * + * TODO + * + * Since: 2.80 + */ +typedef enum { + GI_SECTION_END = 0, + GI_SECTION_DIRECTORY_INDEX = 1 +} SectionType; + +/** + * Section: + * @id: A #SectionType + * @offset: Integer offset for this section + * + * A section is a blob of data that's (at least theoretically) optional, + * and may or may not be present in the typelib. Presently, just used + * for the directory index. This allows a form of dynamic extensibility + * with different tradeoffs from the format minor version. + * + * Since: 2.80 + */ +typedef struct { + guint32 id; + guint32 offset; +} Section; + + +/** + * DirEntry: + * @blob_type: A #GITypelibBlobType + * @local: Whether this entry refers to a blob in this typelib. + * @reserved: Reserved for future use. + * @name: The name of the entry. + * @offset: If is_local is set, this is the offset of the blob in the typelib. + * Otherwise, it is the offset of the namespace in which the blob has to be + * looked up by name. + * + * References to directory entries are stored as 1-based 16-bit indexes. + * + * All blobs pointed to by a directory entry start with the same layout for + * the first 8 bytes (the reserved flags may be used by some blob types) + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + + guint16 local : 1; + guint16 reserved :15; + guint32 name; + guint32 offset; +} DirEntry; + +/** + * SimpleTypeBlobFlags: + * @reserved: Reserved for future use. + * @reserved2: Reserved for future use. + * @pointer: TODO + * @reserved3: Reserved for future use. + * @tag: A #GITypeTag + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint reserved : 8; + guint reserved2 :16; + guint pointer : 1; + guint reserved3 : 2; + guint tag : 5; +} SimpleTypeBlobFlags; + +union _SimpleTypeBlob +{ + SimpleTypeBlobFlags flags; + guint32 offset; +}; + +/** + * SimpleTypeBlob: + * @flags: TODO + * @offset: Offset relative to header->types that points to a TypeBlob. + * Unlike other offsets, this is in words (ie 32bit units) rather + * than bytes. + * + * The SimpleTypeBlob is the general purpose "reference to a type" construct, + * used in method parameters, returns, callback definitions, fields, constants, + * etc. It's actually just a 32 bit integer which you can see from the union + * definition. This is for efficiency reasons, since there are so many + * references to types. + * + * SimpleTypeBlob is divided into two cases; first, if "reserved" and + * "reserved2" are both zero, the type tag for a basic type is embedded in the + * "tag" bits. This allows e.g. GI_TYPE_TAG_UTF8, GI_TYPE_TAG_INT and the like + * to be embedded directly without taking up extra space. + * + * References to "interfaces" (objects, interfaces) are more complicated; + * In this case, the integer is actually an offset into the directory (see + * above). Because the header is larger than 2^8=256 bits, all offsets will + * have one of the upper 24 bits set. + * + * Since: 2.80 + */ +typedef union _SimpleTypeBlob SimpleTypeBlob; + +/** + * ArgBlob: + * @name: A suggested name for the parameter. + * @in: The parameter is an input to the function + * @out: The parameter is used to return an output of the function. Parameters + * can be both in and out. Out parameters implicitly add another level of + * indirection to the parameter type. Ie if the type is uint32 in an out + * parameter, the function actually takes an uint32*. + * @caller_allocates: The parameter is a pointer to a struct or object that + * will receive an output of the function. + * @nullable: Only meaningful for types which are passed as pointers. For an + * in parameter, indicates if it is ok to pass NULL in. Gor an out + * parameter, indicates whether it may return NULL. Note that NULL is a + * valid GList and GSList value, thus allow_none will normally be set + * for parameters of these types. + * @optional: For an out parameter, indicates that NULL may be passed in + * if the value is not needed. + * @transfer_ownership: For an in parameter, indicates that the function takes + * over ownership of the parameter value. For an out parameter, it indicates + * that the caller is responsible for freeing the return value. + * @transfer_container_ownership: For container types, indicates that the + * ownership of the container, but not of its contents is transferred. + * This is typically the case for out parameters returning lists of + * statically allocated things. + * @return_value: The parameter should be considered the return value of the + * function. Only out parameters can be marked as return value, and there + * can be at most one per function call. If an out parameter is marked as + * return value, the actual return value of the function should be either + * void or a boolean indicating the success of the call. + * @scope: A #GIScopeType. If the parameter is of a callback type, this denotes + * the scope of the user_data and the callback function pointer itself + * (for languages that emit code at run-time). + * @skip: Indicates that the parameter is only useful in C and should be skipped. + * @reserved: Reserved for future use. + * @closure: Index of the closure (user_data) parameter associated with the + * callback, or -1. + * @destroy: Index of the destroy notfication callback parameter associated + * with the callback, or -1. + * @padding: TODO + * @arg_type: Describes the type of the parameter. See details below. + * + * Types are specified by four bytes. If the three high bytes are zero, + * the low byte describes a basic type, otherwise the 32bit number is an + * offset which points to a TypeBlob. + * + * Since: 2.80 + */ +typedef struct { + guint32 name; + + guint in : 1; + guint out : 1; + guint caller_allocates : 1; + guint nullable : 1; + guint optional : 1; + guint transfer_ownership : 1; + guint transfer_container_ownership : 1; + guint return_value : 1; + guint scope : 3; + guint skip : 1; + guint reserved :20; + gint8 closure; + gint8 destroy; + + guint16 padding; + + SimpleTypeBlob arg_type; +} ArgBlob; + +/** + * SignatureBlob: + * @return_type: Describes the type of the return value. See details below. + * @may_return_null: Only relevant for pointer types. Indicates whether the + * caller must expect NULL as a return value. + * @caller_owns_return_value: If set, the caller is responsible for freeing + * the return value if it is no longer needed. + * @caller_owns_return_container: This flag is only relevant if the return type + * is a container type. If the flag is set, the caller is resonsible for + * freeing the container, but not its contents. + * @skip_return: Indicates that the return value is only useful in C and should + * be skipped. + * @instance_transfer_ownership: When calling, the function assumes ownership of + * the instance parameter. + * @throws: Denotes the signature takes an additional #GError argument beyond + * the annotated arguments. + * @reserved: Reserved for future use. + * @n_arguments: The number of arguments that this function expects, also the + * length of the array of ArgBlobs. + * @arguments: An array of ArgBlob for the arguments of the function. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + SimpleTypeBlob return_type; + + guint16 may_return_null : 1; + guint16 caller_owns_return_value : 1; + guint16 caller_owns_return_container : 1; + guint16 skip_return : 1; + guint16 instance_transfer_ownership : 1; + guint16 throws : 1; + guint16 reserved :10; + + guint16 n_arguments; + + ArgBlob arguments[]; +} SignatureBlob; + +/** + * CommonBlob: + * @blob_type: A #GITypelibBlobType + * @deprecated: Whether the blob is deprecated. + * @reserved: Reserved for future use. + * @name: The name of the blob. + * + * The #CommonBlob is shared between #FunctionBlob, + * #CallbackBlob, #SignalBlob. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; /* 1 */ + + guint16 deprecated : 1; + guint16 reserved :15; + guint32 name; +} CommonBlob; + +/** + * FunctionBlob: + * @blob_type: #BLOB_TYPE_FUNCTION + * @deprecated: The function is deprecated. + * @setter: The function is a setter for a property. Language bindings may + * prefer to not bind individual setters and rely on the generic + * g_object_set(). + * @getter: The function is a getter for a property. Language bindings may + * prefer to not bind individual getters and rely on the generic + * g_object_get(). + * @constructor: The function acts as a constructor for the object it is + * contained in. + * @wraps_vfunc: The function is a simple wrapper for a virtual function. + * @throws: This is now additionally stored in the #SignatureBlob. (deprecated) + * @index: Index of the property that this function is a setter or getter of + * in the array of properties of the containing interface, or index + * of the virtual function that this function wraps. + * @name: TODO + * @symbol: The symbol which can be used to obtain the function pointer with + * dlsym(). + * @signature: Offset of the SignatureBlob describing the parameter types and the + * return value type. + * @is_static: The function is a "static method"; in other words it's a pure + * function whose name is conceptually scoped to the object. + * @reserved: Reserved for future use. + * @reserved2: Reserved for future use. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; /* 1 */ + + guint16 deprecated : 1; + guint16 setter : 1; + guint16 getter : 1; + guint16 constructor : 1; + guint16 wraps_vfunc : 1; + guint16 throws : 1; + guint16 index :10; + /* Note the bits above need to match CommonBlob + * and are thus exhausted, extend things using + * the reserved block below. */ + + guint32 name; + guint32 symbol; + guint32 signature; + + guint16 is_static : 1; + guint16 reserved : 15; + guint16 reserved2 : 16; +} FunctionBlob; + +/** + * CallbackBlob: + * @blob_type: TODO + * @deprecated: TODO + * @reserved: Reserved for future use. + * @name: TODO + * @signature: Offset of the #SignatureBlob describing the parameter types and + * the return value type. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; /* 2 */ + + guint16 deprecated : 1; + guint16 reserved :15; + guint32 name; + guint32 signature; +} CallbackBlob; + +/** + * InterfaceTypeBlob: + * @pointer: Whether this type represents an indirection + * @reserved: Reserved for future use. + * @tag: A #GITypeTag + * @reserved2: Reserved for future use. + * @interface: Index of the directory entry for the interface. + * + * If the interface is an enum of flags type, is_pointer is 0, otherwise it is 1. + * + * Since: 2.80 + */ +typedef struct { + guint8 pointer :1; + guint8 reserved :2; + guint8 tag :5; + guint8 reserved2; + guint16 interface; +} InterfaceTypeBlob; + +/** + * ArrayTypeDimension: + * @length: TODO + * @size: TODO + * + * TODO + * + * Since: 2.80 + */ +typedef union { + guint16 length; + guint16 size; +} ArrayTypeDimension; + +/** + * ArrayTypeBlob: + * @pointer: TODO + * @reserved: Reserved for future use. + * @tag: TODO + * @zero_terminated: Indicates that the array must be terminated by a suitable + * #NULL value. + * @has_length: Indicates that length points to a parameter specifying the + * length of the array. If both has_length and zero_terminated are set, the + * convention is to pass -1 for the length if the array is zero-terminated. + * @has_size: Indicates that size is the fixed size of the array. + * @array_type: Indicates whether this is a C array, GArray, GPtrArray, or + * GByteArray. If something other than a C array, the length and element + * size are implicit in the structure. + * @reserved2: Reserved for future use. + * @dimensions: TODO + * @type: TODO + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 pointer :1; + guint16 reserved :2; + guint16 tag :5; + + guint16 zero_terminated :1; + guint16 has_length :1; + guint16 has_size :1; + guint16 array_type :2; + guint16 reserved2 :3; + + ArrayTypeDimension dimensions; + + SimpleTypeBlob type; +} ArrayTypeBlob; + +/** + * ParamTypeBlob: + * @pointer: TODO + * @reserved: Reserved for future use. + * @tag: TODO + * @reserved2: Reserved for future use. + * @n_types: The number of parameter types to follow. + * @type: Describes the type of the list elements. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint8 pointer :1; + guint8 reserved :2; + guint8 tag :5; + + guint8 reserved2; + guint16 n_types; + + SimpleTypeBlob type[]; +} ParamTypeBlob; + +/** + * ErrorTypeBlob: + * @pointer: TODO + * @reserved: TODO + * @tag: TODO + * @reserved2: TODO + * @n_domains: TODO: must be 0 + * @domains: TODO + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint8 pointer :1; + guint8 reserved :2; + guint8 tag :5; + + guint8 reserved2; + + guint16 n_domains; /* Must be 0 */ + guint16 domains[]; +} ErrorTypeBlob; + +/** + * ValueBlob: + * @deprecated: Whether this value is deprecated + * @unsigned_value: if set, value is a 32-bit unsigned integer cast to gint32 + * @reserved: Reserved for future use. + * @name: Name of blob + * @value: The numerical value + * + * Values commonly occur in enums and flags. + * + * Since: 2.80 + */ +typedef struct { + guint32 deprecated : 1; + guint32 unsigned_value : 1; + guint32 reserved :30; + guint32 name; + gint32 value; +} ValueBlob; + +/** + * FieldBlob: + * @name: The name of the field. + * @readable: TODO + * @writable: How the field may be accessed. + * @has_embedded_type: An anonymous type follows the FieldBlob. + * @reserved: Reserved for future use. + * @bits: If this field is part of a bitfield, the number of bits which it + * uses, otherwise 0. + * @struct_offset: The offset of the field in the struct. The value 0xFFFF + * indicates that the struct offset is unknown. + * @reserved2: Reserved for future use. + * @type: The type of the field. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint32 name; + + guint8 readable :1; + guint8 writable :1; + guint8 has_embedded_type :1; + guint8 reserved :5; + guint8 bits; + + guint16 struct_offset; + + guint32 reserved2; + + SimpleTypeBlob type; +} FieldBlob; + +/** + * RegisteredTypeBlob: + * @blob_type: TODO + * @deprecated: TODO + * @unregistered: TODO + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: The name under which the type is registered with GType. + * @gtype_init: The symbol name of the get_type() function which registers the + * type. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + guint16 deprecated : 1; + guint16 unregistered : 1; + guint16 reserved :14; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; +} RegisteredTypeBlob; + +/** + * StructBlob: + * @blob_type: #BLOB_TYPE_STRUCT + * @deprecated: Whether this structure is deprecated + * @unregistered: If this is set, the type is not registered with GType. + * @is_gtype_struct: Whether this structure is the class or interface layout + * for a GObject + * @alignment: The byte boundary that the struct is aligned to in memory + * @foreign: If the type is foreign, eg if it's expected to be overridden by + * a native language binding instead of relying of introspected bindings. + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: String name of the associated #GType + * @gtype_init: String naming the symbol which gets the runtime #GType + * @size: The size of the struct in bytes. + * @n_fields: TODO + * @n_methods: TODO + * @copy_func: String pointing to a function which can be called to copy + * the contents of this struct type + * @free_func: String pointing to a function which can be called to free + * the contents of this struct type + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + + guint16 deprecated : 1; + guint16 unregistered : 1; + guint16 is_gtype_struct : 1; + guint16 alignment : 6; + guint16 foreign : 1; + guint16 reserved : 6; + + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint32 size; + + guint16 n_fields; + guint16 n_methods; + + guint32 copy_func; + guint32 free_func; +} StructBlob; + +/** + * UnionBlob: + * @blob_type: TODO + * @deprecated: TODO + * @unregistered: If this is set, the type is not registered with GType. + * @discriminated: Is set if the union is discriminated + * @alignment: The byte boundary that the union is aligned to in memory + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: String name of the associated #GType + * @gtype_init: String naming the symbol which gets the runtime #GType + * @size: TODO + * @n_fields: Length of the arrays + * @n_functions: TODO + * @copy_func: String pointing to a function which can be called to copy + * the contents of this union type + * @free_func: String pointing to a function which can be called to free + * the contents of this union type + * @discriminator_offset: Offset from the beginning of the union where the + * discriminator of a discriminated union is located. The value 0xFFFF + * indicates that the discriminator offset is unknown. + * @discriminator_type: Type of the discriminator + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + guint16 deprecated : 1; + guint16 unregistered : 1; + guint16 discriminated : 1; + guint16 alignment : 6; + guint16 reserved : 7; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint32 size; + + guint16 n_fields; + guint16 n_functions; + + guint32 copy_func; + guint32 free_func; + + gint32 discriminator_offset; + SimpleTypeBlob discriminator_type; +} UnionBlob; + +/** + * EnumBlob: + * @blob_type: TODO + * @deprecated: TODO + * @unregistered: If this is set, the type is not registered with GType. + * @storage_type: The tag of the type used for the enum in the C ABI + * (will be a signed or unsigned integral type) + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: String name of the associated #GType + * @gtype_init: String naming the symbol which gets the runtime #GType + * @n_values: The length of the values array. + * @n_methods: The length of the methods array. + * @error_domain: String naming the #GError domain this enum is associated with + * @values: TODO + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + + guint16 deprecated : 1; + guint16 unregistered : 1; + guint16 storage_type : 5; + guint16 reserved : 9; + + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 n_values; + guint16 n_methods; + + guint32 error_domain; + + ValueBlob values[]; +} EnumBlob; + +#define ACCESSOR_SENTINEL 0x3ff + +/** + * PropertyBlob: + * @name: The name of the property. + * @deprecated: TODO + * @readable: TODO + * @writable: TODO + * @construct: TODO + * @construct_only: The ParamFlags used when registering the property. + * @transfer_ownership: When writing, the type containing the property takes + * ownership of the value. When reading, the returned value needs to be + * released by the caller. + * @transfer_container_ownership: For container types indicates that the + * ownership of the container, but not of its contents, is transferred. + * This is typically the case when reading lists of statically allocated + * things. + * @setter: the index of the setter function for this property, if @writable + * is set; if the method is not known, the value will be set to %ACCESSOR_SENTINEL + * @getter: ths index of the getter function for this property, if @readable + * is set; if the method is not known, the value will be set to %ACCESSOR_SENTINEL + * @reserved: Reserved for future use. + * @reserved2: Reserved for future use. + * @type: Describes the type of the property. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint32 name; + + guint32 deprecated : 1; + guint32 readable : 1; + guint32 writable : 1; + guint32 construct : 1; + guint32 construct_only : 1; + guint32 transfer_ownership : 1; + guint32 transfer_container_ownership : 1; + guint32 setter :10; + guint32 getter :10; + guint32 reserved : 5; + + guint32 reserved2; + + SimpleTypeBlob type; +} PropertyBlob; + +/** + * SignalBlob: + * @deprecated: TODO + * @run_first: TODO + * @run_last: TODO + * @run_cleanup: TODO + * @no_recurse: TODO + * @detailed: TODO + * @action: TODO + * @no_hooks: The flags used when registering the signal. + * @has_class_closure: Set if the signal has a class closure. + * @true_stops_emit: Whether the signal has true-stops-emit semantics + * @reserved: Reserved for future use. + * @class_closure: The index of the class closure in the list of virtual + * functions of the object or interface on which the signal is defined. + * @name: The name of the signal. + * @reserved2: Reserved for future use. + * @signature: Offset of the SignatureBlob describing the parameter types + * and the return value type. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 deprecated : 1; + guint16 run_first : 1; + guint16 run_last : 1; + guint16 run_cleanup : 1; + guint16 no_recurse : 1; + guint16 detailed : 1; + guint16 action : 1; + guint16 no_hooks : 1; + guint16 has_class_closure : 1; + guint16 true_stops_emit : 1; + guint16 reserved : 6; + + guint16 class_closure; + + guint32 name; + + guint32 reserved2; + + guint32 signature; +} SignalBlob; + +/** + * VFuncBlob: + * @name: The name of the virtual function. + * @must_chain_up: If set, every implementation of this virtual function must + * chain up to the implementation of the parent class. + * @must_be_implemented: If set, every derived class must override this virtual + * function. + * @must_not_be_implemented: If set, derived class must not override this + * virtual function. + * @class_closure: Set if this virtual function is the class closure of a + * signal. + * @throws: This is now additionally stored in the #SignatureBlob. (deprecated) + * @reserved: Reserved for future use. + * @signal: The index of the signal in the list of signals of the object or + * interface to which this virtual function belongs. + * @struct_offset: The offset of the function pointer in the class struct. + * The value 0xFFFF indicates that the struct offset is unknown. + * @invoker: If a method invoker for this virtual exists, this is the offset + * in the class structure of the method. If no method is known, this value + * will be 0x3ff. + * @reserved2: Reserved for future use. + * @reserved3: Reserved for future use. + * @signature: Offset of the SignatureBlob describing the parameter types and + * the return value type. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint32 name; + + guint16 must_chain_up : 1; + guint16 must_be_implemented : 1; + guint16 must_not_be_implemented : 1; + guint16 class_closure : 1; + guint16 throws : 1; + guint16 reserved :11; + guint16 signal; + + guint16 struct_offset; + guint16 invoker : 10; /* Number of bits matches @index in FunctionBlob */ + guint16 reserved2 : 6; + + guint32 reserved3; + guint32 signature; +} VFuncBlob; + +/** + * ObjectBlob: + * @blob_type: #BLOB_TYPE_OBJECT + * @deprecated: whether the type is deprecated + * @abstract: whether the type can be instantiated + * @fundamental: this object is not a GObject derived type, instead it's + * an additional fundamental type. + * @final_: whether the type can be derived + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: String name of the associated #GType + * @gtype_init: String naming the symbol which gets the runtime #GType + * @parent: The directory index of the parent type. This is only set for + * objects. If an object does not have a parent, it is zero. + * @gtype_struct: TODO + * @n_interfaces: TODO + * @n_fields: TODO + * @n_properties: TODO + * @n_methods: TODO + * @n_signals: TODO + * @n_vfuncs: TODO + * @n_constants: The lengths of the arrays.Up to 16bits of padding may be + * inserted between the arrays to ensure that they start on a 32bit + * boundary. + * @n_field_callbacks: The number of n_fields which are also callbacks. + * This is used to calculate the fields section size in constant time. + * @ref_func: String pointing to a function which can be called to increase + * the reference count for an instance of this object type. + * @unref_func: String pointing to a function which can be called to decrease + * the reference count for an instance of this object type. + * @set_value_func: String pointing to a function which can be called to + * convert a pointer of this object to a GValue + * @get_value_func: String pointing to a function which can be called to + * convert extract a pointer to this object from a GValue + * @reserved3: Reserved for future use. + * @reserved4: Reserved for future use. + * @interfaces: An array of indices of directory entries for the implemented + * interfaces. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; /* 7 */ + guint16 deprecated : 1; + guint16 abstract : 1; + guint16 fundamental : 1; + guint16 final_ : 1; + guint16 reserved :12; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + + guint16 parent; + guint16 gtype_struct; + + guint16 n_interfaces; + guint16 n_fields; + guint16 n_properties; + guint16 n_methods; + guint16 n_signals; + guint16 n_vfuncs; + guint16 n_constants; + guint16 n_field_callbacks; + + guint32 ref_func; + guint32 unref_func; + guint32 set_value_func; + guint32 get_value_func; + + guint32 reserved3; + guint32 reserved4; + + guint16 interfaces[]; +} ObjectBlob; + +/** + * InterfaceBlob: + * @blob_type: TODO + * @deprecated: TODO + * @reserved: Reserved for future use. + * @name: TODO + * @gtype_name: TODO + * @gtype_init: TODO + * @gtype_struct: Name of the interface "class" C structure + * @n_prerequisites: Number of prerequisites + * @n_properties: Number of properties + * @n_methods: Number of methods + * @n_signals: Number of signals + * @n_vfuncs: Number of virtual functions + * @n_constants: The lengths of the arrays. Up to 16bits of padding may be + * inserted between the arrays to ensure that they start on a 32bit + * boundary. + * @padding: TODO + * @reserved2: Reserved for future use. + * @reserved3: Reserved for future use. + * @prerequisites: An array of indices of directory entries for required + * interfaces. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + guint16 deprecated : 1; + guint16 reserved :15; + guint32 name; + + guint32 gtype_name; + guint32 gtype_init; + guint16 gtype_struct; + + guint16 n_prerequisites; + guint16 n_properties; + guint16 n_methods; + guint16 n_signals; + guint16 n_vfuncs; + guint16 n_constants; + + guint16 padding; + + guint32 reserved2; + guint32 reserved3; + + guint16 prerequisites[]; +} InterfaceBlob; + +/** + * ConstantBlob: + * @blob_type: TODO + * @deprecated: TODO + * @reserved: Reserved for future use. + * @name: TODO + * @type: The type of the value. In most cases this should be a numeric type + * or string. + * @size: The size of the value in bytes. + * @offset: The offset of the value in the typelib. + * @reserved2: Reserved for future use. + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint16 blob_type; + guint16 deprecated : 1; + guint16 reserved :15; + guint32 name; + + SimpleTypeBlob type; + + guint32 size; + guint32 offset; + + guint32 reserved2; +} ConstantBlob; + +/** + * AttributeBlob: + * @offset: The offset of the typelib entry to which this attribute refers. + * Attributes are kept sorted by offset, so that the attributes of an + * entry can be found by a binary search. + * @name: The name of the attribute, a string. + * @value: The value of the attribute (also a string) + * + * TODO + * + * Since: 2.80 + */ +typedef struct { + guint32 offset; + guint32 name; + guint32 value; +} AttributeBlob; + +struct _GITypelib { + /*< private >*/ + guchar *data; + gsize len; + gboolean owns_memory; + GMappedFile *mfile; + GList *modules; + gboolean open_attempted; +}; + +DirEntry *gi_typelib_get_dir_entry (GITypelib *typelib, + guint16 index); + +DirEntry *gi_typelib_get_dir_entry_by_name (GITypelib *typelib, + const char *name); + +DirEntry *gi_typelib_get_dir_entry_by_gtype_name (GITypelib *typelib, + const gchar *gtype_name); + +DirEntry *gi_typelib_get_dir_entry_by_error_domain (GITypelib *typelib, + GQuark error_domain); + +gboolean gi_typelib_matches_gtype_name_prefix (GITypelib *typelib, + const gchar *gtype_name); + + +GI_AVAILABLE_IN_ALL +void gi_typelib_check_sanity (void); + +/** + * gi_typelib_get_string: + * @typelib: TODO + * @offset: TODO + * + * TODO + * + * Returns: TODO + * Since: 2.80 + */ +#define gi_typelib_get_string(typelib,offset) ((const gchar*)&(typelib->data)[(offset)]) + + +/** + * GITypelibError: + * @GI_TYPELIB_ERROR_INVALID: the typelib is invalid + * @GI_TYPELIB_ERROR_INVALID_HEADER: the typelib header is invalid + * @GI_TYPELIB_ERROR_INVALID_DIRECTORY: the typelib directory is invalid + * @GI_TYPELIB_ERROR_INVALID_ENTRY: a typelib entry is invalid + * @GI_TYPELIB_ERROR_INVALID_BLOB: a typelib blob is invalid + * + * A error set while validating the #GITypelib + * + * Since: 2.80 + */ +typedef enum +{ + GI_TYPELIB_ERROR_INVALID, + GI_TYPELIB_ERROR_INVALID_HEADER, + GI_TYPELIB_ERROR_INVALID_DIRECTORY, + GI_TYPELIB_ERROR_INVALID_ENTRY, + GI_TYPELIB_ERROR_INVALID_BLOB +} GITypelibError; + +/** + * GI_TYPELIB_ERROR: + * + * TODO + * + * Since: 2.80 + */ +#define GI_TYPELIB_ERROR (gi_typelib_error_quark ()) + +GQuark gi_typelib_error_quark (void); + + +GI_AVAILABLE_IN_ALL +gboolean gi_typelib_validate (GITypelib *typelib, + GError **error); + + +/* defined in gibaseinfo.c */ +AttributeBlob *_attribute_blob_find_first (GIBaseInfo *info, + guint32 blob_offset); + +/** + * GITypelibHashBuilder: + * + * TODO + * + * Since: 2.80 + */ +typedef struct _GITypelibHashBuilder GITypelibHashBuilder; + +GITypelibHashBuilder * gi_typelib_hash_builder_new (void); + +void gi_typelib_hash_builder_add_string (GITypelibHashBuilder *builder, const char *str, guint16 value); + +gboolean gi_typelib_hash_builder_prepare (GITypelibHashBuilder *builder); + +guint32 gi_typelib_hash_builder_get_buffer_size (GITypelibHashBuilder *builder); + +void gi_typelib_hash_builder_pack (GITypelibHashBuilder *builder, guint8* mem, guint32 size); + +void gi_typelib_hash_builder_destroy (GITypelibHashBuilder *builder); + +guint16 gi_typelib_hash_search (guint8* memory, const char *str, guint n_entries); + + +G_END_DECLS diff --git a/girepository/gitypelib.c b/girepository/gitypelib.c new file mode 100644 index 0000000..447de95 --- /dev/null +++ b/girepository/gitypelib.c @@ -0,0 +1,2570 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: typelib validation, auxiliary functions + * related to the binary typelib format + * + * Copyright (C) 2005 Matthias Clasen + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include +#include + +#include + +#include "gitypelib-internal.h" +#include "gitypelib.h" + +/** + * GITypelib: + * + * `GITypelib` represents a loaded `.typelib` file, which contains a description + * of a single module’s API. + * + * Since: 2.80 + */ + +typedef struct { + GITypelib *typelib; + GSList *context_stack; +} ValidateContext; + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + +static void +push_context (ValidateContext *ctx, const char *name) +{ + ctx->context_stack = g_slist_prepend (ctx->context_stack, (char*)name); +} + +static void +pop_context (ValidateContext *ctx) +{ + g_assert (ctx->context_stack != NULL); + ctx->context_stack = g_slist_delete_link (ctx->context_stack, + ctx->context_stack); +} + +static gboolean +validate_interface_blob (ValidateContext *ctx, + guint32 offset, + GError **error); + +static DirEntry * +get_dir_entry_checked (GITypelib *typelib, + guint16 index, + GError **error) +{ + Header *header = (Header *)typelib->data; + guint32 offset; + + if (index == 0 || index > header->n_entries) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid directory index %d", index); + return FALSE; + } + + offset = header->directory + (index - 1) * header->entry_blob_size; + + if (typelib->len < offset + sizeof (DirEntry)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + return (DirEntry *)&typelib->data[offset]; +} + + +static CommonBlob * +get_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + if (typelib->len < offset + sizeof (CommonBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + return (CommonBlob *)&typelib->data[offset]; +} + +static InterfaceTypeBlob * +get_type_blob (GITypelib *typelib, + SimpleTypeBlob *simple, + GError **error) +{ + if (simple->offset == 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "Expected blob for type"); + return FALSE; + } + + if (simple->flags.reserved == 0 && simple->flags.reserved2 == 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "Expected non-basic type but got %d", + simple->flags.tag); + return FALSE; + } + + return (InterfaceTypeBlob*) get_blob (typelib, simple->offset, error); +} + +/** + * gi_typelib_get_dir_entry: + * @typelib: a #GITypelib + * @index: index to retrieve + * + * Get the typelib directory entry at the given @index. + * + * Returns: (transfer none): a `DirEntry` + * Since: 2.80 + */ +DirEntry * +gi_typelib_get_dir_entry (GITypelib *typelib, + guint16 index) +{ + Header *header = (Header *)typelib->data; + + return (DirEntry *)&typelib->data[header->directory + (index - 1) * header->entry_blob_size]; +} + +static Section * +get_section_by_id (GITypelib *typelib, + SectionType section_type) +{ + Header *header = (Header *)typelib->data; + Section *section; + + if (header->sections == 0) + return NULL; + + for (section = (Section*)&typelib->data[header->sections]; + section->id != GI_SECTION_END; + section++) + { + if (section->id == section_type) + return section; + } + return NULL; +} + +/** + * gi_typelib_get_dir_entry_by_name: + * @typelib: a #GITypelib + * @name: name to look up + * + * Get the typelib directory entry which has @name. + * + * Returns: (transfer none) (nullable): entry corresponding to @name, or `NULL` + * if none was found + * Since: 2.80 + */ +DirEntry * +gi_typelib_get_dir_entry_by_name (GITypelib *typelib, + const char *name) +{ + Section *dirindex; + gint i, n_entries; + const char *entry_name; + DirEntry *entry; + + dirindex = get_section_by_id (typelib, GI_SECTION_DIRECTORY_INDEX); + n_entries = ((Header *)typelib->data)->n_local_entries; + + if (dirindex == NULL) + { + for (i = 1; i <= n_entries; i++) + { + entry = gi_typelib_get_dir_entry (typelib, i); + entry_name = gi_typelib_get_string (typelib, entry->name); + if (strcmp (name, entry_name) == 0) + return entry; + } + return NULL; + } + else + { + guint8 *hash = (guint8*) &typelib->data[dirindex->offset]; + guint16 index; + + index = gi_typelib_hash_search (hash, name, n_entries); + entry = gi_typelib_get_dir_entry (typelib, index + 1); + entry_name = gi_typelib_get_string (typelib, entry->name); + if (strcmp (name, entry_name) == 0) + return entry; + return NULL; + } +} + +/** + * gi_typelib_get_dir_entry_by_gtype_name: + * @typelib: a #GITypelib + * @gtype_name: name of a [type@GObject.Type] to look up + * + * Get the typelib directory entry for the [type@GObject.Type] with the given + * @gtype_name. + * + * Returns: (transfer none) (nullable): entry corresponding to @gtype_name, or + * `NULL` if none was found + * Since: 2.80 + */ +DirEntry * +gi_typelib_get_dir_entry_by_gtype_name (GITypelib *typelib, + const gchar *gtype_name) +{ + Header *header = (Header *)typelib->data; + guint i; + + for (i = 1; i <= header->n_local_entries; i++) + { + RegisteredTypeBlob *blob; + const char *type; + DirEntry *entry = gi_typelib_get_dir_entry (typelib, i); + if (!BLOB_IS_REGISTERED_TYPE (entry)) + continue; + + blob = (RegisteredTypeBlob *)(&typelib->data[entry->offset]); + if (!blob->gtype_name) + continue; + + type = gi_typelib_get_string (typelib, blob->gtype_name); + if (strcmp (type, gtype_name) == 0) + return entry; + } + return NULL; +} + +typedef struct { + const char *s; + const char *separator; + gsize sep_len; + GString buf; +} StrSplitIter; + +static void +strsplit_iter_init (StrSplitIter *iter, + const char *s, + const char *separator) +{ + iter->s = s; + iter->separator = separator; + iter->sep_len = strlen (separator); + iter->buf.str = NULL; + iter->buf.len = 0; + iter->buf.allocated_len = 0; +} + +static gboolean +strsplit_iter_next (StrSplitIter *iter, + const char **out_val) +{ + const char *s = iter->s; + const char *next; + gsize len; + + if (!s) + return FALSE; + next = strstr (s, iter->separator); + if (next) + { + iter->s = next + iter->sep_len; + len = next - s; + } + else + { + iter->s = NULL; + len = strlen (s); + } + if (len == 0) + { + *out_val = ""; + } + else + { + g_string_overwrite_len (&iter->buf, 0, s, (gssize)len); + *out_val = iter->buf.str; + } + return TRUE; +} + +static void +strsplit_iter_clear (StrSplitIter *iter) +{ + g_free (iter->buf.str); +} + +/** + * gi_typelib_matches_gtype_name_prefix: + * @typelib: a #GITypelib + * @gtype_name: name of a [type@GObject.Type] + * + * Check whether the symbol prefix for @typelib is a prefix of the given + * @gtype_name. + * + * Returns: `TRUE` if the prefix for @typelib prefixes @gtype_name + * Since: 2.80 + */ +gboolean +gi_typelib_matches_gtype_name_prefix (GITypelib *typelib, + const gchar *gtype_name) +{ + Header *header = (Header *)typelib->data; + const char *c_prefix; + const gchar *prefix; + gboolean ret = FALSE; + StrSplitIter split_iter; + gsize gtype_name_len; + + c_prefix = gi_typelib_get_string (typelib, header->c_prefix); + if (c_prefix == NULL || strlen (c_prefix) == 0) + return FALSE; + + gtype_name_len = strlen (gtype_name); + + /* c_prefix is a comma separated string of supported prefixes + * in the typelib. + * We match the specified gtype_name if the gtype_name starts + * with the prefix, and is followed by a capital letter. + * For example, a typelib offering the 'Gdk' prefix does match + * GdkX11Cursor, however a typelib offering the 'G' prefix does not. + */ + strsplit_iter_init (&split_iter, c_prefix, ","); + while (strsplit_iter_next (&split_iter, &prefix)) + { + size_t len = strlen (prefix); + + if (gtype_name_len < len) + continue; + + if (strncmp (prefix, gtype_name, len) != 0) + continue; + + if (g_ascii_isupper (gtype_name[len])) + { + ret = TRUE; + break; + } + } + strsplit_iter_clear (&split_iter); + return ret; +} + +/** + * gi_typelib_get_dir_entry_by_error_domain: + * @typelib: a #GITypelib + * @error_domain: name of a [type@GLib.Error] domain to look up + * + * Get the typelib directory entry for the [type@GLib.Error] domain with the + * given @error_domain name. + * + * Returns: (transfer none) (nullable): entry corresponding to @error_domain, or + * `NULL` if none was found + * Since: 2.80 + */ +DirEntry * +gi_typelib_get_dir_entry_by_error_domain (GITypelib *typelib, + GQuark error_domain) +{ + Header *header = (Header *)typelib->data; + guint n_entries = header->n_local_entries; + const char *domain_string = g_quark_to_string (error_domain); + DirEntry *entry; + guint i; + + for (i = 1; i <= n_entries; i++) + { + EnumBlob *blob; + const char *enum_domain_string; + + entry = gi_typelib_get_dir_entry (typelib, i); + if (entry->blob_type != BLOB_TYPE_ENUM) + continue; + + blob = (EnumBlob *)(&typelib->data[entry->offset]); + if (!blob->error_domain) + continue; + + enum_domain_string = gi_typelib_get_string (typelib, blob->error_domain); + if (strcmp (domain_string, enum_domain_string) == 0) + return entry; + } + return NULL; +} + +/** + * gi_typelib_check_sanity: + * + * Check compile-time sizes of various typelib file format types are as + * expected. + * + * Since: 2.80 + */ +void +gi_typelib_check_sanity (void) +{ +#ifndef G_DISABLE_ASSERT + /* Check that struct layout is as we expect */ + + gboolean size_check_ok = TRUE; + +#define CHECK_SIZE(s,n) \ + if (sizeof(s) != n) \ + { \ + g_printerr ("sizeof("#s") is expected to be %d but is %"G_GSIZE_FORMAT".\n", \ + n, sizeof (s)); \ + size_check_ok = FALSE; \ + } + + /* When changing the size of a typelib structure, you are required to update + * the hardcoded size here. Do NOT change these to use sizeof(); these + * should match whatever is defined in the text specification and serve as + * a sanity check on structure modifications. + * + * Everything else in the code however should be using sizeof(). + */ + + CHECK_SIZE (Header, 112); + CHECK_SIZE (DirEntry, 12); + CHECK_SIZE (SimpleTypeBlob, 4); + CHECK_SIZE (ArgBlob, 16); + CHECK_SIZE (SignatureBlob, 8); + CHECK_SIZE (CommonBlob, 8); + CHECK_SIZE (FunctionBlob, 20); + CHECK_SIZE (CallbackBlob, 12); + CHECK_SIZE (InterfaceTypeBlob, 4); + CHECK_SIZE (ArrayTypeBlob, 8); + CHECK_SIZE (ParamTypeBlob, 4); + CHECK_SIZE (ErrorTypeBlob, 4); + CHECK_SIZE (ValueBlob, 12); + CHECK_SIZE (FieldBlob, 16); + CHECK_SIZE (RegisteredTypeBlob, 16); + CHECK_SIZE (StructBlob, 32); + CHECK_SIZE (EnumBlob, 24); + CHECK_SIZE (PropertyBlob, 16); + CHECK_SIZE (SignalBlob, 16); + CHECK_SIZE (VFuncBlob, 20); + CHECK_SIZE (ObjectBlob, 60); + CHECK_SIZE (InterfaceBlob, 40); + CHECK_SIZE (ConstantBlob, 24); + CHECK_SIZE (AttributeBlob, 12); + CHECK_SIZE (UnionBlob, 40); +#undef CHECK_SIZE + + g_assert (size_check_ok); +#endif /* !G_DISABLE_ASSERT */ +} + + +static gboolean +is_aligned (guint32 offset) +{ + return offset == ALIGN_VALUE (offset, 4); +} + +#define MAX_NAME_LEN 2048 + +static const char * +get_string (GITypelib *typelib, guint32 offset, GError **error) +{ + if (typelib->len < offset) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "Buffer is too short while looking up name"); + return NULL; + } + + return (const char*)&typelib->data[offset]; +} + +static const char * +get_string_nofail (GITypelib *typelib, guint32 offset) +{ + const char *ret = get_string (typelib, offset, NULL); + g_assert (ret); + return ret; +} + +static gboolean +validate_name (GITypelib *typelib, + const char *msg, + const guchar *data, guint32 offset, + GError **error) +{ + const char *name; + + name = get_string (typelib, offset, error); + if (!name) + return FALSE; + + if (!memchr (name, '\0', MAX_NAME_LEN)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The %s is too long: %s", + msg, name); + return FALSE; + } + + if (strspn (name, G_CSET_a_2_z G_CSET_A_2_Z G_CSET_DIGITS "-_") < strlen (name)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The %s contains invalid characters: '%s'", + msg, name); + return FALSE; + } + + return TRUE; +} + +/* Fast path sanity check, operates on a memory blob */ +static gboolean +validate_header_basic (const guint8 *memory, + gsize len, + GError **error) +{ + Header *header = (Header *)memory; + + if (len < sizeof (Header)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The specified typelib length %" G_GSIZE_FORMAT " is too short", + len); + return FALSE; + } + + if (strncmp (header->magic, GI_IR_MAGIC, 16) != 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Invalid magic header"); + return FALSE; + + } + + if (header->major_version != 4) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Typelib version mismatch; expected 4, found %d", + header->major_version); + return FALSE; + + } + + if (header->n_entries < header->n_local_entries) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Inconsistent entry counts"); + return FALSE; + } + + if (header->size != len) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Typelib size %" G_GSIZE_FORMAT " does not match %" G_GSIZE_FORMAT, + (gsize) header->size, len); + return FALSE; + } + + /* This is a sanity check for a specific typelib; it + * prevents us from loading an incompatible typelib. + * + * The hardcoded checks in gi_typelib_check_sanity to + * protect against inadvertent or buggy changes to the typelib format + * itself. + */ + + if (header->entry_blob_size != sizeof (DirEntry) || + header->function_blob_size != sizeof (FunctionBlob) || + header->callback_blob_size != sizeof (CallbackBlob) || + header->signal_blob_size != sizeof (SignalBlob) || + header->vfunc_blob_size != sizeof (VFuncBlob) || + header->arg_blob_size != sizeof (ArgBlob) || + header->property_blob_size != sizeof (PropertyBlob) || + header->field_blob_size != sizeof (FieldBlob) || + header->value_blob_size != sizeof (ValueBlob) || + header->constant_blob_size != sizeof (ConstantBlob) || + header->attribute_blob_size != sizeof (AttributeBlob) || + header->signature_blob_size != sizeof (SignatureBlob) || + header->enum_blob_size != sizeof (EnumBlob) || + header->struct_blob_size != sizeof (StructBlob) || + header->object_blob_size != sizeof(ObjectBlob) || + header->interface_blob_size != sizeof (InterfaceBlob) || + header->union_blob_size != sizeof (UnionBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Blob size mismatch"); + return FALSE; + } + + if (!is_aligned (header->directory)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Misaligned directory"); + return FALSE; + } + + if (!is_aligned (header->attributes)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Misaligned attributes"); + return FALSE; + } + + if (header->attributes == 0 && header->n_attributes > 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_HEADER, + "Wrong number of attributes"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_header (ValidateContext *ctx, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + + if (!validate_header_basic (typelib->data, typelib->len, error)) + return FALSE; + + { + Header *header = (Header*)typelib->data; + if (!validate_name (typelib, "namespace", typelib->data, header->namespace, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean validate_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error); + +static gboolean +validate_array_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + /* FIXME validate length */ + + if (!validate_type_blob (typelib, + offset + G_STRUCT_OFFSET (ArrayTypeBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_iface_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + InterfaceTypeBlob *blob; + InterfaceBlob *target; + + blob = (InterfaceTypeBlob*)&typelib->data[offset]; + + target = (InterfaceBlob*) get_dir_entry_checked (typelib, blob->interface, error); + + if (!target) + return FALSE; + if (target->blob_type == 0) /* non-local */ + return TRUE; + + return TRUE; +} + +static gboolean +validate_param_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + gint n_params, + GError **error) +{ + ParamTypeBlob *blob; + gint i; + + blob = (ParamTypeBlob*)&typelib->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + if (blob->n_types != n_params) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Parameter type number mismatch"); + return FALSE; + } + + for (i = 0; i < n_params; i++) + { + if (!validate_type_blob (typelib, + offset + sizeof (ParamTypeBlob) + + i * sizeof (SimpleTypeBlob), + 0, FALSE, error)) + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_error_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + ErrorTypeBlob *blob; + + blob = (ErrorTypeBlob*)&typelib->data[offset]; + + if (!blob->pointer) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", blob->tag); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_type_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + gboolean return_type, + GError **error) +{ + SimpleTypeBlob *simple; + InterfaceTypeBlob *iface; + + simple = (SimpleTypeBlob *)&typelib->data[offset]; + + if (simple->flags.reserved == 0 && + simple->flags.reserved2 == 0) + { + if (!GI_TYPE_TAG_IS_BASIC(simple->flags.tag)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid non-basic tag %d in simple type", simple->flags.tag); + return FALSE; + } + + if (simple->flags.tag >= GI_TYPE_TAG_UTF8 && + simple->flags.tag != GI_TYPE_TAG_UNICHAR && + !simple->flags.pointer) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Pointer type exected for tag %d", simple->flags.tag); + return FALSE; + } + + return TRUE; + } + + iface = (InterfaceTypeBlob*)&typelib->data[simple->offset]; + + switch (iface->tag) + { + case GI_TYPE_TAG_ARRAY: + if (!validate_array_type_blob (typelib, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case GI_TYPE_TAG_INTERFACE: + if (!validate_iface_type_blob (typelib, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + if (!validate_param_type_blob (typelib, simple->offset, + signature_offset, return_type, 1, error)) + return FALSE; + break; + case GI_TYPE_TAG_GHASH: + if (!validate_param_type_blob (typelib, simple->offset, + signature_offset, return_type, 2, error)) + return FALSE; + break; + case GI_TYPE_TAG_ERROR: + if (!validate_error_type_blob (typelib, simple->offset, + signature_offset, return_type, error)) + return FALSE; + break; + default: + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong tag in complex type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_arg_blob (GITypelib *typelib, + guint32 offset, + guint32 signature_offset, + GError **error) +{ + ArgBlob *blob; + + if (typelib->len < offset + sizeof (ArgBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ArgBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "argument", typelib->data, blob->name, error)) + return FALSE; + + if (!validate_type_blob (typelib, + offset + G_STRUCT_OFFSET (ArgBlob, arg_type), + signature_offset, FALSE, error)) + return FALSE; + + return TRUE; +} + +static SimpleTypeBlob * +return_type_from_signature (GITypelib *typelib, + guint32 offset, + GError **error) +{ + SignatureBlob *blob; + if (typelib->len < offset + sizeof (SignatureBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return NULL; + } + + blob = (SignatureBlob*) &typelib->data[offset]; + if (blob->return_type.offset == 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "No return type found in signature"); + return NULL; + } + + return (SimpleTypeBlob *)&typelib->data[offset + G_STRUCT_OFFSET (SignatureBlob, return_type)]; +} + +static gboolean +validate_signature_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + SignatureBlob *blob; + gint i; + + if (typelib->len < offset + sizeof (SignatureBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignatureBlob*) &typelib->data[offset]; + + if (blob->return_type.offset != 0) + { + if (!validate_type_blob (typelib, + offset + G_STRUCT_OFFSET (SignatureBlob, return_type), + offset, TRUE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_arguments; i++) + { + if (!validate_arg_blob (typelib, + offset + sizeof (SignatureBlob) + + i * sizeof (ArgBlob), + offset, + error)) + return FALSE; + } + + /* FIXME check constraints on return_value */ + /* FIXME check array-length pairs */ + return TRUE; +} + +static gboolean +validate_function_blob (ValidateContext *ctx, + guint32 offset, + guint16 container_type, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + FunctionBlob *blob; + + if (typelib->len < offset + sizeof (FunctionBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FunctionBlob*) &typelib->data[offset]; + + if (blob->blob_type != BLOB_TYPE_FUNCTION) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type %d, expected function", blob->blob_type); + return FALSE; + } + + if (!validate_name (typelib, "function", typelib->data, blob->name, error)) + return FALSE; + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + if (!validate_name (typelib, "function symbol", typelib->data, blob->symbol, error)) + return FALSE; + + if (blob->constructor) + { + switch (container_type) + { + case BLOB_TYPE_BOXED: + case BLOB_TYPE_STRUCT: + case BLOB_TYPE_UNION: + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Constructor not allowed"); + return FALSE; + } + } + + if (blob->setter || blob->getter || blob->wraps_vfunc) + { + switch (container_type) + { + case BLOB_TYPE_OBJECT: + case BLOB_TYPE_INTERFACE: + break; + default: + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Setter, getter or wrapper not allowed"); + return FALSE; + } + } + + if (blob->index) + { + if (!(blob->setter || blob->getter || blob->wraps_vfunc)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Must be setter, getter or wrapper"); + return FALSE; + } + } + + /* FIXME: validate index range */ + + if (!validate_signature_blob (typelib, blob->signature, error)) + return FALSE; + + if (blob->constructor) + { + SimpleTypeBlob *simple = return_type_from_signature (typelib, + blob->signature, + error); + InterfaceTypeBlob *iface_type; + + if (!simple) + return FALSE; + iface_type = get_type_blob (typelib, simple, error); + if (!iface_type) + return FALSE; + if (iface_type->tag != GI_TYPE_TAG_INTERFACE && + (container_type == BLOB_TYPE_OBJECT || + container_type == BLOB_TYPE_INTERFACE)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "Invalid return type '%s' for constructor '%s'", + gi_type_tag_to_string (iface_type->tag), + get_string_nofail (typelib, blob->symbol)); + return FALSE; + } + } + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_callback_blob (ValidateContext *ctx, + guint32 offset, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + CallbackBlob *blob; + + if (typelib->len < offset + sizeof (CallbackBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (CallbackBlob*) &typelib->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CALLBACK) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!validate_name (typelib, "callback", typelib->data, blob->name, error)) + return FALSE; + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + if (!validate_signature_blob (typelib, blob->signature, error)) + return FALSE; + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_constant_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + guint value_size[] = { + 0, /* VOID */ + 4, /* BOOLEAN */ + 1, /* INT8 */ + 1, /* UINT8 */ + 2, /* INT16 */ + 2, /* UINT16 */ + 4, /* INT32 */ + 4, /* UINT32 */ + 8, /* INT64 */ + 8, /* UINT64 */ + sizeof (gfloat), + sizeof (gdouble), + 0, /* GTYPE */ + 0, /* UTF8 */ + 0, /* FILENAME */ + 0, /* ARRAY */ + 0, /* INTERFACE */ + 0, /* GLIST */ + 0, /* GSLIST */ + 0, /* GHASH */ + 0, /* ERROR */ + 4 /* UNICHAR */ + }; + ConstantBlob *blob; + SimpleTypeBlob *type; + + g_assert (G_N_ELEMENTS (value_size) == GI_TYPE_TAG_N_TYPES); + + if (typelib->len < offset + sizeof (ConstantBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ConstantBlob*) &typelib->data[offset]; + + if (blob->blob_type != BLOB_TYPE_CONSTANT) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!validate_name (typelib, "constant", typelib->data, blob->name, error)) + return FALSE; + + if (!validate_type_blob (typelib, offset + G_STRUCT_OFFSET (ConstantBlob, type), + 0, FALSE, error)) + return FALSE; + + if (!is_aligned (blob->offset)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Misaligned constant value"); + return FALSE; + } + + type = (SimpleTypeBlob *)&typelib->data[offset + G_STRUCT_OFFSET (ConstantBlob, type)]; + if (type->flags.reserved == 0 && type->flags.reserved2 == 0) + { + if (type->flags.tag == 0) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Constant value type void"); + return FALSE; + } + + if (value_size[type->flags.tag] != 0 && + blob->size != value_size[type->flags.tag]) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Constant value size mismatch"); + return FALSE; + } + /* FIXME check string values */ + } + + return TRUE; +} + +static gboolean +validate_value_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + ValueBlob *blob; + + if (typelib->len < offset + sizeof (ValueBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ValueBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "value", typelib->data, blob->name, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_field_blob (ValidateContext *ctx, + guint32 offset, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + Header *header = (Header *)typelib->data; + FieldBlob *blob; + + if (typelib->len < offset + sizeof (FieldBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (FieldBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "field", typelib->data, blob->name, error)) + return FALSE; + + if (blob->has_embedded_type) + { + if (!validate_callback_blob (ctx, offset + header->field_blob_size, error)) + return FALSE; + } + else if (!validate_type_blob (typelib, + offset + G_STRUCT_OFFSET (FieldBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_property_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + PropertyBlob *blob; + + if (typelib->len < offset + sizeof (PropertyBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (PropertyBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "property", typelib->data, blob->name, error)) + return FALSE; + + if (!validate_type_blob (typelib, + offset + G_STRUCT_OFFSET (PropertyBlob, type), + 0, FALSE, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_signal_blob (GITypelib *typelib, + guint32 offset, + guint32 container_offset, + GError **error) +{ + SignalBlob *blob; + gint n_signals; + + if (typelib->len < offset + sizeof (SignalBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (SignalBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "signal", typelib->data, blob->name, error)) + return FALSE; + + if ((blob->run_first != 0) + + (blob->run_last != 0) + + (blob->run_cleanup != 0) != 1) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid signal run flags"); + return FALSE; + } + + if (blob->has_class_closure) + { + if (((CommonBlob*)&typelib->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&typelib->data[container_offset]; + + n_signals = object->n_signals; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&typelib->data[container_offset]; + + n_signals = iface->n_signals; + } + + if (blob->class_closure >= n_signals) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (typelib, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_vfunc_blob (GITypelib *typelib, + guint32 offset, + guint32 container_offset, + GError **error) +{ + VFuncBlob *blob; + gint n_vfuncs; + + if (typelib->len < offset + sizeof (VFuncBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (VFuncBlob*) &typelib->data[offset]; + + if (!validate_name (typelib, "vfunc", typelib->data, blob->name, error)) + return FALSE; + + if (blob->class_closure) + { + if (((CommonBlob*)&typelib->data[container_offset])->blob_type == BLOB_TYPE_OBJECT) + { + ObjectBlob *object; + + object = (ObjectBlob*)&typelib->data[container_offset]; + + n_vfuncs = object->n_vfuncs; + } + else + { + InterfaceBlob *iface; + + iface = (InterfaceBlob*)&typelib->data[container_offset]; + + n_vfuncs = iface->n_vfuncs; + } + + if (blob->class_closure >= n_vfuncs) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid class closure index"); + return FALSE; + } + } + + if (!validate_signature_blob (typelib, blob->signature, error)) + return FALSE; + + return TRUE; +} + +static gboolean +validate_struct_blob (ValidateContext *ctx, + guint32 offset, + guint16 blob_type, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + StructBlob *blob; + gint i; + guint32 field_offset; + + if (typelib->len < offset + sizeof (StructBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (StructBlob*) &typelib->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!validate_name (typelib, "struct", typelib->data, blob->name, error)) + return FALSE; + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + if (!blob->unregistered) + { + if (!validate_name (typelib, "boxed", typelib->data, blob->gtype_name, error)) + return FALSE; + + if (!validate_name (typelib, "boxed", typelib->data, blob->gtype_init, error)) + return FALSE; + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Gtype data in struct"); + return FALSE; + } + } + + if (typelib->len < offset + sizeof (StructBlob) + + blob->n_fields * sizeof (FieldBlob) + + blob->n_methods * sizeof (FunctionBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + field_offset = offset + sizeof (StructBlob); + for (i = 0; i < blob->n_fields; i++) + { + FieldBlob *field_blob = (FieldBlob*) &typelib->data[field_offset]; + + if (!validate_field_blob (ctx, + field_offset, + error)) + return FALSE; + + field_offset += sizeof (FieldBlob); + if (field_blob->has_embedded_type) + field_offset += sizeof (CallbackBlob); + } + + for (i = 0; i < blob->n_methods; i++) + { + if (!validate_function_blob (ctx, + field_offset + + i * sizeof (FunctionBlob), + blob_type, + error)) + return FALSE; + } + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_enum_blob (ValidateContext *ctx, + guint32 offset, + guint16 blob_type, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + EnumBlob *blob; + gint i; + guint32 offset2; + + if (typelib->len < offset + sizeof (EnumBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (EnumBlob*) &typelib->data[offset]; + + if (blob->blob_type != blob_type) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!blob->unregistered) + { + if (!validate_name (typelib, "enum", typelib->data, blob->gtype_name, error)) + return FALSE; + + if (!validate_name (typelib, "enum", typelib->data, blob->gtype_init, error)) + return FALSE; + } + else + { + if (blob->gtype_name || blob->gtype_init) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Gtype data in unregistered enum"); + return FALSE; + } + } + + if (!validate_name (typelib, "enum", typelib->data, blob->name, error)) + return FALSE; + + if (typelib->len < offset + sizeof (EnumBlob) + + blob->n_values * sizeof (ValueBlob) + + blob->n_methods * sizeof (FunctionBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (EnumBlob); + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + for (i = 0; i < blob->n_values; i++, offset2 += sizeof (ValueBlob)) + { + if (!validate_value_blob (typelib, + offset2, + error)) + return FALSE; + +#if 0 + v1 = (ValueBlob *)&typelib->data[offset2]; + for (j = 0; j < i; j++) + { + v2 = (ValueBlob *)&typelib->data[offset2 + + j * sizeof (ValueBlob)]; + + if (v1->value == v2->value) + { + + /* FIXME should this be an error ? */ + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Duplicate enum value"); + return FALSE; + } + } +#endif + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (ctx, offset2, BLOB_TYPE_ENUM, error)) + return FALSE; + } + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_object_blob (ValidateContext *ctx, + guint32 offset, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + Header *header; + ObjectBlob *blob; + gint i; + guint32 offset2; + guint16 n_field_callbacks; + + header = (Header *)typelib->data; + + if (typelib->len < offset + sizeof (ObjectBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (ObjectBlob*) &typelib->data[offset]; + + if (blob->blob_type != BLOB_TYPE_OBJECT) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type"); + return FALSE; + } + + if (!validate_name (typelib, "object", typelib->data, blob->gtype_name, error)) + return FALSE; + + if (!validate_name (typelib, "object", typelib->data, blob->gtype_init, error)) + return FALSE; + + if (!validate_name (typelib, "object", typelib->data, blob->name, error)) + return FALSE; + + if (blob->parent > header->n_entries) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid parent index"); + return FALSE; + } + + if (blob->parent != 0) + { + DirEntry *entry; + + entry = get_dir_entry_checked (typelib, blob->parent, error); + if (!entry) + return FALSE; + if (entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Parent not object"); + return FALSE; + } + } + + if (blob->gtype_struct != 0) + { + DirEntry *entry; + + entry = get_dir_entry_checked (typelib, blob->gtype_struct, error); + if (!entry) + return FALSE; + if (entry->blob_type != BLOB_TYPE_STRUCT && entry->local) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Class struct invalid type or not local"); + return FALSE; + } + } + + if (typelib->len < offset + sizeof (ObjectBlob) + + (blob->n_interfaces + blob->n_interfaces % 2) * 2 + + blob->n_fields * sizeof (FieldBlob) + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (ObjectBlob); + + for (i = 0; i < blob->n_interfaces; i++, offset2 += 2) + { + guint16 iface; + DirEntry *entry; + + iface = *(guint16*)&typelib->data[offset2]; + if (iface == 0 || iface > header->n_entries) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid interface index"); + return FALSE; + } + + entry = get_dir_entry_checked (typelib, iface, error); + if (!entry) + return FALSE; + + if (entry->blob_type != BLOB_TYPE_INTERFACE && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Not an interface"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_interfaces %2); + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + n_field_callbacks = 0; + for (i = 0; i < blob->n_fields; i++) + { + FieldBlob *field_blob = (FieldBlob*) &typelib->data[offset2]; + + if (!validate_field_blob (ctx, offset2, error)) + return FALSE; + + offset2 += sizeof (FieldBlob); + /* Special case fields which are callbacks. */ + if (field_blob->has_embedded_type) { + offset2 += sizeof (CallbackBlob); + n_field_callbacks++; + } + } + + if (blob->n_field_callbacks != n_field_callbacks) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Incorrect number of field callbacks; expected " + "%" G_GUINT16_FORMAT ", got %" G_GUINT16_FORMAT, + blob->n_field_callbacks, n_field_callbacks); + return FALSE; + } + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (typelib, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (ctx, offset2, BLOB_TYPE_OBJECT, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (typelib, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (typelib, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (typelib, offset2, error)) + return FALSE; + } + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_interface_blob (ValidateContext *ctx, + guint32 offset, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + Header *header; + InterfaceBlob *blob; + gint i; + guint32 offset2; + + header = (Header *)typelib->data; + + if (typelib->len < offset + sizeof (InterfaceBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + blob = (InterfaceBlob*) &typelib->data[offset]; + + if (blob->blob_type != BLOB_TYPE_INTERFACE) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Wrong blob type; expected interface, got %d", blob->blob_type); + return FALSE; + } + + if (!validate_name (typelib, "interface", typelib->data, blob->gtype_name, error)) + return FALSE; + + if (!validate_name (typelib, "interface", typelib->data, blob->gtype_init, error)) + return FALSE; + + if (!validate_name (typelib, "interface", typelib->data, blob->name, error)) + return FALSE; + + if (typelib->len < offset + sizeof (InterfaceBlob) + + (blob->n_prerequisites + blob->n_prerequisites % 2) * 2 + + blob->n_properties * sizeof (PropertyBlob) + + blob->n_methods * sizeof (FunctionBlob) + + blob->n_signals * sizeof (SignalBlob) + + blob->n_vfuncs * sizeof (VFuncBlob) + + blob->n_constants * sizeof (ConstantBlob)) + + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + offset2 = offset + sizeof (InterfaceBlob); + + for (i = 0; i < blob->n_prerequisites; i++, offset2 += 2) + { + DirEntry *entry; + guint16 req; + + req = *(guint16*)&typelib->data[offset2]; + if (req == 0 || req > header->n_entries) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Invalid prerequisite index"); + return FALSE; + } + + entry = gi_typelib_get_dir_entry (typelib, req); + if (entry->blob_type != BLOB_TYPE_INTERFACE && + entry->blob_type != BLOB_TYPE_OBJECT && + (entry->local || entry->blob_type != 0)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_BLOB, + "Not an interface or object"); + return FALSE; + } + } + + offset2 += 2 * (blob->n_prerequisites % 2); + + push_context (ctx, get_string_nofail (typelib, blob->name)); + + for (i = 0; i < blob->n_properties; i++, offset2 += sizeof (PropertyBlob)) + { + if (!validate_property_blob (typelib, offset2, error)) + return FALSE; + } + + for (i = 0; i < blob->n_methods; i++, offset2 += sizeof (FunctionBlob)) + { + if (!validate_function_blob (ctx, offset2, BLOB_TYPE_INTERFACE, error)) + return FALSE; + } + + for (i = 0; i < blob->n_signals; i++, offset2 += sizeof (SignalBlob)) + { + if (!validate_signal_blob (typelib, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_vfuncs; i++, offset2 += sizeof (VFuncBlob)) + { + if (!validate_vfunc_blob (typelib, offset2, offset, error)) + return FALSE; + } + + for (i = 0; i < blob->n_constants; i++, offset2 += sizeof (ConstantBlob)) + { + if (!validate_constant_blob (typelib, offset2, error)) + return FALSE; + } + + pop_context (ctx); + + return TRUE; +} + +static gboolean +validate_union_blob (GITypelib *typelib, + guint32 offset, + GError **error) +{ + return TRUE; +} + +static gboolean +validate_blob (ValidateContext *ctx, + guint32 offset, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + CommonBlob *common; + + if (typelib->len < offset + sizeof (CommonBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + common = (CommonBlob*)&typelib->data[offset]; + + switch (common->blob_type) + { + case BLOB_TYPE_FUNCTION: + if (!validate_function_blob (ctx, offset, 0, error)) + return FALSE; + break; + case BLOB_TYPE_CALLBACK: + if (!validate_callback_blob (ctx, offset, error)) + return FALSE; + break; + case BLOB_TYPE_STRUCT: + case BLOB_TYPE_BOXED: + if (!validate_struct_blob (ctx, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_ENUM: + case BLOB_TYPE_FLAGS: + if (!validate_enum_blob (ctx, offset, common->blob_type, error)) + return FALSE; + break; + case BLOB_TYPE_OBJECT: + if (!validate_object_blob (ctx, offset, error)) + return FALSE; + break; + case BLOB_TYPE_INTERFACE: + if (!validate_interface_blob (ctx, offset, error)) + return FALSE; + break; + case BLOB_TYPE_CONSTANT: + if (!validate_constant_blob (typelib, offset, error)) + return FALSE; + break; + case BLOB_TYPE_UNION: + if (!validate_union_blob (typelib, offset, error)) + return FALSE; + break; + default: + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_ENTRY, + "Invalid blob type"); + return FALSE; + } + + return TRUE; +} + +static gboolean +validate_directory (ValidateContext *ctx, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + Header *header = (Header *)typelib->data; + DirEntry *entry; + gint i; + + if (typelib->len < header->directory + header->n_entries * sizeof (DirEntry)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + for (i = 0; i < header->n_entries; i++) + { + entry = gi_typelib_get_dir_entry (typelib, i + 1); + + if (!validate_name (typelib, "entry", typelib->data, entry->name, error)) + return FALSE; + + if ((entry->local && entry->blob_type == BLOB_TYPE_INVALID) || + entry->blob_type > BLOB_TYPE_UNION) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_DIRECTORY, + "Invalid entry type"); + return FALSE; + } + + if (i < header->n_local_entries) + { + if (!entry->local) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_DIRECTORY, + "Too few local directory entries"); + return FALSE; + } + + if (!is_aligned (entry->offset)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_DIRECTORY, + "Misaligned entry"); + return FALSE; + } + + if (!validate_blob (ctx, entry->offset, error)) + return FALSE; + } + else + { + if (entry->local) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID_DIRECTORY, + "Too many local directory entries"); + return FALSE; + } + + if (!validate_name (typelib, "namespace", typelib->data, entry->offset, error)) + return FALSE; + } + } + + return TRUE; +} + +static gboolean +validate_attributes (ValidateContext *ctx, + GError **error) +{ + GITypelib *typelib = ctx->typelib; + Header *header = (Header *)typelib->data; + + if (header->size < header->attributes + header->n_attributes * sizeof (AttributeBlob)) + { + g_set_error (error, + GI_TYPELIB_ERROR, + GI_TYPELIB_ERROR_INVALID, + "The buffer is too short"); + return FALSE; + } + + return TRUE; +} + +static void +prefix_with_context (GError **error, + const char *section, + ValidateContext *ctx) +{ + GString *str; + GSList *link; + char *buf; + + link = ctx->context_stack; + if (!link) + { + g_prefix_error (error, "In %s:", section); + return; + } + + str = g_string_new (NULL); + + for (; link; link = link->next) + { + g_string_append (str, link->data); + if (link->next) + g_string_append_c (str, '/'); + } + g_string_append_c (str, ')'); + buf = g_string_free (str, FALSE); + g_prefix_error (error, "In %s (Context: %s): ", section, buf); + g_free (buf); +} + +/** + * gi_typelib_validate: + * @typelib: a #GITypelib + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Check whether @typelib is well-formed, i.e. that the file is not corrupt or + * truncated. + * + * Returns: `TRUE` if @typelib is well-formed, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_typelib_validate (GITypelib *typelib, + GError **error) +{ + ValidateContext ctx; + ctx.typelib = typelib; + ctx.context_stack = NULL; + + if (!validate_header (&ctx, error)) + { + prefix_with_context (error, "In header", &ctx); + return FALSE; + } + + if (!validate_directory (&ctx, error)) + { + prefix_with_context (error, "directory", &ctx); + return FALSE; + } + + if (!validate_attributes (&ctx, error)) + { + prefix_with_context (error, "attributes", &ctx); + return FALSE; + } + + return TRUE; +} + +/** + * gi_typelib_error_quark: + * + * Get the quark representing the [type@GIRepository.TypelibError] error domain. + * + * Returns: quark representing the error domain + * Since: 2.80 + */ +GQuark +gi_typelib_error_quark (void) +{ + static GQuark quark = 0; + if (quark == 0) + quark = g_quark_from_static_string ("gi-typelib-error-quark"); + return quark; +} + +static GSList *library_paths; + +/** + * gi_repository_prepend_library_path: + * @directory: (type filename): a single directory to scan for shared libraries + * + * Prepends @directory to the search path that is used to + * search shared libraries referenced by imported namespaces. + * + * Multiple calls to this function all contribute to the final + * list of paths. + * + * The list of paths is unique and shared for all + * [class@GIRepository.Repository] instances across the process, but it doesn’t + * affect namespaces imported before the call. + * + * If the library is not found in the directories configured + * in this way, loading will fall back to the system library + * path (i.e. `LD_LIBRARY_PATH` and `DT_RPATH` in ELF systems). + * See the documentation of your dynamic linker for full details. + * + * Since: 2.80 + */ +void +gi_repository_prepend_library_path (const char *directory) +{ + library_paths = g_slist_prepend (library_paths, + g_strdup (directory)); +} + +/* Note on the GModule flags used by this function: + + * Glade's autoconnect feature and OpenGL's extension mechanism + * as used by Clutter rely on g_module_open(NULL) to work as a means of + * accessing the app's symbols. This keeps us from using + * G_MODULE_BIND_LOCAL. BIND_LOCAL may have other issues as well; + * in general libraries are not expecting multiple copies of + * themselves and are not expecting to be unloaded. So we just + * load modules globally for now. + */ +static GModule * +load_one_shared_library (const char *shlib) +{ + GSList *p; + GModule *m; + +#ifdef __APPLE__ + /* On macOS, @-prefixed shlib paths (@rpath, @executable_path, @loader_path) + need to be treated as absolute; trying to combine them with a + configured library path produces a mangled path that is unresolvable + and may cause unintended side effects (such as loading the library + from a fall-back location on macOS 12.0.1). + */ + if (!g_path_is_absolute (shlib) && !g_str_has_prefix (shlib, "@")) +#else + if (!g_path_is_absolute (shlib)) +#endif + { + /* First try in configured library paths */ + for (p = library_paths; p; p = p->next) + { + char *path = g_build_filename (p->data, shlib, NULL); + + m = g_module_open (path, G_MODULE_BIND_LAZY); + + g_free (path); + if (m != NULL) + return m; + } + } + + /* Then try loading from standard paths */ + /* Do not attempt to fix up shlib to replace .la with .so: + it's done by GModule anyway. + */ + return g_module_open (shlib, G_MODULE_BIND_LAZY); +} + +static void +gi_typelib_do_dlopen (GITypelib *typelib) +{ + Header *header; + const char *shlib_str; + + header = (Header *) typelib->data; + /* note that NULL shlib means to open the main app, which is allowed */ + if (header->shared_library) + shlib_str = gi_typelib_get_string (typelib, header->shared_library); + else + shlib_str = NULL; + + if (shlib_str != NULL && shlib_str[0] != '\0') + { + gchar **shlibs; + gint i; + + /* shared-library is a comma-separated list of libraries */ + shlibs = g_strsplit (shlib_str, ",", 0); + + /* We load all passed libs unconditionally as if the same library is loaded + * again with g_module_open(), the same file handle will be returned. See bug: + * http://bugzilla.gnome.org/show_bug.cgi?id=555294 + */ + for (i = 0; shlibs[i]; i++) + { + GModule *module; + + module = load_one_shared_library (shlibs[i]); + + if (module == NULL) + { + g_warning ("Failed to load shared library '%s' referenced by the typelib: %s", + shlibs[i], g_module_error ()); + } + else + { + typelib->modules = g_list_append (typelib->modules, module); + } + } + + g_strfreev (shlibs); + } + else + { + /* If there's no shared-library entry for this module, assume that + * the module is for the application. Some of the hand-written .gir files + * in gobject-introspection don't have shared-library entries, but no one + * is really going to be calling g_module_symbol on them either. + */ + GModule *module = g_module_open (NULL, 0); + if (module == NULL) + g_warning ("gtypelib.c: Failed to g_module_open (NULL): %s", g_module_error ()); + else + typelib->modules = g_list_prepend (typelib->modules, module); + } +} + +static inline void +gi_typelib_ensure_open (GITypelib *typelib) +{ + if (typelib->open_attempted) + return; + typelib->open_attempted = TRUE; + gi_typelib_do_dlopen (typelib); +} + +/** + * gi_typelib_new_from_memory: (skip) + * @memory: (array length=len): address of memory chunk containing the typelib + * @len: length of memory chunk containing the typelib, in bytes + * @error: a [type@GLib.Error] + * + * Creates a new [type@GIRepository.Typelib] from a memory location. + * + * The memory block pointed to by @typelib will be automatically freed when the + * repository is destroyed. + * + * Returns: (transfer full): the new [type@GIRepository.Typelib] + * Since: 2.80 + */ +GITypelib * +gi_typelib_new_from_memory (guint8 *memory, + gsize len, + GError **error) +{ + GITypelib *meta; + + if (!validate_header_basic (memory, len, error)) + return NULL; + + meta = g_slice_new0 (GITypelib); + meta->data = memory; + meta->len = len; + meta->owns_memory = TRUE; + meta->modules = NULL; + + return meta; +} + +/** + * gi_typelib_new_from_const_memory: (skip) + * @memory: (array length=len): address of memory chunk containing the typelib + * @len: length of memory chunk containing the typelib + * @error: a [type@GLib.Error] + * + * Creates a new [type@GIRepository.Typelib] from a memory location. + * + * Returns: (transfer full): the new [type@GIRepository.Typelib] + * Since: 2.80 + */ +GITypelib * +gi_typelib_new_from_const_memory (const guchar *memory, + gsize len, + GError **error) +{ + GITypelib *meta; + + if (!validate_header_basic (memory, len, error)) + return NULL; + + meta = g_slice_new0 (GITypelib); + meta->data = (guchar *) memory; + meta->len = len; + meta->owns_memory = FALSE; + meta->modules = NULL; + + return meta; +} + +/** + * gi_typelib_new_from_mapped_file: (skip) + * @mfile: (transfer full): a [type@GLib.MappedFile], that will be freed when + * the repository is destroyed + * @error: a #GError + * + * Creates a new [type@GIRepository.Typelib] from a [type@GLib.MappedFile]. + * + * Returns: (transfer full): the new [type@GIRepository.Typelib] + * Since: 2.80 + */ +GITypelib * +gi_typelib_new_from_mapped_file (GMappedFile *mfile, + GError **error) +{ + GITypelib *meta; + guint8 *data = (guint8 *) g_mapped_file_get_contents (mfile); + gsize len = g_mapped_file_get_length (mfile); + + if (!validate_header_basic (data, len, error)) + return NULL; + + meta = g_slice_new0 (GITypelib); + meta->mfile = mfile; + meta->owns_memory = FALSE; + meta->data = data; + meta->len = len; + + return meta; +} + +/** + * gi_typelib_free: + * @typelib: (transfer full): a #GITypelib + * + * Free a [type@GIRepository.Typelib]. + * + * Since: 2.80 + */ +void +gi_typelib_free (GITypelib *typelib) +{ + if (typelib->mfile) + g_mapped_file_unref (typelib->mfile); + else + if (typelib->owns_memory) + g_free (typelib->data); + if (typelib->modules) + { + g_list_foreach (typelib->modules, (GFunc) (void *) g_module_close, NULL); + g_list_free (typelib->modules); + } + g_slice_free (GITypelib, typelib); +} + +/** + * gi_typelib_get_namespace: + * @typelib: a #GITypelib + * + * Get the name of the namespace represented by @typelib. + * + * Returns: name of the namespace represented by @typelib + * Since: 2.80 + */ +const gchar * +gi_typelib_get_namespace (GITypelib *typelib) +{ + return gi_typelib_get_string (typelib, ((Header *) typelib->data)->namespace); +} + +/** + * gi_typelib_symbol: + * @typelib: the typelib + * @symbol_name: name of symbol to be loaded + * @symbol: (out) (nullable): returns a pointer to the symbol value, or `NULL` + * on failure + * + * Loads a symbol from a `GITypelib`. + * + * Returns: `TRUE` on success + * Since: 2.80 + */ +gboolean +gi_typelib_symbol (GITypelib *typelib, const char *symbol_name, gpointer *symbol) +{ + GList *l; + + gi_typelib_ensure_open (typelib); + + /* + * The reason for having multiple modules dates from gir-repository + * when it was desired to inject code (accessors, etc.) into an + * existing library. In that situation, the first module listed + * will be the custom one, which overrides the main one. A bit + * inefficient, but the problem will go away when gir-repository + * does. + * + * For modules with no shared library, we dlopen'd the current + * process above. + */ + for (l = typelib->modules; l; l = l->next) + { + GModule *module = l->data; + + if (g_module_symbol (module, symbol_name, symbol)) + return TRUE; + } + + return FALSE; +} diff --git a/girepository/gitypelib.h b/girepository/gitypelib.h new file mode 100644 index 0000000..0f965a0 --- /dev/null +++ b/girepository/gitypelib.h @@ -0,0 +1,65 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Public typelib API + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +#include + +G_BEGIN_DECLS + +typedef struct _GITypelib GITypelib; + +GI_AVAILABLE_IN_ALL +GITypelib * gi_typelib_new_from_memory (guint8 *memory, + gsize len, + GError **error); + +GI_AVAILABLE_IN_ALL +GITypelib * gi_typelib_new_from_const_memory (const guint8 *memory, + gsize len, + GError **error); + +GI_AVAILABLE_IN_ALL +GITypelib * gi_typelib_new_from_mapped_file (GMappedFile *mfile, + GError **error); + +GI_AVAILABLE_IN_ALL +void gi_typelib_free (GITypelib *typelib); + +GI_AVAILABLE_IN_ALL +gboolean gi_typelib_symbol (GITypelib *typelib, + const gchar *symbol_name, + gpointer *symbol); + +GI_AVAILABLE_IN_ALL +const gchar * gi_typelib_get_namespace (GITypelib *typelib); + + +G_END_DECLS diff --git a/girepository/gitypes.h b/girepository/gitypes.h new file mode 100644 index 0000000..c1e8386 --- /dev/null +++ b/girepository/gitypes.h @@ -0,0 +1,473 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: types + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include +#include + +#include "gi-visibility.h" + +G_BEGIN_DECLS + +/* Documented in gibaseinfo.c */ +typedef struct _GIBaseInfo GIBaseInfo; +typedef struct _GIBaseInfoClass GIBaseInfoClass; + +/* Documented in gicallableinfo.c */ +typedef struct _GICallableInfo GICallableInfo; +GI_AVAILABLE_IN_ALL GType gi_callable_info_get_type (void); + +/* Documented in gifunctioninfo.c */ +typedef struct _GIFunctionInfo GIFunctionInfo; +GI_AVAILABLE_IN_ALL GType gi_function_info_get_type (void); + +/* Documented in gicallbackinfo.c */ +typedef struct _GICallbackInfo GICallbackInfo; +GI_AVAILABLE_IN_ALL GType gi_callback_info_get_type (void); + +/* Documented in giregisteredtypeinfo.c */ +typedef struct _GIRegisteredTypeInfo GIRegisteredTypeInfo; +GI_AVAILABLE_IN_ALL GType gi_registered_type_info_get_type (void); + +/* Documented in gistructinfo.c */ +typedef struct _GIStructInfo GIStructInfo; +GI_AVAILABLE_IN_ALL GType gi_struct_info_get_type (void); + +/* Documented in giunioninfo.c */ +typedef struct _GIUnionInfo GIUnionInfo; +GI_AVAILABLE_IN_ALL GType gi_union_info_get_type (void); + +/* Documented in gienuminfo.c */ +typedef struct _GIEnumInfo GIEnumInfo; +GI_AVAILABLE_IN_ALL GType gi_enum_info_get_type (void); + +/* Documented in giobjectinfo.c */ +typedef struct _GIObjectInfo GIObjectInfo; +GI_AVAILABLE_IN_ALL GType gi_object_info_get_type (void); + +/* Documented in giinterfaceinfo.c */ +typedef struct _GIInterfaceInfo GIInterfaceInfo; +GI_AVAILABLE_IN_ALL GType gi_interface_info_get_type (void); + +/* Documented in giconstantinfo.c */ +typedef struct _GIConstantInfo GIConstantInfo; +GI_AVAILABLE_IN_ALL GType gi_constant_info_get_type (void); + +/* Documented in givalueinfo.c */ +typedef struct _GIValueInfo GIValueInfo; +GI_AVAILABLE_IN_ALL GType gi_value_info_get_type (void); + +/* Documented in gisignalinfo.c */ +typedef struct _GISignalInfo GISignalInfo; +GI_AVAILABLE_IN_ALL GType gi_signal_info_get_type (void); + +/* Documented in givfuncinfo.c */ +typedef struct _GIVFuncInfo GIVFuncInfo; +GI_AVAILABLE_IN_ALL GType gi_vfunc_info_get_type (void); + +/* Documented in gipropertyinfo.c */ +typedef struct _GIPropertyInfo GIPropertyInfo; +GI_AVAILABLE_IN_ALL GType gi_property_info_get_type (void); + +/* Documented in gifieldinfo.c */ +typedef struct _GIFieldInfo GIFieldInfo; +GI_AVAILABLE_IN_ALL GType gi_field_info_get_type (void); + +/* Documented in giarginfo.c */ +typedef struct _GIArgInfo GIArgInfo; +GI_AVAILABLE_IN_ALL GType gi_arg_info_get_type (void); + +/* Documented in gitypeinfo.c */ +typedef struct _GITypeInfo GITypeInfo; +GI_AVAILABLE_IN_ALL GType gi_type_info_get_type (void); + +/* Documented in giunresolvedinfo.c */ +typedef struct _GIUnresolvedInfo GIUnresolvedInfo; +GI_AVAILABLE_IN_ALL GType gi_unresolved_info_get_type (void); + +union _GIArgument +{ + gboolean v_boolean; + gint8 v_int8; + guint8 v_uint8; + gint16 v_int16; + guint16 v_uint16; + gint32 v_int32; + guint32 v_uint32; + gint64 v_int64; + guint64 v_uint64; + gfloat v_float; + gdouble v_double; + gshort v_short; + gushort v_ushort; + gint v_int; + guint v_uint; + glong v_long; + gulong v_ulong; + gssize v_ssize; + gsize v_size; + gchar * v_string; + gpointer v_pointer; +}; + +/** + * GIArgument: + * @v_boolean: boolean value + * @v_int8: 8-bit signed integer value + * @v_uint8: 8-bit unsigned integer value + * @v_int16: 16-bit signed integer value + * @v_uint16: 16-bit unsigned integer value + * @v_int32: 32-bit signed integer value + * @v_uint32: 32-bit unsigned integer value + * @v_int64: 64-bit signed integer value + * @v_uint64: 64-bit unsigned integer value + * @v_float: single float value + * @v_double: double float value + * @v_short: signed short integer value + * @v_ushort: unsigned short integer value + * @v_int: signed integer value + * @v_uint: unsigned integer value + * @v_long: signed long integer value + * @v_ulong: unsigned long integer value + * @v_ssize: sized `size_t` value + * @v_size: unsigned `size_t` value + * @v_string: nul-terminated string value + * @v_pointer: arbitrary pointer value + * + * Stores an argument of varying type. + * + * Since: 2.80 + */ +typedef union _GIArgument GIArgument; + +/** + * GIInfoType: + * @GI_INFO_TYPE_INVALID: invalid type + * @GI_INFO_TYPE_FUNCTION: function, see [class@GIRepository.FunctionInfo] + * @GI_INFO_TYPE_CALLBACK: callback, see [class@GIRepository.FunctionInfo] + * @GI_INFO_TYPE_STRUCT: struct, see [class@GIRepository.StructInfo] + * @GI_INFO_TYPE_BOXED: boxed, see [class@GIRepository.StructInfo] or + * [class@GIRepository.UnionInfo] + * @GI_INFO_TYPE_ENUM: enum, see [class@GIRepository.EnumInfo] + * @GI_INFO_TYPE_FLAGS: flags, see [class@GIRepository.EnumInfo] + * @GI_INFO_TYPE_OBJECT: object, see [class@GIRepository.ObjectInfo] + * @GI_INFO_TYPE_INTERFACE: interface, see [class@GIRepository.InterfaceInfo] + * @GI_INFO_TYPE_CONSTANT: constant, see [class@GIRepository.ConstantInfo] + * @GI_INFO_TYPE_INVALID_0: deleted, used to be `GI_INFO_TYPE_ERROR_DOMAIN`. + * @GI_INFO_TYPE_UNION: union, see [class@GIRepository.UnionInfo] + * @GI_INFO_TYPE_VALUE: enum value, see [class@GIRepository.ValueInfo] + * @GI_INFO_TYPE_SIGNAL: signal, see [class@GIRepository.SignalInfo] + * @GI_INFO_TYPE_VFUNC: virtual function, see [class@GIRepository.VFuncInfo] + * @GI_INFO_TYPE_PROPERTY: [class@GObject.Object] property, see + * [class@GIRepository.PropertyInfo] + * @GI_INFO_TYPE_FIELD: struct or union field, see + * [class@GIRepository.FieldInfo] + * @GI_INFO_TYPE_ARG: argument of a function or callback, see + * [class@GIRepository.ArgInfo] + * @GI_INFO_TYPE_TYPE: type information, see [class@GIRepository.TypeInfo] + * @GI_INFO_TYPE_UNRESOLVED: unresolved type, a type which is not present in + * the typelib, or any of its dependencies, see + * [class@GIRepository.UnresolvedInfo] + * @GI_INFO_TYPE_CALLABLE: an abstract type representing any callable (function, + * callback, vfunc), see [class@GIRepository.CallableInfo] + * @GI_INFO_TYPE_REGISTERED_TYPE: an abstract type representing any registered + * type (enum, interface, object, struct, union), see + * [class@GIRepository.RegisteredTypeInfo] + * + * The type of a [class@GIRepository.BaseInfo] struct. + * + * See [const@GIRepository.INFO_TYPE_N_TYPES] for the total number of elements + * in this enum. + * + * Since: 2.80 + */ +typedef enum +{ + GI_INFO_TYPE_INVALID, + GI_INFO_TYPE_FUNCTION, + GI_INFO_TYPE_CALLBACK, + GI_INFO_TYPE_STRUCT, + GI_INFO_TYPE_BOXED, + GI_INFO_TYPE_ENUM, /* 5 */ + GI_INFO_TYPE_FLAGS, + GI_INFO_TYPE_OBJECT, + GI_INFO_TYPE_INTERFACE, + GI_INFO_TYPE_CONSTANT, + GI_INFO_TYPE_INVALID_0, /* 10 */ + GI_INFO_TYPE_UNION, + GI_INFO_TYPE_VALUE, + GI_INFO_TYPE_SIGNAL, + GI_INFO_TYPE_VFUNC, + GI_INFO_TYPE_PROPERTY, /* 15 */ + GI_INFO_TYPE_FIELD, + GI_INFO_TYPE_ARG, + GI_INFO_TYPE_TYPE, + GI_INFO_TYPE_UNRESOLVED, + GI_INFO_TYPE_CALLABLE, /* 20 */ + GI_INFO_TYPE_REGISTERED_TYPE, + /* keep GI_INFO_TYPE_N_TYPES in sync with this */ +} GIInfoType; + +/** + * GI_INFO_TYPE_N_TYPES: + * + * Number of entries in [enum@GIRepository.InfoType]. + * + * Since: 2.80 + */ +#define GI_INFO_TYPE_N_TYPES (GI_INFO_TYPE_REGISTERED_TYPE + 1) + +/** + * GITransfer: + * @GI_TRANSFER_NOTHING: Transfer nothing from the callee (function or the type + * instance the property belongs to) to the caller. The callee retains the + * ownership of the transfer and the caller doesn’t need to do anything to + * free up the resources of this transfer. + * @GI_TRANSFER_CONTAINER: Transfer the container (list, array, hash table) from + * the callee to the caller. The callee retains the ownership of the + * individual items in the container and the caller has to free up the + * container resources ([func@GLib.List.free], + * [func@GLib.HashTable.destroy], etc) of this transfer. + * @GI_TRANSFER_EVERYTHING: Transfer everything, e.g. the container and its + * contents from the callee to the caller. This is the case when the callee + * creates a copy of all the data it returns. The caller is responsible for + * cleaning up the container and item resources of this transfer. + * + * `GITransfer` specifies who’s responsible for freeing the resources after an + * ownership transfer is complete. + * + * The transfer is the exchange of data between two parts, from the callee to + * the caller. + * + * The callee is either a function/method/signal or an object/interface where a + * property is defined. The caller is the side accessing a property or calling a + * function. + * + * In the case of a containing type such as a list, an array or a hash table the + * container itself is specified differently from the items within the + * container. Each container is freed differently, check the documentation for + * the types themselves for information on how to free them. + * + * Since: 2.80 + */ +typedef enum { + GI_TRANSFER_NOTHING, + GI_TRANSFER_CONTAINER, + GI_TRANSFER_EVERYTHING +} GITransfer; + +/** + * GIDirection: + * @GI_DIRECTION_IN: ‘in’ argument. + * @GI_DIRECTION_OUT: ‘out’ argument. + * @GI_DIRECTION_INOUT: ‘in and out’ argument. + * + * The direction of a [class@GIRepository.ArgInfo]. + * + * Since: 2.80 + */ +typedef enum { + GI_DIRECTION_IN, + GI_DIRECTION_OUT, + GI_DIRECTION_INOUT +} GIDirection; + +/** + * GIScopeType: + * @GI_SCOPE_TYPE_INVALID: The argument is not of callback type. + * @GI_SCOPE_TYPE_CALL: The callback and associated `user_data` is only + * used during the call to this function. + * @GI_SCOPE_TYPE_ASYNC: The callback and associated `user_data` is + * only used until the callback is invoked, and the callback. + * is invoked always exactly once. + * @GI_SCOPE_TYPE_NOTIFIED: The callback and associated + * `user_data` is used until the caller is notified via the + * [type@GLib.DestroyNotify]. + * @GI_SCOPE_TYPE_FOREVER: The callback and associated `user_data` is + * used until the process terminates + * + * Scope type of a [class@GIRepository.ArgInfo] representing callback, + * determines how the callback is invoked and is used to decided when the invoke + * structs can be freed. + * + * Since: 2.80 + */ +typedef enum { + GI_SCOPE_TYPE_INVALID, + GI_SCOPE_TYPE_CALL, + GI_SCOPE_TYPE_ASYNC, + GI_SCOPE_TYPE_NOTIFIED, + GI_SCOPE_TYPE_FOREVER +} GIScopeType; + +/** + * GITypeTag: + * @GI_TYPE_TAG_VOID: void + * @GI_TYPE_TAG_BOOLEAN: boolean + * @GI_TYPE_TAG_INT8: 8-bit signed integer + * @GI_TYPE_TAG_UINT8: 8-bit unsigned integer + * @GI_TYPE_TAG_INT16: 16-bit signed integer + * @GI_TYPE_TAG_UINT16: 16-bit unsigned integer + * @GI_TYPE_TAG_INT32: 32-bit signed integer + * @GI_TYPE_TAG_UINT32: 32-bit unsigned integer + * @GI_TYPE_TAG_INT64: 64-bit signed integer + * @GI_TYPE_TAG_UINT64: 64-bit unsigned integer + * @GI_TYPE_TAG_FLOAT: float + * @GI_TYPE_TAG_DOUBLE: double floating point + * @GI_TYPE_TAG_GTYPE: a [type@GObject.Type] + * @GI_TYPE_TAG_UTF8: a UTF-8 encoded string + * @GI_TYPE_TAG_FILENAME: a filename, encoded in the same encoding + * as the native filesystem is using. + * @GI_TYPE_TAG_ARRAY: an array + * @GI_TYPE_TAG_INTERFACE: an extended interface object + * @GI_TYPE_TAG_GLIST: a [type@GLib.List] + * @GI_TYPE_TAG_GSLIST: a [type@GLib.SList] + * @GI_TYPE_TAG_GHASH: a [type@GLib.HashTable] + * @GI_TYPE_TAG_ERROR: a [type@GLib.Error] + * @GI_TYPE_TAG_UNICHAR: Unicode character + * + * The type tag of a [class@GIRepository.TypeInfo]. + * + * Since: 2.80 + */ +typedef enum { + /* Basic types */ + GI_TYPE_TAG_VOID = 0, + GI_TYPE_TAG_BOOLEAN = 1, + GI_TYPE_TAG_INT8 = 2, /* Start of GI_TYPE_TAG_IS_NUMERIC types */ + GI_TYPE_TAG_UINT8 = 3, + GI_TYPE_TAG_INT16 = 4, + GI_TYPE_TAG_UINT16 = 5, + GI_TYPE_TAG_INT32 = 6, + GI_TYPE_TAG_UINT32 = 7, + GI_TYPE_TAG_INT64 = 8, + GI_TYPE_TAG_UINT64 = 9, + GI_TYPE_TAG_FLOAT = 10, + GI_TYPE_TAG_DOUBLE = 11, /* End of numeric types */ + GI_TYPE_TAG_GTYPE = 12, + GI_TYPE_TAG_UTF8 = 13, + GI_TYPE_TAG_FILENAME = 14, + /* Non-basic types; compare with GI_TYPE_TAG_IS_BASIC */ + GI_TYPE_TAG_ARRAY = 15, /* container (see GI_TYPE_TAG_IS_CONTAINER) */ + GI_TYPE_TAG_INTERFACE = 16, + GI_TYPE_TAG_GLIST = 17, /* container */ + GI_TYPE_TAG_GSLIST = 18, /* container */ + GI_TYPE_TAG_GHASH = 19, /* container */ + GI_TYPE_TAG_ERROR = 20, + /* Another basic type */ + GI_TYPE_TAG_UNICHAR = 21 + /* Note - there is currently only room for 32 tags */ +} GITypeTag; + +/** + * GI_TYPE_TAG_N_TYPES: + * + * Number of entries in [enum@GIRepository.TypeTag]. + * + * Since: 2.80 + */ +#define GI_TYPE_TAG_N_TYPES (GI_TYPE_TAG_UNICHAR+1) + +/** + * GIArrayType: + * @GI_ARRAY_TYPE_C: a C array, `char[]` for instance + * @GI_ARRAY_TYPE_ARRAY: a [type@GLib.Array] array + * @GI_ARRAY_TYPE_PTR_ARRAY: a [type@GLib.PtrArray] array + * @GI_ARRAY_TYPE_BYTE_ARRAY: a [type@GLib.ByteArray] array + * + * The type of array in a [class@GIRepository.TypeInfo]. + * + * Since: 2.80 + */ +typedef enum { + GI_ARRAY_TYPE_C, + GI_ARRAY_TYPE_ARRAY, + GI_ARRAY_TYPE_PTR_ARRAY, + GI_ARRAY_TYPE_BYTE_ARRAY +} GIArrayType; + +/** + * GIFieldInfoFlags: + * @GI_FIELD_IS_READABLE: field is readable. + * @GI_FIELD_IS_WRITABLE: field is writable. + * + * Flags for a [class@GIRepository.FieldInfo]. + * + * Since: 2.80 + */ + +typedef enum +{ + GI_FIELD_IS_READABLE = 1 << 0, + GI_FIELD_IS_WRITABLE = 1 << 1 +} GIFieldInfoFlags; + +/** + * GIVFuncInfoFlags: + * @GI_VFUNC_MUST_CHAIN_UP: chains up to the parent type + * @GI_VFUNC_MUST_OVERRIDE: overrides + * @GI_VFUNC_MUST_NOT_OVERRIDE: does not override + * @GI_VFUNC_THROWS: includes a [type@GLib.Error] + * + * Flags of a [class@GIRepository.VFuncInfo] struct. + * + * Since: 2.80 + */ +typedef enum +{ + GI_VFUNC_MUST_CHAIN_UP = 1 << 0, + GI_VFUNC_MUST_OVERRIDE = 1 << 1, + GI_VFUNC_MUST_NOT_OVERRIDE = 1 << 2, + GI_VFUNC_THROWS = 1 << 3 +} GIVFuncInfoFlags; + +/** + * GIFunctionInfoFlags: + * @GI_FUNCTION_IS_METHOD: is a method. + * @GI_FUNCTION_IS_CONSTRUCTOR: is a constructor. + * @GI_FUNCTION_IS_GETTER: is a getter of a [class@GIRepository.PropertyInfo]. + * @GI_FUNCTION_IS_SETTER: is a setter of a [class@GIRepository.PropertyInfo]. + * @GI_FUNCTION_WRAPS_VFUNC: represents a virtual function. + * @GI_FUNCTION_THROWS: the function may throw an error. + * + * Flags for a [class@GIRepository.FunctionInfo] struct. + * + * Since: 2.80 + */ +typedef enum +{ + GI_FUNCTION_IS_METHOD = 1 << 0, + GI_FUNCTION_IS_CONSTRUCTOR = 1 << 1, + GI_FUNCTION_IS_GETTER = 1 << 2, + GI_FUNCTION_IS_SETTER = 1 << 3, + GI_FUNCTION_WRAPS_VFUNC = 1 << 4, + GI_FUNCTION_THROWS = 1 << 5 +} GIFunctionInfoFlags; + +G_END_DECLS diff --git a/girepository/giunioninfo.c b/girepository/giunioninfo.c new file mode 100644 index 0000000..8901452 --- /dev/null +++ b/girepository/giunioninfo.c @@ -0,0 +1,351 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Union implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giunioninfo.h" + +/** + * GIUnionInfo: + * + * `GIUnionInfo` represents a union type. + * + * A union has methods and fields. Unions can optionally have a + * discriminator, which is a field deciding what type of real union + * fields is valid for specified instance. + * + * Since: 2.80 + */ + +/** + * gi_union_info_get_n_fields: + * @info: a #GIUnionInfo + * + * Obtain the number of fields this union has. + * + * Returns: number of fields + * Since: 2.80 + */ +guint +gi_union_info_get_n_fields (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_fields; +} + +/** + * gi_union_info_get_field: + * @info: a #GIUnionInfo + * @n: a field index + * + * Obtain the type information for the field with the specified index. + * + * Returns: (transfer full): the [type@GIRepository.FieldInfo], free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFieldInfo * +gi_union_info_get_field (GIUnionInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + + return (GIFieldInfo *) gi_info_new (GI_INFO_TYPE_FIELD, (GIBaseInfo*)info, rinfo->typelib, + rinfo->offset + header->union_blob_size + + n * header->field_blob_size); +} + +/** + * gi_union_info_get_n_methods: + * @info: a #GIUnionInfo + * + * Obtain the number of methods this union has. + * + * Returns: number of methods + * Since: 2.80 + */ +guint +gi_union_info_get_n_methods (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->n_functions; +} + +/** + * gi_union_info_get_method: + * @info: a #GIUnionInfo + * @n: a method index + * + * Obtain the type information for the method with the specified index. + * + * Returns: (transfer full): the [type@GIRepository.FunctionInfo], free it + * with [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_union_info_get_method (GIUnionInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + Header *header = (Header *)rinfo->typelib->data; + gint offset; + + offset = rinfo->offset + header->union_blob_size + + blob->n_fields * header->field_blob_size + + n * header->function_blob_size; + return (GIFunctionInfo *) gi_info_new (GI_INFO_TYPE_FUNCTION, (GIBaseInfo*)info, + rinfo->typelib, offset); +} + +/** + * gi_union_info_is_discriminated: + * @info: a #GIUnionInfo + * + * Return `TRUE` if this union contains a discriminator field. + * + * Returns: `TRUE` if this is a discriminated union, `FALSE` otherwise + * Since: 2.80 + */ +gboolean +gi_union_info_is_discriminated (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->discriminated; +} + +/** + * gi_union_info_get_discriminator_offset: + * @info: a #GIUnionInfo + * + * Returns the offset of the discriminator field in the structure. + * + * Returns: offset, in bytes, of the discriminator + * Since: 2.80 + */ +guint +gi_union_info_get_discriminator_offset (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->discriminator_offset; +} + +/** + * gi_union_info_get_discriminator_type: + * @info: a #GIUnionInfo + * + * Obtain the type information of the union discriminator. + * + * Returns: (transfer full): the [type@GIRepository.TypeInfo], free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GITypeInfo * +gi_union_info_get_discriminator_type (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + + return gi_type_info_new ((GIBaseInfo*)info, rinfo->typelib, rinfo->offset + 24); +} + +/** + * gi_union_info_get_discriminator: + * @info: a #GIUnionInfo + * @n: a union field index + * + * Obtain the discriminator value assigned for n-th union field, i.e. the n-th + * union field is the active one if the discriminator contains this + * constant. + * + * If the union is not discriminated, `NULL` is returned. + * + * Returns: (transfer full) (nullable): The [type@GIRepository.ConstantInfo], or + * `NULL` if the union is not discriminated. Free it with + * [method@GIRepository.BaseInfo.unref] when done. + * Since: 2.80 + */ +GIConstantInfo * +gi_union_info_get_discriminator (GIUnionInfo *info, + guint n) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->discriminated) + { + Header *header = (Header *)rinfo->typelib->data; + gint offset; + + offset = rinfo->offset + header->union_blob_size + + blob->n_fields * header->field_blob_size + + blob->n_functions * header->function_blob_size + + n * header->constant_blob_size; + + return (GIConstantInfo *) gi_info_new (GI_INFO_TYPE_CONSTANT, (GIBaseInfo*)info, + rinfo->typelib, offset); + } + + return NULL; +} + +/** + * gi_union_info_find_method: + * @info: a #GIUnionInfo + * @name: a method name + * + * Obtain the type information for the method named @name. + * + * Returns: (transfer full) (nullable): The [type@GIRepository.FunctionInfo], or + * `NULL` if none was found. Free it with [method@GIRepository.BaseInfo.unref] + * when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_union_info_find_method (GIUnionInfo *info, + const gchar *name) +{ + gint offset; + GIRealInfo *rinfo = (GIRealInfo *)info; + Header *header = (Header *)rinfo->typelib->data; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + offset = rinfo->offset + header->union_blob_size + + blob->n_fields * header->field_blob_size; + + return gi_base_info_find_method ((GIBaseInfo*)info, offset, blob->n_functions, name); +} + +/** + * gi_union_info_get_size: + * @info: a #GIUnionInfo + * + * Obtain the total size of the union. + * + * Returns: size of the union, in bytes + * Since: 2.80 + */ +gsize +gi_union_info_get_size (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->size; +} + +/** + * gi_union_info_get_alignment: + * @info: a #GIUnionInfo + * + * Obtain the required alignment of the union. + * + * Returns: required alignment, in bytes + * Since: 2.80 + */ +gsize +gi_union_info_get_alignment (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->alignment; +} + +/** + * gi_union_info_get_copy_function_name: + * @info: a union information blob + * + * Retrieves the name of the copy function for @info, if any is set. + * + * Returns: (transfer none) (nullable): the name of the copy function, or `NULL` + * if none is set + * Since: 2.80 + */ +const char * +gi_union_info_get_copy_function_name (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL); + + blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->copy_func) + return gi_typelib_get_string (rinfo->typelib, blob->copy_func); + + return NULL; +} + +/** + * gi_union_info_get_free_function_name: + * @info: a union information blob + * + * Retrieves the name of the free function for @info, if any is set. + * + * Returns: (transfer none) (nullable): the name of the free function, or `NULL` + * if none is set + * Since: 2.80 + */ +const char * +gi_union_info_get_free_function_name (GIUnionInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + UnionBlob *blob; + + g_return_val_if_fail (info != NULL, NULL); + g_return_val_if_fail (GI_IS_UNION_INFO (info), NULL); + + blob = (UnionBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->free_func) + return gi_typelib_get_string (rinfo->typelib, blob->free_func); + + return NULL; +} + +void +gi_union_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_UNION; +} diff --git a/girepository/giunioninfo.h b/girepository/giunioninfo.h new file mode 100644 index 0000000..f0e0bbd --- /dev/null +++ b/girepository/giunioninfo.h @@ -0,0 +1,89 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Union + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_UNION_INFO: + * @info: an info structure + * + * Checks if @info is a [struct@GIRepository.UnionInfo]. + * + * Since: 2.80 + */ +#define GI_IS_UNION_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_UNION) + +GI_AVAILABLE_IN_ALL +guint gi_union_info_get_n_fields (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +GIFieldInfo * gi_union_info_get_field (GIUnionInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +guint gi_union_info_get_n_methods (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_union_info_get_method (GIUnionInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +gboolean gi_union_info_is_discriminated (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +guint gi_union_info_get_discriminator_offset (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +GITypeInfo * gi_union_info_get_discriminator_type (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +GIConstantInfo * gi_union_info_get_discriminator (GIUnionInfo *info, + guint n); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_union_info_find_method (GIUnionInfo *info, + const gchar *name); + +GI_AVAILABLE_IN_ALL +gsize gi_union_info_get_size (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +gsize gi_union_info_get_alignment (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +const char * gi_union_info_get_copy_function_name (GIUnionInfo *info); + +GI_AVAILABLE_IN_ALL +const char * gi_union_info_get_free_function_name (GIUnionInfo *info); + +G_END_DECLS diff --git a/girepository/giunresolvedinfo.c b/girepository/giunresolvedinfo.c new file mode 100644 index 0000000..b099f9b --- /dev/null +++ b/girepository/giunresolvedinfo.c @@ -0,0 +1,52 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright 2023 GNOME Foundation, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "giunresolvedinfo.h" + +/** + * GIUnresolvedInfo: + * + * `GIUnresolvedInfo` represents an unresolved symbol. + * + * Since: 2.80 + */ + +void +gi_unresolved_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_UNRESOLVED; +} diff --git a/girepository/giunresolvedinfo.h b/girepository/giunresolvedinfo.h new file mode 100644 index 0000000..5ca4879 --- /dev/null +++ b/girepository/giunresolvedinfo.h @@ -0,0 +1,45 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Callable + * + * Copyright 2023 GNOME Foundation, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_UNRESOLVED_INFO: + * @info: an info structure + * + * Checks if @info is a [class@GIRepository.UnresolvedInfo] or derived from it. + * + * Since: 2.80 + */ +#define GI_IS_UNRESOLVED_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_UNRESOLVED) + +G_END_DECLS diff --git a/girepository/givfuncinfo.c b/girepository/givfuncinfo.c new file mode 100644 index 0000000..781e370 --- /dev/null +++ b/girepository/givfuncinfo.c @@ -0,0 +1,385 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Virtual Function implementation + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include "config.h" + +#include + +#include + +#include +#include "gibaseinfo-private.h" +#include "girepository-private.h" +#include "gitypelib-internal.h" +#include "givfuncinfo.h" + +/** + * GIVFuncInfo: + * + * `GIVFuncInfo` represents a virtual function. + * + * A virtual function is a callable object that belongs to either a + * [type@GIRepository.ObjectInfo] or a [type@GIRepository.InterfaceInfo]. + * + * Since: 2.80 + */ + +GIVFuncInfo * +gi_base_info_find_vfunc (GIRealInfo *rinfo, + guint32 offset, + guint n_vfuncs, + const gchar *name) +{ + /* FIXME hash */ + Header *header = (Header *)rinfo->typelib->data; + + for (guint i = 0; i < n_vfuncs; i++) + { + VFuncBlob *fblob = (VFuncBlob *)&rinfo->typelib->data[offset]; + const gchar *fname = (const gchar *)&rinfo->typelib->data[fblob->name]; + + if (strcmp (name, fname) == 0) + return (GIVFuncInfo *) gi_info_new (GI_INFO_TYPE_VFUNC, (GIBaseInfo*) rinfo, + rinfo->typelib, offset); + + offset += header->vfunc_blob_size; + } + + return NULL; +} + +/** + * gi_vfunc_info_get_flags: + * @info: a #GIVFuncInfo + * + * Obtain the flags for this virtual function info. + * + * See [flags@GIRepository.VFuncInfoFlags] for more information about possible + * flag values. + * + * Returns: the flags + * Since: 2.80 + */ +GIVFuncInfoFlags +gi_vfunc_info_get_flags (GIVFuncInfo *info) +{ + GIVFuncInfoFlags flags; + GIRealInfo *rinfo = (GIRealInfo *)info; + VFuncBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0); + + blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + + flags = 0; + + if (blob->must_chain_up) + flags = flags | GI_VFUNC_MUST_CHAIN_UP; + + if (blob->must_be_implemented) + flags = flags | GI_VFUNC_MUST_OVERRIDE; + + if (blob->must_not_be_implemented) + flags = flags | GI_VFUNC_MUST_NOT_OVERRIDE; + + if (blob->throws) + flags = flags | GI_VFUNC_THROWS; + + return flags; +} + +/** + * gi_vfunc_info_get_offset: + * @info: a #GIVFuncInfo + * + * Obtain the offset of the function pointer in the class struct. + * + * The value `0xFFFF` indicates that the struct offset is unknown. + * + * Returns: the struct offset or `0xFFFF` if it’s unknown + * Since: 2.80 + */ +guint +gi_vfunc_info_get_offset (GIVFuncInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + VFuncBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0); + + blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + + return blob->struct_offset; +} + +/** + * gi_vfunc_info_get_signal: + * @info: a #GIVFuncInfo + * + * Obtain the signal for the virtual function if one is set. + * + * The signal comes from the object or interface to which + * this virtual function belongs. + * + * Returns: (transfer full) (nullable): the signal, or `NULL` if none is set + * Since: 2.80 + */ +GISignalInfo * +gi_vfunc_info_get_signal (GIVFuncInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + VFuncBlob *blob; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0); + + blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + + if (blob->class_closure) + return gi_interface_info_get_signal ((GIInterfaceInfo *)rinfo->container, blob->signal); + + return NULL; +} + +/** + * gi_vfunc_info_get_invoker: + * @info: a #GIVFuncInfo + * + * If this virtual function has an associated invoker method, this + * method will return it. An invoker method is a C entry point. + * + * Not all virtuals will have invokers. + * + * Returns: (transfer full) (nullable): The [type@GIRepository.FunctionInfo] or + * `NULL` if none is set. Free it with [method@GIRepository.BaseInfo.unref] + * when done. + * Since: 2.80 + */ +GIFunctionInfo * +gi_vfunc_info_get_invoker (GIVFuncInfo *info) +{ + GIRealInfo *rinfo = (GIRealInfo *)info; + VFuncBlob *blob; + GIBaseInfo *container; + GIInfoType parent_type; + + g_return_val_if_fail (info != NULL, 0); + g_return_val_if_fail (GI_IS_VFUNC_INFO (info), 0); + + blob = (VFuncBlob *)&rinfo->typelib->data[rinfo->offset]; + + /* 1023 = 0x3ff is the maximum of the 10 bits for invoker index */ + if (blob->invoker == 1023) + return NULL; + + container = rinfo->container; + parent_type = gi_base_info_get_info_type (container); + if (parent_type == GI_INFO_TYPE_OBJECT) + return gi_object_info_get_method ((GIObjectInfo*)container, blob->invoker); + else if (parent_type == GI_INFO_TYPE_INTERFACE) + return gi_interface_info_get_method ((GIInterfaceInfo*)container, blob->invoker); + else + g_assert_not_reached (); +} + +/** + * gi_vfunc_info_get_address: + * @info: a #GIVFuncInfo + * @implementor_gtype: [type@GObject.Type] implementing this virtual function + * @error: return location for a [type@GLib.Error], or `NULL` + * + * Looks up where the implementation for @info is inside the type struct of + * @implementor_gtype. + * + * Returns: address to a function + * Since: 2.80 + */ +gpointer +gi_vfunc_info_get_address (GIVFuncInfo *vfunc_info, + GType implementor_gtype, + GError **error) +{ + GIBaseInfo *container_info; + GIInterfaceInfo *interface_info; + GIObjectInfo *object_info; + GIStructInfo *struct_info; + GIFieldInfo *field_info = NULL; + int length, i, offset; + gpointer implementor_class, implementor_vtable; + gpointer func = NULL; + + g_return_val_if_fail (vfunc_info != NULL, NULL); + g_return_val_if_fail (GI_IS_VFUNC_INFO (vfunc_info), NULL); + g_return_val_if_fail (error == NULL || *error == NULL, NULL); + + container_info = gi_base_info_get_container ((GIBaseInfo *) vfunc_info); + if (gi_base_info_get_info_type (container_info) == GI_INFO_TYPE_OBJECT) + { + object_info = (GIObjectInfo*) container_info; + interface_info = NULL; + struct_info = gi_object_info_get_class_struct (object_info); + } + else + { + interface_info = (GIInterfaceInfo*) container_info; + object_info = NULL; + struct_info = gi_interface_info_get_iface_struct (interface_info); + } + + length = gi_struct_info_get_n_fields (struct_info); + for (i = 0; i < length; i++) + { + field_info = gi_struct_info_get_field (struct_info, i); + + if (strcmp (gi_base_info_get_name ( (GIBaseInfo*) field_info), + gi_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) { + gi_base_info_unref ((GIBaseInfo *) field_info); + field_info = NULL; + continue; + } + + break; + } + + if (field_info == NULL) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Couldn't find struct field for this vfunc"); + goto out; + } + + implementor_class = g_type_class_ref (implementor_gtype); + + if (object_info) + { + implementor_vtable = implementor_class; + } + else + { + GType interface_type; + + interface_type = gi_registered_type_info_get_g_type ((GIRegisteredTypeInfo*) interface_info); + implementor_vtable = g_type_interface_peek (implementor_class, interface_type); + } + + offset = gi_field_info_get_offset (field_info); + func = *(gpointer*) G_STRUCT_MEMBER_P (implementor_vtable, offset); + g_type_class_unref (implementor_class); + gi_base_info_unref ((GIBaseInfo *) field_info); + + if (func == NULL) + { + g_set_error (error, + GI_INVOKE_ERROR, + GI_INVOKE_ERROR_SYMBOL_NOT_FOUND, + "Class %s doesn't implement %s", + g_type_name (implementor_gtype), + gi_base_info_get_name ( (GIBaseInfo*) vfunc_info)); + goto out; + } + + out: + gi_base_info_unref ((GIBaseInfo*) struct_info); + + return func; +} + +/** + * gi_vfunc_info_invoke: (skip) + * @info: a #GIVFuncInfo describing the virtual function to invoke + * @implementor: [type@GObject.Type] of the type that implements this virtual + * function + * @in_args: (array length=n_in_args) (nullable): an array of + * [struct@GIRepository.Argument]s, one for each ‘in’ parameter of @info. If + * there are no ‘in’ parameters, @in_args can be `NULL` + * @n_in_args: the length of the @in_args array + * @out_args: (array length=n_out_args) (nullable): an array of + * [struct@GIRepository.Argument]s allocated by the caller, one for each + * ‘out’ parameter of @info. If there are no ‘out’ parameters, @out_args may + * be `NULL` + * @n_out_args: the length of the @out_args array + * @return_value: (out caller-allocates) (not optional) (nullable): return + * location for the return value from the vfunc; `NULL` may be returned if + * the vfunc returns that + * @error: return location for detailed error information, or `NULL` + * + * Invokes the function described in @info with the given + * arguments. + * + * Note that ‘inout’ parameters must appear in both argument lists. + * + * Returns: `TRUE` if the vfunc was executed successfully and didn’t throw + * a [type@GLib.Error]; `FALSE` if @error is set + * Since: 2.80 + */ +gboolean +gi_vfunc_info_invoke (GIVFuncInfo *info, + GType implementor, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + GError **error) +{ + gpointer func; + GError *local_error = NULL; + + g_return_val_if_fail (info != NULL, FALSE); + g_return_val_if_fail (GI_IS_VFUNC_INFO (info), FALSE); + g_return_val_if_fail (in_args != NULL || n_in_args == 0, FALSE); + g_return_val_if_fail (out_args != NULL || n_out_args == 0, FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + + func = gi_vfunc_info_get_address (info, implementor, &local_error); + if (local_error != NULL) + { + g_propagate_error (error, g_steal_pointer (&local_error)); + return FALSE; + } + + return gi_callable_info_invoke ((GICallableInfo*) info, + func, + in_args, + n_in_args, + out_args, + n_out_args, + return_value, + TRUE, + FALSE, + error); +} + +void +gi_vfunc_info_class_init (gpointer g_class, + gpointer class_data) +{ + GIBaseInfoClass *info_class = g_class; + + info_class->info_type = GI_INFO_TYPE_VFUNC; +} diff --git a/girepository/givfuncinfo.h b/girepository/givfuncinfo.h new file mode 100644 index 0000000..f5bcc2d --- /dev/null +++ b/girepository/givfuncinfo.h @@ -0,0 +1,73 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Virtual Functions + * + * Copyright (C) 2005 Matthias Clasen + * Copyright (C) 2008,2009 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#pragma once + +#if !defined (__GIREPOSITORY_H_INSIDE__) && !defined (GI_COMPILATION) +#error "Only can be included directly." +#endif + +#include + +G_BEGIN_DECLS + +/** + * GI_IS_VFUNC_INFO: + * @info: an info structure + * + * Checks if @info is a [struct@GIRepository.VFuncInfo]. + * + * Since: 2.80 + */ +#define GI_IS_VFUNC_INFO(info) \ + (gi_base_info_get_info_type ((GIBaseInfo*) info) == GI_INFO_TYPE_VFUNC) + +GI_AVAILABLE_IN_ALL +GIVFuncInfoFlags gi_vfunc_info_get_flags (GIVFuncInfo *info); + +GI_AVAILABLE_IN_ALL +guint gi_vfunc_info_get_offset (GIVFuncInfo *info); + +GI_AVAILABLE_IN_ALL +GISignalInfo * gi_vfunc_info_get_signal (GIVFuncInfo *info); + +GI_AVAILABLE_IN_ALL +GIFunctionInfo * gi_vfunc_info_get_invoker (GIVFuncInfo *info); + +GI_AVAILABLE_IN_ALL +gpointer gi_vfunc_info_get_address (GIVFuncInfo *info, + GType implementor_gtype, + GError **error); + +GI_AVAILABLE_IN_ALL +gboolean gi_vfunc_info_invoke (GIVFuncInfo *info, + GType implementor, + const GIArgument *in_args, + gsize n_in_args, + const GIArgument *out_args, + gsize n_out_args, + GIArgument *return_value, + GError **error); + +G_END_DECLS diff --git a/girepository/gthash-test.c b/girepository/gthash-test.c new file mode 100644 index 0000000..ac55db9 --- /dev/null +++ b/girepository/gthash-test.c @@ -0,0 +1,67 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Test typelib hashing + * + * Copyright (C) 2010 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include "gitypelib-internal.h" + +static void +test_build_retrieve (void) +{ + GITypelibHashBuilder *builder; + guint32 bufsize; + guint8* buf; + + builder = gi_typelib_hash_builder_new (); + + gi_typelib_hash_builder_add_string (builder, "Action", 0); + gi_typelib_hash_builder_add_string (builder, "ZLibDecompressor", 42); + gi_typelib_hash_builder_add_string (builder, "VolumeMonitor", 9); + gi_typelib_hash_builder_add_string (builder, "FileMonitorFlags", 31); + + if (!gi_typelib_hash_builder_prepare (builder)) + g_assert_not_reached (); + + bufsize = gi_typelib_hash_builder_get_buffer_size (builder); + + buf = g_malloc (bufsize); + + gi_typelib_hash_builder_pack (builder, buf, bufsize); + + gi_typelib_hash_builder_destroy (builder); + + g_assert (gi_typelib_hash_search (buf, "Action", 4) == 0); + g_assert (gi_typelib_hash_search (buf, "ZLibDecompressor", 4) == 42); + g_assert (gi_typelib_hash_search (buf, "VolumeMonitor", 4) == 9); + g_assert (gi_typelib_hash_search (buf, "FileMonitorFlags", 4) == 31); +} + +int +main(int argc, char **argv) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/gthash/build-retrieve", test_build_retrieve); + + return g_test_run (); +} + diff --git a/girepository/gthash.c b/girepository/gthash.c new file mode 100644 index 0000000..4a23e4a --- /dev/null +++ b/girepository/gthash.c @@ -0,0 +1,229 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- + * GObject introspection: Typelib hashing + * + * Copyright (C) 2010 Red Hat, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ + +#include +#include +#include + +#include "cmph/cmph.h" +#include "gitypelib-internal.h" + +#define ALIGN_VALUE(this, boundary) \ + (( ((unsigned long)(this)) + (((unsigned long)(boundary)) -1)) & (~(((unsigned long)(boundary))-1))) + +/* + * String hashing in the typelib. We have a set of static (fixed) strings, + * and given one, we need to find its index number. This problem is perfect + * hashing: http://en.wikipedia.org/wiki/Perfect_hashing + * + * I chose CMPH (http://cmph.sourceforge.net/) as it seemed high + * quality, well documented, and easy to embed. + * + * CMPH provides a number of algorithms; I chose BDZ, because while CHD + * appears to be the "best", the simplicitly of BDZ appealed, and really, + * we're only talking about thousands of strings here, not millions, so + * a few microseconds is no big deal. + * + * In memory, the format is: + * INT32 mph_size + * MPH (mph_size bytes) + * (padding for alignment to uint32 if necessary) + * INDEX (array of guint16) + * + * Because BDZ is not order preserving, we need a lookaside table which + * maps the hash value into the directory index. + */ + +struct _GITypelibHashBuilder { + gboolean prepared; + gboolean buildable; + cmph_t *c; + GHashTable *strings; + guint32 dirmap_offset; + guint32 packed_size; +}; + +GITypelibHashBuilder * +gi_typelib_hash_builder_new (void) +{ + GITypelibHashBuilder *builder = g_slice_new0 (GITypelibHashBuilder); + builder->c = NULL; + builder->strings = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + return builder; +} + +void +gi_typelib_hash_builder_add_string (GITypelibHashBuilder *builder, + const char *str, + guint16 value) +{ + g_return_if_fail (builder->c == NULL); + g_hash_table_insert (builder->strings, g_strdup (str), GUINT_TO_POINTER ((guint) value)); +} + +gboolean +gi_typelib_hash_builder_prepare (GITypelibHashBuilder *builder) +{ + char **strs; + GHashTableIter hashiter; + gpointer key, value; + cmph_io_adapter_t *io; + cmph_config_t *config; + guint32 num_elts; + guint32 offset; + guint i; + + if (builder->prepared) + return builder->buildable; + g_assert (builder->c == NULL); + + num_elts = g_hash_table_size (builder->strings); + g_assert (num_elts <= 65536); + + strs = (char**) g_new (char *, num_elts + 1); + + i = 0; + g_hash_table_iter_init (&hashiter, builder->strings); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *str = key; + + strs[i++] = g_strdup (str); + } + strs[i++] = NULL; + + io = cmph_io_vector_adapter (strs, num_elts); + config = cmph_config_new (io); + cmph_config_set_algo (config, CMPH_BDZ); + + builder->c = cmph_new (config); + builder->prepared = TRUE; + if (!builder->c) + { + builder->buildable = FALSE; + goto out; + } + builder->buildable = TRUE; + g_assert (cmph_size (builder->c) == num_elts); + + /* Pack a size counter at front */ + offset = sizeof(guint32) + cmph_packed_size (builder->c); + builder->dirmap_offset = ALIGN_VALUE (offset, 4); + builder->packed_size = builder->dirmap_offset + (num_elts * sizeof(guint16)); + out: + cmph_config_destroy (config); + cmph_io_vector_adapter_destroy (io); + return builder->buildable; +} + +guint32 +gi_typelib_hash_builder_get_buffer_size (GITypelibHashBuilder *builder) +{ + g_return_val_if_fail (builder != NULL, 0); + g_return_val_if_fail (builder->prepared, 0); + g_return_val_if_fail (builder->buildable, 0 ); + + return builder->packed_size; +} + +void +gi_typelib_hash_builder_pack (GITypelibHashBuilder *builder, guint8* mem, guint32 len) +{ + guint16 *table; + GHashTableIter hashiter; + gpointer key, value; +#ifndef G_DISABLE_ASSERT + guint32 num_elts; +#endif + guint8 *packed_mem; + + g_return_if_fail (builder != NULL); + g_return_if_fail (builder->prepared); + g_return_if_fail (builder->buildable); + + g_assert (len >= builder->packed_size); + g_assert ((((size_t)mem) & 0x3) == 0); + + memset (mem, 0, len); + + *((guint32*) mem) = builder->dirmap_offset; + packed_mem = (guint8*)(mem + sizeof(guint32)); + cmph_pack (builder->c, packed_mem); + + table = (guint16*) (mem + builder->dirmap_offset); + +#ifndef G_DISABLE_ASSERT + num_elts = g_hash_table_size (builder->strings); +#endif + g_hash_table_iter_init (&hashiter, builder->strings); + while (g_hash_table_iter_next (&hashiter, &key, &value)) + { + const char *str = key; + guint16 strval = (guint16)GPOINTER_TO_UINT(value); + guint32 hashv; + + hashv = cmph_search_packed (packed_mem, str, strlen (str)); + g_assert (hashv < num_elts); + table[hashv] = strval; + } +} + +void +gi_typelib_hash_builder_destroy (GITypelibHashBuilder *builder) +{ + if (builder->c) + { + cmph_destroy (builder->c); + builder->c = NULL; + } + g_hash_table_destroy (builder->strings); + g_slice_free (GITypelibHashBuilder, builder); +} + +guint16 +gi_typelib_hash_search (guint8* memory, const char *str, guint n_entries) +{ + guint32 *mph; + guint16 *table; + guint32 dirmap_offset; + guint32 offset; + + g_assert ((((size_t)memory) & 0x3) == 0); + mph = ((guint32*)memory)+1; + + offset = cmph_search_packed (mph, str, strlen (str)); + + /* Make sure that offset always lies in the entries array. cmph + cometimes generates offset larger than number of entries (for + 'str' argument which is not in the hashed list). In this case, + fake the correct result and depend on caller's final check that + the entry is really the one that the caller wanted. */ + if (offset >= n_entries) + offset = 0; + + dirmap_offset = *((guint32*)memory); + table = (guint16*) (memory + dirmap_offset); + + return table[offset]; +} + diff --git a/girepository/meson.build b/girepository/meson.build new file mode 100644 index 0000000..c39efa6 --- /dev/null +++ b/girepository/meson.build @@ -0,0 +1,259 @@ +# SPDX-License-Identifier: LGPL-2.1-or-later +# SPDX-FileCopyrightText: 2017 Patrick Griffis +# SPDX-FileCopyrightText: 2017 Danny Forghieri +# SPDX-FileCopyrightText: 2017 Nirbheek Chauhan +# SPDX-FileCopyrightText: 2017, 2021, 2022 Emmanuele Bassi +# SPDX-FileCopyrightText: 2018 Mathieu Duponchelle +# SPDX-FileCopyrightText: 2018, 2019, 2020 Christoph Reiter +# SPDX-FileCopyrightText: 2018 Kai Kang +# SPDX-FileCopyrightText: 2018 Carlos Garnacho +# SPDX-FileCopyrightText: 2018, 2019, 2020 Alexander Kanavin +# SPDX-FileCopyrightText: 2019, 2020 Chun-wei Fan +# SPDX-FileCopyrightText: 2019 Aaron Boxer +# SPDX-FileCopyrightText: 2019 Thibault Saunier +# SPDX-FileCopyrightText: 2019 Joshua Watt +# SPDX-FileCopyrightText: 2020 Xavier Claessens +# SPDX-FileCopyrightText: 2020 Philip Chimento +# SPDX-FileCopyrightText: 2021 John Ericson +# SPDX-FileCopyrightText: 2021 Cimbali +# SPDX-FileCopyrightText: 2021, 2023 Simon McVittie +# SPDX-FileCopyrightText: 2022 Andoni Morales Alastruey + +subdir('cmph') + +gir_dir_prefix = get_option('gir_dir_prefix') +if gir_dir_prefix == '' or gir_dir_prefix == get_option('datadir') + gir_dir_prefix = get_option('datadir') + gir_dir_pc_prefix = '${datadir}' +else + gir_dir_pc_prefix = join_paths('${prefix}', gir_dir_prefix) +endif + +glib_girdir = get_option('prefix') / gir_dir_prefix / 'gir-1.0' + +gir_includedir = glib_includedir / 'girepository' + +gi_visibility_h = custom_target( + output: 'gi-visibility.h', + command: [gen_visibility_macros, meson.project_version(), 'visibility-macros', 'GI', '@OUTPUT@'], + install: true, + install_dir: gir_includedir, + install_tag: 'devel', +) + +girepo_headers = files( + 'giarginfo.h', + 'gibaseinfo.h', + 'gicallableinfo.h', + 'gicallbackinfo.h', + 'giconstantinfo.h', + 'gienuminfo.h', + 'gifieldinfo.h', + 'gifunctioninfo.h', + 'giinterfaceinfo.h', + 'giobjectinfo.h', + 'gipropertyinfo.h', + 'giregisteredtypeinfo.h', + 'girepository.h', + 'gisignalinfo.h', + 'gistructinfo.h', + 'gitypeinfo.h', + 'gitypelib.h', + 'gitypes.h', + 'giunioninfo.h', + 'giunresolvedinfo.h', + 'givfuncinfo.h', +) + +girepo_ffi_headers = [ + 'girffi.h', +] + +girepo_ffi_sources = files( + 'girffi.c', +) + +install_headers(girepo_headers + girepo_ffi_headers, install_dir: gir_includedir) + +gir_c_args = [ + '-DGI_COMPILATION', + '-DG_LOG_DOMAIN="GLib-GIRepository"', + '-DGIR_SUFFIX="gir-1.0"', + '-DGIR_DIR="@0@"'.format(glib_girdir), + '-DGOBJECT_INTROSPECTION_LIBDIR="@0@"'.format(glib_libdir), + '-DGOBJECT_INTROSPECTION_DATADIR="@0@"'.format(glib_datadir), +] + +custom_c_args = [] + +if cc.get_id() != 'msvc' + custom_c_args = cc.get_supported_arguments([ + '-Wno-old-style-definition', + '-Wno-cast-align', + ]) +endif + +girepo_gthash_lib = static_library('girepository-gthash', + sources: ['gthash.c', gi_visibility_h], + include_directories : [configinc, girepoinc], + c_args: gir_c_args + custom_c_args, + dependencies: [ + cmph_dep, + libglib_dep, + libgmodule_dep, + libgobject_dep, + ], +) + +girepo_gthash_dep = declare_dependency( + link_with: girepo_gthash_lib, + dependencies: [libglib_dep, libgmodule_dep, libgobject_dep], + include_directories: [girepoinc], +) + +if cc.get_id() != 'msvc' + custom_c_args = cc.get_supported_arguments([ + '-Wno-unused-parameter', + '-Wno-duplicated-branches', + '-Wno-cast-align', + ]) +endif + +libgirepository_internals = static_library('girepository-internals', + sources: [ + 'girmodule.c', + 'girnode.c', + 'giroffsets.c', + 'girparser.c', + 'girwriter.c', + gi_visibility_h, + ], + c_args: gir_c_args + custom_c_args, + include_directories : [configinc, girepoinc], + dependencies: [girepo_gthash_dep, libffi_dep], +) + +libgirepository_internals_dep = declare_dependency( + link_with: libgirepository_internals, + dependencies: libffi_dep, + include_directories: [girepoinc], +) + +girepo_sources = files( + 'gdump.c', + 'giarginfo.c', + 'gibaseinfo.c', + 'gicallableinfo.c', + 'gicallbackinfo.c', + 'giconstantinfo.c', + 'gienuminfo.c', + 'gifieldinfo.c', + 'gifunctioninfo.c', + 'ginvoke.c', + 'giinterfaceinfo.c', + 'giobjectinfo.c', + 'gipropertyinfo.c', + 'giregisteredtypeinfo.c', + 'girepository.c', + 'girffi.c', + 'gisignalinfo.c', + 'gistructinfo.c', + 'gitypeinfo.c', + 'gitypelib.c', + 'giunioninfo.c', + 'giunresolvedinfo.c', + 'givfuncinfo.c', +) + +if cc.get_id() != 'msvc' + custom_c_args = cc.get_supported_arguments([ + '-Wno-unused-parameter', + '-Wno-duplicated-branches', + '-Wno-type-limits', + '-Wno-cast-align', + '-Wno-missing-field-initializers', + ]) +endif + +libgirepository = shared_library('girepository-2.0', + sources: girepo_sources + girepo_ffi_sources + [gi_visibility_h], + include_directories: [configinc, girepoinc], + c_args: gir_c_args, + version: library_version, + soversion: soversion, + darwin_versions: darwin_versions, + gnu_symbol_visibility: 'hidden', + link_args: glib_link_flags, + dependencies: [ + libglib_dep, + libgobject_dep, + libgmodule_dep, + libgio_dep, + libgirepository_internals_dep, + ], + install: true, +) + +libgirepository_dep = declare_dependency( + link_with: libgirepository, + dependencies: [libglib_dep, libgobject_dep, libgio_dep, libgmodule_dep], + sources: [gi_visibility_h], + include_directories: [girepoinc], +) + +executable('gi-dump-types', + sources: 'gi-dump-types.c', + dependencies: [ + libgirepository_dep, + libgiounix_dep, + libgiowin32_dep + ], +) + +pkgconfig_variables = [ + 'gidatadir=${datadir}/gobject-introspection-1.0', + 'girdir=' + gir_dir_pc_prefix / 'gir-1.0', + 'typelibdir=${libdir}/girepository-1.0', +] + +pkg.generate(libgirepository, + name: 'girepository', + version: glib_version, + filebase: 'girepository-2.0', + install_dir: glib_pkgconfigreldir, + description: 'GObject Introspection repository parser', + variables: pkgconfig_variables, + libraries: [libglib_dep, libgobject_dep], +) + +if enable_gir + libgirepository_gir_sources = [ + gi_visibility_h, + girepo_headers, + girepo_sources, + ] + libgirepository_gir_packages = [ 'girepository-2.0' ] + libgirepository_gir_args = [ + '-DGI_COMPILATION', + '--symbol-prefix=gi', + '--identifier-prefix=GI', + ] + + girepository_gir = gnome.generate_gir(libgirepository, + sources: libgirepository_gir_sources, + namespace: 'GIRepository', + nsversion: '3.0', + identifier_prefix: 'GI', + symbol_prefix: 'gi', + export_packages: libgirepository_gir_packages, + header: 'girepository/girepository.h', + includes: [ glib_gir[0], gmodule_gir[0], gobject_gir[0], gio_gir[0] ], + install: true, + dependencies: [ libglib_dep, libgobject_dep, libgmodule_dep, libgio_dep ], + extra_args: gir_args + libgirepository_gir_args, + ) +endif + +if build_tests + subdir('tests') +endif diff --git a/girepository/tests/meson.build b/girepository/tests/meson.build new file mode 100644 index 0000000..a3386a1 --- /dev/null +++ b/girepository/tests/meson.build @@ -0,0 +1,89 @@ +girepository_tests = {} + +# Some GIR files are needed to test against +if enable_gir + girepository_tests += { + 'repository' : { + 'depends': [glib_gir, gobject_gir], + }, + 'repository-search-paths' : { + 'c_args': '-DGOBJECT_INTROSPECTION_LIBDIR="@0@"'.format(glib_libdir), + 'depends': [glib_gir], + }, + } +endif + +test_env = environment() +test_env.set('G_TEST_SRCDIR', meson.current_source_dir()) +test_env.set('G_TEST_BUILDDIR', meson.current_build_dir()) + +test_deps = [libm, thread_dep, libgirepository_dep] +test_cargs = ['-DG_LOG_DOMAIN="GIRepository"', '-UG_DISABLE_ASSERT'] +test_cpp_args = test_cargs + +foreach test_name, extra_args : girepository_tests + source = extra_args.get('source', test_name + '.c') + install = installed_tests_enabled and extra_args.get('install', true) + installed_tests_env = extra_args.get('installed_tests_env', {}) + + if install + test_conf = configuration_data() + test_conf.set('installed_tests_dir', installed_tests_execdir) + test_conf.set('program', test_name) + test_env_override = '' + if installed_tests_env != {} + envs = [] + foreach var, value : installed_tests_env + envs += '@0@=@1@'.format(var, value) + endforeach + test_env_override = '@0@ @1@ '.format(env_program.full_path(), ' '.join(envs)) + endif + test_conf.set('env', test_env_override) + configure_file( + input: installed_tests_template_tap, + output: test_name + '.test', + install_dir: installed_tests_metadir, + install_tag: 'tests', + configuration: test_conf + ) + endif + + exe = executable(test_name, source, + c_args: test_cargs + extra_args.get('c_args', []), + cpp_args: test_cpp_args + extra_args.get('cpp_args', []), + link_args: extra_args.get('link_args', []), + override_options: extra_args.get('override_options', []), + dependencies: test_deps + extra_args.get('dependencies', []), + link_with: extra_args.get('link_with', []), + install_dir: installed_tests_execdir, + install_tag: 'tests', + install: install, + ) + + depends = [extra_args.get('depends', [])] + suite = ['girepository', 'core'] + extra_args.get('suite', []) + timeout = suite.contains('slow') ? test_timeout_slow : test_timeout + + if extra_args.get('can_fail', false) + suite += 'failing' + endif + + foreach program : extra_args.get('extra_programs', []) + depends += test_extra_programs_targets[program] + endforeach + + local_test_env = test_env + foreach var, value : extra_args.get('env', {}) + local_test_env.append(var, value) + endforeach + + test(test_name, exe, + args: extra_args.get('args', []), + protocol: extra_args.get('protocol', test_protocol), + depends: depends, + env: local_test_env, + timeout: timeout, + suite: suite, + should_fail: extra_args.get('should_fail', false), + ) +endforeach diff --git a/girepository/tests/repository-search-paths.c b/girepository/tests/repository-search-paths.c new file mode 100644 index 0000000..55eebef --- /dev/null +++ b/girepository/tests/repository-search-paths.c @@ -0,0 +1,117 @@ +/* + * Copyright 2023 Canonical Ltd. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: Marco Trevisan + */ + +#include "glib.h" +#include "girepository.h" + +/* Keep this test first, not to add search paths to other tests */ +static void +test_repository_search_paths_unset (void) +{ + const char * const *search_paths; + size_t n_search_paths; + + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + g_assert_cmpstrv (search_paths, ((char *[]){NULL})); + g_assert_cmpuint (n_search_paths, ==, 0); + + search_paths = gi_repository_get_search_path (NULL); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 0); +} + +static void +test_repository_search_paths_default (void) +{ + const char * const *search_paths; + size_t n_search_paths; + + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + + /* Init default paths */ + g_assert_nonnull (gi_repository_get_default ()); + + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 2); + + g_assert_cmpstr (search_paths[0], ==, g_get_tmp_dir ()); + +#ifndef G_PLATFORM_WIN32 + char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); + g_assert_cmpstr (search_paths[1], ==, expected_path); + g_clear_pointer (&expected_path, g_free); +#endif +} + +static void +test_repository_search_paths_prepend (void) +{ + const char * const *search_paths; + size_t n_search_paths; + + gi_repository_prepend_search_path (g_test_get_dir (G_TEST_BUILT)); + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 3); + + g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_BUILT)); + g_assert_cmpstr (search_paths[1], ==, g_get_tmp_dir ()); + +#ifndef G_PLATFORM_WIN32 + char *expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); + g_assert_cmpstr (search_paths[2], ==, expected_path); + g_clear_pointer (&expected_path, g_free); +#endif + + gi_repository_prepend_search_path (g_test_get_dir (G_TEST_DIST)); + search_paths = gi_repository_get_search_path (&n_search_paths); + g_assert_nonnull (search_paths); + g_assert_cmpuint (g_strv_length ((char **) search_paths), ==, 4); + + g_assert_cmpstr (search_paths[0], ==, g_test_get_dir (G_TEST_DIST)); + g_assert_cmpstr (search_paths[1], ==, g_test_get_dir (G_TEST_BUILT)); + g_assert_cmpstr (search_paths[2], ==, g_get_tmp_dir ()); + +#ifndef G_PLATFORM_WIN32 + expected_path = g_build_filename (GOBJECT_INTROSPECTION_LIBDIR, "girepository-1.0", NULL); + g_assert_cmpstr (search_paths[3], ==, expected_path); + g_clear_pointer (&expected_path, g_free); +#endif +} + +int +main (int argc, + char *argv[]) +{ + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + /* Isolate from the system typelibs and GIRs. */ + g_setenv ("GI_TYPELIB_PATH", g_get_tmp_dir (), TRUE); + g_setenv ("GI_GIR_PATH", g_get_user_cache_dir (), TRUE); + + g_test_add_func ("/repository-search-paths/unset", test_repository_search_paths_unset); + g_test_add_func ("/repository-search-paths/default", test_repository_search_paths_default); + g_test_add_func ("/repository-search-paths/prepend", test_repository_search_paths_prepend); + + return g_test_run (); +} diff --git a/girepository/tests/repository.c b/girepository/tests/repository.c new file mode 100644 index 0000000..762f9be --- /dev/null +++ b/girepository/tests/repository.c @@ -0,0 +1,164 @@ +/* + * Copyright 2023 GNOME Foundation, Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see . + * + * Author: Philip Withnall + */ + +#include "glib.h" +#include "girepository.h" + +static void +test_repository_basic (void) +{ + GIRepository *repository; + char *gobject_typelib_dir = NULL; + const char * const * search_paths; + GITypelib *typelib = NULL; + char **namespaces = NULL; + const char *expected_namespaces[] = { "GLib", NULL }; + GError *local_error = NULL; + char **versions; + size_t n_versions; + + g_test_summary ("Test basic opening of a repository and requiring a typelib"); + + gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); + g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); + gi_repository_prepend_search_path (gobject_typelib_dir); + + repository = gi_repository_new (); + g_assert_nonnull (repository); + + versions = gi_repository_enumerate_versions (repository, "SomeInvalidNamespace", &n_versions); + g_assert_nonnull (versions); + g_assert_cmpstrv (versions, ((char *[]){NULL})); + g_assert_cmpuint (n_versions, ==, 0); + g_clear_pointer (&versions, g_strfreev); + + versions = gi_repository_enumerate_versions (repository, "GLib", NULL); + g_assert_nonnull (versions); + g_assert_cmpstrv (versions, ((char *[]){"2.0", NULL})); + g_clear_pointer (&versions, g_strfreev); + + search_paths = gi_repository_get_search_path (NULL); + g_assert_nonnull (search_paths); + g_assert_cmpuint (g_strv_length ((char **) search_paths), >, 0); + g_assert_cmpstr (search_paths[0], ==, gobject_typelib_dir); + + typelib = gi_repository_require (repository, "GLib", "2.0", 0, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (typelib); + + namespaces = gi_repository_get_loaded_namespaces (repository); + g_assert_cmpstrv (namespaces, expected_namespaces); + g_strfreev (namespaces); + + g_free (gobject_typelib_dir); + g_clear_object (&repository); +} + +static void +test_repository_info (void) +{ + GIRepository *repository; + char *gobject_typelib_dir = NULL; + GITypelib *typelib = NULL; + GIObjectInfo *object_info = NULL; + GISignalInfo *signal_info = NULL; + GError *local_error = NULL; + + g_test_summary ("Test retrieving some basic info blobs from a typelib"); + + gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "introspection", NULL); + g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); + gi_repository_prepend_search_path (gobject_typelib_dir); + g_free (gobject_typelib_dir); + + repository = gi_repository_new (); + g_assert_nonnull (repository); + + typelib = gi_repository_require (repository, "GObject", "2.0", 0, &local_error); + g_assert_no_error (local_error); + g_assert_nonnull (typelib); + + object_info = (GIObjectInfo *) gi_repository_find_by_name (repository, "GObject", "Object"); + g_assert_nonnull (object_info); + + g_assert_cmpint (gi_base_info_get_info_type ((GIBaseInfo *) object_info), ==, GI_INFO_TYPE_OBJECT); + g_assert_cmpstr (gi_base_info_get_name ((GIBaseInfo *) object_info), ==, "Object"); + g_assert_cmpstr (gi_base_info_get_namespace ((GIBaseInfo *) object_info), ==, "GObject"); + + signal_info = gi_object_info_find_signal (object_info, "notify"); + g_assert_nonnull (signal_info); + + g_assert_cmpint (gi_signal_info_get_flags (signal_info), ==, + G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION); + + gi_base_info_unref ((GIBaseInfo *) signal_info); + gi_base_info_unref ((GIBaseInfo *) object_info); + g_clear_object (&repository); +} + +static void +test_repository_dependencies (void) +{ + GIRepository *repository; + GITypelib *typelib; + GError *error = NULL; + char *gobject_typelib_dir = NULL; + char **dependencies; + + g_test_summary ("Test ensures namespace dependencies are correctly exposed"); + + gobject_typelib_dir = g_test_build_filename (G_TEST_BUILT, "..", "..", "gobject", NULL); + g_test_message ("Using GI_TYPELIB_DIR = %s", gobject_typelib_dir); + gi_repository_prepend_search_path (gobject_typelib_dir); + g_free (gobject_typelib_dir); + + repository = gi_repository_new (); + g_assert_nonnull (repository); + + typelib = gi_repository_require (repository, "GObject", "2.0", 0, &error); + g_assert_no_error (error); + g_assert_nonnull (typelib); + + dependencies = gi_repository_get_dependencies (repository, "GObject"); + g_assert_cmpuint (g_strv_length (dependencies), ==, 1); + g_assert_true (g_strv_contains ((const char **) dependencies, "GLib-2.0")); + + g_clear_error (&error); + g_clear_object (&repository); + g_clear_pointer (&dependencies, g_strfreev); +} + +int +main (int argc, + char *argv[]) +{ + /* Isolate from the system typelibs and GIRs. */ + g_setenv ("GI_TYPELIB_PATH", "/dev/null", TRUE); + g_setenv ("GI_GIR_PATH", "/dev/null", TRUE); + + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); + + g_test_add_func ("/repository/basic", test_repository_basic); + g_test_add_func ("/repository/info", test_repository_info); + g_test_add_func ("/repository/dependencies", test_repository_dependencies); + + return g_test_run (); +} diff --git a/glib/deprecated/gcache.c b/glib/deprecated/gcache.c index fb0bb18..d7da83c 100644 --- a/glib/deprecated/gcache.c +++ b/glib/deprecated/gcache.c @@ -42,19 +42,18 @@ #include "gtestutils.h" /** - * SECTION:caches - * @title: Caches - * @short_description: caches allow sharing of complex data structures - * to save resources + * GCache: * - * A #GCache allows sharing of complex data structures, in order to + * A `GCache` allows sharing of complex data structures, in order to * save system resources. * - * GCache uses keys and values. A GCache key describes the properties - * of a particular resource. A GCache value is the actual resource. + * `GCache` uses keys and values. A `GCache` key describes the properties + * of a particular resource. A `GCache` value is the actual resource. * - * GCache has been marked as deprecated, since this API is rarely + * `GCache` has been marked as deprecated, since this API is rarely * used and not very actively maintained. + * + * Deprecated:2.32: Use a #GHashTable instead */ typedef struct _GCacheNode GCacheNode; @@ -66,15 +65,6 @@ struct _GCacheNode gint ref_count; }; -/** - * GCache: - * - * The #GCache struct is an opaque data structure containing - * information about a #GCache. It should only be accessed via the - * following functions. - * - * Deprecated:2.32: Use a #GHashTable instead - */ struct _GCache { /* Called to create a value from a key */ @@ -147,6 +137,7 @@ g_cache_node_destroy (GCacheNode *node) * value corresponding to the key. * * Returns: a new #GCache value corresponding to the key. + * Deprecated:2.32: Use a #GHashTable instead */ /** @@ -157,6 +148,8 @@ g_cache_node_destroy (GCacheNode *node) * functions passed to g_cache_new(). The functions are passed a * pointer to the #GCache key or #GCache value and should free any * memory and other resources associated with it. + * + * Deprecated:2.32: Use a #GHashTable instead */ /** @@ -170,6 +163,7 @@ g_cache_node_destroy (GCacheNode *node) * should return a duplicate of the key. * * Returns: a copy of the #GCache key + * Deprecated:2.32: Use a #GHashTable instead */ GCache* g_cache_new (GCacheNewFunc value_new_func, @@ -306,7 +300,7 @@ g_cache_remove (GCache *cache, /** * g_cache_key_foreach: * @cache: a #GCache - * @func: the function to call with each #GCache key + * @func: (scope call): the function to call with each #GCache key * @user_data: user data to pass to the function * * Calls the given function for each of the keys in the #GCache. @@ -332,7 +326,7 @@ g_cache_key_foreach (GCache *cache, /** * g_cache_value_foreach: * @cache: a #GCache - * @func: the function to call with each #GCache value + * @func: (scope call): the function to call with each #GCache value * @user_data: user data to pass to the function * * Calls the given function for each of the values in the #GCache. diff --git a/glib/deprecated/gcompletion.c b/glib/deprecated/gcompletion.c index 3bc77d3..7319289 100644 --- a/glib/deprecated/gcompletion.c +++ b/glib/deprecated/gcompletion.c @@ -44,56 +44,51 @@ #include /** - * SECTION:completion - * @title: Automatic String Completion - * @short_description: support for automatic completion using a group - * of target strings + * GCompletion: + * @items: list of target items (strings or data structures). + * @func: function which is called to get the string associated with a + * target item. It is %NULL if the target items are strings. + * @prefix: the last prefix passed to g_completion_complete() or + * g_completion_complete_utf8(). + * @cache: the list of items which begin with @prefix. + * @strncmp_func: The function to use when comparing strings. Use + * g_completion_set_compare() to modify this function. * - * #GCompletion provides support for automatic completion of a string + * `GCompletion` provides support for automatic completion of a string * using any group of target strings. It is typically used for file * name completion as is common in many UNIX shells. * - * A #GCompletion is created using g_completion_new(). Target items are - * added and removed with g_completion_add_items(), - * g_completion_remove_items() and g_completion_clear_items(). A - * completion attempt is requested with g_completion_complete() or - * g_completion_complete_utf8(). When no longer needed, the - * #GCompletion is freed with g_completion_free(). + * A `GCompletion` is created using [func@GLib.Completion.new]. Target items are + * added and removed with [method@GLib.Completion.add_items], + * [method@GLib.Completion.remove_items] and + * [method@GLib.Completion.clear_items]. A completion attempt is requested with + * [method@GLib.Completion.complete] or [method@GLib.Completion.complete_utf8]. + * When no longer needed, the `GCompletion` is freed with + * [method@GLib.Completion.free]. * * Items in the completion can be simple strings (e.g. filenames), or * pointers to arbitrary data structures. If data structures are used - * you must provide a #GCompletionFunc in g_completion_new(), which - * retrieves the item's string from the data structure. You can change + * you must provide a [type@GLib.CompletionFunc] in [func@GLib.Completion.new], + * which retrieves the item’s string from the data structure. You can change * the way in which strings are compared by setting a different - * #GCompletionStrncmpFunc in g_completion_set_compare(). + * [type@GLib.CompletionStrncmpFunc] in [method@GLib.Completion.set_compare]. * - * GCompletion has been marked as deprecated, since this API is rarely + * `GCompletion` has been marked as deprecated, since this API is rarely * used and not very actively maintained. - **/ - -/** - * GCompletion: - * @items: list of target items (strings or data structures). - * @func: function which is called to get the string associated with a - * target item. It is %NULL if the target items are strings. - * @prefix: the last prefix passed to g_completion_complete() or - * g_completion_complete_utf8(). - * @cache: the list of items which begin with @prefix. - * @strncmp_func: The function to use when comparing strings. Use - * g_completion_set_compare() to modify this function. * - * The data structure used for automatic completion. + * Deprecated: 2.26: Rarely used API **/ /** * GCompletionFunc: - * @Param1: the completion item. + * @item: the completion item. * * Specifies the type of the function passed to g_completion_new(). It * should return the string corresponding to the given target item. * This is used when you use data structures as #GCompletion items. * * Returns: the string corresponding to the item. + * Deprecated: 2.26: Rarely used API **/ /** @@ -110,6 +105,7 @@ * the first @n bytes of @s1 is found, respectively, to be * less than, to match, or to be greater than the first @n * bytes of @s2. + * Deprecated: 2.26: Rarely used API **/ static void completion_check_cache (GCompletion* cmp, @@ -124,6 +120,7 @@ static void completion_check_cache (GCompletion* cmp, * Creates a new #GCompletion. * * Returns: the new #GCompletion. + * Deprecated: 2.26: Rarely used API **/ GCompletion* g_completion_new (GCompletionFunc func) diff --git a/glib/deprecated/gcompletion.h b/glib/deprecated/gcompletion.h index 2be87d2..7f9f782 100644 --- a/glib/deprecated/gcompletion.h +++ b/glib/deprecated/gcompletion.h @@ -37,7 +37,7 @@ G_BEGIN_DECLS typedef struct _GCompletion GCompletion; -typedef gchar* (*GCompletionFunc) (gpointer); +typedef gchar* (*GCompletionFunc) (gpointer item); /* GCompletion */ diff --git a/glib/deprecated/grel.c b/glib/deprecated/grel.c index bca8266..aae9dc7 100644 --- a/glib/deprecated/grel.c +++ b/glib/deprecated/grel.c @@ -48,61 +48,53 @@ #include /** - * SECTION:relations - * @title: Relations and Tuples - * @short_description: tables of data which can be indexed on any - * number of fields + * GRelation: * - * A #GRelation is a table of data which can be indexed on any number - * of fields, rather like simple database tables. A #GRelation contains + * A `GRelation` is a table of data which can be indexed on any number + * of fields, rather like simple database tables. A `GRelation` contains * a number of records, called tuples. Each record contains a number of * fields. Records are not ordered, so it is not possible to find the * record at a particular index. * - * Note that #GRelation tables are currently limited to 2 fields. + * Note that `GRelation` tables are currently limited to 2 fields. * - * To create a GRelation, use g_relation_new(). + * To create a `GRelation`, use [func@GLib.Relation.new]. * - * To specify which fields should be indexed, use g_relation_index(). + * To specify which fields should be indexed, use [method@GLib.Relation.index]. * Note that this must be called before any tuples are added to the - * #GRelation. + * `GRelation`. * - * To add records to a #GRelation use g_relation_insert(). + * To add records to a `GRelation` use [method@GLib.Relation.insert]. * - * To determine if a given record appears in a #GRelation, use - * g_relation_exists(). Note that fields are compared directly, so + * To determine if a given record appears in a `GRelation`, use + * [method@GLib.Relation.exists]. Note that fields are compared directly, so * pointers must point to the exact same position (i.e. different * copies of the same string will not match.) * * To count the number of records which have a particular value in a - * given field, use g_relation_count(). + * given field, use [method@GLib.Relation.count]. * * To get all the records which have a particular value in a given - * field, use g_relation_select(). To access fields of the resulting - * records, use g_tuples_index(). To free the resulting records use - * g_tuples_destroy(). + * field, use [method@GLib.Relation.select]. To access fields of the resulting + * records, use [method@GLib.Tuples.index]. To free the resulting records use + * [method@GLib.Tuples.destroy]. * * To delete all records which have a particular value in a given - * field, use g_relation_delete(). + * field, use [method@GLib.Relation.delete]. * - * To destroy the #GRelation, use g_relation_destroy(). + * To destroy the `GRelation`, use [method@GLib.Relation.destroy]. * - * To help debug #GRelation objects, use g_relation_print(). + * To help debug `GRelation` objects, use [method@GLib.Relation.print]. * - * GRelation has been marked as deprecated, since this API has never + * `GRelation` has been marked as deprecated, since this API has never * been fully implemented, is not very actively maintained and rarely * used. + * + * Deprecated: 2.26: Rarely used API **/ typedef struct _GRealTuples GRealTuples; -/** - * GRelation: - * - * The #GRelation struct is an opaque data structure to represent a - * [Relation][glib-Relations-and-Tuples]. It should - * only be accessed via the following functions. - **/ struct _GRelation { gint fields; @@ -122,6 +114,8 @@ struct _GRelation * #GRelation by g_relation_select(). It only contains one public * member - the number of records that matched. To access the matched * records, you must use g_tuples_index(). + * + * Deprecated: 2.26: Rarely used API **/ struct _GRealTuples { diff --git a/glib/deprecated/grel.h b/glib/deprecated/grel.h index 071e609..1f29998 100644 --- a/glib/deprecated/grel.h +++ b/glib/deprecated/grel.h @@ -43,29 +43,6 @@ struct _GTuples guint len; }; -/* GRelation - * - * Indexed Relations. Imagine a really simple table in a - * database. Relations are not ordered. This data type is meant for - * maintaining a N-way mapping. - * - * g_relation_new() creates a relation with FIELDS fields - * - * g_relation_destroy() frees all resources - * g_tuples_destroy() frees the result of g_relation_select() - * - * g_relation_index() indexes relation FIELD with the provided - * equality and hash functions. this must be done before any - * calls to insert are made. - * - * g_relation_insert() inserts a new tuple. you are expected to - * provide the right number of fields. - * - * g_relation_delete() deletes all relations with KEY in FIELD - * g_relation_select() returns ... - * g_relation_count() counts ... - */ - GLIB_DEPRECATED_IN_2_26 GRelation* g_relation_new (gint fields); GLIB_DEPRECATED_IN_2_26 diff --git a/glib/deprecated/gthread-deprecated.c b/glib/deprecated/gthread-deprecated.c index 49bcf4f..ec0f1a7 100644 --- a/glib/deprecated/gthread-deprecated.c +++ b/glib/deprecated/gthread-deprecated.c @@ -41,17 +41,6 @@ /* {{{1 Documentation */ /** - * SECTION:threads-deprecated - * @title: Deprecated thread API - * @short_description: old thread APIs (for reference only) - * @see_also: #GThread - * - * These APIs are deprecated. You should not use them in new code. - * This section remains only to assist with understanding code that was - * written to use these APIs at some point in the past. - **/ - -/** * GThreadPriority: * @G_THREAD_PRIORITY_LOW: a priority lower than normal * @G_THREAD_PRIORITY_NORMAL: the default priority @@ -232,7 +221,7 @@ g_thread_set_priority (GThread *thread, /** * g_thread_foreach: - * @thread_func: function to call for all #GThread structures + * @thread_func: (scope call): function to call for all #GThread structures * @user_data: second argument to @thread_func * * Call @thread_func on all #GThreads that have been diff --git a/glib/deprecated/gthread.h b/glib/deprecated/gthread.h index a366136..a18a730 100644 --- a/glib/deprecated/gthread.h +++ b/glib/deprecated/gthread.h @@ -286,7 +286,7 @@ void g_cond_free (GCond *cond); GLIB_DEPRECATED_IN_2_32 gboolean g_cond_timed_wait (GCond *cond, GMutex *mutex, - GTimeVal *timeval); + GTimeVal *abs_time); G_GNUC_END_IGNORE_DEPRECATIONS diff --git a/glib/docs.c b/glib/docs.c index 450616e..b4457ac 100644 --- a/glib/docs.c +++ b/glib/docs.c @@ -25,1087 +25,9 @@ * files. */ -/* Basic types {{{1 */ - -/** - * SECTION:types - * @title: Basic Types - * @short_description: standard GLib types, defined for ease-of-use - * and portability - * - * GLib defines a number of commonly used types, which can be divided - * into several groups: - * - New types which are not part of standard C (but are defined in - * various C standard library header files) — #gboolean, #gssize. - * - Integer types which are guaranteed to be the same size across - * all platforms — #gint8, #guint8, #gint16, #guint16, #gint32, - * #guint32, #gint64, #guint64. - * - Types which are easier to use than their standard C counterparts - - * #gpointer, #gconstpointer, #guchar, #guint, #gushort, #gulong. - * - Types which correspond exactly to standard C types, but are - * included for completeness — #gchar, #gint, #gshort, #glong, - * #gfloat, #gdouble. - * - Types which correspond exactly to standard C99 types, but are available - * to use even if your compiler does not support C99 — #gsize, #goffset, - * #gintptr, #guintptr. - * - * GLib also defines macros for the limits of some of the standard - * integer and floating point types, as well as macros for suitable - * printf() formats for these types. - * - * Note that depending on the platform and build configuration, the format - * macros might not be compatible with the system provided printf() function, - * because GLib might use a different printf() implementation internally. - * The format macros will always work with GLib API (like g_print()), and with - * any C99 compatible printf() implementation. - */ - -/** - * gboolean: - * - * A standard boolean type. - * Variables of this type should only contain the value - * %TRUE or %FALSE. - * - * Never directly compare the contents of a #gboolean variable with the values - * %TRUE or %FALSE. Use `if (condition)` to check a #gboolean is "true", instead - * of `if (condition == TRUE)`. Likewise use `if (!condition)` to check a - * #gboolean is "false". - * - * There is no validation when assigning to a #gboolean variable and so it could - * contain any value represented by a #gint. This is why the use of `if - * (condition)` is recommended. All non-zero values in C evaluate to "true". - */ - -/** - * gpointer: - * - * An untyped pointer, exactly equivalent to `void *`. - * - * The standard C `void *` type should usually be preferred in - * new code, but `gpointer` can be used in contexts where a type name - * must be a single word, such as in the g_type_name() of %G_TYPE_POINTER - * or when generating a family of function names for multiple types - * using macros. - */ - -/** - * gconstpointer: - * - * An untyped pointer to constant data, exactly equivalent to `const void *`. - * - * The data pointed to should not be changed. - * - * This is typically used in function prototypes to indicate - * that the data pointed to will not be altered by the function. - * - * The standard C `const void *` type should usually be preferred in - * new code, but `gconstpointer` can be used in contexts where a type name - * must be a single word. - */ - -/** - * gchar: - * - * Equivalent to the standard C `char` type. - * - * This type only exists for symmetry with `guchar`. - * The standard C `char` type should be preferred in new code. - */ - -/** - * guchar: - * - * Equivalent to the standard C `unsigned char` type. - * - * The standard C `unsigned char` type should usually be preferred in - * new code, but `guchar` can be used in contexts where a type name - * must be a single word, such as in the g_type_name() of %G_TYPE_UCHAR - * or when generating a family of function names for multiple types - * using macros. - */ - -/** - * gint: - * - * Equivalent to the standard C `int` type. - * - * Values of this type can range from `INT_MIN` to `INT_MAX`, - * or equivalently from %G_MININT to %G_MAXINT. - * - * This type only exists for symmetry with `guint`. - * The standard C `int` type should be preferred in new code. - */ - -/** - * G_MININT: - * - * The minimum value which can be held in a #gint. - * - * This is the same as standard C `INT_MIN`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * G_MAXINT: - * - * The maximum value which can be held in a #gint. - * - * This is the same as standard C `INT_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * guint: - * - * Equivalent to the standard C `unsigned int` type. - * - * Values of this type can range from 0 to `UINT_MAX`, - * or equivalently 0 to %G_MAXUINT. - * - * The standard C `unsigned int` type should usually be preferred in - * new code, but `guint` can be used in contexts where a type name - * must be a single word, such as in the g_type_name() of %G_TYPE_UINT - * or when generating a family of function names for multiple types - * using macros. - */ - -/** - * G_MAXUINT: - * - * The maximum value which can be held in a #guint. - * - * This is the same as standard C `UINT_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gshort: - * - * Equivalent to the standard C `short` type. - * - * Values of this type can range from `SHRT_MIN` to `SHRT_MAX`, - * or equivalently %G_MINSHORT to %G_MAXSHORT. - * - * This type only exists for symmetry with `gushort`. - * The standard C `short` type should be preferred in new code. - */ - -/** - * G_MINSHORT: - * - * The minimum value which can be held in a #gshort. - * - * This is the same as standard C `SHRT_MIN`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * G_MAXSHORT: - * - * The maximum value which can be held in a #gshort. - * - * This is the same as standard C `SHRT_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gushort: - * - * Equivalent to the standard C `unsigned short` type. - * - * Values of this type can range from 0 to `USHRT_MAX`, - * or equivalently from 0 to %G_MAXUSHORT. - * - * The standard C `unsigned short` type should usually be preferred in - * new code, but `gushort` can be used in contexts where a type name - * must be a single word, such as when generating a family of function - * names for multiple types using macros. - */ - -/** - * G_MAXUSHORT: - * - * The maximum value which can be held in a #gushort. - * - * This is the same as standard C `USHRT_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * glong: - * - * Equivalent to the standard C `long` type. - * - * Values of this type can range from `LONG_MIN` to `LONG_MAX`, - * or equivalently %G_MINLONG to %G_MAXLONG. - * - * This type only exists for symmetry with `gulong`. - * The standard C `long` type should be preferred in new code. - */ - -/** - * G_MINLONG: - * - * The minimum value which can be held in a #glong. - * - * This is the same as standard C `LONG_MIN`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * G_MAXLONG: - * - * The maximum value which can be held in a #glong. - * - * This is the same as standard C `ULONG_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gulong: - * - * Equivalent to the standard C `unsigned long` type. - * - * Values of this type can range from 0 to %G_MAXULONG. - * - * The standard C `unsigned long` type should usually be preferred in - * new code, but `gulong` can be used in contexts where a type name - * must be a single word, such as in the g_type_name() of %G_TYPE_ULONG - * or when generating a family of function names for multiple types - * using macros. - */ - -/** - * G_MAXULONG: - * - * The maximum value which can be held in a #gulong. - * - * This is the same as standard C `ULONG_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gint8: - * - * A signed integer guaranteed to be 8 bits on all platforms, - * similar to the standard C `int8_t`. - * - * The `int8_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `gint8` - * (see #gsize for more details). - * - * Values of this type can range from %G_MININT8 (= -128) to - * %G_MAXINT8 (= 127). - */ - -/** - * G_MAXINT8: - * - * The maximum value which can be held in a #gint8. - * - * This is the same as standard C `INT8_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * guint8: - * - * An unsigned integer guaranteed to be 8 bits on all platforms, - * similar to the standard C `uint8_t`. - * - * The `uint8_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `guint8` - * (see #gsize for more details). - * - * Values of this type can range from 0 to %G_MAXUINT8 (= 255). - */ - -/** - * G_MAXUINT8: - * - * The maximum value which can be held in a #guint8. - * - * This is the same as standard C `UINT8_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * gint16: - * - * A signed integer guaranteed to be 16 bits on all platforms, - * similar to the standard C `int16_t`. - * - * The `int16_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `gint16` - * (see #gsize for more details). - * - * Values of this type can range from %G_MININT16 (= -32,768) to - * %G_MAXINT16 (= 32,767). - * - * To print or scan values of this type, use - * %G_GINT16_MODIFIER and/or %G_GINT16_FORMAT. - */ - -/** - * G_MAXINT16: - * - * The maximum value which can be held in a #gint16. - * - * This is the same as standard C `INT16_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * G_GINT16_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gint16 or #guint16. It - * is a string literal, but doesn't include the percent-sign, such - * that you can add precision and length modifiers between percent-sign - * and conversion specifier and append a conversion specifier. - * - * The following example prints "0x7b"; - * |[ - * gint16 value = 123; - * g_print ("%#" G_GINT16_MODIFIER "x", value); - * ]| - * - * This is not necessarily the correct modifier for printing and scanning - * `int16_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId16` and `SCNd16` should be used for `int16_t`. - * - * Since: 2.4 - */ - -/** - * G_GINT16_FORMAT: - * - * This is the platform dependent conversion specifier for scanning and - * printing values of type #gint16. It is a string literal, but doesn't - * include the percent-sign, such that you can add precision and length - * modifiers between percent-sign and conversion specifier. - * - * |[ - * gint16 in; - * gint32 out; - * sscanf ("42", "%" G_GINT16_FORMAT, &in) - * out = in * 1000; - * g_print ("%" G_GINT32_FORMAT, out); - * - * This is not necessarily the correct format for printing and scanning - * `int16_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId16` and `SCNd16` should be used for `int16_t`. - * ]| - */ - -/** - * guint16: - * - * An unsigned integer guaranteed to be 16 bits on all platforms, - * similar to the standard C `uint16_t`. - * - * The `uint16_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `guint16` - * (see #gsize for more details). - * - * Values of this type can range from 0 to %G_MAXUINT16 (= 65,535). - * - * To print or scan values of this type, use - * %G_GINT16_MODIFIER and/or %G_GUINT16_FORMAT. - */ - -/** - * G_MAXUINT16: - * - * The maximum value which can be held in a #guint16. - * - * This is the same as standard C `UINT16_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * G_GUINT16_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #guint16. See also %G_GINT16_FORMAT - * - * This is not necessarily the correct modifier for printing and scanning - * `uint16_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRIu16` and `SCNu16` should be used for `uint16_t`. - */ - -/** - * gint32: - * - * A signed integer guaranteed to be 32 bits on all platforms. - * - * The `int32_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `gint16` - * (see #gsize for more details). - * - * Values of this type can range from %G_MININT32 (= -2,147,483,648) - * to %G_MAXINT32 (= 2,147,483,647). - * - * To print or scan values of this type, use - * %G_GINT32_MODIFIER and/or %G_GINT32_FORMAT. - * - * Note that on platforms with more than one 32-bit standard integer type, - * `gint32` and `int32_t` are not necessarily implemented by the same - * 32-bit integer type. - * For example, on an ILP32 platform where `int` and `long` are both 32-bit, - * it might be the case that one of these types is `int` and the other - * is `long`. - * See #gsize for more details of what this implies. - */ - -/** - * G_MAXINT32: - * - * The maximum value which can be held in a #gint32. - * - * This is the same as standard C `INT32_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * G_GINT32_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gint32 or #guint32. It - * is a string literal. See also %G_GINT16_MODIFIER. - * - * This is not necessarily the correct modifier for printing and scanning - * `int32_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId32` and `SCNd32` should be used for `int32_t`. - * - * Since: 2.4 - */ - -/** - * G_GINT32_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #gint32. See also %G_GINT16_FORMAT. - * - * This is not necessarily the correct modifier for printing and scanning - * `int32_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId32` and `SCNd32` should be used for `int32_t`. - */ - -/** - * guint32: - * - * An unsigned integer guaranteed to be 32 bits on all platforms, - * similar to the standard C `uint32_t`. - * - * The `uint32_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `guint32` - * (see #gsize for more details). - * - * Values of this type can range from 0 to %G_MAXUINT32 (= 4,294,967,295). - * - * To print or scan values of this type, use - * %G_GINT32_MODIFIER and/or %G_GUINT32_FORMAT. - * - * Note that on platforms with more than one 32-bit standard integer type, - * `guint32` and `uint32_t` are not necessarily implemented by the same - * 32-bit integer type. - * See #gsize for more details of what this implies. - */ - -/** - * G_MAXUINT32: - * - * The maximum value which can be held in a #guint32. - * - * This is the same as standard C `UINT32_MAX`, which should be - * preferred in new code. - * - * Since: 2.4 - */ - -/** - * G_GUINT32_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #guint32. See also %G_GINT16_FORMAT. - * - * This is not necessarily the correct modifier for printing and scanning - * `uint32_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRIu32` and `SCNu32` should be used for `uint32_t`. - */ - -/** - * gint64: - * - * A signed integer guaranteed to be 64 bits on all platforms, - * similar to the standard C `int64_t`. - * - * The `int64_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `gint64` - * (see #gsize for more details). - * - * Values of this type can range from %G_MININT64 - * (= -9,223,372,036,854,775,808) to %G_MAXINT64 - * (= 9,223,372,036,854,775,807). - * - * To print or scan values of this type, use - * %G_GINT64_MODIFIER and/or %G_GINT64_FORMAT. - * - * Note that on platforms with more than one 64-bit standard integer type, - * `gint64` and `int64_t` are not necessarily implemented by the same - * 64-bit integer type. - * For example, on a platform where both `long` and `long long` are 64-bit, - * it might be the case that one of those types is used for `gint64` - * and the other is used for `int64_t`. - * See #gsize for more details of what this implies. - */ - -/** - * G_MAXINT64: - * - * The maximum value which can be held in a #gint64. - */ - -/** - * G_GINT64_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gint64 or #guint64. - * It is a string literal. - * - * Some platforms do not support printing 64-bit integers, even - * though the types are supported. On such platforms %G_GINT64_MODIFIER - * is not defined. - * - * This is not necessarily the correct modifier for printing and scanning - * `int64_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId64` and `SCNd64` should be used for `int64_t`. - * - * Since: 2.4 - */ - -/** - * G_GINT64_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #gint64. See also %G_GINT16_FORMAT. - * - * Some platforms do not support scanning and printing 64-bit integers, - * even though the types are supported. On such platforms %G_GINT64_FORMAT - * is not defined. Note that scanf() may not support 64-bit integers, even - * if %G_GINT64_FORMAT is defined. Due to its weak error handling, scanf() - * is not recommended for parsing anyway; consider using g_ascii_strtoull() - * instead. - * - * This is not necessarily the correct format for printing and scanning - * `int64_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRId64` and `SCNd64` should be used for `int64_t`. - */ - -/** - * guint64: - * - * An unsigned integer guaranteed to be 64-bits on all platforms, - * similar to the standard C `uint64_t` type. - * - * The `uint64_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires use of `guint64` - * (see #gsize for more details). - * - * Values of this type can range from 0 to %G_MAXUINT64 - * (= 18,446,744,073,709,551,615). - * - * To print or scan values of this type, use - * %G_GINT64_MODIFIER and/or %G_GUINT64_FORMAT. - * - * Note that on platforms with more than one 64-bit standard integer type, - * `guint64` and `uint64_t` are not necessarily implemented by the same - * 64-bit integer type. - * See #gsize for more details of what this implies. - */ - -/** - * G_MAXUINT64: - * - * The maximum value which can be held in a #guint64. - * - * This is the same as standard C `UINT64_MAX`, which should be - * preferred in new code. - */ - -/** - * G_GUINT64_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #guint64. See also %G_GINT16_FORMAT. - * - * Some platforms do not support scanning and printing 64-bit integers, - * even though the types are supported. On such platforms %G_GUINT64_FORMAT - * is not defined. Note that scanf() may not support 64-bit integers, even - * if %G_GINT64_FORMAT is defined. Due to its weak error handling, scanf() - * is not recommended for parsing anyway; consider using g_ascii_strtoull() - * instead. - * - * This is not necessarily the correct modifier for printing and scanning - * `uint64_t` values, even though the in-memory representation is the same. - * Standard C macros like `PRIu64` and `SCNu64` should be used for `uint64_t`. - */ - -/** - * G_GINT64_CONSTANT: - * @val: a literal integer value, e.g. 0x1d636b02300a7aa7 - * - * This macro is used to insert 64-bit integer literals - * into the source code. - * - * It is similar to the standard C `INT64_C` macro, - * which should be preferred in new code. - */ - -/** - * G_GUINT64_CONSTANT: - * @val: a literal integer value, e.g. 0x1d636b02300a7aa7U - * - * This macro is used to insert 64-bit unsigned integer - * literals into the source code. - * - * It is similar to the standard C `UINT64_C` macro, - * which should be preferred in new code. - * - * Since: 2.10 - */ - -/** - * gfloat: - * - * Equivalent to the standard C `float` type. - * - * Values of this type can range from `-FLT_MAX` to `FLT_MAX`, - * or equivalently from -%G_MAXFLOAT to %G_MAXFLOAT. - */ - -/** - * G_MINFLOAT: - * - * The minimum positive value which can be held in a #gfloat. - * - * If you are interested in the smallest value which can be held - * in a #gfloat, use -%G_MAXFLOAT. - * - * This is the same as standard C `FLT_MIN`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * G_MAXFLOAT: - * - * The maximum value which can be held in a #gfloat. - * - * This is the same as standard C `FLT_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gdouble: - * - * Equivalent to the standard C `double` type. - * - * Values of this type can range from `-DBL_MAX` to `DBL_MAX`, - * or equivalently from -%G_MAXDOUBLE to %G_MAXDOUBLE. - */ - -/** - * G_MINDOUBLE: - * - * The minimum positive value which can be held in a #gdouble. - * - * If you are interested in the smallest value which can be held - * in a #gdouble, use -%G_MAXDOUBLE. - * - * This is the same as standard C `DBL_MIN`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * G_MAXDOUBLE: - * - * The maximum value which can be held in a #gdouble. - * - * This is the same as standard C `DBL_MAX`, which is available since C99 - * and should be preferred in new code. - */ - -/** - * gsize: - * - * An unsigned integer type of the result of the `sizeof` operator, - * corresponding to the `size_t` type defined in C99. - * - * The standard `size_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires `gsize` - * (see below for more details). - * - * `gsize` is usually 32 bit wide on a 32-bit platform and 64 bit wide - * on a 64-bit platform. Values of this type can range from 0 to - * %G_MAXSIZE. - * - * This type is wide enough to hold the size of the largest possible - * memory allocation, but is not guaranteed to be wide enough to hold - * the numeric value of a pointer: on platforms that use tagged pointers, - * such as [CHERI](https://cheri-cpu.org/), pointers can be numerically - * larger than the size of the address space. - * If the numeric value of a pointer needs to be stored in an integer - * without information loss, use the standard C types `intptr_t` or - * `uintptr_t`, or the similar GLib types #gintptr or #guintptr. - * - * To print or scan values of this type, use - * %G_GSIZE_MODIFIER and/or %G_GSIZE_FORMAT. - * - * Note that on platforms where more than one standard integer type is - * the same size, `size_t` and `gsize` are always the same size but are - * not necessarily implemented by the same standard integer type. - * For example, on an ILP32 platform where `int`, `long` and pointers - * are all 32-bit, `size_t` might be `unsigned long` while `gsize` - * might be `unsigned int`. - * This can result in compiler warnings or unexpected C++ name-mangling - * if the two types are used inconsistently. - * - * As a result, changing a type from `gsize` to `size_t` in existing APIs - * might be an incompatible API or ABI change, especially if C++ - * is involved. The safe option is to leave existing APIs using the same type - * that they have historically used, and only use the standard C types in - * new APIs. - * - * Similar considerations apply to all the fixed-size types - * (#gint8, #guint8, #gint16, #guint16, #gint32, #guint32, #gint64, - * #guint64 and #goffset), as well as #gintptr and #guintptr. - * Types that are 32 bits or larger are particularly likely to be - * affected by this. - */ - -/** - * G_MAXSIZE: - * - * The maximum value which can be held in a #gsize. - * - * This is the same as standard C `SIZE_MAX` (available since C99), - * which should be preferred in new code. - * - * Since: 2.4 - */ - -/** - * G_GSIZE_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gsize. It - * is a string literal. - * - * Note that this is not necessarily the correct modifier to scan or - * print a `size_t`, even though the in-memory representation is the - * same. The Standard C `"z"` modifier should be used for `size_t`, - * assuming a C99-compliant `printf` implementation is available. - * - * Since: 2.6 - */ - -/** - * G_GSIZE_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #gsize. See also %G_GINT16_FORMAT. - * - * Note that this is not necessarily the correct format to scan or - * print a `size_t`, even though the in-memory representation is the - * same. The standard C `"zu"` format should be used for `size_t`, - * assuming a C99-compliant `printf` implementation is available. - * - * Since: 2.6 - */ - -/** - * gssize: - * - * A signed variant of #gsize, corresponding to the - * `ssize_t` defined in POSIX or the similar `SSIZE_T` in Windows. - * - * In new platform-specific code, consider using `ssize_t` or `SSIZE_T` - * directly. - * - * Values of this type can range from %G_MINSSIZE - * to %G_MAXSSIZE. - * - * Note that on platforms where `ssize_t` is implemented, `ssize_t` and - * `gssize` might be implemented by different standard integer types - * of the same size. Similarly, on Windows, `SSIZE_T` and `gssize` - * might be implemented by different standard integer types of the same - * size. See #gsize for more details. - * - * This type is also not guaranteed to be the same as standard C - * `ptrdiff_t`, although they are the same on many platforms. - * - * To print or scan values of this type, use - * %G_GSSIZE_MODIFIER and/or %G_GSSIZE_FORMAT. - */ - -/** - * G_MINSSIZE: - * - * The minimum value which can be held in a #gssize. - * - * Since: 2.14 - */ - -/** - * G_MAXSSIZE: - * - * The maximum value which can be held in a #gssize. - * - * Since: 2.14 - */ - -/** - * G_GSSIZE_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #gssize. See also %G_GINT16_FORMAT. - * - * Note that this is not necessarily the correct format to scan or print - * a POSIX `ssize_t` or a Windows `SSIZE_T`, even though the in-memory - * representation is the same. - * On POSIX platforms, the `"zd"` format should be used for `ssize_t`. - * - * Since: 2.6 - */ - -/** - * G_GSSIZE_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gssize. It - * is a string literal. - * - * Note that this is not necessarily the correct modifier to scan or print - * a POSIX `ssize_t` or a Windows `SSIZE_T`, even though the in-memory - * representation is the same. - * On POSIX platforms, the `"z"` modifier should be used for `ssize_t`. - * - * Since: 2.6 - */ - -/** - * goffset: - * - * A signed integer type that is used for file offsets, - * corresponding to the POSIX type `off_t` as if compiling with - * `_FILE_OFFSET_BITS` set to 64. #goffset is always 64 bits wide, even on - * 32-bit architectures, and even if `off_t` is only 32 bits. - * Values of this type can range from %G_MINOFFSET to - * %G_MAXOFFSET. - * - * To print or scan values of this type, use - * %G_GOFFSET_MODIFIER and/or %G_GOFFSET_FORMAT. - * - * On platforms with more than one 64-bit standard integer type, - * even if `off_t` is also 64 bits in size, `goffset` and `off_t` are not - * necessarily implemented by the same 64-bit integer type. - * See #gsize for more details of what this implies. - * - * Since: 2.14 - */ - -/** - * G_MINOFFSET: - * - * The minimum value which can be held in a #goffset. - */ - -/** - * G_MAXOFFSET: - * - * The maximum value which can be held in a #goffset. - */ - -/** - * G_GOFFSET_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #goffset. It is a string - * literal. See also %G_GINT64_MODIFIER. - * - * This modifier should only be used with #goffset values, and not - * with `off_t`, which is not necessarily the same type or even the same size. - * - * Since: 2.20 - */ - -/** - * G_GOFFSET_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #goffset. See also %G_GINT64_FORMAT. - * - * This format should only be used with #goffset values, and not - * with `off_t`, which is not necessarily the same type or even the same size. - * - * Since: 2.20 - */ - -/** - * G_GOFFSET_CONSTANT: - * @val: a literal integer value, e.g. 0x1d636b02300a7aa7 - * - * This macro is used to insert #goffset 64-bit integer literals - * into the source code. - * - * See also G_GINT64_CONSTANT(). - * - * Since: 2.20 - */ - -/** - * gintptr: - * - * Corresponds to the C99 type intptr_t, - * a signed integer type that can hold any pointer. - * - * The standard `intptr_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires `gintptr`. - * Note that `intptr_t` and `gintptr` might be implemented by different - * standard integer types of the same size. See #gsize for more details. - * - * #gintptr is not guaranteed to be the same type or the same size as #gssize, - * even though they are the same on many CPU architectures. - * - * To print or scan values of this type, use - * %G_GINTPTR_MODIFIER and/or %G_GINTPTR_FORMAT. - * - * Since: 2.18 - */ - -/** - * G_GINTPTR_MODIFIER: - * - * The platform dependent length modifier for conversion specifiers - * for scanning and printing values of type #gintptr or #guintptr. - * It is a string literal. - * - * Note that this is not necessarily the correct modifier to scan or - * print an `intptr_t`, even though the in-memory representation is the - * same. - * Standard C macros like `PRIdPTR` and `SCNdPTR` should be used for - * `intptr_t`. - * - * Since: 2.22 - */ - -/** - * G_GINTPTR_FORMAT: - * - * This is the platform dependent conversion specifier for scanning - * and printing values of type #gintptr. - * - * Note that this is not necessarily the correct format to scan or - * print an `intptr_t`, even though the in-memory representation is the - * same. - * Standard C macros like `PRIdPTR` and `SCNdPTR` should be used for - * `intptr_t`. - * - * Since: 2.22 - */ - -/** - * guintptr: - * - * Corresponds to the C99 type uintptr_t, - * an unsigned integer type that can hold any pointer. - * - * The standard `uintptr_t` type should be preferred in new code, unless - * consistency with pre-existing APIs requires `guintptr`. - * Note that `uintptr_t` and `guintptr` might be implemented by different - * standard integer types of the same size. See #gsize for more details. - * - * #guintptr is not guaranteed to be the same type or the same size as #gsize, - * even though they are the same on many CPU architectures. - * - * To print or scan values of this type, use - * %G_GINTPTR_MODIFIER and/or %G_GUINTPTR_FORMAT. - * - * Since: 2.18 - */ - -/** - * G_GUINTPTR_FORMAT: - * - * This is the platform dependent conversion specifier - * for scanning and printing values of type #guintptr. - * - * Note that this is not necessarily the correct format to scan or - * print a `uintptr_t`, even though the in-memory representation is the - * same. - * Standard C macros like `PRIuPTR` and `SCNuPTR` should be used for - * `uintptr_t`. - * - * Since: 2.22 - */ - /* Type conversion {{{1 */ /** - * SECTION:type_conversion - * @title: Type Conversion Macros - * @short_description: portably storing integers in pointer variables - * - * Many times GLib, GTK, and other libraries allow you to pass "user - * data" to a callback, in the form of a void pointer. From time to time - * you want to pass an integer instead of a pointer. You could allocate - * an integer, with something like: - * |[ - * int *ip = g_new (int, 1); - * *ip = 42; - * ]| - * But this is inconvenient, and it's annoying to have to free the - * memory at some later time. - * - * Pointers are always at least 32 bits in size (on all platforms GLib - * intends to support). Thus you can store at least 32-bit integer values - * in a pointer value. Naively, you might try this, but it's incorrect: - * |[ - * gpointer p; - * int i; - * p = (void*) 42; - * i = (int) p; - * ]| - * Again, that example was not correct, don't copy it. - * The problem is that on some systems you need to do this: - * |[ - * gpointer p; - * int i; - * p = (void*) (long) 42; - * i = (int) (long) p; - * ]| - * The GLib macros GPOINTER_TO_INT(), GINT_TO_POINTER(), etc. take care - * to do the right thing on every platform. - * - * Warning: You may not store pointers in integers. This is not - * portable in any way, shape or form. These macros only allow storing - * integers in pointers, and only preserve 32 bits of the integer; values - * outside the range of a 32-bit integer will be mangled. - */ - -/** * GINT_TO_POINTER: * @i: integer to stuff into a pointer * @@ -1150,6 +72,12 @@ * @s: #gsize to stuff into the pointer * * Stuffs a #gsize into a pointer type. + * + * Remember, you may not store pointers in integers. This is not portable + * in any way, shape or form. These macros only allow storing integers in + * pointers, and preserve all bits of a pointer (e.g. on CHERI systems). + * The only types that can store pointers as well as integers are #guintptr + * and #gintptr. */ /** @@ -1158,44 +86,17 @@ * * Extracts a #gsize from a pointer. The #gsize must have * been stored in the pointer with GSIZE_TO_POINTER(). - */ - -/* Byte order {{{1 */ - -/** - * SECTION:byte_order - * @title: Byte Order Macros - * @short_description: a portable way to convert between different byte orders - * - * These macros provide a portable way to determine the host byte order - * and to convert values between different byte orders. - * - * The byte order is the order in which bytes are stored to create larger - * data types such as the #gint and #glong values. - * The host byte order is the byte order used on the current machine. - * - * Some processors store the most significant bytes (i.e. the bytes that - * hold the largest part of the value) first. These are known as big-endian - * processors. Other processors (notably the x86 family) store the most - * significant byte last. These are known as little-endian processors. - * - * Finally, to complicate matters, some other processors store the bytes in - * a rather curious order known as PDP-endian. For a 4-byte word, the 3rd - * most significant byte is stored first, then the 4th, then the 1st and - * finally the 2nd. * - * Obviously there is a problem when these different processors communicate - * with each other, for example over networks or by using binary file formats. - * This is where these macros come in. They are typically used to convert - * values into a byte order which has been agreed on for use when - * communicating between different processors. The Internet uses what is - * known as 'network byte order' as the standard byte order (which is in - * fact the big-endian byte order). + * Remember, you may not store pointers in integers. This is not portable + * in any way, shape or form. These macros only allow storing integers in + * pointers, and preserve all bits of a pointer (e.g. on CHERI systems). + * The only types that can store pointers as well as integers are #guintptr + * and #gintptr. * - * Note that the byte order conversion macros may evaluate their arguments - * multiple times, thus you should not use them with arguments which have - * side-effects. + * See also GPOINTER_TO_TYPE() for #gsize. */ + +/* Byte order {{{1 */ /** * G_BYTE_ORDER: @@ -1765,27 +666,6 @@ */ /* Bounds-checked integer arithmetic {{{1 */ -/** - * SECTION:checkedmath - * @title: Bounds-checking integer arithmetic - * @short_description: a set of helpers for performing checked integer arithmetic - * - * GLib offers a set of macros for doing additions and multiplications - * of unsigned integers, with checks for overflows. - * - * The helpers all have three arguments. A pointer to the destination - * is always the first argument and the operands to the operation are - * the other two. - * - * Following standard GLib convention, the helpers return %TRUE in case - * of success (ie: no overflow). - * - * The helpers may be macros, normal functions or inlines. They may be - * implemented with inline assembly or compiler intrinsics where - * available. - * - * Since: 2.48 - */ /** * g_uint_checked_add @@ -1891,23 +771,6 @@ /* Numerical Definitions {{{1 */ /** - * SECTION:numerical - * @title: Numerical Definitions - * @short_description: mathematical constants, and floating point decomposition - * - * GLib offers mathematical constants such as %G_PI for the value of pi; - * many platforms have these in the C library, but some don't, the GLib - * versions always exist. - * - * The #GFloatIEEE754 and #GDoubleIEEE754 unions are used to access the - * sign, mantissa and exponent of IEEE floats and doubles. These unions are - * defined as appropriate for a given platform. IEEE floats and doubles are - * supported (used for storage) by at least Intel, PPC and Sparc. See - * [IEEE 754-2008](http://en.wikipedia.org/wiki/IEEE_float) - * for more information about IEEE number formats. - */ - -/** * G_IEEE754_FLOAT_BIAS: * * The bias by which exponents in single-precision floats are offset. @@ -1986,16 +849,8 @@ * * Multiplying the base 2 exponent by this number yields the base 10 exponent. */ - -/* Macros {{{1 */ -/** - * SECTION:macros - * @title: Standard Macros - * @short_description: commonly-used macros - * - * These macros provide a few commonly-used features. - */ +/* Macros {{{1 */ /** * G_OS_WIN32: @@ -2202,15 +1057,6 @@ /* Miscellaneous Macros {{{1 */ /** - * SECTION:macros_misc - * @title: Miscellaneous Macros - * @short_description: specialized macros which are not used often - * - * These macros provide more specialized features which are not - * needed so often by application programmers. - */ - -/** * G_STMT_START: * * Used within multi-statement macros so that they can be used in places @@ -2978,74 +1824,9 @@ * Since: 2.44 */ -/* Warnings and Assertions {{{1 */ - -/** - * SECTION:warnings - * @title: Warnings and Assertions - * @short_description: warnings and assertions to use in runtime code - * - * GLib defines several warning functions and assertions which can be used to - * warn of programmer errors when calling functions, and print error messages - * from command line programs. - * - * The g_return_if_fail(), g_return_val_if_fail(), g_return_if_reached() and - * g_return_val_if_reached() macros are intended as pre-condition assertions, to - * be used at the top of a public function to check that the function’s - * arguments are acceptable. Any failure of such a pre-condition assertion is - * considered a programming error on the part of the caller of the public API, - * and the program is considered to be in an undefined state afterwards. They - * are similar to the libc assert() function, but provide more context on - * failures. - * - * For example: - * |[ - * gboolean - * g_dtls_connection_shutdown (GDtlsConnection *conn, - * gboolean shutdown_read, - * gboolean shutdown_write, - * GCancellable *cancellable, - * GError **error) - * { - * // local variable declarations - * - * g_return_val_if_fail (G_IS_DTLS_CONNECTION (conn), FALSE); - * g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); - * g_return_val_if_fail (error == NULL || *error == NULL, FALSE); - * - * // function body - * - * return return_val; - * } - * ]| - * - * g_print() and g_printerr() are intended to be used for - * output from command line applications, since they output to standard output - * and standard error by default — whereas functions like g_message() and - * g_log() may be redirected to special purpose message windows, files, or the - * system journal. - * - * If the console encoding is not UTF-8 (as specified by g_get_console_charset()) - * then these functions convert the message first. Any Unicode - * characters not defined by that charset are replaced by `'?'`. On Linux, - * setlocale() must be called early in main() to load the encoding. This behaviour - * can be changed by providing custom handlers to g_set_print_handler(), - * g_set_printerr_handler() and g_log_set_handler(). - */ - /* Windows Compatibility Functions {{{1 */ /** - * SECTION:windows - * @title: Windows Compatibility Functions - * @short_description: UNIX emulation on Windows - * - * These functions provide some level of UNIX emulation on the - * Windows platform. If your application really needs the POSIX - * APIs, we suggest you try the Cygwin project. - */ - -/** * MAXPATHLEN: * * Provided for UNIX emulation on Windows; equivalent to UNIX diff --git a/glib/garcbox.c b/glib/garcbox.c index d69e75d..da19cd4 100644 --- a/glib/garcbox.c +++ b/glib/garcbox.c @@ -36,131 +36,6 @@ #define G_ARC_BOX(p) (GArcBox *) (((char *) (p)) - G_ARC_BOX_SIZE) /** - * SECTION:arcbox - * @Title: Atomically reference counted data - * @Short_description: Allocated memory with atomic reference counting semantics - * - * An "atomically reference counted box", or "ArcBox", is an opaque wrapper - * data type that is guaranteed to be as big as the size of a given data type, - * and which augments the given data type with thread safe reference counting - * semantics for its memory management. - * - * ArcBox is useful if you have a plain old data type, like a structure - * typically placed on the stack, and you wish to provide additional API - * to use it on the heap; or if you want to implement a new type to be - * passed around by reference without necessarily implementing copy/free - * semantics or your own reference counting. - * - * The typical use is: - * - * |[ - * typedef struct { - * char *name; - * char *address; - * char *city; - * char *state; - * int age; - * } Person; - * - * Person * - * person_new (void) - * { - * return g_atomic_rc_box_new0 (Person); - * } - * ]| - * - * Every time you wish to acquire a reference on the memory, you should - * call g_atomic_rc_box_acquire(); similarly, when you wish to release a reference - * you should call g_atomic_rc_box_release(): - * - * |[ - * // Add a Person to the Database; the Database acquires ownership - * // of the Person instance - * void - * add_person_to_database (Database *db, Person *p) - * { - * db->persons = g_list_prepend (db->persons, g_atomic_rc_box_acquire (p)); - * } - * - * // Removes a Person from the Database; the reference acquired by - * // add_person_to_database() is released here - * void - * remove_person_from_database (Database *db, Person *p) - * { - * db->persons = g_list_remove (db->persons, p); - * g_atomic_rc_box_release (p); - * } - * ]| - * - * If you have additional memory allocated inside the structure, you can - * use g_atomic_rc_box_release_full(), which takes a function pointer, which - * will be called if the reference released was the last: - * - * |[ - * void - * person_clear (Person *p) - * { - * g_free (p->name); - * g_free (p->address); - * g_free (p->city); - * g_free (p->state); - * } - * - * void - * remove_person_from_database (Database *db, Person *p) - * { - * db->persons = g_list_remove (db->persons, p); - * g_atomic_rc_box_release_full (p, (GDestroyNotify) person_clear); - * } - * ]| - * - * If you wish to transfer the ownership of a reference counted data - * type without increasing the reference count, you can use g_steal_pointer(): - * - * |[ - * Person *p = g_atomic_rc_box_new (Person); - * - * fill_person_details (p); - * - * add_person_to_database (db, g_steal_pointer (&p)); - * ]| - * - * ## Thread safety - * - * The reference counting operations on data allocated using g_atomic_rc_box_alloc(), - * g_atomic_rc_box_new(), and g_atomic_rc_box_dup() are guaranteed to be atomic, and thus - * can be safely be performed by different threads. It is important to note that - * only the reference acquisition and release are atomic; changes to the content - * of the data are your responsibility. - * - * ## Automatic pointer clean up - * - * If you want to add g_autoptr() support to your plain old data type through - * reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and - * g_atomic_rc_box_release(): - * - * |[ - * G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_atomic_rc_box_release) - * ]| - * - * If you need to clear the contents of the data, you will need to use an - * ancillary function that calls g_rc_box_release_full(): - * - * |[ - * static void - * my_data_struct_release (MyDataStruct *data) - * { - * // my_data_struct_clear() is defined elsewhere - * g_atomic_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear); - * } - * - * G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release) - * ]| - * - * Since: 2.58 - */ - -/** * g_atomic_rc_box_alloc: * @block_size: the size of the allocation, must be greater than 0 * diff --git a/glib/garray.c b/glib/garray.c index e6cef31..ba109ae 100644 --- a/glib/garray.c +++ b/glib/garray.c @@ -47,53 +47,6 @@ #include "grefcount.h" #include "gutilsprivate.h" -/** - * SECTION:arrays - * @title: Arrays - * @short_description: arrays of arbitrary elements which grow - * automatically as elements are added - * - * Arrays are similar to standard C arrays, except that they grow - * automatically as elements are added. - * - * Array elements can be of any size (though all elements of one array - * are the same size), and the array can be automatically cleared to - * '0's and zero-terminated. - * - * To create a new array use g_array_new(). - * - * To add elements to an array with a cost of O(n) at worst, use - * g_array_append_val(), g_array_append_vals(), g_array_prepend_val(), - * g_array_prepend_vals(), g_array_insert_val() and g_array_insert_vals(). - * - * To access an element of an array in O(1) (to read it or to write it), - * use g_array_index(). - * - * To set the size of an array, use g_array_set_size(). - * - * To free an array, use g_array_unref() or g_array_free(). - * - * All the sort functions are internally calling a quick-sort (or similar) - * function with an average cost of O(n log(n)) and a worst case - * cost of O(n^2). - * - * Here is an example that stores integers in a #GArray: - * |[ - * GArray *garray; - * gint i; - * // We create a new array to store gint values. - * // We don't want it zero-terminated or cleared to 0's. - * garray = g_array_new (FALSE, FALSE, sizeof (gint)); - * for (i = 0; i < 10000; i++) - * g_array_append_val (garray, i); - * for (i = 0; i < 10000; i++) - * if (g_array_index (garray, gint, i) != i) - * g_print ("ERROR: got %d instead of %d\n", - * g_array_index (garray, gint, i), i); - * g_array_free (garray, TRUE); - * ]| - */ - #define MIN_ARRAY_SIZE 16 typedef struct _GRealArray GRealArray; @@ -1126,54 +1079,6 @@ g_array_maybe_expand (GRealArray *array, } } -/** - * SECTION:arrays_pointer - * @title: Pointer Arrays - * @short_description: arrays of pointers to any type of data, which - * grow automatically as new elements are added - * - * Pointer Arrays are similar to Arrays but are used only for storing - * pointers. - * - * If you remove elements from the array, elements at the end of the - * array are moved into the space previously occupied by the removed - * element. This means that you should not rely on the index of particular - * elements remaining the same. You should also be careful when deleting - * elements while iterating over the array. - * - * To create a pointer array, use g_ptr_array_new(). - * - * To add elements to a pointer array, use g_ptr_array_add(). - * - * To remove elements from a pointer array, use g_ptr_array_remove(), - * g_ptr_array_remove_index() or g_ptr_array_remove_index_fast(). - * - * To access an element of a pointer array, use g_ptr_array_index(). - * - * To set the size of a pointer array, use g_ptr_array_set_size(). - * - * To free a pointer array, use g_ptr_array_free(). - * - * An example using a #GPtrArray: - * |[ - * GPtrArray *array; - * gchar *string1 = "one"; - * gchar *string2 = "two"; - * gchar *string3 = "three"; - * - * array = g_ptr_array_new (); - * g_ptr_array_add (array, (gpointer) string1); - * g_ptr_array_add (array, (gpointer) string2); - * g_ptr_array_add (array, (gpointer) string3); - * - * if (g_ptr_array_index (array, 0) != (gpointer) string1) - * g_print ("ERROR: got %p instead of %p\n", - * g_ptr_array_index (array, 0), string1); - * - * g_ptr_array_free (array, TRUE); - * ]| - */ - typedef struct _GRealPtrArray GRealPtrArray; /** @@ -2766,45 +2671,6 @@ g_ptr_array_find_with_equal_func (GPtrArray *haystack, } /** - * SECTION:arrays_byte - * @title: Byte Arrays - * @short_description: arrays of bytes - * - * #GByteArray is a mutable array of bytes based on #GArray, to provide arrays - * of bytes which grow automatically as elements are added. - * - * To create a new #GByteArray use g_byte_array_new(). To add elements to a - * #GByteArray, use g_byte_array_append(), and g_byte_array_prepend(). - * - * To set the size of a #GByteArray, use g_byte_array_set_size(). - * - * To free a #GByteArray, use g_byte_array_free(). - * - * An example for using a #GByteArray: - * |[ - * GByteArray *gbarray; - * gint i; - * - * gbarray = g_byte_array_new (); - * for (i = 0; i < 10000; i++) - * g_byte_array_append (gbarray, (guint8*) "abcd", 4); - * - * for (i = 0; i < 10000; i++) - * { - * g_assert (gbarray->data[4*i] == 'a'); - * g_assert (gbarray->data[4*i+1] == 'b'); - * g_assert (gbarray->data[4*i+2] == 'c'); - * g_assert (gbarray->data[4*i+3] == 'd'); - * } - * - * g_byte_array_free (gbarray, TRUE); - * ]| - * - * See #GBytes if you are interested in an immutable object representing a - * sequence of bytes. - */ - -/** * GByteArray: * @data: a pointer to the element data. The data may be moved as * elements are added to the #GByteArray @@ -2895,7 +2761,7 @@ g_byte_array_new_take (guint8 *data, * bytes to the array. Note however that the size of the array is still * 0. * - * Returns: the new #GByteArray + * Returns: (transfer full): the new #GByteArray */ GByteArray* g_byte_array_sized_new (guint reserved_size) @@ -2959,7 +2825,7 @@ g_byte_array_free_to_bytes (GByteArray *array) * Atomically increments the reference count of @array by one. * This function is thread-safe and may be called from any thread. * - * Returns: The passed in #GByteArray + * Returns: (transfer full): The passed in #GByteArray * * Since: 2.22 */ @@ -2995,7 +2861,7 @@ g_byte_array_unref (GByteArray *array) * Adds the given bytes to the end of the #GByteArray. * The array will grow in size automatically if necessary. * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray */ GByteArray* g_byte_array_append (GByteArray *array, @@ -3016,7 +2882,7 @@ g_byte_array_append (GByteArray *array, * Adds the given data to the start of the #GByteArray. * The array will grow in size automatically if necessary. * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray */ GByteArray* g_byte_array_prepend (GByteArray *array, @@ -3035,7 +2901,7 @@ g_byte_array_prepend (GByteArray *array, * * Sets the size of the #GByteArray, expanding it if necessary. * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray */ GByteArray* g_byte_array_set_size (GByteArray *array, @@ -3054,7 +2920,7 @@ g_byte_array_set_size (GByteArray *array, * Removes the byte at the given index from a #GByteArray. * The following bytes are moved down one place. * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray **/ GByteArray* g_byte_array_remove_index (GByteArray *array, @@ -3075,7 +2941,7 @@ g_byte_array_remove_index (GByteArray *array, * does not preserve the order of the #GByteArray. But it is faster * than g_byte_array_remove_index(). * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray */ GByteArray* g_byte_array_remove_index_fast (GByteArray *array, @@ -3095,7 +2961,7 @@ g_byte_array_remove_index_fast (GByteArray *array, * Removes the given number of bytes starting at the given index from a * #GByteArray. The following elements are moved to close the gap. * - * Returns: the #GByteArray + * Returns: (transfer none): the #GByteArray * * Since: 2.4 */ @@ -3114,7 +2980,7 @@ g_byte_array_remove_range (GByteArray *array, /** * g_byte_array_sort: * @array: a #GByteArray - * @compare_func: comparison function + * @compare_func: (scope call): comparison function * * Sorts a byte array, using @compare_func which should be a * qsort()-style comparison function (returns less than zero for first @@ -3137,7 +3003,7 @@ g_byte_array_sort (GByteArray *array, /** * g_byte_array_sort_with_data: * @array: a #GByteArray - * @compare_func: comparison function + * @compare_func: (scope call): comparison function * @user_data: data to pass to @compare_func * * Like g_byte_array_sort(), but the comparison function takes an extra diff --git a/glib/gasyncqueue.c b/glib/gasyncqueue.c index 0518763..8bb0279 100644 --- a/glib/gasyncqueue.c +++ b/glib/gasyncqueue.c @@ -37,56 +37,6 @@ #include "gthread.h" #include "deprecated/gthread.h" - -/** - * SECTION:async_queues - * @title: Asynchronous Queues - * @short_description: asynchronous communication between threads - * @see_also: #GThreadPool - * - * Often you need to communicate between different threads. In general - * it's safer not to do this by shared memory, but by explicit message - * passing. These messages only make sense asynchronously for - * multi-threaded applications though, as a synchronous operation could - * as well be done in the same thread. - * - * Asynchronous queues are an exception from most other GLib data - * structures, as they can be used simultaneously from multiple threads - * without explicit locking and they bring their own builtin reference - * counting. This is because the nature of an asynchronous queue is that - * it will always be used by at least 2 concurrent threads. - * - * For using an asynchronous queue you first have to create one with - * g_async_queue_new(). #GAsyncQueue structs are reference counted, - * use g_async_queue_ref() and g_async_queue_unref() to manage your - * references. - * - * A thread which wants to send a message to that queue simply calls - * g_async_queue_push() to push the message to the queue. - * - * A thread which is expecting messages from an asynchronous queue - * simply calls g_async_queue_pop() for that queue. If no message is - * available in the queue at that point, the thread is now put to sleep - * until a message arrives. The message will be removed from the queue - * and returned. The functions g_async_queue_try_pop() and - * g_async_queue_timeout_pop() can be used to only check for the presence - * of messages or to only wait a certain time for messages respectively. - * - * For almost every function there exist two variants, one that locks - * the queue and one that doesn't. That way you can hold the queue lock - * (acquire it with g_async_queue_lock() and release it with - * g_async_queue_unlock()) over multiple queue accessing instructions. - * This can be necessary to ensure the integrity of the queue, but should - * only be used when really necessary, as it can make your life harder - * if used unwisely. Normally you should only use the locking function - * variants (those without the _unlocked suffix). - * - * In many cases, it may be more convenient to use #GThreadPool when - * you need to distribute work to a set of worker threads instead of - * using #GAsyncQueue manually. #GThreadPool uses a GAsyncQueue - * internally. - */ - /** * GAsyncQueue: * @@ -111,11 +61,11 @@ typedef struct } SortData; /** - * g_async_queue_new: + * g_async_queue_new: (constructor) * * Creates a new asynchronous queue. * - * Returns: a new #GAsyncQueue. Free with g_async_queue_unref() + * Returns: (transfer full): a new #GAsyncQueue. Free with g_async_queue_unref() */ GAsyncQueue * g_async_queue_new (void) @@ -124,14 +74,14 @@ g_async_queue_new (void) } /** - * g_async_queue_new_full: + * g_async_queue_new_full: (constructor) * @item_free_func: (nullable): function to free queue elements * * Creates a new asynchronous queue and sets up a destroy notify * function that is used to free any remaining queue items when * the queue is destroyed after the final unref. * - * Returns: a new #GAsyncQueue. Free with g_async_queue_unref() + * Returns: (transfer full): a new #GAsyncQueue. Free with g_async_queue_unref() * * Since: 2.16 */ @@ -158,7 +108,7 @@ g_async_queue_new_full (GDestroyNotify item_free_func) * Increases the reference count of the asynchronous @queue by 1. * You do not need to hold the lock to call this function. * - * Returns: the @queue that was passed in (since 2.6) + * Returns: (transfer full): the @queue that was passed in (since 2.6) */ GAsyncQueue * g_async_queue_ref (GAsyncQueue *queue) @@ -212,7 +162,7 @@ g_async_queue_unref_and_unlock (GAsyncQueue *queue) /** * g_async_queue_unref: - * @queue: a #GAsyncQueue. + * @queue: (transfer full): a #GAsyncQueue. * * Decreases the reference count of the asynchronous @queue by 1. * @@ -326,7 +276,7 @@ g_async_queue_push_unlocked (GAsyncQueue *queue, * g_async_queue_push_sorted: * @queue: a #GAsyncQueue * @data: (not nullable): the @data to push into the @queue - * @func: the #GCompareDataFunc is used to sort @queue + * @func: (scope call): the #GCompareDataFunc is used to sort @queue * @user_data: user data passed to @func. * * Inserts @data into @queue using @func to determine the new @@ -367,7 +317,7 @@ g_async_queue_invert_compare (gpointer v1, * g_async_queue_push_sorted_unlocked: * @queue: a #GAsyncQueue * @data: the data to push into the @queue - * @func: the #GCompareDataFunc is used to sort @queue + * @func: (scope call): the #GCompareDataFunc is used to sort @queue * @user_data: user data passed to @func. * * Inserts @data into @queue using @func to determine the new @@ -722,7 +672,7 @@ g_async_queue_length_unlocked (GAsyncQueue *queue) /** * g_async_queue_sort: * @queue: a #GAsyncQueue - * @func: the #GCompareDataFunc is used to sort @queue + * @func: (scope call): the #GCompareDataFunc is used to sort @queue * @user_data: user data passed to @func * * Sorts @queue using @func. @@ -766,7 +716,7 @@ g_async_queue_sort (GAsyncQueue *queue, /** * g_async_queue_sort_unlocked: * @queue: a #GAsyncQueue - * @func: the #GCompareDataFunc is used to sort @queue + * @func: (scope call): the #GCompareDataFunc is used to sort @queue * @user_data: user data passed to @func * * Sorts @queue using @func. diff --git a/glib/gatomic.c b/glib/gatomic.c index 6c1ea76..2d3755e 100644 --- a/glib/gatomic.c +++ b/glib/gatomic.c @@ -24,49 +24,6 @@ #include "gatomic.h" /** - * SECTION:atomic_operations - * @title: Atomic Operations - * @short_description: basic atomic integer and pointer operations - * @see_also: #GMutex - * - * The following is a collection of compiler macros to provide atomic - * access to integer and pointer-sized values. - * - * The macros that have 'int' in the name will operate on pointers to - * #gint and #guint. The macros with 'pointer' in the name will operate - * on pointers to any pointer-sized value, including #gsize. There is - * no support for 64bit operations on platforms with 32bit pointers - * because it is not generally possible to perform these operations - * atomically. - * - * The get, set and exchange operations for integers and pointers - * nominally operate on #gint and #gpointer, respectively. Of the - * arithmetic operations, the 'add' operation operates on (and returns) - * signed integer values (#gint and #gssize) and the 'and', 'or', and - * 'xor' operations operate on (and return) unsigned integer values - * (#guint and #gsize). - * - * All of the operations act as a full compiler and (where appropriate) - * hardware memory barrier. Acquire and release or producer and - * consumer barrier semantics are not available through this API. - * - * It is very important that all accesses to a particular integer or - * pointer be performed using only this API and that different sizes of - * operation are not mixed or used on overlapping memory regions. Never - * read or assign directly from or to a value -- always use this API. - * - * For simple reference counting purposes you should use - * g_atomic_int_inc() and g_atomic_int_dec_and_test(). Other uses that - * fall outside of simple reference counting patterns are prone to - * subtle bugs and occasionally undefined behaviour. It is also worth - * noting that since all of these operations require global - * synchronisation of the entire machine, they can be quite slow. In - * the case of performing multiple atomic operations it can often be - * faster to simply acquire a mutex lock around the critical area, - * perform the operations normally and then release the lock. - **/ - -/** * G_ATOMIC_LOCK_FREE: * * This macro is defined if the atomic operations of GLib are @@ -538,11 +495,15 @@ gpointer * While @atomic has a `volatile` qualifier, this is a historical artifact and * the pointer passed to it should not be `volatile`. * + * In GLib 2.80, the return type was changed from #gssize to #gintptr to add + * support for platforms with 128-bit pointers. This should not affect existing + * code. + * * Returns: the value of @atomic before the add, signed * * Since: 2.30 **/ -gssize +gintptr (g_atomic_pointer_add) (volatile void *atomic, gssize val) { @@ -565,11 +526,15 @@ gssize * While @atomic has a `volatile` qualifier, this is a historical artifact and * the pointer passed to it should not be `volatile`. * + * In GLib 2.80, the return type was changed from #gsize to #guintptr to add + * support for platforms with 128-bit pointers. This should not affect existing + * code. + * * Returns: the value of @atomic before the operation, unsigned * * Since: 2.30 **/ -gsize +guintptr (g_atomic_pointer_and) (volatile void *atomic, gsize val) { @@ -592,11 +557,15 @@ gsize * While @atomic has a `volatile` qualifier, this is a historical artifact and * the pointer passed to it should not be `volatile`. * + * In GLib 2.80, the return type was changed from #gsize to #guintptr to add + * support for platforms with 128-bit pointers. This should not affect existing + * code. + * * Returns: the value of @atomic before the operation, unsigned * * Since: 2.30 **/ -gsize +guintptr (g_atomic_pointer_or) (volatile void *atomic, gsize val) { @@ -619,11 +588,15 @@ gsize * While @atomic has a `volatile` qualifier, this is a historical artifact and * the pointer passed to it should not be `volatile`. * + * In GLib 2.80, the return type was changed from #gsize to #guintptr to add + * support for platforms with 128-bit pointers. This should not affect existing + * code. + * * Returns: the value of @atomic before the operation, unsigned * * Since: 2.30 **/ -gsize +guintptr (g_atomic_pointer_xor) (volatile void *atomic, gsize val) { @@ -820,7 +793,7 @@ gpointer return InterlockedExchangePointer (atomic, newval); } -gssize +gintptr (g_atomic_pointer_add) (volatile void *atomic, gssize val) { @@ -831,7 +804,7 @@ gssize #endif } -gsize +guintptr (g_atomic_pointer_and) (volatile void *atomic, gsize val) { @@ -842,7 +815,7 @@ gsize #endif } -gsize +guintptr (g_atomic_pointer_or) (volatile void *atomic, gsize val) { @@ -853,7 +826,7 @@ gsize #endif } -gsize +guintptr (g_atomic_pointer_xor) (volatile void *atomic, gsize val) { @@ -1112,12 +1085,12 @@ gpointer return oldval; } -gssize +gintptr (g_atomic_pointer_add) (volatile void *atomic, gssize val) { - gssize *ptr = atomic; - gssize oldval; + gintptr *ptr = atomic; + gintptr oldval; pthread_mutex_lock (&g_atomic_lock); oldval = *ptr; @@ -1127,12 +1100,12 @@ gssize return oldval; } -gsize +guintptr (g_atomic_pointer_and) (volatile void *atomic, gsize val) { - gsize *ptr = atomic; - gsize oldval; + guintptr *ptr = atomic; + guintptr oldval; pthread_mutex_lock (&g_atomic_lock); oldval = *ptr; @@ -1142,12 +1115,12 @@ gsize return oldval; } -gsize +guintptr (g_atomic_pointer_or) (volatile void *atomic, gsize val) { - gsize *ptr = atomic; - gsize oldval; + guintptr *ptr = atomic; + guintptr oldval; pthread_mutex_lock (&g_atomic_lock); oldval = *ptr; @@ -1157,12 +1130,12 @@ gsize return oldval; } -gsize +guintptr (g_atomic_pointer_xor) (volatile void *atomic, gsize val) { - gsize *ptr = atomic; - gsize oldval; + guintptr *ptr = atomic; + guintptr oldval; pthread_mutex_lock (&g_atomic_lock); oldval = *ptr; diff --git a/glib/gatomic.h b/glib/gatomic.h index 148424d..9399888 100644 --- a/glib/gatomic.h +++ b/glib/gatomic.h @@ -83,16 +83,16 @@ GLIB_AVAILABLE_IN_2_74 gpointer g_atomic_pointer_exchange (void *atomic, gpointer newval); GLIB_AVAILABLE_IN_ALL -gssize g_atomic_pointer_add (volatile void *atomic, +gintptr g_atomic_pointer_add (volatile void *atomic, gssize val); GLIB_AVAILABLE_IN_2_30 -gsize g_atomic_pointer_and (volatile void *atomic, +guintptr g_atomic_pointer_and (volatile void *atomic, gsize val); GLIB_AVAILABLE_IN_2_30 -gsize g_atomic_pointer_or (volatile void *atomic, +guintptr g_atomic_pointer_or (volatile void *atomic, gsize val); GLIB_AVAILABLE_IN_ALL -gsize g_atomic_pointer_xor (volatile void *atomic, +guintptr g_atomic_pointer_xor (volatile void *atomic, gsize val); GLIB_DEPRECATED_IN_2_30_FOR(g_atomic_int_add) @@ -280,34 +280,34 @@ G_END_DECLS G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gssize) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \ + (gintptr) __atomic_fetch_add ((atomic), (val), __ATOMIC_SEQ_CST); \ })) #define g_atomic_pointer_and(atomic, val) \ (G_GNUC_EXTENSION ({ \ - gsize *gapa_atomic = (gsize *) (atomic); \ + guintptr *gapa_atomic = (guintptr *) (atomic); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ - G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \ + (guintptr) __atomic_fetch_and (gapa_atomic, (val), __ATOMIC_SEQ_CST); \ })) #define g_atomic_pointer_or(atomic, val) \ (G_GNUC_EXTENSION ({ \ - gsize *gapo_atomic = (gsize *) (atomic); \ + guintptr *gapo_atomic = (guintptr *) (atomic); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ - G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \ + (guintptr) __atomic_fetch_or (gapo_atomic, (val), __ATOMIC_SEQ_CST); \ })) #define g_atomic_pointer_xor(atomic, val) \ (G_GNUC_EXTENSION ({ \ - gsize *gapx_atomic = (gsize *) (atomic); \ + guintptr *gapx_atomic = (guintptr *) (atomic); \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ - G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gsize)); \ + G_STATIC_ASSERT (sizeof *(atomic) == sizeof (guintptr)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \ + (guintptr) __atomic_fetch_xor (gapx_atomic, (val), __ATOMIC_SEQ_CST); \ })) #else /* defined(__ATOMIC_SEQ_CST) */ @@ -374,7 +374,7 @@ G_END_DECLS (void) (0 ? (gpointer) *(atomic) : NULL); \ __sync_synchronize (); \ __asm__ __volatile__ ("" : : : "memory"); \ - *(atomic) = (glib_typeof (*(atomic))) (gsize) (newval); \ + *(atomic) = (glib_typeof (*(atomic))) (guintptr) (newval); \ })) #else /* if !(defined(glib_typeof) */ #define g_atomic_pointer_set(atomic, newval) \ @@ -383,7 +383,7 @@ G_END_DECLS (void) (0 ? (gpointer) *(atomic) : NULL); \ __sync_synchronize (); \ __asm__ __volatile__ ("" : : : "memory"); \ - *(atomic) = (gpointer) (gsize) (newval); \ + *(atomic) = (gpointer) (guintptr) (newval); \ })) #endif /* if defined(glib_typeof) */ @@ -498,28 +498,28 @@ G_END_DECLS G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gssize) __sync_fetch_and_add ((atomic), (val)); \ + (gintptr) __sync_fetch_and_add ((atomic), (val)); \ })) #define g_atomic_pointer_and(atomic, val) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __sync_fetch_and_and ((atomic), (val)); \ + (guintptr) __sync_fetch_and_and ((atomic), (val)); \ })) #define g_atomic_pointer_or(atomic, val) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __sync_fetch_and_or ((atomic), (val)); \ + (guintptr) __sync_fetch_and_or ((atomic), (val)); \ })) #define g_atomic_pointer_xor(atomic, val) \ (G_GNUC_EXTENSION ({ \ G_STATIC_ASSERT (sizeof *(atomic) == sizeof (gpointer)); \ (void) (0 ? (gpointer) *(atomic) : NULL); \ (void) (0 ? (val) ^ (val) : 1); \ - (gsize) __sync_fetch_and_xor ((atomic), (val)); \ + (guintptr) __sync_fetch_and_xor ((atomic), (val)); \ })) #endif /* !defined(__ATOMIC_SEQ_CST) */ diff --git a/glib/gbase64.c b/glib/gbase64.c index 3c427f8..043593b 100644 --- a/glib/gbase64.c +++ b/glib/gbase64.c @@ -31,30 +31,6 @@ #include "gtestutils.h" #include "glibintl.h" - -/** - * SECTION:base64 - * @title: Base64 Encoding - * @short_description: encodes and decodes data in Base64 format - * - * Base64 is an encoding that allows a sequence of arbitrary bytes to be - * encoded as a sequence of printable ASCII characters. For the definition - * of Base64, see - * [RFC 1421](http://www.ietf.org/rfc/rfc1421.txt) - * or - * [RFC 2045](http://www.ietf.org/rfc/rfc2045.txt). - * Base64 is most commonly used as a MIME transfer encoding - * for email. - * - * GLib supports incremental encoding using g_base64_encode_step() and - * g_base64_encode_close(). Incremental decoding can be done with - * g_base64_decode_step(). To encode or decode data in one go, use - * g_base64_encode() or g_base64_decode(). To avoid memory allocation when - * decoding, you can use g_base64_decode_inplace(). - * - * Support for Base64 encoding has been added in GLib 2.12. - */ - static const char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; diff --git a/glib/gbitlock.c b/glib/gbitlock.c index 9c34de8..eeeaabc 100644 --- a/glib/gbitlock.c +++ b/glib/gbitlock.c @@ -424,7 +424,7 @@ void contended: { - gsize *pointer_address = address_nonvolatile; + gpointer *pointer_address = address_nonvolatile; gsize mask = 1u << lock_bit; gsize v; @@ -440,9 +440,9 @@ void } goto retry; #else - gsize *pointer_address = address_nonvolatile; + gpointer *pointer_address = address_nonvolatile; gsize mask = 1u << lock_bit; - gsize v; + guintptr v; retry: v = g_atomic_pointer_or (pointer_address, mask); @@ -499,15 +499,15 @@ gboolean return result; #else void *address_nonvolatile = (void *) address; - gsize *pointer_address = address_nonvolatile; + gpointer *pointer_address = address_nonvolatile; gsize mask = 1u << lock_bit; - gsize v; + guintptr v; g_return_val_if_fail (lock_bit < 32, FALSE); v = g_atomic_pointer_or (pointer_address, mask); - return ~v & mask; + return (~(gsize) v & mask) != 0; #endif } } @@ -543,7 +543,7 @@ void : "r" (address), "r" ((gsize) lock_bit) : "cc", "memory"); #else - gsize *pointer_address = address_nonvolatile; + gpointer *pointer_address = address_nonvolatile; gsize mask = 1u << lock_bit; g_atomic_pointer_and (pointer_address, ~mask); diff --git a/glib/gbookmarkfile.c b/glib/gbookmarkfile.c index 80e835b..043d0fa 100644 --- a/glib/gbookmarkfile.c +++ b/glib/gbookmarkfile.c @@ -52,51 +52,6 @@ #include "gutils.h" -/** - * SECTION:gbookmarkfile - * @title: Bookmark file parser - * @short_description: parses files containing bookmarks - * - * GBookmarkFile lets you parse, edit or create files containing bookmarks - * to URI, along with some meta-data about the resource pointed by the URI - * like its MIME type, the application that is registering the bookmark and - * the icon that should be used to represent the bookmark. The data is stored - * using the - * [Desktop Bookmark Specification](http://www.gnome.org/~ebassi/bookmark-spec). - * - * The syntax of the bookmark files is described in detail inside the - * Desktop Bookmark Specification, here is a quick summary: bookmark - * files use a sub-class of the XML Bookmark Exchange Language - * specification, consisting of valid UTF-8 encoded XML, under the - * root element; each bookmark is stored inside a - * element, using its URI: no relative paths can - * be used inside a bookmark file. The bookmark may have a user defined - * title and description, to be used instead of the URI. Under the - * element, with its owner attribute set to - * `http://freedesktop.org`, is stored the meta-data about a resource - * pointed by its URI. The meta-data consists of the resource's MIME - * type; the applications that have registered a bookmark; the groups - * to which a bookmark belongs to; a visibility flag, used to set the - * bookmark as "private" to the applications and groups that has it - * registered; the URI and MIME type of an icon, to be used when - * displaying the bookmark inside a GUI. - * - * Here is an example of a bookmark file: - * [bookmarks.xbel](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/bookmarks.xbel) - * - * A bookmark file might contain more than one bookmark; each bookmark - * is accessed through its URI. - * - * The important caveat of bookmark files is that when you add a new - * bookmark you must also add the application that is registering it, using - * g_bookmark_file_add_application() or g_bookmark_file_set_application_info(). - * If a bookmark has no applications then it won't be dumped when creating - * the on disk representation, using g_bookmark_file_to_data() or - * g_bookmark_file_to_file(). - * - * The #GBookmarkFile parser was added in GLib 2.12. - */ - /* XBEL 1.0 standard entities */ #define XBEL_VERSION "1.0" #define XBEL_DTD_NICK "xbel" diff --git a/glib/gbookmarkfile.h b/glib/gbookmarkfile.h index f753420..dbf45a0 100644 --- a/glib/gbookmarkfile.h +++ b/glib/gbookmarkfile.h @@ -75,7 +75,45 @@ GQuark g_bookmark_file_error_quark (void); /** * GBookmarkFile: * - * An opaque data structure representing a set of bookmarks. + * `GBookmarkFile` lets you parse, edit or create files containing bookmarks. + * + * Bookmarks refer to a URI, along with some meta-data about the resource + * pointed by the URI like its MIME type, the application that is registering + * the bookmark and the icon that should be used to represent the bookmark. + * The data is stored using the + * [Desktop Bookmark Specification](http://www.gnome.org/~ebassi/bookmark-spec). + * + * The syntax of the bookmark files is described in detail inside the + * Desktop Bookmark Specification, here is a quick summary: bookmark + * files use a sub-class of the XML Bookmark Exchange Language + * specification, consisting of valid UTF-8 encoded XML, under the + * `` root element; each bookmark is stored inside a + * `` element, using its URI: no relative paths can + * be used inside a bookmark file. The bookmark may have a user defined + * title and description, to be used instead of the URI. Under the + * `` element, with its owner attribute set to + * `http://freedesktop.org`, is stored the meta-data about a resource + * pointed by its URI. The meta-data consists of the resource's MIME + * type; the applications that have registered a bookmark; the groups + * to which a bookmark belongs to; a visibility flag, used to set the + * bookmark as "private" to the applications and groups that has it + * registered; the URI and MIME type of an icon, to be used when + * displaying the bookmark inside a GUI. + * + * Here is an example of a bookmark file: + * [bookmarks.xbel](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/bookmarks.xbel) + * + * A bookmark file might contain more than one bookmark; each bookmark + * is accessed through its URI. + * + * The important caveat of bookmark files is that when you add a new + * bookmark you must also add the application that is registering it, using + * [method@GLib.BookmarkFile.add_application] or [method@GLib.BookmarkFile.set_application_info]. + * If a bookmark has no applications then it won't be dumped when creating + * the on disk representation, using [method@GLib.BookmarkFile.to_data] or + * [method@GLib.BookmarkFile.to_file]. + * + * Since: 2.12 */ typedef struct _GBookmarkFile GBookmarkFile; diff --git a/glib/gcharset.c b/glib/gcharset.c index 82cd0a7..040b499 100644 --- a/glib/gcharset.c +++ b/glib/gcharset.c @@ -500,11 +500,11 @@ unalias_lang (char *lang) char *p; int i; - if (g_once_init_enter (&alias_table)) + if (g_once_init_enter_pointer (&alias_table)) { GHashTable *table = g_hash_table_new (g_str_hash, g_str_equal); read_aliases ("/usr/share/locale/locale.alias", table); - g_once_init_leave (&alias_table, table); + g_once_init_leave_pointer (&alias_table, table); } i = 0; diff --git a/glib/gchecksum.c b/glib/gchecksum.c index fea7803..28de99d 100644 --- a/glib/gchecksum.c +++ b/glib/gchecksum.c @@ -33,25 +33,26 @@ /** - * SECTION:checksum - * @title: Data Checksums - * @short_description: computes the checksum for data + * GChecksum: * - * GLib provides a generic API for computing checksums (or "digests") + * GLib provides a generic API for computing checksums (or ‘digests’) * for a sequence of arbitrary bytes, using various hashing algorithms * like MD5, SHA-1 and SHA-256. Checksums are commonly used in various * environments and specifications. * - * GLib supports incremental checksums using the GChecksum data - * structure, by calling g_checksum_update() as long as there's data - * available and then using g_checksum_get_string() or - * g_checksum_get_digest() to compute the checksum and return it either - * as a string in hexadecimal form, or as a raw sequence of bytes. To - * compute the checksum for binary blobs and NUL-terminated strings in - * one go, use the convenience functions g_compute_checksum_for_data() - * and g_compute_checksum_for_string(), respectively. + * To create a new `GChecksum`, use [ctor@GLib.Checksum.new]. To free + * a `GChecksum`, use [method@GLib.Checksum.free]. * - * Support for checksums has been added in GLib 2.16 + * GLib supports incremental checksums using the `GChecksum` data + * structure, by calling [method@GLib.Checksum.update] as long as there’s data + * available and then using [method@GLib.Checksum.get_string] or + * [method@GLib.Checksum.get_digest] to compute the checksum and return it + * either as a string in hexadecimal form, or as a raw sequence of bytes. To + * compute the checksum for binary blobs and nul-terminated strings in + * one go, use the convenience functions [func@GLib.compute_checksum_for_data] + * and [func@GLib.compute_checksum_for_string], respectively. + * + * Since: 2.16 **/ #define IS_VALID_TYPE(type) ((type) >= G_CHECKSUM_MD5 && (type) <= G_CHECKSUM_SHA384) diff --git a/glib/gchecksum.h b/glib/gchecksum.h index e5c54e7..3dd84fd 100644 --- a/glib/gchecksum.h +++ b/glib/gchecksum.h @@ -54,16 +54,6 @@ typedef enum { G_CHECKSUM_SHA384 } GChecksumType; -/** - * GChecksum: - * - * An opaque structure representing a checksumming operation. - * - * To create a new GChecksum, use g_checksum_new(). To free - * a GChecksum, use g_checksum_free(). - * - * Since: 2.16 - */ typedef struct _GChecksum GChecksum; GLIB_AVAILABLE_IN_ALL diff --git a/glib/gconstructor.h b/glib/gconstructor.h index 9d2554c..ce42492 100644 --- a/glib/gconstructor.h +++ b/glib/gconstructor.h @@ -54,8 +54,7 @@ #define G_DEFINE_CONSTRUCTOR(_func) static void __attribute__((constructor)) _func (void); #define G_DEFINE_DESTRUCTOR(_func) static void __attribute__((destructor)) _func (void); -#elif defined (_MSC_VER) && (_MSC_VER >= 1500) -/* Visual studio 2008 and later has _Pragma */ +#elif defined (_MSC_VER) /* * Only try to include gslist.h if not already included via glib.h, @@ -110,28 +109,6 @@ __pragma(section(".CRT$XCU",read)) \ __declspec(allocate(".CRT$XCU")) int (* _array ## _func)(void) = _func ## _constructor; -#elif defined (_MSC_VER) - -#define G_HAS_CONSTRUCTORS 1 - -/* Pre Visual studio 2008 must use #pragma section */ -#define G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA 1 -#define G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA 1 - -#define G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(_func) \ - section(".CRT$XCU",read) -#define G_DEFINE_CONSTRUCTOR(_func) \ - static void _func(void); \ - static int _func ## _wrapper(void) { _func(); return 0; } \ - __declspec(allocate(".CRT$XCU")) static int (*p)(void) = _func ## _wrapper; - -#define G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(_func) \ - section(".CRT$XCU",read) -#define G_DEFINE_DESTRUCTOR(_func) \ - static void _func(void); \ - static int _func ## _constructor(void) { atexit (_func); return 0; } \ - __declspec(allocate(".CRT$XCU")) static int (* _array ## _func)(void) = _func ## _constructor; - #elif defined(__SUNPRO_C) /* This is not tested, but i believe it should work, based on: diff --git a/glib/gconstructorprivate.h b/glib/gconstructorprivate.h new file mode 100644 index 0000000..1c8e64c --- /dev/null +++ b/glib/gconstructorprivate.h @@ -0,0 +1,69 @@ +/* + * Copyright © 2023 Luca Bacci + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + */ + +#include "gconstructor.h" + +#ifdef _WIN32 +#include +#endif + +#ifdef _WIN32 + +#ifdef __cplusplus +/* const defaults to static (internal visibility) in C++, + * but we want extern instead */ +#define G_EXTERN_CONST extern const +#else +/* Using extern const in C is perfectly valid, but triggers + * a warning in GCC and CLANG, therefore we avoid it */ +#define G_EXTERN_CONST const +#endif + +#ifdef _MSC_VER + +#define G_HAS_TLS_CALLBACKS 1 + +#define G_DEFINE_TLS_CALLBACK(func) \ +__pragma (section (".CRT$XLCE", long, read)) \ + \ +static void NTAPI func (PVOID, DWORD, PVOID); \ + \ +G_BEGIN_DECLS \ +__declspec (allocate (".CRT$XLCE")) \ +G_EXTERN_CONST PIMAGE_TLS_CALLBACK _ptr_##func = func; \ +G_END_DECLS \ + \ +__pragma (comment (linker, "/INCLUDE:" G_MSVC_SYMBOL_PREFIX "_tls_used")) \ +__pragma (comment (linker, "/INCLUDE:" G_MSVC_SYMBOL_PREFIX "_ptr_" #func)) + +#else + +#define G_HAS_TLS_CALLBACKS 1 + +#define G_DEFINE_TLS_CALLBACK(func) \ +static void NTAPI func (PVOID, DWORD, PVOID); \ + \ +G_BEGIN_DECLS \ +__attribute__ ((section (".CRT$XLCE"))) \ +G_EXTERN_CONST PIMAGE_TLS_CALLBACK _ptr_##func = func; \ +G_END_DECLS + +#endif /* _MSC_VER */ + +#endif /* _WIN32 */ diff --git a/glib/gconvert.c b/glib/gconvert.c index 69bcc2f..4eaabc2 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -56,105 +56,6 @@ #include "glibintl.h" -/** - * SECTION:conversions - * @title: Character Set Conversion - * @short_description: convert strings between different character sets - * - * The g_convert() family of function wraps the functionality of iconv(). - * In addition to pure character set conversions, GLib has functions to - * deal with the extra complications of encodings for file names. - * - * ## File Name Encodings - * - * Historically, UNIX has not had a defined encoding for file names: - * a file name is valid as long as it does not have path separators - * in it ("/"). However, displaying file names may require conversion: - * from the character set in which they were created, to the character - * set in which the application operates. Consider the Spanish file name - * "Presentación.sxi". If the application which created it uses - * ISO-8859-1 for its encoding, - * |[ - * Character: P r e s e n t a c i ó n . s x i - * Hex code: 50 72 65 73 65 6e 74 61 63 69 f3 6e 2e 73 78 69 - * ]| - * However, if the application use UTF-8, the actual file name on - * disk would look like this: - * |[ - * Character: P r e s e n t a c i ó n . s x i - * Hex code: 50 72 65 73 65 6e 74 61 63 69 c3 b3 6e 2e 73 78 69 - * ]| - * GLib uses UTF-8 for its strings, and GUI toolkits like GTK that use - * GLib do the same thing. If you get a file name from the file system, - * for example, from readdir() or from g_dir_read_name(), and you wish - * to display the file name to the user, you will need to convert it - * into UTF-8. The opposite case is when the user types the name of a - * file they wish to save: the toolkit will give you that string in - * UTF-8 encoding, and you will need to convert it to the character - * set used for file names before you can create the file with open() - * or fopen(). - * - * By default, GLib assumes that file names on disk are in UTF-8 - * encoding. This is a valid assumption for file systems which - * were created relatively recently: most applications use UTF-8 - * encoding for their strings, and that is also what they use for - * the file names they create. However, older file systems may - * still contain file names created in "older" encodings, such as - * ISO-8859-1. In this case, for compatibility reasons, you may want - * to instruct GLib to use that particular encoding for file names - * rather than UTF-8. You can do this by specifying the encoding for - * file names in the [`G_FILENAME_ENCODING`][G_FILENAME_ENCODING] - * environment variable. For example, if your installation uses - * ISO-8859-1 for file names, you can put this in your `~/.profile`: - * |[ - * export G_FILENAME_ENCODING=ISO-8859-1 - * ]| - * GLib provides the functions g_filename_to_utf8() and - * g_filename_from_utf8() to perform the necessary conversions. - * These functions convert file names from the encoding specified - * in `G_FILENAME_ENCODING` to UTF-8 and vice-versa. This - * [diagram][file-name-encodings-diagram] illustrates how - * these functions are used to convert between UTF-8 and the - * encoding for file names in the file system. - * - * ## Conversion between file name encodings # {#file-name-encodings-diagram) - * - * ![](file-name-encodings.png) - * - * ## Checklist for Application Writers - * - * This section is a practical summary of the detailed - * things to do to make sure your applications process file - * name encodings correctly. - * - * 1. If you get a file name from the file system from a function - * such as readdir() or gtk_file_chooser_get_filename(), you do - * not need to do any conversion to pass that file name to - * functions like open(), rename(), or fopen() -- those are "raw" - * file names which the file system understands. - * - * 2. If you need to display a file name, convert it to UTF-8 first - * by using g_filename_to_utf8(). If conversion fails, display a - * string like "Unknown file name". Do not convert this string back - * into the encoding used for file names if you wish to pass it to - * the file system; use the original file name instead. - * - * For example, the document window of a word processor could display - * "Unknown file name" in its title bar but still let the user save - * the file, as it would keep the raw file name internally. This - * can happen if the user has not set the `G_FILENAME_ENCODING` - * environment variable even though they have files whose names are - * not encoded in UTF-8. - * - * 3. If your user interface lets the user type a file name for saving - * or renaming, convert it to the encoding used for file names in - * the file system by using g_filename_from_utf8(). Pass the converted - * file name to functions like fopen(). If conversion fails, ask the - * user to enter a different file name. This can happen if the user - * types Japanese characters when `G_FILENAME_ENCODING` is set to - * `ISO-8859-1`, for example. - */ - /* We try to terminate strings in unknown charsets with this many zero bytes * to ensure that multibyte strings really are nul-terminated when we return * them from g_convert() and friends. diff --git a/glib/gdataset.c b/glib/gdataset.c index 452c487..2d6735a 100644 --- a/glib/gdataset.c +++ b/glib/gdataset.c @@ -49,84 +49,11 @@ #include "galloca.h" /** - * SECTION:datasets - * @title: Datasets - * @short_description: associate groups of data elements with - * particular memory locations - * - * Datasets associate groups of data elements with particular memory - * locations. These are useful if you need to associate data with a - * structure returned from an external library. Since you cannot modify - * the structure, you use its location in memory as the key into a - * dataset, where you can associate any number of data elements with it. - * - * There are two forms of most of the dataset functions. The first form - * uses strings to identify the data elements associated with a - * location. The second form uses #GQuark identifiers, which are - * created with a call to g_quark_from_string() or - * g_quark_from_static_string(). The second form is quicker, since it - * does not require looking up the string in the hash table of #GQuark - * identifiers. - * - * There is no function to create a dataset. It is automatically - * created as soon as you add elements to it. - * - * To add data elements to a dataset use g_dataset_id_set_data(), - * g_dataset_id_set_data_full(), g_dataset_set_data() and - * g_dataset_set_data_full(). - * - * To get data elements from a dataset use g_dataset_id_get_data() and - * g_dataset_get_data(). - * - * To iterate over all data elements in a dataset use - * g_dataset_foreach() (not thread-safe). - * - * To remove data elements from a dataset use - * g_dataset_id_remove_data() and g_dataset_remove_data(). - * - * To destroy a dataset, use g_dataset_destroy(). - **/ - -/** - * SECTION:datalist - * @title: Keyed Data Lists - * @short_description: lists of data elements which are accessible by a - * string or GQuark identifier - * - * Keyed data lists provide lists of arbitrary data elements which can - * be accessed either with a string or with a #GQuark corresponding to - * the string. - * - * The #GQuark methods are quicker, since the strings have to be - * converted to #GQuarks anyway. - * - * Data lists are used for associating arbitrary data with #GObjects, - * using g_object_set_data() and related functions. - * - * To create a datalist, use g_datalist_init(). - * - * To add data elements to a datalist use g_datalist_id_set_data(), - * g_datalist_id_set_data_full(), g_datalist_set_data() and - * g_datalist_set_data_full(). - * - * To get data elements from a datalist use g_datalist_id_get_data() - * and g_datalist_get_data(). - * - * To iterate over all data elements in a datalist use - * g_datalist_foreach() (not thread-safe). - * - * To remove data elements from a datalist use - * g_datalist_id_remove_data() and g_datalist_remove_data(). - * - * To remove all data elements from a datalist, use g_datalist_clear(). - **/ - -/** * GData: * * An opaque data structure that represents a keyed data list. * - * See also: [Keyed data lists][glib-Keyed-Data-Lists]. + * See also: [Keyed data lists](datalist-and-dataset.html). **/ /** @@ -142,13 +69,13 @@ /* datalist pointer accesses have to be carried out atomically */ #define G_DATALIST_GET_POINTER(datalist) \ - ((GData*) ((gsize) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK_INTERNAL)) + ((GData*) ((guintptr) g_atomic_pointer_get (datalist) & ~(gsize) G_DATALIST_FLAGS_MASK_INTERNAL)) #define G_DATALIST_SET_POINTER(datalist, pointer) G_STMT_START { \ gpointer _oldv = g_atomic_pointer_get (datalist); \ gpointer _newv; \ do { \ - _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK_INTERNAL) | (gsize) pointer); \ + _newv = (gpointer) (((gsize) _oldv & G_DATALIST_FLAGS_MASK_INTERNAL) | (guintptr) pointer); \ } while (!g_atomic_pointer_compare_and_exchange_full ((void**) datalist, _oldv, \ _newv, &_oldv)); \ } G_STMT_END diff --git a/glib/gdate.c b/glib/gdate.c index f60ec0c..c509bd3 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -60,21 +60,29 @@ #endif /** - * SECTION:date - * @title: Date and Time Functions - * @short_description: calendrical calculations and miscellaneous time stuff + * GDate: + * @julian_days: the Julian representation of the date + * @julian: this bit is set if @julian_days is valid + * @dmy: this is set if @day, @month and @year are valid + * @day: the day of the day-month-year representation of the date, + * as a number between 1 and 31 + * @month: the month of the day-month-year representation of the date, + * as a number between 1 and 12 + * @year: the year of the day-month-year representation of the date + * + * `GDate` is a struct for calendrical calculations. * - * The #GDate data structure represents a day between January 1, Year 1, + * The `GDate` data structure represents a day between January 1, Year 1, * and sometime a few thousand years in the future (right now it will go - * to the year 65535 or so, but g_date_set_parse() only parses up to the - * year 8000 or so - just count on "a few thousand"). #GDate is meant to + * to the year 65535 or so, but [method@GLib.Date.set_parse] only parses up to the + * year 8000 or so - just count on "a few thousand"). `GDate` is meant to * represent everyday dates, not astronomical dates or historical dates * or ISO timestamps or the like. It extrapolates the current Gregorian * calendar forward and backward in time; there is no attempt to change - * the calendar to match time periods or locations. #GDate does not store + * the calendar to match time periods or locations. `GDate` does not store * time information; it represents a day. * - * The #GDate implementation has several nice features; it is only a + * The `GDate` implementation has several nice features; it is only a * 64-bit struct, so storing large numbers of dates is very efficient. It * can keep both a Julian and day-month-year representation of the date, * since some calculations are much easier with one representation or the @@ -84,25 +92,23 @@ * technical sense; technically, Julian dates count from the start of the * Julian period, Jan 1, 4713 BC). * - * #GDate is simple to use. First you need a "blank" date; you can get a - * dynamically allocated date from g_date_new(), or you can declare an - * automatic variable or array and initialize it by - * calling g_date_clear(). A cleared date is safe; it's safe to call - * g_date_set_dmy() and the other mutator functions to initialize the - * value of a cleared date. However, a cleared date is initially - * invalid, meaning that it doesn't represent a day that exists. - * It is undefined to call any of the date calculation routines on an - * invalid date. If you obtain a date from a user or other - * unpredictable source, you should check its validity with the - * g_date_valid() predicate. g_date_valid() is also used to check for - * errors with g_date_set_parse() and other functions that can - * fail. Dates can be invalidated by calling g_date_clear() again. + * `GDate` is simple to use. First you need a "blank" date; you can get a + * dynamically allocated date from [ctor@GLib.Date.new], or you can declare an + * automatic variable or array and initialize it by calling [method@GLib.Date.clear]. + * A cleared date is safe; it's safe to call [method@GLib.Date.set_dmy] and the other + * mutator functions to initialize the value of a cleared date. However, a cleared date + * is initially invalid, meaning that it doesn't represent a day that exists. + * It is undefined to call any of the date calculation routines on an invalid date. + * If you obtain a date from a user or other unpredictable source, you should check + * its validity with the [method@GLib.Date.valid] predicate. [method@GLib.Date.valid] + * is also used to check for errors with [method@GLib.Date.set_parse] and other functions + * that can fail. Dates can be invalidated by calling [method@GLib.Date.clear] again. * - * It is very important to use the API to access the #GDate - * struct. Often only the day-month-year or only the Julian - * representation is valid. Sometimes neither is valid. Use the API. + * It is very important to use the API to access the `GDate` struct. Often only the + * day-month-year or only the Julian representation is valid. Sometimes neither is valid. + * Use the API. * - * GLib also features #GDateTime which represents a precise time. + * GLib also features `GDateTime` which represents a precise time. */ /** @@ -132,30 +138,6 @@ */ /** - * GDate: - * @julian_days: the Julian representation of the date - * @julian: this bit is set if @julian_days is valid - * @dmy: this is set if @day, @month and @year are valid - * @day: the day of the day-month-year representation of the date, - * as a number between 1 and 31 - * @month: the day of the day-month-year representation of the date, - * as a number between 1 and 12 - * @year: the day of the day-month-year representation of the date - * - * Represents a day between January 1, Year 1 and a few thousand years in - * the future. None of its members should be accessed directly. - * - * If the `GDate` is obtained from g_date_new(), it will be safe - * to mutate but invalid and thus not safe for calendrical computations. - * - * If it's declared on the stack, it will contain garbage so must be - * initialized with g_date_clear(). g_date_clear() makes the date invalid - * but safe. An invalid date doesn't represent a day, it's "empty." A date - * becomes valid after you set it to a Julian day or you set a day, month, - * and year. - */ - -/** * GTime: * * Simply a replacement for `time_t`. It has been deprecated diff --git a/glib/gdate.h b/glib/gdate.h index 5ef21cb..35a2e91 100644 --- a/glib/gdate.h +++ b/glib/gdate.h @@ -38,15 +38,6 @@ G_BEGIN_DECLS -/* GDate - * - * Date calculations (not time for now, to be resolved). These are a - * mutant combination of Steffen Beyer's DateCalc routines - * (http://www.perl.com/CPAN/authors/id/STBEY/) and Jon Trowbridge's - * date routines (written for in-house software). Written by Havoc - * Pennington - */ - typedef gint32 GTime GLIB_DEPRECATED_TYPE_IN_2_62_FOR(GDateTime); typedef guint16 GDateYear; typedef guint8 GDateDay; /* day of the month */ diff --git a/glib/gdatetime-private.c b/glib/gdatetime-private.c new file mode 100644 index 0000000..b392b62 --- /dev/null +++ b/glib/gdatetime-private.c @@ -0,0 +1,257 @@ +/* + * Copyright 2023 GNOME Foundation Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Authors: + * - Philip Withnall + */ + +#include "glib.h" +#include "gdatetime-private.h" + +/** + * _g_era_date_compare: + * @date1: first date + * @date2: second date + * + * Compare two #GEraDates for ordering, taking into account negative and + * positive infinity. + * + * Returns: strcmp()-style integer, `<0` indicates `date1 < date2`, `0` + * indicates `date1 == date2`, `>0` indicates `date1 > date2` + * Since: 2.80 + */ +int +_g_era_date_compare (const GEraDate *date1, + const GEraDate *date2) +{ + if (date1->type == G_ERA_DATE_SET && + date2->type == G_ERA_DATE_SET) + { + if (date1->year != date2->year) + return date1->year - date2->year; + if (date1->month != date2->month) + return date1->month - date2->month; + return date1->day - date2->day; + } + + if (date1->type == date2->type) + return 0; + + if (date1->type == G_ERA_DATE_MINUS_INFINITY || date2->type == G_ERA_DATE_PLUS_INFINITY) + return -1; + if (date1->type == G_ERA_DATE_PLUS_INFINITY || date2->type == G_ERA_DATE_MINUS_INFINITY) + return 1; + + g_assert_not_reached (); +} + +static gboolean +parse_era_date (const char *str, + const char *endptr, + GEraDate *out_date) +{ + const char *str_endptr = NULL; + int year_multiplier; + guint64 year, month, day; + + year_multiplier = (str[0] == '-') ? -1 : 1; + if (str[0] == '-' || str[0] == '+') + str++; + + year = g_ascii_strtoull (str, (gchar **) &str_endptr, 10); + g_assert (str_endptr <= endptr); + if (str_endptr == endptr || *str_endptr != '/' || year > G_MAXINT) + return FALSE; + str = str_endptr + 1; + + month = g_ascii_strtoull (str, (gchar **) &str_endptr, 10); + g_assert (str_endptr <= endptr); + if (str_endptr == endptr || *str_endptr != '/' || month < 1 || month > 12) + return FALSE; + str = str_endptr + 1; + + day = g_ascii_strtoull (str, (gchar **) &str_endptr, 10); + g_assert (str_endptr <= endptr); + if (str_endptr != endptr || day < 1 || day > 31) + return FALSE; + + /* Success */ + out_date->type = G_ERA_DATE_SET; + out_date->year = year_multiplier * year; + out_date->month = month; + out_date->day = day; + + return TRUE; +} + +/** + * _g_era_description_segment_ref: + * @segment: a #GEraDescriptionSegment + * + * Increase the ref count of @segment. + * + * Returns: (transfer full): @segment + * Since: 2.80 + */ +GEraDescriptionSegment * +_g_era_description_segment_ref (GEraDescriptionSegment *segment) +{ + g_atomic_ref_count_inc (&segment->ref_count); + return segment; +} + +/** + * _g_era_description_segment_unref: + * @segment: (transfer full): a #GEraDescriptionSegment to unref + * + * Decreases the ref count of @segment. + * + * Since: 2.80 + */ +void +_g_era_description_segment_unref (GEraDescriptionSegment *segment) +{ + if (g_atomic_ref_count_dec (&segment->ref_count)) + { + g_free (segment->era_format); + g_free (segment->era_name); + g_free (segment); + } +} + +/** + * _g_era_description_parse: + * @desc: an `ERA` description string from `nl_langinfo()` + * + * Parse an ERA description string. See [`nl_langinfo(3)`](man:nl_langinfo(3)). + * + * Example description string for th_TH.UTF-8: + * ``` + * +:1:-543/01/01:+*:พ.ศ.:%EC %Ey + * ``` + * + * @desc must be in UTF-8, so all conversion from the locale encoding must + * happen before this function is called. The resulting `era_name` and + * `era_format` in the returned segments will be in UTF-8. + * + * Returns: (transfer full) (nullable) (element-type GEraDescriptionSegment): + * array of one or more parsed era segments, or %NULL if parsing failed + * Since: 2.80 + */ +GPtrArray * +_g_era_description_parse (const char *desc) +{ + GPtrArray *segments = g_ptr_array_new_with_free_func ((GDestroyNotify) _g_era_description_segment_unref); + + for (const char *p = desc; *p != '\0';) + { + const char *next_colon, *endptr = NULL; + GEraDescriptionSegment *segment = NULL; + char direction; + guint64 offset; + GEraDate start_date, end_date; + char *era_name = NULL, *era_format = NULL; + + /* direction */ + direction = *p++; + if (direction != '+' && direction != '-') + goto error; + + if (*p++ != ':') + goto error; + + /* offset */ + next_colon = strchr (p, ':'); + if (next_colon == NULL) + goto error; + + offset = g_ascii_strtoull (p, (gchar **) &endptr, 10); + if (endptr != next_colon) + goto error; + p = next_colon + 1; + + /* start_date */ + next_colon = strchr (p, ':'); + if (next_colon == NULL) + goto error; + + if (!parse_era_date (p, next_colon, &start_date)) + goto error; + p = next_colon + 1; + + /* end_date */ + next_colon = strchr (p, ':'); + if (next_colon == NULL) + goto error; + + if (strncmp (p, "-*", 2) == 0) + end_date.type = G_ERA_DATE_MINUS_INFINITY; + else if (strncmp (p, "+*", 2) == 0) + end_date.type = G_ERA_DATE_PLUS_INFINITY; + else if (!parse_era_date (p, next_colon, &end_date)) + goto error; + p = next_colon + 1; + + /* era_name */ + next_colon = strchr (p, ':'); + if (next_colon == NULL) + goto error; + + if (next_colon - p == 0) + goto error; + era_name = g_strndup (p, next_colon - p); + p = next_colon + 1; + + /* era_format; either the final field in the segment (followed by a + * semicolon) or the description (followed by nul) */ + next_colon = strchr (p, ';'); + if (next_colon == NULL) + next_colon = p + strlen (p); + + if (next_colon - p == 0) + { + g_free (era_name); + goto error; + } + era_format = g_strndup (p, next_colon - p); + if (*next_colon == ';') + p = next_colon + 1; + else + p = next_colon; + + /* Successfully parsed that segment. */ + segment = g_new0 (GEraDescriptionSegment, 1); + g_atomic_ref_count_init (&segment->ref_count); + segment->offset = offset; + segment->start_date = start_date; + segment->end_date = end_date; + segment->direction_multiplier = + ((_g_era_date_compare (&segment->start_date, &segment->end_date) <= 0) ? 1 : -1) * + ((direction == '-') ? -1 : 1); + segment->era_name = g_steal_pointer (&era_name); + segment->era_format = g_steal_pointer (&era_format); + + g_ptr_array_add (segments, g_steal_pointer (&segment)); + } + + return g_steal_pointer (&segments); + +error: + g_ptr_array_unref (segments); + return NULL; +} diff --git a/glib/gdatetime-private.h b/glib/gdatetime-private.h new file mode 100644 index 0000000..1513141 --- /dev/null +++ b/glib/gdatetime-private.h @@ -0,0 +1,88 @@ +/* + * Copyright 2023 GNOME Foundation Inc. + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see . + * + * Authors: + * - Philip Withnall + */ + +#pragma once + +#include "glib.h" + +G_BEGIN_DECLS + +/** + * GEraDate: + * @type: the type of date + * @year: year of the date, in the Gregorian calendar + * @month: month of the date, in the Gregorian calendar + * @day: day of the date, in the Gregorian calendar + * + * A date from a #GEraDescriptionSegment. + * + * If @type is %G_ERA_DATE_SET, @year, @month and @day are valid. Otherwise, + * they are undefined. + * + * Since: 2.80 + */ +typedef struct { + enum { + G_ERA_DATE_SET, + G_ERA_DATE_PLUS_INFINITY, + G_ERA_DATE_MINUS_INFINITY, + } type; + int year; + int month; + int day; +} GEraDate; + +int _g_era_date_compare (const GEraDate *date1, + const GEraDate *date2); + +/** + * GEraDescriptionSegment: + * @ref_count: reference count + * @direction_multiplier: `-1` or `1` depending on the order of @start_date and + * @end_date + * @offset: offset of the first year in the era + * @start_date: start date (in the Gregorian calendar) of the era + * @end_date: end date (in the Gregorian calendar) of the era + * @era_name: (not nullable): name of the era + * @era_format: (not nullable): format string to use for `%EY` + * + * A segment of an `ERA` description string, describing a single era. See + * [`nl_langinfo(3)`](man:nl_langinfo(3)). + * + * Since: 2.80 + */ +typedef struct { + gatomicrefcount ref_count; + int direction_multiplier; + guint64 offset; + GEraDate start_date; /* inclusive */ + GEraDate end_date; /* inclusive */ + char *era_name; /* UTF-8 encoded */ + char *era_format; /* UTF-8 encoded */ +} GEraDescriptionSegment; + +GPtrArray *_g_era_description_parse (const char *desc); + +GEraDescriptionSegment *_g_era_description_segment_ref (GEraDescriptionSegment *segment); +void _g_era_description_segment_unref (GEraDescriptionSegment *segment); + +G_END_DECLS diff --git a/glib/gdatetime.c b/glib/gdatetime.c index 2640e3b..4b1811f 100644 --- a/glib/gdatetime.c +++ b/glib/gdatetime.c @@ -5,6 +5,7 @@ * Copyright (C) 2010 Emmanuele Bassi * Copyright © 2010 Codethink Limited * Copyright © 2018 Tomasz Miąsko + * Copyright 2023 GNOME Foundation Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later * @@ -26,6 +27,7 @@ * Emmanuele Bassi * Ryan Lortie * Robert Ancell + * Philip Withnall */ /* Algorithms within this file are based on the Calendar FAQ by @@ -54,6 +56,7 @@ #define _GNU_SOURCE 1 #endif +#include #include #include #include @@ -68,6 +71,7 @@ #include "gconvert.h" #include "gconvertprivate.h" #include "gdatetime.h" +#include "gdatetime-private.h" #include "gfileutils.h" #include "ghash.h" #include "glibintl.h" @@ -89,39 +93,6 @@ #endif #endif /* !G_OS_WIN32 */ -/** - * SECTION:date-time - * @title: GDateTime - * @short_description: a structure representing Date and Time - * @see_also: #GTimeZone - * - * #GDateTime is a structure that combines a Gregorian date and time - * into a single structure. It provides many conversion and methods to - * manipulate dates and times. Time precision is provided down to - * microseconds and the time can range (proleptically) from 0001-01-01 - * 00:00:00 to 9999-12-31 23:59:59.999999. #GDateTime follows POSIX - * time in the sense that it is oblivious to leap seconds. - * - * #GDateTime is an immutable object; once it has been created it cannot - * be modified further. All modifiers will create a new #GDateTime. - * Nearly all such functions can fail due to the date or time going out - * of range, in which case %NULL will be returned. - * - * #GDateTime is reference counted: the reference count is increased by calling - * g_date_time_ref() and decreased by calling g_date_time_unref(). When the - * reference count drops to 0, the resources allocated by the #GDateTime - * structure are released. - * - * Many parts of the API may produce non-obvious results. As an - * example, adding two months to January 31st will yield March 31st - * whereas adding one month and then one month again will yield either - * March 28th or March 29th. Also note that adding 24 hours is not - * always the same as adding one day (since days containing daylight - * savings time transitions are either 23 or 25 hours in length). - * - * #GDateTime is available since GLib 2.26. - */ - struct _GDateTime { /* Microsecond timekeeping within Day */ @@ -587,6 +558,28 @@ get_month_name_abbr_with_day (gint month) #endif /* HAVE_LANGINFO_ABALTMON */ +#ifdef HAVE_LANGINFO_ERA + +#define PREFERRED_ERA_DATE_TIME_FMT nl_langinfo (ERA_D_T_FMT) +#define PREFERRED_ERA_DATE_FMT nl_langinfo (ERA_D_FMT) +#define PREFERRED_ERA_TIME_FMT nl_langinfo (ERA_T_FMT) + +#define ERA_DESCRIPTION nl_langinfo (ERA) +#define ERA_DESCRIPTION_IS_LOCALE TRUE +#define ERA_DESCRIPTION_N_SEGMENTS (int) (gintptr) nl_langinfo (_NL_TIME_ERA_NUM_ENTRIES) + +#else /* if !HAVE_LANGINFO_ERA */ + +#define PREFERRED_ERA_DATE_TIME_FMT PREFERRED_DATE_TIME_FMT +#define PREFERRED_ERA_DATE_FMT PREFERRED_DATE_FMT +#define PREFERRED_ERA_TIME_FMT PREFERRED_TIME_FMT + +#define ERA_DESCRIPTION NULL +#define ERA_DESCRIPTION_IS_LOCALE FALSE +#define ERA_DESCRIPTION_N_SEGMENTS 0 + +#endif /* !HAVE_LANGINFO_ERA */ + /* Format AM/PM indicator if the locale does not have a localized version. */ static const gchar * get_fallback_ampm (gint hour) @@ -1040,15 +1033,41 @@ g_date_time_new_now_utc (void) GDateTime * g_date_time_new_from_unix_local (gint64 t) { - GDateTime *datetime; - GTimeZone *local; - if (t > G_MAXINT64 / USEC_PER_SECOND || t < G_MININT64 / USEC_PER_SECOND) return NULL; + return g_date_time_new_from_unix_local_usec (t * USEC_PER_SECOND); +} + +/** + * g_date_time_new_from_unix_local_usec: (constructor) + * @usecs: the Unix time in microseconds + * + * Creates a [struct@GLib.DateTime] corresponding to the given Unix time @t in the + * local time zone. + * + * Unix time is the number of microseconds that have elapsed since 1970-01-01 + * 00:00:00 UTC, regardless of the local time offset. + * + * This call can fail (returning `NULL`) if @t represents a time outside + * of the supported range of #GDateTime. + * + * You should release the return value by calling [method@GLib.DateTime.unref] + * when you are done with it. + * + * Returns: (transfer full) (nullable): a new [struct@GLib.DateTime], or `NULL` + * + * Since: 2.80 + **/ +GDateTime * +g_date_time_new_from_unix_local_usec (gint64 usecs) +{ + GDateTime *datetime; + GTimeZone *local; + local = g_time_zone_new_local (); - datetime = g_date_time_new_from_unix (local, t * USEC_PER_SECOND); + datetime = g_date_time_new_from_unix (local, usecs); g_time_zone_unref (local); return datetime; @@ -1076,15 +1095,40 @@ g_date_time_new_from_unix_local (gint64 t) GDateTime * g_date_time_new_from_unix_utc (gint64 t) { - GDateTime *datetime; - GTimeZone *utc; - if (t > G_MAXINT64 / USEC_PER_SECOND || t < G_MININT64 / USEC_PER_SECOND) return NULL; + return g_date_time_new_from_unix_utc_usec (t * USEC_PER_SECOND); +} + +/** + * g_date_time_new_from_unix_utc: (constructor) + * @usecs: the Unix time in microseconds + * + * Creates a [struct@GLib.DateTime] corresponding to the given Unix time @t in UTC. + * + * Unix time is the number of microseconds that have elapsed since 1970-01-01 + * 00:00:00 UTC. + * + * This call can fail (returning `NULL`) if @t represents a time outside + * of the supported range of #GDateTime. + * + * You should release the return value by calling [method@GLib.DateTime.unref] + * when you are done with it. + * + * Returns: (transfer full) (nullable): a new [struct@GLib.DateTime], or `NULL` + * + * Since: 2.80 + **/ +GDateTime * +g_date_time_new_from_unix_utc_usec (gint64 usecs) +{ + GDateTime *datetime; + GTimeZone *utc; + utc = g_time_zone_new_utc (); - datetime = g_date_time_new_from_unix (utc, t * USEC_PER_SECOND); + datetime = g_date_time_new_from_unix (utc, usecs); g_time_zone_unref (utc); return datetime; @@ -2574,6 +2618,27 @@ g_date_time_to_unix (GDateTime *datetime) } /** + * g_date_time_to_unix_usec: + * @datetime: a #GDateTime + * + * Gives the Unix time corresponding to @datetime, in microseconds. + * + * Unix time is the number of microseconds that have elapsed since 1970-01-01 + * 00:00:00 UTC, regardless of the time zone associated with @datetime. + * + * Returns: the Unix time corresponding to @datetime + * + * Since: 2.80 + **/ +gint64 +g_date_time_to_unix_usec (GDateTime *datetime) +{ + g_return_val_if_fail (datetime != NULL, 0); + + return INSTANT_TO_UNIX_USECS (g_date_time_to_instant (datetime)); +} + +/** * g_date_time_to_timeval: * @datetime: a #GDateTime * @tv: a #GTimeVal to modify @@ -2853,6 +2918,9 @@ format_z (GString *outstr, /* Initializes the array with UTF-8 encoded alternate digits suitable for use * in current locale. Returns NULL when current locale does not use alternate * digits or there was an error converting them to UTF-8. + * + * This needs external locking, so must only be called from within + * format_number(). */ static const gchar * const * initialize_alt_digits (void) @@ -2894,6 +2962,134 @@ initialize_alt_digits (void) } #endif /* HAVE_LANGINFO_OUTDIGIT */ +/* Look up the era which contains @datetime, in the ERA description from libc + * which corresponds to the currently set LC_TIME locale. The ERA is parsed and + * cached the first time this function is called (or when LC_TIME changes). + * See nl_langinfo(3). + * + * The return value is (transfer full). */ +static GEraDescriptionSegment * +date_time_lookup_era (GDateTime *datetime, + gboolean locale_is_utf8) +{ + static GMutex era_mutex; + static GPtrArray *static_era_description = NULL; /* (mutex era_mutex) (element-type GEraDescriptionSegment) */ + static const char *static_era_description_locale = NULL; /* (mutex era_mutex) */ + const char *current_lc_time = setlocale (LC_TIME, NULL); + GPtrArray *local_era_description; /* (element-type GEraDescriptionSegment) */ + GEraDate datetime_date; + + g_mutex_lock (&era_mutex); + + if (static_era_description_locale != current_lc_time) + { + const char *era_description_str; + size_t era_description_str_len; + char *tmp = NULL; + + era_description_str = ERA_DESCRIPTION; + if (era_description_str != NULL) + { + /* FIXME: glibc 2.37 seems to return the era segments nul-separated rather + * than semicolon-separated (which is what nl_langinfo(3) specifies). + * Fix that up before sending it to the parsing code. + * See https://sourceware.org/bugzilla/show_bug.cgi?id=31030*/ + { + /* Work out the length of the whole description string, regardless + * of whether it uses nuls or semicolons as separators. */ + int n_entries = ERA_DESCRIPTION_N_SEGMENTS; + const char *s = era_description_str; + + for (int i = 1; i < n_entries; i++) + { + const char *next_semicolon = strchr (s, ';'); + const char *next_nul = strchr (s, '\0'); + + if (next_semicolon != NULL && next_semicolon < next_nul) + s = next_semicolon + 1; + else + s = next_nul + 1; + } + + era_description_str_len = strlen (s) + (s - era_description_str); + + /* Replace all the nuls with semicolons. */ + era_description_str = tmp = g_memdup2 (era_description_str, era_description_str_len + 1); + s = era_description_str; + + for (int i = 1; i < n_entries; i++) + { + char *next_nul = strchr (s, '\0'); + + if ((size_t) (next_nul - era_description_str) >= era_description_str_len) + break; + + *next_nul = ';'; + s = next_nul + 1; + } + } + + /* Convert from the LC_TIME encoding to UTF-8 if needed. */ + if (!locale_is_utf8 && ERA_DESCRIPTION_IS_LOCALE) + { + char *tmp2 = NULL; + era_description_str = tmp2 = g_locale_to_utf8 (era_description_str, -1, NULL, NULL, NULL); + g_free (tmp); + tmp = g_steal_pointer (&tmp2); + } + + g_clear_pointer (&static_era_description, g_ptr_array_unref); + + if (era_description_str != NULL) + static_era_description = _g_era_description_parse (era_description_str); + if (static_era_description == NULL) + g_warning ("Could not parse ERA description: %s", era_description_str); + } + else + { + g_clear_pointer (&static_era_description, g_ptr_array_unref); + } + + g_free (tmp); + + static_era_description_locale = current_lc_time; + } + + if (static_era_description == NULL) + { + g_mutex_unlock (&era_mutex); + return NULL; + } + + local_era_description = g_ptr_array_ref (static_era_description); + g_mutex_unlock (&era_mutex); + + /* Search through the eras and see if one matches. */ + datetime_date.type = G_ERA_DATE_SET; + datetime_date.year = g_date_time_get_year (datetime); + datetime_date.month = g_date_time_get_month (datetime); + datetime_date.day = g_date_time_get_day_of_month (datetime); + + for (unsigned int i = 0; i < local_era_description->len; i++) + { + GEraDescriptionSegment *segment = g_ptr_array_index (local_era_description, i); + + if ((_g_era_date_compare (&segment->start_date, &datetime_date) <= 0 && + _g_era_date_compare (&datetime_date, &segment->end_date) <= 0) || + (_g_era_date_compare (&segment->end_date, &datetime_date) <= 0 && + _g_era_date_compare (&datetime_date, &segment->start_date) <= 0)) + { + /* @datetime is within this era segment. */ + g_ptr_array_unref (local_era_description); + return _g_era_description_segment_ref (segment); + } + } + + g_ptr_array_unref (local_era_description); + + return NULL; +} + static void format_number (GString *str, gboolean use_alt_digits, @@ -2907,6 +3103,9 @@ format_number (GString *str, const gchar * const *digits = ascii_digits; const gchar *tmp[10]; gint i = 0; +#ifdef HAVE_LANGINFO_OUTDIGIT + static GMutex alt_digits_mutex; +#endif g_return_if_fail (width <= 10); @@ -2914,16 +3113,22 @@ format_number (GString *str, if (use_alt_digits) { static const gchar * const *alt_digits = NULL; - static gsize initialised; + static char *alt_digits_locale = NULL; + const char *current_ctype_locale = setlocale (LC_CTYPE, NULL); - if G_UNLIKELY (g_once_init_enter (&initialised)) + /* Lock so we can initialise (or re-initialise, if the locale has changed) + * and hold access to the digits buffer until done formatting. */ + g_mutex_lock (&alt_digits_mutex); + + if (g_strcmp0 (alt_digits_locale, current_ctype_locale) != 0) { alt_digits = initialize_alt_digits (); if (alt_digits == NULL) alt_digits = ascii_digits; - g_once_init_leave (&initialised, TRUE); + g_free (alt_digits_locale); + alt_digits_locale = g_strdup (current_ctype_locale); } digits = alt_digits; @@ -2940,6 +3145,11 @@ format_number (GString *str, while (pad && i < width) tmp[i++] = *pad == '0' ? digits[0] : pad; +#ifdef HAVE_LANGINFO_OUTDIGIT + if (use_alt_digits) + g_mutex_unlock (&alt_digits_mutex); +#endif + /* should really be impossible */ g_assert (i <= 10); @@ -3013,13 +3223,17 @@ g_date_time_format_locale (GDateTime *datetime, static inline gboolean string_append (GString *string, const gchar *s, + gboolean do_strup, gboolean s_is_utf8) { gchar *utf8; gsize utf8_len; + char *tmp = NULL; if (s_is_utf8) { + if (do_strup) + s = tmp = g_utf8_strup (s, -1); g_string_append (string, s); } else @@ -3027,10 +3241,18 @@ string_append (GString *string, utf8 = _g_time_locale_to_utf8 (s, -1, NULL, &utf8_len, NULL); if (utf8 == NULL) return FALSE; + if (do_strup) + { + tmp = g_utf8_strup (utf8, utf8_len); + g_free (utf8); + utf8 = g_steal_pointer (&tmp); + } g_string_append_len (string, utf8, utf8_len); g_free (utf8); } + g_free (tmp); + return TRUE; } @@ -3047,11 +3269,15 @@ g_date_time_format_utf8 (GDateTime *datetime, guint colons; gunichar c; gboolean alt_digits = FALSE; + gboolean alt_era = FALSE; gboolean pad_set = FALSE; + gboolean mod_case = FALSE; gboolean name_is_utf8; const gchar *pad = ""; + const gchar *mod = ""; const gchar *name; const gchar *tz; + char *tmp = NULL; while (*utf8_format) { @@ -3070,7 +3296,9 @@ g_date_time_format_utf8 (GDateTime *datetime, colons = 0; alt_digits = FALSE; + alt_era = FALSE; pad_set = FALSE; + mod_case = FALSE; next_mod: c = g_utf8_get_char (utf8_format); @@ -3078,24 +3306,24 @@ g_date_time_format_utf8 (GDateTime *datetime, switch (c) { case 'a': - name = WEEKDAY_ABBR (datetime); + name = WEEKDAY_ABBR (datetime); if (g_strcmp0 (name, "") == 0) return FALSE; name_is_utf8 = locale_is_utf8 || !WEEKDAY_ABBR_IS_LOCALE; - if (!string_append (outstr, name, name_is_utf8)) + if (!string_append (outstr, name, mod_case, name_is_utf8)) return FALSE; break; case 'A': - name = WEEKDAY_FULL (datetime); + name = WEEKDAY_FULL (datetime); if (g_strcmp0 (name, "") == 0) return FALSE; name_is_utf8 = locale_is_utf8 || !WEEKDAY_FULL_IS_LOCALE; - if (!string_append (outstr, name, name_is_utf8)) + if (!string_append (outstr, name, mod_case, name_is_utf8)) return FALSE; break; @@ -3109,7 +3337,7 @@ g_date_time_format_utf8 (GDateTime *datetime, ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) || (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE)); - if (!string_append (outstr, name, name_is_utf8)) + if (!string_append (outstr, name, mod_case, name_is_utf8)) return FALSE; break; @@ -3123,20 +3351,37 @@ g_date_time_format_utf8 (GDateTime *datetime, ((alt_digits && !MONTH_FULL_STANDALONE_IS_LOCALE) || (!alt_digits && !MONTH_FULL_WITH_DAY_IS_LOCALE)); - if (!string_append (outstr, name, name_is_utf8)) + if (!string_append (outstr, name, mod_case, name_is_utf8)) return FALSE; break; case 'c': { - if (g_strcmp0 (PREFERRED_DATE_TIME_FMT, "") == 0) + const char *subformat = alt_era ? PREFERRED_ERA_DATE_TIME_FMT : PREFERRED_DATE_TIME_FMT; + + /* Fallback */ + if (alt_era && g_strcmp0 (subformat, "") == 0) + subformat = PREFERRED_DATE_TIME_FMT; + + if (g_strcmp0 (subformat, "") == 0) return FALSE; - if (!g_date_time_format_locale (datetime, PREFERRED_DATE_TIME_FMT, + if (!g_date_time_format_locale (datetime, subformat, outstr, locale_is_utf8)) return FALSE; } break; case 'C': + if (alt_era) + { + GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8); + if (era != NULL) + { + g_string_append (outstr, era->era_name); + _g_era_description_segment_unref (era); + break; + } + } + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, g_date_time_get_year (datetime) / 100); break; @@ -3176,7 +3421,7 @@ g_date_time_format_utf8 (GDateTime *datetime, ((alt_digits && !MONTH_ABBR_STANDALONE_IS_LOCALE) || (!alt_digits && !MONTH_ABBR_WITH_DAY_IS_LOCALE)); - if (!string_append (outstr, name, name_is_utf8)) + if (!string_append (outstr, name, mod_case, name_is_utf8)) return FALSE; break; @@ -3214,12 +3459,19 @@ g_date_time_format_utf8 (GDateTime *datetime, case 'O': alt_digits = TRUE; goto next_mod; + case 'E': + alt_era = TRUE; + goto next_mod; case 'p': - if (!format_ampm (datetime, outstr, locale_is_utf8, TRUE)) + if (!format_ampm (datetime, outstr, locale_is_utf8, + mod_case && g_strcmp0 (mod, "#") == 0 ? FALSE + : TRUE)) return FALSE; break; case 'P': - if (!format_ampm (datetime, outstr, locale_is_utf8, FALSE)) + if (!format_ampm (datetime, outstr, locale_is_utf8, + mod_case && g_strcmp0 (mod, "^") == 0 ? TRUE + : FALSE)) return FALSE; break; case 'r': @@ -3266,29 +3518,78 @@ g_date_time_format_utf8 (GDateTime *datetime, break; case 'x': { - if (g_strcmp0 (PREFERRED_DATE_FMT, "") == 0) + const char *subformat = alt_era ? PREFERRED_ERA_DATE_FMT : PREFERRED_DATE_FMT; + + /* Fallback */ + if (alt_era && g_strcmp0 (subformat, "") == 0) + subformat = PREFERRED_DATE_FMT; + + if (g_strcmp0 (subformat, "") == 0) return FALSE; - if (!g_date_time_format_locale (datetime, PREFERRED_DATE_FMT, + if (!g_date_time_format_locale (datetime, subformat, outstr, locale_is_utf8)) return FALSE; } break; case 'X': { - if (g_strcmp0 (PREFERRED_TIME_FMT, "") == 0) + const char *subformat = alt_era ? PREFERRED_ERA_TIME_FMT : PREFERRED_TIME_FMT; + + /* Fallback */ + if (alt_era && g_strcmp0 (subformat, "") == 0) + subformat = PREFERRED_TIME_FMT; + + if (g_strcmp0 (subformat, "") == 0) return FALSE; - if (!g_date_time_format_locale (datetime, PREFERRED_TIME_FMT, + if (!g_date_time_format_locale (datetime, subformat, outstr, locale_is_utf8)) return FALSE; } break; case 'y': - format_number (outstr, alt_digits, pad_set ? pad : "0", 2, - g_date_time_get_year (datetime) % 100); + if (alt_era) + { + GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8); + if (era != NULL) + { + int delta = g_date_time_get_year (datetime) - era->start_date.year; + + /* Both these years are in the Gregorian calendar (CE/BCE), + * which has no year zero. So take one from the delta if they + * cross across where year zero would be. */ + if ((g_date_time_get_year (datetime) < 0) != (era->start_date.year < 0)) + delta -= 1; + + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + era->offset + delta * era->direction_multiplier); + _g_era_description_segment_unref (era); + break; + } + } + + format_number (outstr, alt_digits, pad_set ? pad : "0", 2, + g_date_time_get_year (datetime) % 100); break; case 'Y': - format_number (outstr, alt_digits, 0, 0, - g_date_time_get_year (datetime)); + if (alt_era) + { + GEraDescriptionSegment *era = date_time_lookup_era (datetime, locale_is_utf8); + if (era != NULL) + { + if (!g_date_time_format_utf8 (datetime, era->era_format, + outstr, locale_is_utf8)) + { + _g_era_description_segment_unref (era); + return FALSE; + } + + _g_era_description_segment_unref (era); + break; + } + } + + format_number (outstr, alt_digits, 0, 0, + g_date_time_get_year (datetime)); break; case 'z': { @@ -3299,8 +3600,11 @@ g_date_time_format_utf8 (GDateTime *datetime, } break; case 'Z': - tz = g_date_time_get_timezone_abbreviation (datetime); + tz = g_date_time_get_timezone_abbreviation (datetime); + if (mod_case && g_strcmp0 (mod, "#") == 0) + tz = tmp = g_utf8_strdown (tz, -1); g_string_append (outstr, tz); + g_free (tmp); break; case '%': g_string_append_c (outstr, '%'); @@ -3323,9 +3627,17 @@ g_date_time_format_utf8 (GDateTime *datetime, return FALSE; colons++; goto next_mod; - default: - return FALSE; - } + case '^': + mod_case = TRUE; + mod = "^"; + goto next_mod; + case '#': + mod_case = TRUE; + mod = "#"; + goto next_mod; + default: + return FALSE; + } } return TRUE; @@ -3418,8 +3730,9 @@ g_date_time_format_utf8 (GDateTime *datetime, * - `%%`: a literal `%` character * * Some conversion specifications can be modified by preceding the - * conversion specifier by one or more modifier characters. The - * following modifiers are supported for many of the numeric + * conversion specifier by one or more modifier characters. + * + * The following modifiers are supported for many of the numeric * conversions: * * - `O`: Use alternative numeric symbols, if the current locale supports those. @@ -3430,6 +3743,13 @@ g_date_time_format_utf8 (GDateTime *datetime, * - `0`: Pad a numeric result with zeros. This overrides the default padding * for the specifier. * + * The following modifiers are supported for many of the alphabetic conversions: + * + * - `^`: Use upper case if possible. This is a gnulib `strftime()` extension. + * Since: 2.80 + * - `#`: Use opposite case if possible. This is a gnulib `strftime()` + * extension. Since: 2.80 + * * Additionally, when `O` is used with `B`, `b`, or `h`, it produces the alternative * form of a month name. The alternative form should be used when the month * name is used without a day number (e.g., standalone). It is required in @@ -3438,6 +3758,22 @@ g_date_time_format_utf8 (GDateTime *datetime, * `strftime()` extension expected to be added to the future POSIX specification, * `%Ob` and `%Oh` are GNU `strftime()` extensions. Since: 2.56 * + * Since GLib 2.80, when `E` is used with `%c`, `%C`, `%x`, `%X`, `%y` or `%Y`, + * the date is formatted using an alternate era representation specific to the + * locale. This is typically used for the Thai solar calendar or Japanese era + * names, for example. + * + * - `%Ec`: the preferred date and time representation for the current locale, + * using the alternate era representation + * - `%EC`: the name of the era + * - `%Ex`: the preferred date representation for the current locale without + * the time, using the alternate era representation + * - `%EX`: the preferred time representation for the current locale without + * the date, using the alternate era representation + * - `%Ey`: the year since the beginning of the era denoted by the `%EC` + * specifier + * - `%EY`: the full alternative year representation + * * Returns: (transfer full) (nullable): a newly allocated string formatted to * the requested format or %NULL in the case that there was an error (such * as a format specifier not being supported in the current locale). The diff --git a/glib/gdatetime.h b/glib/gdatetime.h index 4312433..846d22c 100644 --- a/glib/gdatetime.h +++ b/glib/gdatetime.h @@ -91,7 +91,31 @@ typedef gint64 GTimeSpan; /** * GDateTime: * - * An opaque structure that represents a date and time, including a time zone. + * `GDateTime` is a structure that combines a Gregorian date and time + * into a single structure. + * + * `GDateTime` provides many conversion and methods to manipulate dates and times. + * Time precision is provided down to microseconds and the time can range + * (proleptically) from 0001-01-01 00:00:00 to 9999-12-31 23:59:59.999999. + * `GDateTime` follows POSIX time in the sense that it is oblivious to leap + * seconds. + * + * `GDateTime` is an immutable object; once it has been created it cannot + * be modified further. All modifiers will create a new `GDateTime`. + * Nearly all such functions can fail due to the date or time going out + * of range, in which case %NULL will be returned. + * + * `GDateTime` is reference counted: the reference count is increased by calling + * [method@GLib.DateTime.ref] and decreased by calling [method@GLib.DateTime.unref]. + * When the reference count drops to 0, the resources allocated by the `GDateTime` + * structure are released. + * + * Many parts of the API may produce non-obvious results. As an + * example, adding two months to January 31st will yield March 31st + * whereas adding one month and then one month again will yield either + * March 28th or March 29th. Also note that adding 24 hours is not + * always the same as adding one day (since days containing daylight + * savings time transitions are either 23 or 25 hours in length). * * Since: 2.26 */ @@ -114,6 +138,11 @@ GDateTime * g_date_time_new_from_unix_local (gint64 GLIB_AVAILABLE_IN_ALL GDateTime * g_date_time_new_from_unix_utc (gint64 t); +GLIB_AVAILABLE_IN_2_80 +GDateTime * g_date_time_new_from_unix_local_usec (gint64 usecs); +GLIB_AVAILABLE_IN_2_80 +GDateTime * g_date_time_new_from_unix_utc_usec (gint64 usecs); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS GLIB_DEPRECATED_IN_2_62_FOR(g_date_time_new_from_unix_local) GDateTime * g_date_time_new_from_timeval_local (const GTimeVal *tv); @@ -241,6 +270,9 @@ gdouble g_date_time_get_seconds (GDateTi GLIB_AVAILABLE_IN_ALL gint64 g_date_time_to_unix (GDateTime *datetime); +GLIB_AVAILABLE_IN_2_80 +gint64 g_date_time_to_unix_usec (GDateTime *datetime); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS GLIB_DEPRECATED_IN_2_62_FOR(g_date_time_to_unix) gboolean g_date_time_to_timeval (GDateTime *datetime, diff --git a/glib/gdir.c b/glib/gdir.c index c9283de..073be6a 100644 --- a/glib/gdir.c +++ b/glib/gdir.c @@ -56,6 +56,7 @@ struct _GDir { + gatomicrefcount ref_count; #ifdef G_OS_WIN32 _WDIR *wdirp; #else @@ -89,10 +90,13 @@ GDir * g_dir_open_with_errno (const gchar *path, guint flags) { - GDir dir; #ifdef G_OS_WIN32 + GDir *dir; + _WDIR *wdirp; gint saved_errno; wchar_t *wpath; +#else + DIR *dirp; #endif g_return_val_if_fail (path != NULL, NULL); @@ -102,25 +106,31 @@ g_dir_open_with_errno (const gchar *path, g_return_val_if_fail (wpath != NULL, NULL); - dir.wdirp = _wopendir (wpath); + wdirp = _wopendir (wpath); saved_errno = errno; g_free (wpath); errno = saved_errno; - if (dir.wdirp == NULL) + if (wdirp == NULL) return NULL; + + dir = g_new0 (GDir, 1); + g_atomic_ref_count_init (&dir->ref_count); + dir->wdirp = wdirp; + + return g_steal_pointer (&dir); #else - dir.dirp = opendir (path); + dirp = opendir (path); - if (dir.dirp == NULL) + if (dirp == NULL) return NULL; -#endif - return g_memdup2 (&dir, sizeof dir); + return g_dir_new_from_dirp (dirp); +#endif } /** - * g_dir_open: + * g_dir_open: (constructor) * @path: the path to the directory you are interested in. On Unix * in the on-disk encoding. On Windows in UTF-8 * @flags: Currently must be set to 0. Reserved for future use. @@ -132,7 +142,7 @@ g_dir_open_with_errno (const gchar *path, * directory can then be retrieved using g_dir_read_name(). Note * that the ordering is not defined. * - * Returns: a newly allocated #GDir on success, %NULL on failure. + * Returns: (transfer full): a newly allocated #GDir on success, %NULL on failure. * If non-%NULL, you must free the result with g_dir_close() * when you are finished with it. **/ @@ -187,7 +197,8 @@ g_dir_new_from_dirp (gpointer dirp) g_return_val_if_fail (dirp != NULL, NULL); - dir = g_new (GDir, 1); + dir = g_new0 (GDir, 1); + g_atomic_ref_count_init (&dir->ref_count); dir->dirp = dirp; return dir; @@ -287,23 +298,84 @@ g_dir_rewind (GDir *dir) #endif } +static void +g_dir_actually_close (GDir *dir) +{ +#ifdef G_OS_WIN32 + g_clear_pointer (&dir->wdirp, _wclosedir); +#else + g_clear_pointer (&dir->dirp, closedir); +#endif +} + /** * g_dir_close: - * @dir: a #GDir* created by g_dir_open() + * @dir: (transfer full): a #GDir* created by g_dir_open() * - * Closes the directory and deallocates all related resources. + * Closes the directory immediately and decrements the reference count. + * + * Once the reference count reaches zero, the `GDir` structure itself will be + * freed. Prior to GLib 2.80, `GDir` was not reference counted. + * + * It is an error to call any of the `GDir` methods other than + * [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling + * [method@GLib.Dir.close] on it. **/ void g_dir_close (GDir *dir) { g_return_if_fail (dir != NULL); -#ifdef G_OS_WIN32 - _wclosedir (dir->wdirp); -#else - closedir (dir->dirp); -#endif - g_free (dir); + g_dir_actually_close (dir); + g_dir_unref (dir); +} + +/** + * g_dir_ref: + * @dir: (transfer none): a `GDir` + * + * Increment the reference count of `dir`. + * + * Returns: (transfer full): the same pointer as `dir` + * Since: 2.80 + */ +GDir * +g_dir_ref (GDir *dir) +{ + g_return_val_if_fail (dir != NULL, NULL); + + g_atomic_ref_count_inc (&dir->ref_count); + return dir; +} + +/** + * g_dir_unref: + * @dir: (transfer full): a `GDir` + * + * Decrements the reference count of `dir`. + * + * Once the reference count reaches zero, the directory will be closed and all + * resources associated with it will be freed. If [method@GLib.Dir.close] is + * called when the reference count is greater than zero, the directory is closed + * but the `GDir` structure will not be freed until its reference count reaches + * zero. + * + * It is an error to call any of the `GDir` methods other than + * [method@GLib.Dir.ref] and [method@GLib.Dir.unref] on a `GDir` after calling + * [method@GLib.Dir.close] on it. + * + * Since: 2.80 + */ +void +g_dir_unref (GDir *dir) +{ + g_return_if_fail (dir != NULL); + + if (g_atomic_ref_count_dec (&dir->ref_count)) + { + g_dir_actually_close (dir); + g_free (dir); + } } #ifdef G_OS_WIN32 diff --git a/glib/gdir.h b/glib/gdir.h index 0d3ee82..1b59b27 100644 --- a/glib/gdir.h +++ b/glib/gdir.h @@ -49,6 +49,11 @@ void g_dir_rewind (GDir *dir); GLIB_AVAILABLE_IN_ALL void g_dir_close (GDir *dir); +GLIB_AVAILABLE_IN_2_80 +GDir * g_dir_ref (GDir *dir); +GLIB_AVAILABLE_IN_2_80 +void g_dir_unref (GDir *dir); + G_END_DECLS #endif /* __G_DIR_H__ */ diff --git a/glib/gen-unicode-tables.pl b/glib/gen-unicode-tables.pl index f4b5bab..e47ef3b 100755 --- a/glib/gen-unicode-tables.pl +++ b/glib/gen-unicode-tables.pl @@ -111,6 +111,9 @@ $FOLDING_MAPPING = 2; ( 'AI' => "G_UNICODE_BREAK_AMBIGUOUS", 'AL' => "G_UNICODE_BREAK_ALPHABETIC", + 'AK' => "G_UNICODE_BREAK_AKSARA", + 'AP' => "G_UNICODE_BREAK_AKSARA_PRE_BASE", + 'AS' => "G_UNICODE_BREAK_AKSARA_START", 'B2' => "G_UNICODE_BREAK_BEFORE_AND_AFTER", 'BA' => "G_UNICODE_BREAK_AFTER", 'BB' => "G_UNICODE_BREAK_BEFORE", @@ -148,6 +151,8 @@ $FOLDING_MAPPING = 2; 'SG' => "G_UNICODE_BREAK_SURROGATE", 'SP' => "G_UNICODE_BREAK_SPACE", 'SY' => "G_UNICODE_BREAK_SYMBOL", + 'VF' => "G_UNICODE_BREAK_VIRAMA_FINAL", + 'VI' => "G_UNICODE_BREAK_VIRAMA", 'WJ' => "G_UNICODE_BREAK_WORD_JOINER", 'XX' => "G_UNICODE_BREAK_UNKNOWN", 'ZW' => "G_UNICODE_BREAK_ZERO_WIDTH_SPACE", @@ -332,7 +337,11 @@ while () next; } - if ($fields[$CODE] =~ /([A-F0-9]{4,6})\.\.([A-F0-9]{4,6})/) + # Trim leading and trailing whitespace + $fields[$CODE] =~ s/^\s+|\s+$//; + $fields[$BREAK_PROPERTY] =~ s/^\s+|\s+$//; + + if ($fields[$CODE] =~ /([A-F0-9]{4,6})\.\.([A-F0-9]{4,6})/) { $start_code = hex ($1); $end_code = hex ($2); @@ -803,7 +812,7 @@ sub print_row print OUT "\n "; $column = 4; } - else + elsif ($i > $start) { print OUT " " } diff --git a/glib/gerror.c b/glib/gerror.c index ea168e0..ea985ac 100644 --- a/glib/gerror.c +++ b/glib/gerror.c @@ -24,481 +24,6 @@ * GLib at ftp://ftp.gtk.org/pub/gtk/. */ -/** - * SECTION:error_reporting - * @Title: Error Reporting - * @Short_description: a system for reporting errors - * - * GLib provides a standard method of reporting errors from a called - * function to the calling code. (This is the same problem solved by - * exceptions in other languages.) It's important to understand that - * this method is both a data type (the #GError struct) and a [set of - * rules][gerror-rules]. If you use #GError incorrectly, then your code will not - * properly interoperate with other code that uses #GError, and users - * of your API will probably get confused. In most cases, [using #GError is - * preferred over numeric error codes][gerror-comparison], but there are - * situations where numeric error codes are useful for performance. - * - * First and foremost: #GError should only be used to report recoverable - * runtime errors, never to report programming errors. If the programmer - * has screwed up, then you should use g_warning(), g_return_if_fail(), - * g_assert(), g_error(), or some similar facility. (Incidentally, - * remember that the g_error() function should only be used for - * programming errors, it should not be used to print any error - * reportable via #GError.) - * - * Examples of recoverable runtime errors are "file not found" or - * "failed to parse input." Examples of programming errors are "NULL - * passed to strcmp()" or "attempted to free the same pointer twice." - * These two kinds of errors are fundamentally different: runtime errors - * should be handled or reported to the user, programming errors should - * be eliminated by fixing the bug in the program. This is why most - * functions in GLib and GTK do not use the #GError facility. - * - * Functions that can fail take a return location for a #GError as their - * last argument. On error, a new #GError instance will be allocated and - * returned to the caller via this argument. For example: - * |[ - * gboolean g_file_get_contents (const gchar *filename, - * gchar **contents, - * gsize *length, - * GError **error); - * ]| - * If you pass a non-%NULL value for the `error` argument, it should - * point to a location where an error can be placed. For example: - * |[ - * gchar *contents; - * GError *err = NULL; - * - * g_file_get_contents ("foo.txt", &contents, NULL, &err); - * g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL)); - * if (err != NULL) - * { - * // Report error to user, and free error - * g_assert (contents == NULL); - * fprintf (stderr, "Unable to read file: %s\n", err->message); - * g_error_free (err); - * } - * else - * { - * // Use file contents - * g_assert (contents != NULL); - * } - * ]| - * Note that `err != NULL` in this example is a reliable indicator - * of whether g_file_get_contents() failed. Additionally, - * g_file_get_contents() returns a boolean which - * indicates whether it was successful. - * - * Because g_file_get_contents() returns %FALSE on failure, if you - * are only interested in whether it failed and don't need to display - * an error message, you can pass %NULL for the @error argument: - * |[ - * if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) // ignore errors - * // no error occurred - * ; - * else - * // error - * ; - * ]| - * - * The #GError object contains three fields: @domain indicates the module - * the error-reporting function is located in, @code indicates the specific - * error that occurred, and @message is a user-readable error message with - * as many details as possible. Several functions are provided to deal - * with an error received from a called function: g_error_matches() - * returns %TRUE if the error matches a given domain and code, - * g_propagate_error() copies an error into an error location (so the - * calling function will receive it), and g_clear_error() clears an - * error location by freeing the error and resetting the location to - * %NULL. To display an error to the user, simply display the @message, - * perhaps along with additional context known only to the calling - * function (the file being opened, or whatever - though in the - * g_file_get_contents() case, the @message already contains a filename). - * - * Since error messages may be displayed to the user, they need to be valid - * UTF-8 (all GTK widgets expect text to be UTF-8). Keep this in mind in - * particular when formatting error messages with filenames, which are in - * the 'filename encoding', and need to be turned into UTF-8 using - * g_filename_to_utf8(), g_filename_display_name() or g_utf8_make_valid(). - * - * Note, however, that many error messages are too technical to display to the - * user in an application, so prefer to use g_error_matches() to categorize errors - * from called functions, and build an appropriate error message for the context - * within your application. Error messages from a #GError are more appropriate - * to be printed in system logs or on the command line. They are typically - * translated. - * - * When implementing a function that can report errors, the basic - * tool is g_set_error(). Typically, if a fatal error occurs you - * want to g_set_error(), then return immediately. g_set_error() - * does nothing if the error location passed to it is %NULL. - * Here's an example: - * |[ - * gint - * foo_open_file (GError **error) - * { - * gint fd; - * int saved_errno; - * - * g_return_val_if_fail (error == NULL || *error == NULL, -1); - * - * fd = open ("file.txt", O_RDONLY); - * saved_errno = errno; - * - * if (fd < 0) - * { - * g_set_error (error, - * FOO_ERROR, // error domain - * FOO_ERROR_BLAH, // error code - * "Failed to open file: %s", // error message format string - * g_strerror (saved_errno)); - * return -1; - * } - * else - * return fd; - * } - * ]| - * - * Things are somewhat more complicated if you yourself call another - * function that can report a #GError. If the sub-function indicates - * fatal errors in some way other than reporting a #GError, such as - * by returning %TRUE on success, you can simply do the following: - * |[ - * gboolean - * my_function_that_can_fail (GError **err) - * { - * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); - * - * if (!sub_function_that_can_fail (err)) - * { - * // assert that error was set by the sub-function - * g_assert (err == NULL || *err != NULL); - * return FALSE; - * } - * - * // otherwise continue, no error occurred - * g_assert (err == NULL || *err == NULL); - * } - * ]| - * - * If the sub-function does not indicate errors other than by - * reporting a #GError (or if its return value does not reliably indicate - * errors) you need to create a temporary #GError - * since the passed-in one may be %NULL. g_propagate_error() is - * intended for use in this case. - * |[ - * gboolean - * my_function_that_can_fail (GError **err) - * { - * GError *tmp_error; - * - * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); - * - * tmp_error = NULL; - * sub_function_that_can_fail (&tmp_error); - * - * if (tmp_error != NULL) - * { - * // store tmp_error in err, if err != NULL, - * // otherwise call g_error_free() on tmp_error - * g_propagate_error (err, tmp_error); - * return FALSE; - * } - * - * // otherwise continue, no error occurred - * } - * ]| - * - * Error pileups are always a bug. For example, this code is incorrect: - * |[ - * gboolean - * my_function_that_can_fail (GError **err) - * { - * GError *tmp_error; - * - * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); - * - * tmp_error = NULL; - * sub_function_that_can_fail (&tmp_error); - * other_function_that_can_fail (&tmp_error); - * - * if (tmp_error != NULL) - * { - * g_propagate_error (err, tmp_error); - * return FALSE; - * } - * } - * ]| - * @tmp_error should be checked immediately after sub_function_that_can_fail(), - * and either cleared or propagated upward. The rule is: after each error, - * you must either handle the error, or return it to the calling function. - * - * Note that passing %NULL for the error location is the equivalent - * of handling an error by always doing nothing about it. So the - * following code is fine, assuming errors in sub_function_that_can_fail() - * are not fatal to my_function_that_can_fail(): - * |[ - * gboolean - * my_function_that_can_fail (GError **err) - * { - * GError *tmp_error; - * - * g_return_val_if_fail (err == NULL || *err == NULL, FALSE); - * - * sub_function_that_can_fail (NULL); // ignore errors - * - * tmp_error = NULL; - * other_function_that_can_fail (&tmp_error); - * - * if (tmp_error != NULL) - * { - * g_propagate_error (err, tmp_error); - * return FALSE; - * } - * } - * ]| - * - * Note that passing %NULL for the error location ignores errors; - * it's equivalent to - * `try { sub_function_that_can_fail (); } catch (...) {}` - * in C++. It does not mean to leave errors unhandled; it means - * to handle them by doing nothing. - * - * Error domains and codes are conventionally named as follows: - * - * - The error domain is called __ERROR, - * for example %G_SPAWN_ERROR or %G_THREAD_ERROR: - * |[ - * #define G_SPAWN_ERROR g_spawn_error_quark () - * - * G_DEFINE_QUARK (g-spawn-error-quark, g_spawn_error) - * ]| - * - * - The quark function for the error domain is called - * __error_quark, - * for example g_spawn_error_quark() or g_thread_error_quark(). - * - * - The error codes are in an enumeration called - * Error; - * for example, #GThreadError or #GSpawnError. - * - * - Members of the error code enumeration are called - * __ERROR_, - * for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN. - * - * - If there's a "generic" or "unknown" error code for unrecoverable - * errors it doesn't make sense to distinguish with specific codes, - * it should be called __ERROR_FAILED, - * for example %G_SPAWN_ERROR_FAILED. In the case of error code - * enumerations that may be extended in future releases, you should - * generally not handle this error code explicitly, but should - * instead treat any unrecognized error code as equivalent to - * FAILED. - * - * ## Comparison of #GError and traditional error handling # {#gerror-comparison} - * - * #GError has several advantages over traditional numeric error codes: - * importantly, tools like - * [gobject-introspection](https://developer.gnome.org/gi/stable/) understand - * #GErrors and convert them to exceptions in bindings; the message includes - * more information than just a code; and use of a domain helps prevent - * misinterpretation of error codes. - * - * #GError has disadvantages though: it requires a memory allocation, and - * formatting the error message string has a performance overhead. This makes it - * unsuitable for use in retry loops where errors are a common case, rather than - * being unusual. For example, using %G_IO_ERROR_WOULD_BLOCK means hitting these - * overheads in the normal control flow. String formatting overhead can be - * eliminated by using g_set_error_literal() in some cases. - * - * These performance issues can be compounded if a function wraps the #GErrors - * returned by the functions it calls: this multiplies the number of allocations - * and string formatting operations. This can be partially mitigated by using - * g_prefix_error(). - * - * ## Rules for use of #GError # {#gerror-rules} - * - * Summary of rules for use of #GError: - * - * - Do not report programming errors via #GError. - * - * - The last argument of a function that returns an error should - * be a location where a #GError can be placed (i.e. `GError **error`). - * If #GError is used with varargs, the `GError**` should be the last - * argument before the `...`. - * - * - The caller may pass %NULL for the `GError**` if they are not interested - * in details of the exact error that occurred. - * - * - If %NULL is passed for the `GError**` argument, then errors should - * not be returned to the caller, but your function should still - * abort and return if an error occurs. That is, control flow should - * not be affected by whether the caller wants to get a #GError. - * - * - If a #GError is reported, then your function by definition had a - * fatal failure and did not complete whatever it was supposed to do. - * If the failure was not fatal, then you handled it and you should not - * report it. If it was fatal, then you must report it and discontinue - * whatever you were doing immediately. - * - * - If a #GError is reported, out parameters are not guaranteed to - * be set to any defined value. - * - * - A `GError*` must be initialized to %NULL before passing its address - * to a function that can report errors. - * - * - #GError structs must not be stack-allocated. - * - * - "Piling up" errors is always a bug. That is, if you assign a - * new #GError to a `GError*` that is non-%NULL, thus overwriting - * the previous error, it indicates that you should have aborted - * the operation instead of continuing. If you were able to continue, - * you should have cleared the previous error with g_clear_error(). - * g_set_error() will complain if you pile up errors. - * - * - By convention, if you return a boolean value indicating success - * then %TRUE means success and %FALSE means failure. Avoid creating - * functions which have a boolean return value and a #GError parameter, - * but where the boolean does something other than signal whether the - * #GError is set. Among other problems, it requires C callers to allocate - * a temporary error. Instead, provide a `gboolean *` out parameter. - * There are functions in GLib itself such as g_key_file_has_key() that - * are hard to use because of this. If %FALSE is returned, the error must - * be set to a non-%NULL value. One exception to this is that in situations - * that are already considered to be undefined behaviour (such as when a - * g_return_val_if_fail() check fails), the error need not be set. - * Instead of checking separately whether the error is set, callers - * should ensure that they do not provoke undefined behaviour, then - * assume that the error will be set on failure. - * - * - A %NULL return value is also frequently used to mean that an error - * occurred. You should make clear in your documentation whether %NULL - * is a valid return value in non-error cases; if %NULL is a valid value, - * then users must check whether an error was returned to see if the - * function succeeded. - * - * - When implementing a function that can report errors, you may want - * to add a check at the top of your function that the error return - * location is either %NULL or contains a %NULL error (e.g. - * `g_return_if_fail (error == NULL || *error == NULL);`). - * - * ## Extended #GError Domains # {#gerror-extended-domains} - * - * Since GLib 2.68 it is possible to extend the #GError type. This is - * done with the G_DEFINE_EXTENDED_ERROR() macro. To create an - * extended #GError type do something like this in the header file: - * |[ - * typedef enum - * { - * MY_ERROR_BAD_REQUEST, - * } MyError; - * #define MY_ERROR (my_error_quark ()) - * GQuark my_error_quark (void); - * int - * my_error_get_parse_error_id (GError *error); - * const char * - * my_error_get_bad_request_details (GError *error); - * ]| - * and in implementation: - * |[ - * typedef struct - * { - * int parse_error_id; - * char *bad_request_details; - * } MyErrorPrivate; - * - * static void - * my_error_private_init (MyErrorPrivate *priv) - * { - * priv->parse_error_id = -1; - * // No need to set priv->bad_request_details to NULL, - * // the struct is initialized with zeros. - * } - * - * static void - * my_error_private_copy (const MyErrorPrivate *src_priv, MyErrorPrivate *dest_priv) - * { - * dest_priv->parse_error_id = src_priv->parse_error_id; - * dest_priv->bad_request_details = g_strdup (src_priv->bad_request_details); - * } - * - * static void - * my_error_private_clear (MyErrorPrivate *priv) - * { - * g_free (priv->bad_request_details); - * } - * - * // This defines the my_error_get_private and my_error_quark functions. - * G_DEFINE_EXTENDED_ERROR (MyError, my_error) - * - * int - * my_error_get_parse_error_id (GError *error) - * { - * MyErrorPrivate *priv = my_error_get_private (error); - * g_return_val_if_fail (priv != NULL, -1); - * return priv->parse_error_id; - * } - * - * const char * - * my_error_get_bad_request_details (GError *error) - * { - * MyErrorPrivate *priv = my_error_get_private (error); - * g_return_val_if_fail (priv != NULL, NULL); - * g_return_val_if_fail (error->code != MY_ERROR_BAD_REQUEST, NULL); - * return priv->bad_request_details; - * } - * - * static void - * my_error_set_bad_request (GError **error, - * const char *reason, - * int error_id, - * const char *details) - * { - * MyErrorPrivate *priv; - * g_set_error (error, MY_ERROR, MY_ERROR_BAD_REQUEST, "Invalid request: %s", reason); - * if (error != NULL && *error != NULL) - * { - * priv = my_error_get_private (error); - * g_return_val_if_fail (priv != NULL, NULL); - * priv->parse_error_id = error_id; - * priv->bad_request_details = g_strdup (details); - * } - * } - * ]| - * An example of use of the error could be: - * |[ - * gboolean - * send_request (GBytes *request, GError **error) - * { - * ParseFailedStatus *failure = validate_request (request); - * if (failure != NULL) - * { - * my_error_set_bad_request (error, failure->reason, failure->error_id, failure->details); - * parse_failed_status_free (failure); - * return FALSE; - * } - * - * return send_one (request, error); - * } - * ]| - * - * Please note that if you are a library author and your library - * exposes an existing error domain, then you can't make this error - * domain an extended one without breaking ABI. This is because - * earlier it was possible to create an error with this error domain - * on the stack and then copy it with g_error_copy(). If the new - * version of your library makes the error domain an extended one, - * then g_error_copy() called by code that allocated the error on the - * stack will try to copy more data than it used to, which will lead - * to undefined behavior. You must not stack-allocate errors with an - * extended error domain, and it is bad practice to stack-allocate any - * other #GErrors. - * - * Extended error domains in unloadable plugins/modules are not - * supported. - */ - #include "config.h" #include "gvalgrind.h" @@ -581,9 +106,9 @@ error_domain_register (GQuark error_quark, * g_error_domain_register_static: * @error_type_name: static string to create a #GQuark from * @error_type_private_size: size of the private error data in bytes - * @error_type_init: function initializing fields of the private error data - * @error_type_copy: function copying fields of the private error data - * @error_type_clear: function freeing fields of the private error data + * @error_type_init: (scope forever): function initializing fields of the private error data + * @error_type_copy: (scope forever): function copying fields of the private error data + * @error_type_clear: (scope forever): function freeing fields of the private error data * * This function registers an extended #GError domain. * @@ -634,9 +159,9 @@ g_error_domain_register_static (const char *error_type_name, * g_error_domain_register: * @error_type_name: string to create a #GQuark from * @error_type_private_size: size of the private error data in bytes - * @error_type_init: function initializing fields of the private error data - * @error_type_copy: function copying fields of the private error data - * @error_type_clear: function freeing fields of the private error data + * @error_type_init: (scope forever): function initializing fields of the private error data + * @error_type_copy: (scope forever): function copying fields of the private error data + * @error_type_clear: (scope forever): function freeing fields of the private error data * * This function registers an extended #GError domain. * @error_type_name will be duplicated. Otherwise does the same as @@ -1106,7 +631,7 @@ g_prefix_error (GError **err, /** * g_prefix_error_literal: - * @err: (allow-none): a return location for a #GError, or %NULL + * @err: (inout) (nullable) (optional): a return location for a #GError, or %NULL * @prefix: string to prefix @err with * * Prefixes @prefix to an existing error message. If @err or *@err is diff --git a/glib/gfileutils.c b/glib/gfileutils.c index 0918a65..4e217c1 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -60,43 +60,6 @@ /** - * SECTION:fileutils - * @title: File Utilities - * @short_description: various file-related functions - * - * Do not use these APIs unless you are porting a POSIX application to Windows. - * A more high-level file access API is provided as GIO — see the documentation - * for #GFile. - * - * There is a group of functions which wrap the common POSIX functions - * dealing with filenames (g_open(), g_rename(), g_mkdir(), g_stat(), - * g_unlink(), g_remove(), g_fopen(), g_freopen()). The point of these - * wrappers is to make it possible to handle file names with any Unicode - * characters in them on Windows without having to use ifdefs and the - * wide character API in the application code. - * - * On some Unix systems, these APIs may be defined as identical to their POSIX - * counterparts. For this reason, you must check for and include the necessary - * header files (such as `fcntl.h`) before using functions like g_creat(). You - * must also define the relevant feature test macros. - * - * The pathname argument should be in the GLib file name encoding. - * On POSIX this is the actual on-disk encoding which might correspond - * to the locale settings of the process (or the `G_FILENAME_ENCODING` - * environment variable), or not. - * - * On Windows the GLib file name encoding is UTF-8. Note that the - * Microsoft C library does not use UTF-8, but has separate APIs for - * current system code page and wide characters (UTF-16). The GLib - * wrappers call the wide character API if present (on modern Windows - * systems), otherwise convert to/from the system code page. - * - * Another group of functions allows to open and read directories - * in the GLib file name encoding. These are g_dir_open(), - * g_dir_read_name(), g_dir_rewind(), g_dir_close(). - */ - -/** * GFileError: * @G_FILE_ERROR_EXIST: Operation not permitted; only the owner of * the file (or other resource) or processes with special privileges @@ -750,9 +713,9 @@ get_contents_stdio (const gchar *filename, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, - g_dngettext (GETTEXT_PACKAGE, "Could not allocate %lu byte to read file “%s”", "Could not allocate %lu bytes to read file “%s”", (gulong)total_allocated), - (gulong) total_allocated, - display_filename); + g_dngettext (GETTEXT_PACKAGE, "Could not allocate %" G_GSIZE_MODIFIER "u byte to read file “%s”", "Could not allocate %" G_GSIZE_MODIFIER "u bytes to read file “%s”", total_allocated), + total_allocated, + display_filename); g_free (display_filename); goto error; @@ -830,7 +793,19 @@ get_contents_regfile (const gchar *filename, gsize size; gsize alloc_size; gchar *display_filename; - + + if ((G_MAXOFFSET >= G_MAXSIZE) && (stat_buf->st_size > (goffset) (G_MAXSIZE - 1))) + { + display_filename = g_filename_display_name (filename); + g_set_error (error, + G_FILE_ERROR, + G_FILE_ERROR_FAILED, + _("File “%s” is too large"), + display_filename); + g_free (display_filename); + goto error; + } + size = stat_buf->st_size; alloc_size = size + 1; @@ -842,9 +817,9 @@ get_contents_regfile (const gchar *filename, g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOMEM, - g_dngettext (GETTEXT_PACKAGE, "Could not allocate %lu byte to read file “%s”", "Could not allocate %lu bytes to read file “%s”", (gulong)alloc_size), - (gulong) alloc_size, - display_filename); + g_dngettext (GETTEXT_PACKAGE, "Could not allocate %" G_GSIZE_MODIFIER "u byte to read file “%s”", "Could not allocate %" G_GSIZE_MODIFIER "u bytes to read file “%s”", alloc_size), + alloc_size, + display_filename); g_free (display_filename); goto error; } @@ -891,7 +866,7 @@ get_contents_regfile (const gchar *filename, return TRUE; - error: +error: close (fd); @@ -1161,7 +1136,7 @@ truncate_file (int fd, if (error != NULL) set_file_error (error, dest_file, - "Failed to write file “%s”: ftruncate() failed: %s", + _("Failed to write file “%s”: ftruncate() failed: %s"), saved_errno); return FALSE; } diff --git a/glib/ggettext.c b/glib/ggettext.c index 71654fb..21933d9 100644 --- a/glib/ggettext.c +++ b/glib/ggettext.c @@ -462,57 +462,6 @@ g_dngettext (const gchar *domain, return dngettext (domain, msgid, msgid_plural, n); } - -/** - * SECTION:i18n - * @title: Internationalization - * @short_description: gettext support macros - * @see_also: the gettext manual - * - * GLib doesn't force any particular localization method upon its users. - * But since GLib itself is localized using the gettext() mechanism, it seems - * natural to offer the de-facto standard gettext() support macros in an - * easy-to-use form. - * - * In order to use these macros in an application, you must include - * ``. For use in a library, you must include - * `` - * after defining the %GETTEXT_PACKAGE macro suitably for your library: - * |[ - * #define GETTEXT_PACKAGE "gtk20" - * #include - * ]| - * For an application, note that you also have to call bindtextdomain(), - * bind_textdomain_codeset(), textdomain() and setlocale() early on in your - * main() to make gettext() work. For example: - * |[ - * #include - * #include - * - * int - * main (int argc, char **argv) - * { - * setlocale (LC_ALL, ""); - * bindtextdomain (GETTEXT_PACKAGE, DATADIR "/locale"); - * bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); - * textdomain (GETTEXT_PACKAGE); - * - * // Rest of your application. - * } - * ]| - * where `DATADIR` is as typically provided by automake or Meson. - * - * For a library, you only have to call bindtextdomain() and - * bind_textdomain_codeset() in your initialization function. If your library - * doesn't have an initialization function, you can call the functions before - * the first translated message. - * - * The - * [gettext manual](http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers) - * covers details of how to integrate gettext into a project’s build system and - * workflow. - */ - /** * _: * @String: the string to be translated diff --git a/glib/ghash.c b/glib/ghash.c index 500d503..e8d8f17 100644 --- a/glib/ghash.c +++ b/glib/ghash.c @@ -64,65 +64,6 @@ #endif /** - * SECTION:hash_tables - * @title: Hash Tables - * @short_description: associations between keys and values so that - * given a key the value can be found quickly - * - * A #GHashTable provides associations between keys and values which is - * optimized so that given a key, the associated value can be found, - * inserted or removed in amortized O(1). All operations going through - * each element take O(n) time (list all keys/values, table resize, etc.). - * - * Note that neither keys nor values are copied when inserted into the - * #GHashTable, so they must exist for the lifetime of the #GHashTable. - * This means that the use of static strings is OK, but temporary - * strings (i.e. those created in buffers and those returned by GTK - * widgets) should be copied with g_strdup() before being inserted. - * - * If keys or values are dynamically allocated, you must be careful to - * ensure that they are freed when they are removed from the - * #GHashTable, and also when they are overwritten by new insertions - * into the #GHashTable. It is also not advisable to mix static strings - * and dynamically-allocated strings in a #GHashTable, because it then - * becomes difficult to determine whether the string should be freed. - * - * To create a #GHashTable, use g_hash_table_new(). - * - * To insert a key and value into a #GHashTable, use - * g_hash_table_insert(). - * - * To look up a value corresponding to a given key, use - * g_hash_table_lookup() and g_hash_table_lookup_extended(). - * - * g_hash_table_lookup_extended() can also be used to simply - * check if a key is present in the hash table. - * - * To remove a key and value, use g_hash_table_remove(). - * - * To call a function for each key and value pair use - * g_hash_table_foreach() or use an iterator to iterate over the - * key/value pairs in the hash table, see #GHashTableIter. The iteration order - * of a hash table is not defined, and you must not rely on iterating over - * keys/values in the same order as they were inserted. - * - * To destroy a #GHashTable use g_hash_table_destroy(). - * - * A common use-case for hash tables is to store information about a - * set of keys, without associating any particular value with each - * key. GHashTable optimizes one way of doing so: If you store only - * key-value pairs where key == value, then GHashTable does not - * allocate memory to store the values, which can be a considerable - * space saving, if your set is large. The functions - * g_hash_table_add() and g_hash_table_contains() are designed to be - * used when using #GHashTable this way. - * - * #GHashTable is not designed to be statically initialised with keys and - * values known at compile time. To build a static hash table, use a tool such - * as [gperf](https://www.gnu.org/software/gperf/). - */ - -/** * GHashTable: * * The #GHashTable struct is an opaque data structure to represent a @@ -1029,7 +970,7 @@ g_hash_table_ensure_keyval_fits (GHashTable *hash_table, gpointer key, gpointer * as its first parameter, and the user-provided key to check against as * its second. * - * Returns: a new #GHashTable + * Returns: (transfer full): a new #GHashTable */ GHashTable * g_hash_table_new (GHashFunc hash_func, @@ -1062,7 +1003,7 @@ g_hash_table_new (GHashFunc hash_func, * calling g_hash_table_remove_all() before releasing the last reference using * g_hash_table_unref(). * - * Returns: a new #GHashTable + * Returns: (transfer full): a new #GHashTable */ GHashTable * g_hash_table_new_full (GHashFunc hash_func, @@ -1160,7 +1101,7 @@ g_hash_table_iter_init (GHashTableIter *iter, /** * g_hash_table_iter_next: * @iter: an initialized #GHashTableIter - * @key: (out) (optional): a location to store the key + * @key: (out) (optional) (nullable): a location to store the key * @value: (out) (optional) (nullable): a location to store the value * * Advances @iter and retrieves the key and/or value that are now @@ -1213,7 +1154,7 @@ g_hash_table_iter_next (GHashTableIter *iter, * * Returns the #GHashTable associated with @iter. * - * Returns: the #GHashTable associated with @iter. + * Returns: (transfer none): the #GHashTable associated with @iter. * * Since: 2.16 */ @@ -1457,7 +1398,7 @@ g_hash_table_iter_steal (GHashTableIter *iter) * Atomically increments the reference count of @hash_table by one. * This function is MT-safe and may be called from any thread. * - * Returns: the passed in #GHashTable + * Returns: (transfer full): the passed in #GHashTable * * Since: 2.10 */ @@ -1473,7 +1414,7 @@ g_hash_table_ref (GHashTable *hash_table) /** * g_hash_table_unref: - * @hash_table: a valid #GHashTable + * @hash_table: (transfer full): a valid #GHashTable * * Atomically decrements the reference count of @hash_table by one. * If the reference count drops to 0, all keys and values will be @@ -2078,7 +2019,7 @@ g_hash_table_foreach_remove_or_steal (GHashTable *hash_table, /** * g_hash_table_foreach_remove: * @hash_table: a #GHashTable - * @func: the function to call for each key/value pair + * @func: (scope call): the function to call for each key/value pair * @user_data: user data to pass to the function * * Calls the given function for each key/value pair in the @@ -2106,7 +2047,7 @@ g_hash_table_foreach_remove (GHashTable *hash_table, /** * g_hash_table_foreach_steal: * @hash_table: a #GHashTable - * @func: the function to call for each key/value pair + * @func: (scope call): the function to call for each key/value pair * @user_data: user data to pass to the function * * Calls the given function for each key/value pair in the @@ -2133,7 +2074,7 @@ g_hash_table_foreach_steal (GHashTable *hash_table, /** * g_hash_table_foreach: * @hash_table: a #GHashTable - * @func: the function to call for each key/value pair + * @func: (scope call): the function to call for each key/value pair * @user_data: user data to pass to the function * * Calls the given function for each of the key/value pairs in the @@ -2184,7 +2125,7 @@ g_hash_table_foreach (GHashTable *hash_table, /** * g_hash_table_find: * @hash_table: a #GHashTable - * @predicate: function to test the key/value pairs for a certain property + * @predicate: (scope call): function to test the key/value pairs for a certain property * @user_data: user data to pass to the function * * Calls the given function for key/value pairs in the #GHashTable @@ -2612,6 +2553,50 @@ g_int_hash (gconstpointer v) } /** + * g_uint_equal: + * @v1: (not nullable): a pointer to a #guint key + * @v2: (not nullable): a pointer to a #guint key to compare with @v1 + * + * Compares the two #guint values being pointed to and returns + * %TRUE if they are equal. + * It can be passed to g_hash_table_new() as the @key_equal_func + * parameter, when using non-%NULL pointers to integers as keys in a + * #GHashTable. + * + * Note that this function acts on pointers to #guint, not on #guint + * directly: if your hash table's keys are of the form + * `GUINT_TO_POINTER (n)`, use g_direct_equal() instead. + * + * Returns: %TRUE if the two keys match. + */ +gboolean +g_uint_equal (gconstpointer v1, + gconstpointer v2) +{ + return *((const guint *) v1) == *((const guint *) v2); +} + +/** + * g_uint_hash: + * @v: (not nullable): a pointer to a #guint key + * + * Converts a pointer to a #guint to a hash value. + * It can be passed to g_hash_table_new() as the @hash_func parameter, + * when using non-%NULL pointers to integer values as keys in a #GHashTable. + * + * Note that this function acts on pointers to #guint, not on #guint + * directly: if your hash table's keys are of the form + * `GUINT_TO_POINTER (n)`, use g_direct_hash() instead. + * + * Returns: a hash value corresponding to the key. + */ +guint +g_uint_hash (gconstpointer v) +{ + return *(const guint *) v; +} + +/** * g_int64_equal: * @v1: (not nullable): a pointer to a #gint64 key * @v2: (not nullable): a pointer to a #gint64 key to compare with @v1 diff --git a/glib/ghmac.c b/glib/ghmac.c index 7ad28d6..97e2fff 100644 --- a/glib/ghmac.c +++ b/glib/ghmac.c @@ -37,9 +37,7 @@ /** - * SECTION:hmac - * @title: Secure HMAC Digests - * @short_description: computes the HMAC for data + * GHmac: * * HMACs should be used when producing a cookie or hash based on data * and a key. Simple mechanisms for using SHA1 and other algorithms to @@ -53,6 +51,11 @@ * * Support for HMAC Digests has been added in GLib 2.30, and support for SHA-512 * in GLib 2.42. Support for SHA-384 was added in GLib 2.52. + * + * To create a new `GHmac`, use [ctor@GLib.Hmac.new]. To free a `GHmac`, use + * [method@GLib.Hmac.unref]. + * + * Since: 2.30 */ struct _GHmac @@ -64,7 +67,7 @@ struct _GHmac }; /** - * g_hmac_new: + * g_hmac_new: (constructor) * @digest_type: the desired type of digest * @key: (array length=key_len): the key for the HMAC * @key_len: the length of the keys @@ -86,7 +89,7 @@ struct _GHmac * Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42. * Support for %G_CHECKSUM_SHA384 was added in GLib 2.52. * - * Returns: the newly created #GHmac, or %NULL. + * Returns: (nullable) (transfer full): the newly created #GHmac, or %NULL. * Use g_hmac_unref() to free the memory allocated by it. * * Since: 2.30 @@ -177,7 +180,7 @@ g_hmac_new (GChecksumType digest_type, * g_hmac_get_string() or g_hmac_get_digest(), the copied * HMAC will be closed as well. * - * Returns: the copy of the passed #GHmac. Use g_hmac_unref() + * Returns: (transfer full): the copy of the passed #GHmac. Use g_hmac_unref() * when finished using it. * * Since: 2.30 @@ -206,7 +209,7 @@ g_hmac_copy (const GHmac *hmac) * * This function is MT-safe and may be called from any thread. * - * Returns: the passed in #GHmac. + * Returns: (transfer full): the passed in #GHmac. * * Since: 2.30 **/ @@ -222,7 +225,7 @@ g_hmac_ref (GHmac *hmac) /** * g_hmac_unref: - * @hmac: a #GHmac + * @hmac: (transfer full): a #GHmac * * Atomically decrements the reference count of @hmac by one. * diff --git a/glib/ghmac.h b/glib/ghmac.h index 346b451..79380b6 100644 --- a/glib/ghmac.h +++ b/glib/ghmac.h @@ -30,15 +30,6 @@ G_BEGIN_DECLS -/** - * GHmac: - * - * An opaque structure representing a HMAC operation. - * To create a new GHmac, use g_hmac_new(). To free - * a GHmac, use g_hmac_unref(). - * - * Since: 2.30 - */ typedef struct _GHmac GHmac; GLIB_AVAILABLE_IN_2_30 diff --git a/glib/ghook.c b/glib/ghook.c index 3db2201..2c38dbc 100644 --- a/glib/ghook.c +++ b/glib/ghook.c @@ -39,16 +39,6 @@ #include "gslice.h" /** - * SECTION:hooks - * @title: Hook Functions - * @short_description: support for manipulating lists of hook functions - * - * The #GHookList, #GHook and their related functions provide support for - * lists of hook functions. Functions can be added and removed from the lists, - * and the list of hook functions can be invoked. - */ - -/** * GHookList: * @seq_id: the next free #GHook id * @hook_size: the size of the #GHookList elements, in bytes @@ -597,7 +587,7 @@ g_hook_list_invoke_check (GHookList *hook_list, * @may_recurse: %TRUE if hooks which are currently running * (e.g. in another thread) are considered valid. If set to %FALSE, * these are skipped - * @marshaller: the function to call for each #GHook + * @marshaller: (scope call): the function to call for each #GHook * @marshal_data: data to pass to @marshaller * * Calls a function on each valid #GHook and destroys it if the @@ -647,7 +637,7 @@ g_hook_list_marshal_check (GHookList *hook_list, * @may_recurse: %TRUE if hooks which are currently running * (e.g. in another thread) are considered valid. If set to %FALSE, * these are skipped - * @marshaller: the function to call for each #GHook + * @marshaller: (scope call): the function to call for each #GHook * @marshal_data: data to pass to @marshaller * * Calls a function on each valid #GHook. @@ -805,7 +795,7 @@ g_hook_get (GHookList *hook_list, * @hook_list: a #GHookList * @need_valids: %TRUE if #GHook elements which have been destroyed * should be skipped - * @func: the function to call for each #GHook, which should return + * @func: (scope call): the function to call for each #GHook, which should return * %TRUE when the #GHook has been found * @data: the data to pass to @func * @@ -982,7 +972,7 @@ g_hook_find_func_data (GHookList *hook_list, * g_hook_insert_sorted: * @hook_list: a #GHookList * @hook: the #GHook to insert - * @func: the comparison function used to sort the #GHook elements + * @func: (scope call): the comparison function used to sort the #GHook elements * * Inserts a #GHook into a #GHookList, sorted by the given function. */ diff --git a/glib/ghostutils.c b/glib/ghostutils.c index db6d687..fbc9b11 100644 --- a/glib/ghostutils.c +++ b/glib/ghostutils.c @@ -41,24 +41,6 @@ #endif -/** - * SECTION:ghostutils - * @short_description: Internet hostname utilities - * - * Functions for manipulating internet hostnames; in particular, for - * converting between Unicode and ASCII-encoded forms of - * Internationalized Domain Names (IDNs). - * - * The - * [Internationalized Domain Names for Applications (IDNA)](http://www.ietf.org/rfc/rfc3490.txt) - * standards allow for the use - * of Unicode domain names in applications, while providing - * backward-compatibility with the old ASCII-only DNS, by defining an - * ASCII-Compatible Encoding of any given Unicode name, which can be - * used with non-IDN-aware applications and protocols. (For example, - * "Παν語.org" maps to "xn--4wa8awb4637h.org".) - **/ - #define IDNA_ACE_PREFIX "xn--" #define IDNA_ACE_PREFIX_LEN 4 diff --git a/glib/giochannel.c b/glib/giochannel.c index 7572c47..b44fff3 100644 --- a/glib/giochannel.c +++ b/glib/giochannel.c @@ -44,55 +44,44 @@ /** - * SECTION:iochannels - * @title: IO Channels - * @short_description: portable support for using files, pipes and sockets - * @see_also: g_io_add_watch(), g_io_add_watch_full(), g_source_remove(), - * #GMainLoop + * GIOChannel: * - * The #GIOChannel data type aims to provide a portable method for + * The `GIOChannel` data type aims to provide a portable method for * using file descriptors, pipes, and sockets, and integrating them - * into the [main event loop][glib-The-Main-Event-Loop]. Currently, - * full support is available on UNIX platforms, support for Windows + * into the main event loop (see [struct@GLib.MainContext]). Currently, + * full support is available on UNIX platforms; support for Windows * is only partially complete. * - * To create a new #GIOChannel on UNIX systems use - * g_io_channel_unix_new(). This works for plain file descriptors, + * To create a new `GIOChannel` on UNIX systems use + * [ctor@GLib.IOChannel.unix_new]. This works for plain file descriptors, * pipes and sockets. Alternatively, a channel can be created for a - * file in a system independent manner using g_io_channel_new_file(). + * file in a system independent manner using [ctor@GLib.IOChannel.new_file]. * - * Once a #GIOChannel has been created, it can be used in a generic - * manner with the functions g_io_channel_read_chars(), - * g_io_channel_write_chars(), g_io_channel_seek_position(), and - * g_io_channel_shutdown(). + * Once a `GIOChannel` has been created, it can be used in a generic + * manner with the functions [method@GLib.IOChannel.read_chars], + * [method@GLib.IOChannel.write_chars], [method@GLib.IOChannel.seek_position], + * and [method@GLib.IOChannel.shutdown]. * - * To add a #GIOChannel to the [main event loop][glib-The-Main-Event-Loop], - * use g_io_add_watch() or g_io_add_watch_full(). Here you specify which - * events you are interested in on the #GIOChannel, and provide a - * function to be called whenever these events occur. + * To add a `GIOChannel` to the main event loop, use [func@GLib.io_add_watch] or + * [func@GLib.io_add_watch_full]. Here you specify which events you are + * interested in on the `GIOChannel`, and provide a function to be called + * whenever these events occur. * - * #GIOChannel instances are created with an initial reference count of 1. - * g_io_channel_ref() and g_io_channel_unref() can be used to + * `GIOChannel` instances are created with an initial reference count of 1. + * [method@GLib.IOChannel.ref] and [method@GLib.IOChannel.unref] can be used to * increment or decrement the reference count respectively. When the - * reference count falls to 0, the #GIOChannel is freed. (Though it - * isn't closed automatically, unless it was created using - * g_io_channel_new_file().) Using g_io_add_watch() or - * g_io_add_watch_full() increments a channel's reference count. - * - * The new functions g_io_channel_read_chars(), - * g_io_channel_read_line(), g_io_channel_read_line_string(), - * g_io_channel_read_to_end(), g_io_channel_write_chars(), - * g_io_channel_seek_position(), and g_io_channel_flush() should not be - * mixed with the deprecated functions g_io_channel_read(), - * g_io_channel_write(), and g_io_channel_seek() on the same channel. - **/ - -/** - * GIOChannel: - * - * A data structure representing an IO Channel. The fields should be - * considered private and should only be accessed with the following - * functions. + * reference count falls to 0, the `GIOChannel` is freed. (Though it + * isn’t closed automatically, unless it was created using + * [ctor@GLib.IOChannel.new_file].) Using [func@GLib.io_add_watch] or + * [func@GLib.io_add_watch_full] increments a channel’s reference count. + * + * The new functions [method@GLib.IOChannel.read_chars], + * [method@GLib.IOChannel.read_line], [method@GLib.IOChannel.read_line_string], + * [method@GLib.IOChannel.read_to_end], [method@GLib.IOChannel.write_chars], + * [method@GLib.IOChannel.seek_position], and [method@GLib.IOChannel.flush] + * should not be mixed with the deprecated functions + * [method@GLib.IOChannel.read], [method@GLib.IOChannel.write], and + * [method@GLib.IOChannel.seek] on the same channel. **/ /** @@ -105,7 +94,7 @@ * various functions such as g_io_channel_write_chars() to * write raw bytes to the channel. Encoding and buffering * issues are dealt with at a higher level. - * @io_seek: (optional) seeks the channel. This is called from + * @io_seek: (optional): seeks the channel. This is called from * g_io_channel_seek() on channels that support it. * @io_close: closes the channel. This is called from * g_io_channel_close() after flushing the buffers. diff --git a/glib/giowin32.c b/glib/giowin32.c index f0e025d..ecc337a 100644 --- a/glib/giowin32.c +++ b/glib/giowin32.c @@ -1661,7 +1661,7 @@ g_io_channel_new_file (const gchar *filename, mode_num |= MODE_PLUS; break; } - /* Fall through */ + G_GNUC_FALLTHROUGH; default: g_warning ("Invalid GIOFileMode %s.", mode); return NULL; diff --git a/glib/gkeyfile.c b/glib/gkeyfile.c index d08a485..637ac9c 100644 --- a/glib/gkeyfile.c +++ b/glib/gkeyfile.c @@ -74,23 +74,22 @@ /** - * SECTION:gkeyfile - * @title: Key-value file parser - * @short_description: parses .ini-like config files + * GKeyFile: + * + * `GKeyFile` parses .ini-like config files. * - * #GKeyFile lets you parse, edit or create files containing groups of + * `GKeyFile` lets you parse, edit or create files containing groups of * key-value pairs, which we call "key files" for lack of a better name. * Several freedesktop.org specifications use key files now, e.g the * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec) - * and the - * [Icon Theme Specification](http://freedesktop.org/Standards/icon-theme-spec). + * and the [Icon Theme Specification](http://freedesktop.org/Standards/icon-theme-spec). * * The syntax of key files is described in detail in the * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec), - * here is a quick summary: Key files - * consists of groups of key-value pairs, interspersed with comments. + * here is a quick summary: Key files consists of groups of key-value pairs, interspersed + * with comments. * - * |[ + * ```txt * # this is just an example * # there can be comments before the first group * @@ -103,14 +102,13 @@ * Welcome[de]=Hallo * Welcome[fr_FR]=Bonjour * Welcome[it]=Ciao - * Welcome[be@latin]=Hello * * [Another Group] * * Numbers=2;20;-200;0 * * Booleans=true;false;true;true - * ]| + * ``` * * Lines beginning with a '#' and blank lines are considered comments. * @@ -118,15 +116,13 @@ * in '[' and ']', and ended implicitly by the start of the next group or * the end of the file. Each key-value pair must be contained in a group. * - * Key-value pairs generally have the form `key=value`, with the - * exception of localized strings, which have the form - * `key[locale]=value`, with a locale identifier of the - * form `lang_COUNTRY@MODIFIER` where `COUNTRY` and `MODIFIER` - * are optional. - * Space before and after the '=' character are ignored. Newline, tab, - * carriage return and backslash characters in value are escaped as \n, - * \t, \r, and \\\\, respectively. To preserve leading spaces in values, - * these can also be escaped as \s. + * Key-value pairs generally have the form `key=value`, with the exception + * of localized strings, which have the form `key[locale]=value`, with a + * locale identifier of the form `lang_COUNTRY@MODIFIER` where `COUNTRY` + * and `MODIFIER` are optional. Space before and after the '=' character + * are ignored. Newline, tab, carriage return and backslash characters in + * value are escaped as `\n`, `\t`, `\r`, and `\\\\`, respectively. To preserve + * leading spaces in values, these can also be escaped as `\s`. * * Key files can store strings (possibly with localized variants), integers, * booleans and lists of these. Lists are separated by a separator character, @@ -153,15 +149,14 @@ * * Note that in contrast to the * [Desktop Entry Specification](http://freedesktop.org/Standards/desktop-entry-spec), - * groups in key files may contain the same - * key multiple times; the last entry wins. Key files may also contain - * multiple groups with the same name; they are merged together. - * Another difference is that keys and group names in key files are not + * groups in key files may contain the same key multiple times; the last entry wins. + * Key files may also contain multiple groups with the same name; they are merged + * together. Another difference is that keys and group names in key files are not * restricted to ASCII characters. * * Here is an example of loading a key file and reading a value: * - * |[ + * ```c * g_autoptr(GError) error = NULL; * g_autoptr(GKeyFile) key_file = g_key_file_new (); * @@ -184,11 +179,11 @@ * // Fall back to a default value. * val = g_strdup ("default-value"); * } - * ]| + * ``` * * Here is an example of creating and saving a key file: * - * |[ + * ```c * g_autoptr(GKeyFile) key_file = g_key_file_new (); * const gchar *val = …; * g_autoptr(GError) error = NULL; @@ -211,7 +206,7 @@ * return; * } * g_autoptr(GBytes) bytes = g_bytes_new_take (g_steal_pointer (&data), data_len); - * ]| + * ``` */ /** @@ -499,12 +494,6 @@ typedef struct _GKeyFileGroup GKeyFileGroup; -/** - * GKeyFile: - * - * The GKeyFile struct contains only private data - * and should not be accessed directly. - */ struct _GKeyFile { GList *groups; @@ -4351,7 +4340,6 @@ g_key_file_parse_value_as_string (GKeyFile *key_file, break; case '\0': - g_clear_error (error); g_set_error_literal (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, _("Key file contains escape character " @@ -4374,25 +4362,11 @@ g_key_file_parse_value_as_string (GKeyFile *key_file, sequence[1] = *p; sequence[2] = '\0'; - /* FIXME: This should be a fatal error, but there was a - * bug which prevented that being reported for a long - * time, so a lot of applications and in-the-field key - * files use invalid escape sequences without anticipating - * problems. For now (GLib 2.78), message about it; in - * future, the behaviour may become fatal again. - * - * The previous behaviour was to set the #GError but not - * return failure from the function, so the caller could - * explicitly check for invalid escapes, but also ignore - * the error if they want. This is not how #GError is - * meant to be used, but the #GKeyFile code is very old. - * - * See https://gitlab.gnome.org/GNOME/glib/-/issues/3098 */ - g_clear_error (error); g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE, _("Key file contains invalid escape " "sequence “%s”"), sequence); + goto error; } } break; diff --git a/glib/glib-autocleanups.h b/glib/glib-autocleanups.h index 6adf232..68be87c 100644 --- a/glib/glib-autocleanups.h +++ b/glib/glib-autocleanups.h @@ -23,6 +23,8 @@ #error "Only can be included directly." #endif +#ifndef __GI_SCANNER__ + static inline void g_autoptr_cleanup_generic_gfree (void *p) { @@ -105,3 +107,5 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC (GPathBuf, g_path_buf_free) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (GPathBuf, g_path_buf_clear) G_GNUC_END_IGNORE_DEPRECATIONS + +#endif /* __GI_SCANNER__ */ diff --git a/glib/glib-init.c b/glib/glib-init.c index 933f891..7d4a4d5 100644 --- a/glib/glib-init.c +++ b/glib/glib-init.c @@ -26,6 +26,7 @@ #include "gtypes.h" #include "gutils.h" /* for GDebugKey */ #include "gconstructor.h" +#include "gconstructorprivate.h" #include "gmem.h" /* for g_mem_gc_friendly */ #include @@ -448,32 +449,60 @@ DllMain (HINSTANCE hinstDLL, return TRUE; } -#elif defined(G_HAS_CONSTRUCTORS) /* && G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION */ -#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA -#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_init_ctor) +#else + +#ifndef G_HAS_CONSTRUCTORS +#error static compilation on Windows requires constructor support #endif -#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA -#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS(glib_init_dtor) + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS(glib_priv_constructor) #endif -G_DEFINE_CONSTRUCTOR (glib_init_ctor) +static gboolean tls_callback_invoked; + +G_DEFINE_CONSTRUCTOR (glib_priv_constructor) static void -glib_init_ctor (void) +glib_priv_constructor (void) { glib_win32_init (); + + if (!tls_callback_invoked) + g_critical ("TLS callback not invoked"); } -G_DEFINE_DESTRUCTOR (glib_init_dtor) +#ifndef G_HAS_TLS_CALLBACKS +#error static compilation on Windows requires TLS callbacks support +#endif + +G_DEFINE_TLS_CALLBACK (glib_priv_tls_callback) -static void -glib_init_dtor (void) +static void NTAPI +glib_priv_tls_callback (LPVOID hinstance, + DWORD reason, + LPVOID reserved) { - glib_win32_deinit (FALSE); + switch (reason) + { + case DLL_PROCESS_ATTACH: + glib_dll = hinstance; + tls_callback_invoked = TRUE; + break; + case DLL_THREAD_DETACH: +#ifdef THREADS_WIN32 + g_thread_win32_thread_detach (); +#endif + break; + case DLL_PROCESS_DETACH: + glib_win32_deinit (reserved == NULL); + break; + + default: + break; + } } -#else /* G_PLATFORM_WIN32 && GLIB_STATIC_COMPILATION && !G_HAS_CONSTRUCTORS */ -#error Your platform/compiler is missing constructor support #endif /* GLIB_STATIC_COMPILATION */ #elif defined(G_HAS_CONSTRUCTORS) /* && !G_PLATFORM_WIN32 */ diff --git a/glib/glib-private.c b/glib/glib-private.c index 9f4887a..c2b68a0 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -23,6 +23,7 @@ #include "glib-private.h" #include "glib-init.h" +#include "gutilsprivate.h" #ifdef USE_INVALID_PARAMETER_HANDLER #include @@ -71,6 +72,8 @@ glib__private__ (void) g_find_program_for_path, g_uri_get_default_scheme_port, + + g_set_prgname_once, }; return &table; diff --git a/glib/glib-private.h b/glib/glib-private.h index f49e38f..50aa8a0 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -37,14 +37,63 @@ /* * %_GLIB_ADDRESS_SANITIZER: * - * Private macro defined if the AddressSanitizer is in use. + * Private macro defined if the AddressSanitizer is in use by GLib itself. */ #define _GLIB_ADDRESS_SANITIZER #include +/* If GLib itself is not compiled with ASAN sanitizer we may still want to + * control it in case it's linked by the loading application, so we need to + * do this check dynamically. + * However MinGW doesn't support weak attribute properly (even if it advertises + * it), so we ignore it in such case since it's not convenient to go through + * dlsym(). + * Under MSVC we could use alternatename, but it doesn't seem to be as reliable + * as we'd like: https://stackoverflow.com/a/11529277/210151 and + * https://devblogs.microsoft.com/oldnewthing/20200731-00/?p=104024 + */ +#elif defined (G_OS_UNIX) && !defined (__APPLE__) && g_macro__has_attribute (weak) + +#define HAS_DYNAMIC_ASAN_LOADING + +void __lsan_enable (void) __attribute__ ((weak)); +void __lsan_disable (void) __attribute__ ((weak)); +void __lsan_ignore_object (const void *p) __attribute__ ((weak)); + #endif +/** + * G_CONTAINER_OF: + * @ptr: a pointer to a member @field of type @type. + * @type: the type of the container in which @field is embedded. + * @field: the name of the field in @type. + * + * Casts away constness of @ptr. + * + * Returns: a pointer to the container, so that "&(@container)->field == (@ptr)" holds. + */ +#define G_CONTAINER_OF(ptr, type, field) ((type *) G_STRUCT_MEMBER_P (ptr, -G_STRUCT_OFFSET (type, field))) + +/* + * g_leak_sanitizer_is_supported: + * + * Checks at runtime if LeakSanitizer is currently supported by the running + * binary. This may imply that GLib itself is not compiled with sanitizer + * but that the loading program is. + */ +static inline gboolean +g_leak_sanitizer_is_supported (void) +{ +#if defined (_GLIB_ADDRESS_SANITIZER) + return TRUE; +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + return __lsan_enable != NULL && __lsan_ignore_object != NULL; +#else + return FALSE; +#endif +} + /* * g_ignore_leak: * @p: any pointer @@ -57,9 +106,12 @@ static inline void g_ignore_leak (gconstpointer p) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) if (p != NULL) __lsan_ignore_object (p); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (p != NULL && __lsan_ignore_object != NULL) + __lsan_ignore_object (p); #endif } @@ -73,9 +125,11 @@ g_ignore_leak (gconstpointer p) static inline void g_ignore_strv_leak (GStrv strv) { -#ifdef _GLIB_ADDRESS_SANITIZER gchar **item; + if (!g_leak_sanitizer_is_supported ()) + return; + if (strv) { g_ignore_leak (strv); @@ -83,7 +137,6 @@ g_ignore_strv_leak (GStrv strv) for (item = strv; *item != NULL; item++) g_ignore_leak (*item); } -#endif } /* @@ -98,8 +151,11 @@ g_ignore_strv_leak (GStrv strv) static inline void g_begin_ignore_leaks (void) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) __lsan_disable (); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (__lsan_disable != NULL) + __lsan_disable (); #endif } @@ -112,11 +168,16 @@ g_begin_ignore_leaks (void) static inline void g_end_ignore_leaks (void) { -#ifdef _GLIB_ADDRESS_SANITIZER +#if defined (_GLIB_ADDRESS_SANITIZER) __lsan_enable (); +#elif defined (HAS_DYNAMIC_ASAN_LOADING) + if (__lsan_enable != NULL) + __lsan_enable (); #endif } +#undef HAS_DYNAMIC_ASAN_LOADING + GMainContext * g_get_worker_context (void); gboolean g_check_setuid (void); GMainContext * g_main_context_new_with_next_id (guint next_id); @@ -227,6 +288,9 @@ typedef struct { /* See guri.c */ int (* g_uri_get_default_scheme_port) (const char *scheme); + /* See gutils.c */ + gboolean (* g_set_prgname_once) (const gchar *prgname); + /* Add other private functions here, initialize them in glib-private.c */ } GLibPrivateVTable; @@ -254,4 +318,7 @@ GLibPrivateVTable *glib__private__ (void); # define GLIB_DEFAULT_LOCALE "" #endif +gboolean g_uint_equal (gconstpointer v1, gconstpointer v2); +guint g_uint_hash (gconstpointer v); + #endif /* __GLIB_PRIVATE_H__ */ diff --git a/glib/glib-unix.c b/glib/glib-unix.c index df5726c..a7716fb 100644 --- a/glib/glib-unix.c +++ b/glib/glib-unix.c @@ -1,5 +1,6 @@ /* GLIB - Library of useful routines for C programming * Copyright (C) 2011 Red Hat, Inc. + * Copyright 2023 Collabora Ltd. * * glib-unix.c: UNIX specific API wrappers and convenience functions * @@ -43,21 +44,6 @@ G_STATIC_ASSERT (G_ALIGNOF (GPid) == G_ALIGNOF (pid_t)); * might not be true everywhere. */ G_STATIC_ASSERT (O_NONBLOCK != FD_CLOEXEC); -/** - * SECTION:gunix - * @title: UNIX-specific utilities and integration - * @short_description: pipes, signal handling - * @include: glib-unix.h - * - * Most of GLib is intended to be portable; in contrast, this set of - * functions is designed for programs which explicitly target UNIX, - * or are using it to build higher level abstractions which would be - * conditionally compiled if the platform matches %G_OS_UNIX. - * - * To use these functions, you must explicitly include the - * "glib-unix.h" header. - */ - G_DEFINE_QUARK (g-unix-error-quark, g_unix_error) static gboolean @@ -87,6 +73,9 @@ g_unix_set_error_from_errno (GError **error, * you wanted to configure `O_NONBLOCK` then that had to be done separately with * `fcntl()`. * + * Since GLib 2.80, the constants %G_UNIX_PIPE_END_READ and + * %G_UNIX_PIPE_END_WRITE can be used as mnemonic indexes in @fds. + * * It is a programmer error to call this function with unsupported flags, and a * critical warning will be raised. * diff --git a/glib/glib-unix.h b/glib/glib-unix.h index 7cf4f0d..c58769e 100644 --- a/glib/glib-unix.h +++ b/glib/glib-unix.h @@ -1,5 +1,6 @@ /* glib-unix.h - Unix specific integration * Copyright (C) 2011 Red Hat, Inc. + * Copyright 2023 Collabora Ltd. * * SPDX-License-Identifier: LGPL-2.1-or-later * @@ -33,6 +34,7 @@ #include #include +#include #ifndef G_OS_UNIX #error "This header may only be used on UNIX" @@ -120,6 +122,212 @@ GLIB_AVAILABLE_IN_2_64 struct passwd *g_unix_get_passwd_entry (const gchar *user_name, GError **error); +/** + * GUnixPipe: + * @fds: A pair of file descriptors, each negative if closed or not yet opened. + * The file descriptor with index %G_UNIX_PIPE_END_READ is readable. + * The file descriptor with index %G_UNIX_PIPE_END_WRITE is writable. + * + * A Unix pipe. The advantage of this type over `int[2]` is that it can + * be closed automatically when it goes out of scope, using `g_auto(GUnixPipe)`, + * on compilers that support that feature. + * + * Since: 2.80 + */ +GLIB_AVAILABLE_TYPE_IN_2_80 +typedef struct { + int fds[2]; +} GUnixPipe; + +/** + * GUnixPipeEnd: + * @G_UNIX_PIPE_END_READ: The readable file descriptor 0 + * @G_UNIX_PIPE_END_WRITE: The writable file descriptor 1 + * + * Mnemonic constants for the ends of a Unix pipe. + * + * Since: 2.80 + */ +GLIB_AVAILABLE_TYPE_IN_2_80 +typedef enum +{ + G_UNIX_PIPE_END_READ = 0, + G_UNIX_PIPE_END_WRITE = 1 +} GUnixPipeEnd; + +/** + * G_UNIX_PIPE_INIT: + * + * Initializer for a #GUnixPipe that has not yet been opened. + * Both of its file descriptors are initialized to `-1` (invalid), + * the same as if they had been closed. + * + * Since: 2.80 + */ +#define G_UNIX_PIPE_INIT { { -1, -1 } } GLIB_AVAILABLE_MACRO_IN_2_80 + +/* Suppress "Not available before" warnings when declaring the + * implementations */ +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +/** + * g_unix_pipe_open: + * @self: A pair of file descriptors + * @flags: Flags to pass to g_unix_open_pipe(), typically `FD_CLOEXEC` + * @error: Used to report an error on failure + * + * Open a pipe. This is the same as g_unix_open_pipe(), but uses the + * #GUnixPipe data structure. + * + * Returns: %TRUE on success + * + * Since: 2.80 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_80 +static inline gboolean +g_unix_pipe_open (GUnixPipe *self, + int flags, + GError **error) +{ + return g_unix_open_pipe (self->fds, flags, error); +} + +/** + * g_unix_pipe_get: + * @self: A pair of file descriptors + * @end: One of the ends of the pipe + * + * Return one of the ends of the pipe. It remains owned by @self. + * + * This function is async-signal safe (see [`signal(7)`](man:signal(7)) and + * [`signal-safety(7)`](man:signal-safety(7))), making it safe to call from a + * signal handler or a #GSpawnChildSetupFunc. + * + * This function preserves the value of `errno`. + * + * Returns: a non-negative file descriptor owned by @self, which must not + * be closed by the caller, or a negative number if the corresponding + * end of the pipe was already closed or stolen + * + * Since: 2.80 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_80 +static inline int +g_unix_pipe_get (GUnixPipe *self, + GUnixPipeEnd end) +{ + return self->fds[end]; +} + +/** + * g_unix_pipe_steal: + * @self: A pair of file descriptors + * @end: One of the ends of the pipe + * + * Return one of the ends of the pipe. It becomes owned by the caller, + * and the file descriptor in the data structure is set to `-1`, + * similar to g_steal_fd(). + * + * This function is async-signal safe (see [`signal(7)`](man:signal(7)) and + * [`signal-safety(7)`](man:signal-safety(7))), making it safe to call from a + * signal handler or a #GSpawnChildSetupFunc. + * + * This function preserves the value of `errno`. + * + * Returns: a non-negative file descriptor, which becomes owned by the + * caller and must be closed by the caller if required, or a negative + * number if the corresponding end of the pipe was already closed or stolen + * + * Since: 2.80 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_80 +static inline int +g_unix_pipe_steal (GUnixPipe *self, + GUnixPipeEnd end) +{ + return g_steal_fd (&self->fds[end]); +} + +/** + * g_unix_pipe_close: + * @self: A pair of file descriptors + * @end: One of the ends of the pipe + * @error: Optionally used to report an error on failure + * + * Close one of the ends of the pipe and set the relevant member of @fds + * to `-1` before returning, equivalent to g_clear_fd(). + * + * Like g_close(), if closing the file descriptor fails, the error is + * stored in both %errno and @error. If this function succeeds, + * %errno is undefined. + * + * This function is async-signal safe if @error is %NULL and the relevant + * member of @fds is either negative or a valid open file descriptor. + * This makes it safe to call from a signal handler or a #GSpawnChildSetupFunc + * under those conditions. + * See [`signal(7)`](man:signal(7)) and + * [`signal-safety(7)`](man:signal-safety(7)) for more details. + * + * To close both file descriptors and ignore any errors, use + * g_unix_pipe_clear() instead. + * + * Returns: %TRUE on success + * + * Since: 2.80 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_80 +static inline gboolean +g_unix_pipe_close (GUnixPipe *self, + GUnixPipeEnd end, + GError **error) +{ + return g_clear_fd (&self->fds[end], error); +} + +/** + * g_unix_pipe_clear: + * @self: a #GUnixPipe + * + * Close both ends of the pipe, unless they have already been closed or + * stolen. Any errors are ignored: use g_unix_pipe_close() or g_clear_fd() + * if error-handling is required. + * + * This function is async-signal safe if @error is %NULL and each member + * of @fds are either negative or a valid open file descriptor. + * As a result, it is safe to call this function or use `g_auto(GUnixPipe)` + * (on compilers that support it) in a signal handler or a + * #GSpawnChildSetupFunc, as long as those conditions are ensured to be true. + * See [`signal(7)`](man:signal(7)) and + * [`signal-safety(7)`](man:signal-safety(7)) for more details. + * + * This function preserves the value of `errno`. + * + * Since: 2.80 + */ +GLIB_AVAILABLE_STATIC_INLINE_IN_2_80 +static inline void +g_unix_pipe_clear (GUnixPipe *self) +{ + /* Don't overwrite thread-local errno if closing the fd fails */ + int errsv = errno; + + if (!g_unix_pipe_close (self, G_UNIX_PIPE_END_READ, NULL)) + { + /* ignore */ + } + + if (!g_unix_pipe_close (self, G_UNIX_PIPE_END_WRITE, NULL)) + { + /* ignore */ + } + + errno = errsv; +} + +G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC (GUnixPipe, g_unix_pipe_clear) + +G_GNUC_END_IGNORE_DEPRECATIONS + G_END_DECLS #endif /* __G_UNIX_H__ */ diff --git a/glib/glist.c b/glib/glist.c index 754a3ec..d56ff7c 100644 --- a/glib/glist.c +++ b/glib/glist.c @@ -37,90 +37,6 @@ #include "gtestutils.h" /** - * SECTION:linked_lists_double - * @title: Doubly-Linked Lists - * @short_description: linked lists that can be iterated over in both directions - * - * The #GList structure and its associated functions provide a standard - * doubly-linked list data structure. The benefit of this data-structure - * is to provide insertion/deletion operations in O(1) complexity where - * access/search operations are in O(n). The benefit of #GList over - * #GSList (singly linked list) is that the worst case on access/search - * operations is divided by two which comes at a cost in space as we need - * to retain two pointers in place of one. - * - * Each element in the list contains a piece of data, together with - * pointers which link to the previous and next elements in the list. - * Using these pointers it is possible to move through the list in both - * directions (unlike the singly-linked [GSList][glib-Singly-Linked-Lists], - * which only allows movement through the list in the forward direction). - * - * The double linked list does not keep track of the number of items - * and does not keep track of both the start and end of the list. If - * you want fast access to both the start and the end of the list, - * and/or the number of items in the list, use a - * [GQueue][glib-Double-ended-Queues] instead. - * - * The data contained in each element can be either integer values, by - * using one of the [Type Conversion Macros][glib-Type-Conversion-Macros], - * or simply pointers to any type of data. - * - * List elements are allocated from the [slice allocator][glib-Memory-Slices], - * which is more efficient than allocating elements individually. - * - * Note that most of the #GList functions expect to be passed a pointer - * to the first element in the list. The functions which insert - * elements return the new start of the list, which may have changed. - * - * There is no function to create a #GList. %NULL is considered to be - * a valid, empty list so you simply set a #GList* to %NULL to initialize - * it. - * - * To add elements, use g_list_append(), g_list_prepend(), - * g_list_insert() and g_list_insert_sorted(). - * - * To visit all elements in the list, use a loop over the list: - * |[ - * GList *l; - * for (l = list; l != NULL; l = l->next) - * { - * // do something with l->data - * } - * ]| - * - * To call a function for each element in the list, use g_list_foreach(). - * - * To loop over the list and modify it (e.g. remove a certain element) - * a while loop is more appropriate, for example: - * |[ - * GList *l = list; - * while (l != NULL) - * { - * GList *next = l->next; - * if (should_be_removed (l)) - * { - * // possibly free l->data - * list = g_list_delete_link (list, l); - * } - * l = next; - * } - * ]| - * - * To remove elements, use g_list_remove(). - * - * To navigate in a list, use g_list_first(), g_list_last(), - * g_list_next(), g_list_previous(). - * - * To find elements in the list use g_list_nth(), g_list_nth_data(), - * g_list_find() and g_list_find_custom(). - * - * To find the index of an element use g_list_position() and - * g_list_index(). - * - * To free the entire list, use g_list_free() or g_list_free_full(). - */ - -/** * GList: * @data: holds the element's data, which can be a pointer to any kind * of data, or any integer value using the @@ -718,7 +634,7 @@ g_list_copy (GList *list) /** * g_list_copy_deep: * @list: a #GList, this must point to the top of the list - * @func: a copy function used to copy every element in the list + * @func: (scope call): a copy function used to copy every element in the list * @user_data: user data passed to the copy function @func, or %NULL * * Makes a full (deep) copy of a #GList. @@ -905,7 +821,7 @@ g_list_find (GList *list, * g_list_find_custom: * @list: a #GList, this must point to the top of the list * @data: user data passed to the function - * @func: the function to call for each element. + * @func: (scope call): the function to call for each element. * It should return 0 when the desired element is found * * Finds an element in a #GList, using a supplied function to @@ -1065,7 +981,7 @@ g_list_length (GList *list) /** * g_list_foreach: * @list: a #GList, this must point to the top of the list - * @func: the function to call with each element's data + * @func: (scope call): the function to call with each element's data * @user_data: user data to pass to the function * * Calls a function for each element of a #GList. @@ -1151,7 +1067,7 @@ g_list_insert_sorted_real (GList *list, * @list: a pointer to a #GList, this must point to the top of the * already sorted list * @data: the data for the new element - * @func: the function to compare elements in the list. It should + * @func: (scope call): the function to compare elements in the list. It should * return a number > 0 if the first parameter comes after the * second parameter in the sort order. * @@ -1178,7 +1094,7 @@ g_list_insert_sorted (GList *list, * @list: a pointer to a #GList, this must point to the top of the * already sorted list * @data: the data for the new element - * @func: the function to compare elements in the list. It should + * @func: (scope call): the function to compare elements in the list. It should * return a number > 0 if the first parameter comes after the * second parameter in the sort order. * @user_data: user data to pass to comparison function @@ -1273,7 +1189,7 @@ g_list_sort_real (GList *list, /** * g_list_sort: * @list: a #GList, this must point to the top of the list - * @compare_func: the comparison function used to sort the #GList. + * @compare_func: (scope call): the comparison function used to sort the #GList. * This function is passed the data from 2 elements of the #GList * and should return 0 if they are equal, a negative value if the * first element comes before the second, or a positive value if @@ -1307,7 +1223,7 @@ g_list_sort (GList *list, /** * g_list_sort_with_data: * @list: a #GList, this must point to the top of the list - * @compare_func: comparison function + * @compare_func: (scope call): comparison function * @user_data: user data to pass to comparison function * * Like g_list_sort(), but the comparison function accepts diff --git a/glib/gmacros.h b/glib/gmacros.h index 1be50a4..2d66c2f 100644 --- a/glib/gmacros.h +++ b/glib/gmacros.h @@ -185,6 +185,7 @@ #define g_macro__has_attribute___pure__ G_GNUC_CHECK_VERSION (2, 96) #define g_macro__has_attribute___sentinel__ G_GNUC_CHECK_VERSION (4, 0) #define g_macro__has_attribute___unused__ G_GNUC_CHECK_VERSION (2, 4) +#define g_macro__has_attribute___weak__ G_GNUC_CHECK_VERSION (2, 8) #define g_macro__has_attribute_cleanup G_GNUC_CHECK_VERSION (3, 3) #define g_macro__has_attribute_fallthrough G_GNUC_CHECK_VERSION (6, 0) #define g_macro__has_attribute_may_alias G_GNUC_CHECK_VERSION (3, 3) diff --git a/glib/gmain.c b/glib/gmain.c index 8400e97..6d56ab3 100644 --- a/glib/gmain.c +++ b/glib/gmain.c @@ -127,134 +127,6 @@ #include "glib-init.h" #include "glib-private.h" -/** - * SECTION:main - * @title: The Main Event Loop - * @short_description: manages all available sources of events - * - * The main event loop manages all the available sources of events for - * GLib and GTK applications. These events can come from any number of - * different types of sources such as file descriptors (plain files, - * pipes or sockets) and timeouts. New types of event sources can also - * be added using g_source_attach(). - * - * To allow multiple independent sets of sources to be handled in - * different threads, each source is associated with a #GMainContext. - * A #GMainContext can only be running in a single thread, but - * sources can be added to it and removed from it from other threads. All - * functions which operate on a #GMainContext or a built-in #GSource are - * thread-safe. - * - * Each event source is assigned a priority. The default priority, - * %G_PRIORITY_DEFAULT, is 0. Values less than 0 denote higher priorities. - * Values greater than 0 denote lower priorities. Events from high priority - * sources are always processed before events from lower priority sources: if - * several sources are ready to dispatch, the ones with equal-highest priority - * will be dispatched on the current #GMainContext iteration, and the rest wait - * until a subsequent #GMainContext iteration when they have the highest - * priority of the sources which are ready for dispatch. - * - * Idle functions can also be added, and assigned a priority. These will - * be run whenever no events with a higher priority are ready to be dispatched. - * - * The #GMainLoop data type represents a main event loop. A GMainLoop is - * created with g_main_loop_new(). After adding the initial event sources, - * g_main_loop_run() is called. This continuously checks for new events from - * each of the event sources and dispatches them. Finally, the processing of - * an event from one of the sources leads to a call to g_main_loop_quit() to - * exit the main loop, and g_main_loop_run() returns. - * - * It is possible to create new instances of #GMainLoop recursively. - * This is often used in GTK applications when showing modal dialog - * boxes. Note that event sources are associated with a particular - * #GMainContext, and will be checked and dispatched for all main - * loops associated with that GMainContext. - * - * GTK contains wrappers of some of these functions, e.g. gtk_main(), - * gtk_main_quit() and gtk_events_pending(). - * - * ## Creating new source types - * - * One of the unusual features of the #GMainLoop functionality - * is that new types of event source can be created and used in - * addition to the builtin type of event source. A new event source - * type is used for handling GDK events. A new source type is created - * by "deriving" from the #GSource structure. The derived type of - * source is represented by a structure that has the #GSource structure - * as a first element, and other elements specific to the new source - * type. To create an instance of the new source type, call - * g_source_new() passing in the size of the derived structure and - * a table of functions. These #GSourceFuncs determine the behavior of - * the new source type. - * - * New source types basically interact with the main context - * in two ways. Their prepare function in #GSourceFuncs can set a timeout - * to determine the maximum amount of time that the main loop will sleep - * before checking the source again. In addition, or as well, the source - * can add file descriptors to the set that the main context checks using - * g_source_add_poll(). - * - * ## Customizing the main loop iteration - * - * Single iterations of a #GMainContext can be run with - * g_main_context_iteration(). In some cases, more detailed control - * of exactly how the details of the main loop work is desired, for - * instance, when integrating the #GMainLoop with an external main loop. - * In such cases, you can call the component functions of - * g_main_context_iteration() directly. These functions are - * g_main_context_prepare(), g_main_context_query(), - * g_main_context_check() and g_main_context_dispatch(). - * - * If the event loop thread releases #GMainContext ownership until the results - * required by g_main_context_check() are ready you must create a context with - * the flag %G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING or else you'll lose - * g_source_attach() notifications. This happens for instance when you integrate - * the GLib event loop into implementations that follow the proactor pattern - * (i.e. in these contexts the `poll()` implementation will reclaim the thread for - * other tasks until the results are ready). One example of the proactor pattern - * is the Boost.Asio library. - * - * ## State of a Main Context # {#mainloop-states} - * - * The operation of these functions can best be seen in terms - * of a state diagram, as shown in this image. - * - * ![](mainloop-states.gif) - * - * On UNIX, the GLib mainloop is incompatible with fork(). Any program - * using the mainloop must either exec() or exit() from the child - * without returning to the mainloop. - * - * ## Memory management of sources # {#mainloop-memory-management} - * - * There are two options for memory management of the user data passed to a - * #GSource to be passed to its callback on invocation. This data is provided - * in calls to g_timeout_add(), g_timeout_add_full(), g_idle_add(), etc. and - * more generally, using g_source_set_callback(). This data is typically an - * object which ‘owns’ the timeout or idle callback, such as a widget or a - * network protocol implementation. In many cases, it is an error for the - * callback to be invoked after this owning object has been destroyed, as that - * results in use of freed memory. - * - * The first, and preferred, option is to store the source ID returned by - * functions such as g_timeout_add() or g_source_attach(), and explicitly - * remove that source from the main context using g_source_remove() when the - * owning object is finalized. This ensures that the callback can only be - * invoked while the object is still alive. - * - * The second option is to hold a strong reference to the object in the - * callback, and to release it in the callback’s #GDestroyNotify. This ensures - * that the object is kept alive until after the source is finalized, which is - * guaranteed to be after it is invoked for the final time. The #GDestroyNotify - * is another callback passed to the ‘full’ variants of #GSource functions (for - * example, g_timeout_add_full()). It is called when the source is finalized, - * and is designed for releasing references like this. - * - * One important caveat of this second approach is that it will keep the object - * alive indefinitely if the main loop is stopped before the #GSource is - * invoked, which may be undesirable. - */ - /* Types */ typedef struct _GIdleSource GIdleSource; @@ -275,6 +147,7 @@ typedef struct _GSourceList GSourceList; struct _GSourceList { + GList link; GSource *head, *tail; gint priority; }; @@ -319,7 +192,7 @@ struct _GMainContext gint timeout; /* Timeout for current iteration */ guint next_id; - GList *source_lists; + GQueue source_lists; gint in_check_or_prepare; GPollRec *poll_records; @@ -669,12 +542,13 @@ g_main_context_unref (GMainContext *context) g_source_destroy_internal (source, context, TRUE); } - for (sl_iter = context->source_lists; sl_iter; sl_iter = sl_iter->next) + sl_iter = context->source_lists.head; + while (sl_iter != NULL) { list = sl_iter->data; + sl_iter = sl_iter->next; g_slice_free (GSourceList, list); } - g_list_free (context->source_lists); g_hash_table_destroy (context->sources); @@ -763,7 +637,7 @@ g_main_context_new_with_flags (GMainContextFlags flags) g_mutex_init (&context->mutex); g_cond_init (&context->cond); - context->sources = g_hash_table_new (NULL, NULL); + context->sources = g_hash_table_new (g_uint_hash, g_uint_equal); context->owner = NULL; context->flags = flags; context->waiters = NULL; @@ -771,9 +645,7 @@ g_main_context_new_with_flags (GMainContextFlags flags) context->ref_count = 1; context->next_id = 1; - - context->source_lists = NULL; - + context->poll_func = g_poll; context->cached_poll_array = NULL; @@ -815,7 +687,7 @@ g_main_context_default (void) { static GMainContext *default_main_context = NULL; - if (g_once_init_enter (&default_main_context)) + if (g_once_init_enter_pointer (&default_main_context)) { GMainContext *context; @@ -828,7 +700,7 @@ g_main_context_default (void) g_print ("global-default main context=%p\n", context); #endif - g_once_init_leave (&default_main_context, context); + g_once_init_leave_pointer (&default_main_context, context); } return default_main_context; @@ -1126,7 +998,7 @@ g_source_iter_next (GSourceIter *iter, GSource **source) if (iter->current_list) iter->current_list = iter->current_list->next; else - iter->current_list = iter->context->source_lists; + iter->current_list = iter->context->source_lists.head; if (iter->current_list) { @@ -1176,11 +1048,10 @@ find_source_list_for_priority (GMainContext *context, gint priority, gboolean create) { - GList *iter, *last; + GList *iter; GSourceList *source_list; - last = NULL; - for (iter = context->source_lists; iter != NULL; last = iter, iter = iter->next) + for (iter = context->source_lists.head; iter; iter = iter->next) { source_list = iter->data; @@ -1193,10 +1064,11 @@ find_source_list_for_priority (GMainContext *context, return NULL; source_list = g_slice_new0 (GSourceList); + source_list->link.data = source_list; source_list->priority = priority; - context->source_lists = g_list_insert_before (context->source_lists, - iter, - source_list); + g_queue_insert_before_link (&context->source_lists, + iter, + &source_list->link); return source_list; } } @@ -1205,18 +1077,10 @@ find_source_list_for_priority (GMainContext *context, return NULL; source_list = g_slice_new0 (GSourceList); + source_list->link.data = source_list; source_list->priority = priority; + g_queue_push_tail_link (&context->source_lists, &source_list->link); - if (!last) - context->source_lists = g_list_append (NULL, source_list); - else - { - /* This just appends source_list to the end of - * context->source_lists without having to walk the list again. - */ - last = g_list_append (last, source_list); - (void) last; - } return source_list; } @@ -1284,7 +1148,7 @@ source_remove_from_context (GSource *source, if (source_list->head == NULL) { - context->source_lists = g_list_remove (context->source_lists, source_list); + g_queue_unlink (&context->source_lists, &source_list->link); g_slice_free (GSourceList, source_list); } } @@ -1302,13 +1166,13 @@ g_source_attach_unlocked (GSource *source, */ do id = context->next_id++; - while (id == 0 || g_hash_table_contains (context->sources, GUINT_TO_POINTER (id))); + while (id == 0 || g_hash_table_contains (context->sources, &id)); source->context = context; source->source_id = id; g_source_ref (source); - g_hash_table_insert (context->sources, GUINT_TO_POINTER (id), source); + g_hash_table_add (context->sources, &source->source_id); source_add_to_context (source, context); @@ -2088,8 +1952,8 @@ g_source_set_ready_time (GSource *source, * Gets the "ready time" of @source, as set by * g_source_set_ready_time(). * - * Any time before the current monotonic time (including 0) is an - * indication that the source will fire immediately. + * Any time before or equal to the current monotonic time (including 0) + * is an indication that the source will fire immediately. * * Returns: the monotonic ready time, -1 for "never" **/ @@ -2375,7 +2239,7 @@ g_source_unref_internal (GSource *source, g_warning (G_STRLOC ": ref_count == 0, but source was still attached to a context!"); source_remove_from_context (source, context); - g_hash_table_remove (context->sources, GUINT_TO_POINTER (source->source_id)); + g_hash_table_remove (context->sources, &source->source_id); } if (source->source_funcs->finalize) @@ -2484,7 +2348,8 @@ GSource * g_main_context_find_source_by_id (GMainContext *context, guint source_id) { - GSource *source; + GSource *source = NULL; + gconstpointer ptr; g_return_val_if_fail (source_id > 0, NULL); @@ -2492,12 +2357,15 @@ g_main_context_find_source_by_id (GMainContext *context, context = g_main_context_default (); LOCK_CONTEXT (context); - source = g_hash_table_lookup (context->sources, GUINT_TO_POINTER (source_id)); + ptr = g_hash_table_lookup (context->sources, &source_id); + if (ptr) + { + source = G_CONTAINER_OF (ptr, GSource, source_id); + if (SOURCE_DESTROYED (source)) + source = NULL; + } UNLOCK_CONTEXT (context); - if (source && SOURCE_DESTROYED (source)) - source = NULL; - return source; } diff --git a/glib/gmarkup.c b/glib/gmarkup.c index 9422abd..f838ab0 100644 --- a/glib/gmarkup.c +++ b/glib/gmarkup.c @@ -38,60 +38,6 @@ #include "glibintl.h" #include "gthread.h" -/** - * SECTION:markup - * @Title: Simple XML Subset Parser - * @Short_description: parses a subset of XML - * @See_also: [XML Specification](http://www.w3.org/TR/REC-xml/) - * - * The "GMarkup" parser is intended to parse a simple markup format - * that's a subset of XML. This is a small, efficient, easy-to-use - * parser. It should not be used if you expect to interoperate with - * other applications generating full-scale XML, and must not be used if you - * expect to parse untrusted input. However, it's very - * useful for application data files, config files, etc. where you - * know your application will be the only one writing the file. - * Full-scale XML parsers should be able to parse the subset used by - * GMarkup, so you can easily migrate to full-scale XML at a later - * time if the need arises. - * - * GMarkup is not guaranteed to signal an error on all invalid XML; - * the parser may accept documents that an XML parser would not. - * However, XML documents which are not well-formed (which is a - * weaker condition than being valid. See the - * [XML specification](http://www.w3.org/TR/REC-xml/) - * for definitions of these terms.) are not considered valid GMarkup - * documents. - * - * Simplifications to XML include: - * - * - Only UTF-8 encoding is allowed - * - * - No user-defined entities - * - * - Processing instructions, comments and the doctype declaration - * are "passed through" but are not interpreted in any way - * - * - No DTD or validation - * - * The markup format does support: - * - * - Elements - * - * - Attributes - * - * - 5 standard entities: & < > " ' - * - * - Character references - * - * - Sections marked as CDATA - - * ## An example parser # {#example} - * - * Here is an example for a markup parser: - * [markup-example.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/markup-example.c) - */ - G_DEFINE_QUARK (g-markup-error-quark, g_markup_error) typedef enum @@ -1939,7 +1885,7 @@ g_markup_parse_context_get_element (GMarkupParseContext *context) * would merely return the name of the element that is being * processed. * - * Returns: the element stack, which must not be modified + * Returns: (element-type utf8): the element stack, which must not be modified * * Since: 2.16 */ diff --git a/glib/gmem.c b/glib/gmem.c index 07e23af..c72c9cc 100644 --- a/glib/gmem.c +++ b/glib/gmem.c @@ -77,36 +77,6 @@ static GMemVTable glib_mem_vtable = { realloc, }; -/** - * SECTION:memory - * @Short_Description: general memory-handling - * @Title: Memory Allocation - * - * These functions provide support for allocating and freeing memory. - * - * If any call to allocate memory using functions g_new(), g_new0(), g_renew(), - * g_malloc(), g_malloc0(), g_malloc0_n(), g_realloc(), and g_realloc_n() - * fails, the application is terminated. This also means that there is no - * need to check if the call succeeded. On the other hand, the `g_try_...()` family - * of functions returns %NULL on failure that can be used as a check - * for unsuccessful memory allocation. The application is not terminated - * in this case. - * - * As all GLib functions and data structures use `g_malloc()` internally, unless - * otherwise specified, any allocation failure will result in the application - * being terminated. - * - * It's important to match g_malloc() (and wrappers such as g_new()) with - * g_free(), g_slice_alloc() (and wrappers such as g_slice_new()) with - * g_slice_free(), plain malloc() with free(), and (if you're using C++) - * new with delete and new[] with delete[]. Otherwise bad things can happen, - * since these allocators may use different memory pools (and new/delete call - * constructors and destructors). - * - * Since GLib 2.46 g_malloc() is hardcoded to always use the system malloc - * implementation. - */ - /* --- functions --- */ /** * g_malloc: diff --git a/glib/gmessages.c b/glib/gmessages.c index 5460dcf..a47e347 100644 --- a/glib/gmessages.c +++ b/glib/gmessages.c @@ -28,146 +28,6 @@ * MT safe */ -/** - * SECTION:messages - * @Title: Message Output and Debugging Functions - * @Short_description: functions to output messages and help debug applications - * - * These functions provide support for outputting messages. - * - * The g_return family of macros (g_return_if_fail(), - * g_return_val_if_fail(), g_return_if_reached(), - * g_return_val_if_reached()) should only be used for programming - * errors, a typical use case is checking for invalid parameters at - * the beginning of a public function. They should not be used if - * you just mean "if (error) return", they should only be used if - * you mean "if (bug in program) return". The program behavior is - * generally considered undefined after one of these checks fails. - * They are not intended for normal control flow, only to give a - * perhaps-helpful warning before giving up. - * - * Structured logging output is supported using g_log_structured(). This differs - * from the traditional g_log() API in that log messages are handled as a - * collection of key–value pairs representing individual pieces of information, - * rather than as a single string containing all the information in an arbitrary - * format. - * - * The convenience macros g_info(), g_message(), g_debug(), g_warning() and g_error() - * will use the traditional g_log() API unless you define the symbol - * %G_LOG_USE_STRUCTURED before including `glib.h`. But note that even messages - * logged through the traditional g_log() API are ultimatively passed to - * g_log_structured(), so that all log messages end up in same destination. - * If %G_LOG_USE_STRUCTURED is defined, g_test_expect_message() will become - * ineffective for the wrapper macros g_warning() and friends (see - * [Testing for Messages][testing-for-messages]). - * - * The support for structured logging was motivated by the following needs (some - * of which were supported previously; others weren’t): - * * Support for multiple logging levels. - * * Structured log support with the ability to add `MESSAGE_ID`s (see - * g_log_structured()). - * * Moving the responsibility for filtering log messages from the program to - * the log viewer — instead of libraries and programs installing log handlers - * (with g_log_set_handler()) which filter messages before output, all log - * messages are outputted, and the log viewer program (such as `journalctl`) - * must filter them. This is based on the idea that bugs are sometimes hard - * to reproduce, so it is better to log everything possible and then use - * tools to analyse the logs than it is to not be able to reproduce a bug to - * get additional log data. Code which uses logging in performance-critical - * sections should compile out the g_log_structured() calls in - * release builds, and compile them in in debugging builds. - * * A single writer function which handles all log messages in a process, from - * all libraries and program code; rather than multiple log handlers with - * poorly defined interactions between them. This allows a program to easily - * change its logging policy by changing the writer function, for example to - * log to an additional location or to change what logging output fallbacks - * are used. The log writer functions provided by GLib are exposed publicly - * so they can be used from programs’ log writers. This allows log writer - * policy and implementation to be kept separate. - * * If a library wants to add standard information to all of its log messages - * (such as library state) or to redact private data (such as passwords or - * network credentials), it should use a wrapper function around its - * g_log_structured() calls or implement that in the single log writer - * function. - * * If a program wants to pass context data from a g_log_structured() call to - * its log writer function so that, for example, it can use the correct - * server connection to submit logs to, that user data can be passed as a - * zero-length #GLogField to g_log_structured_array(). - * * Color output needed to be supported on the terminal, to make reading - * through logs easier. - * - * ## Using Structured Logging ## {#using-structured-logging} - * - * To use structured logging (rather than the old-style logging), either use - * the g_log_structured() and g_log_structured_array() functions; or define - * `G_LOG_USE_STRUCTURED` before including any GLib header, and use the - * g_message(), g_debug(), g_error() (etc.) macros. - * - * You do not need to define `G_LOG_USE_STRUCTURED` to use g_log_structured(), - * but it is a good idea to avoid confusion. - * - * ## Log Domains ## {#log-domains} - * - * Log domains may be used to broadly split up the origins of log messages. - * Typically, there are one or a few log domains per application or library. - * %G_LOG_DOMAIN should be used to define the default log domain for the current - * compilation unit — it is typically defined at the top of a source file, or in - * the preprocessor flags for a group of source files. - * - * Log domains must be unique, and it is recommended that they are the - * application or library name, optionally followed by a hyphen and a sub-domain - * name. For example, `bloatpad` or `bloatpad-io`. - * - * ## Debug Message Output ## {#debug-message-output} - * - * The default log functions (g_log_default_handler() for the old-style API and - * g_log_writer_default() for the structured API) both drop debug and - * informational messages by default, unless the log domains of those messages - * are listed in the `G_MESSAGES_DEBUG` environment variable (or it is set to - * `all`). - * - * It is recommended that custom log writer functions re-use the - * `G_MESSAGES_DEBUG` environment variable, rather than inventing a custom one, - * so that developers can re-use the same debugging techniques and tools across - * projects. Since GLib 2.68, this can be implemented by dropping messages - * for which g_log_writer_default_would_drop() returns %TRUE. - * - * ## Testing for Messages ## {#testing-for-messages} - * - * With the old g_log() API, g_test_expect_message() and - * g_test_assert_expected_messages() could be used in simple cases to check - * whether some code under test had emitted a given log message. These - * functions have been deprecated with the structured logging API, for several - * reasons: - * * They relied on an internal queue which was too inflexible for many use - * cases, where messages might be emitted in several orders, some - * messages might not be emitted deterministically, or messages might be - * emitted by unrelated log domains. - * * They do not support structured log fields. - * * Examining the log output of code is a bad approach to testing it, and - * while it might be necessary for legacy code which uses g_log(), it should - * be avoided for new code using g_log_structured(). - * - * They will continue to work as before if g_log() is in use (and - * %G_LOG_USE_STRUCTURED is not defined). They will do nothing if used with the - * structured logging API. - * - * Examining the log output of code is discouraged: libraries should not emit to - * `stderr` during defined behaviour, and hence this should not be tested. If - * the log emissions of a library during undefined behaviour need to be tested, - * they should be limited to asserting that the library aborts and prints a - * suitable error message before aborting. This should be done with - * g_test_trap_assert_stderr(). - * - * If it is really necessary to test the structured log messages emitted by a - * particular piece of code – and the code cannot be restructured to be more - * suitable to more conventional unit testing – you should write a custom log - * writer function (see g_log_set_writer_func()) which appends all log messages - * to a queue. When you want to check the log messages, examine and clear the - * queue, ignoring irrelevant log messages (for example, from log domains other - * than the one under test). - */ - #include "config.h" #include @@ -450,7 +310,8 @@ * * Such messages are suppressed by the g_log_default_handler() and * g_log_writer_default() unless the `G_MESSAGES_DEBUG` environment variable is - * set appropriately. + * set appropriately. If you need to set the allowed domains at runtime, use + * g_log_writer_default_set_debug_domains(). * * If structured logging is enabled, this will use g_log_structured(); * otherwise it will use g_log(). See @@ -473,7 +334,8 @@ * * Such messages are suppressed by the g_log_default_handler() and * g_log_writer_default() unless the `G_MESSAGES_DEBUG` environment variable is - * set appropriately. + * set appropriately. If you need to set the allowed domains at runtime, use + * g_log_writer_default_set_debug_domains(). * * If structured logging is enabled, this will use g_log_structured(); * otherwise it will use g_log(). See @@ -566,27 +428,6 @@ static gboolean win32_keep_fatal_message = FALSE; * called with huge strings, is it? */ static gchar fatal_msg_buf[1000] = "Unspecified fatal error encountered, aborting."; -static gchar *fatal_msg_ptr = fatal_msg_buf; - -#undef write -static inline int -dowrite (int fd, - const void *buf, - unsigned int len) -{ - if (win32_keep_fatal_message) - { - memcpy (fatal_msg_ptr, buf, len); - fatal_msg_ptr += len; - *fatal_msg_ptr = 0; - return len; - } - - write (fd, buf, len); - - return len; -} -#define write(fd, buf, len) dowrite(fd, buf, len) #endif @@ -2626,6 +2467,56 @@ log_is_old_api (const GLogField *fields, g_strcmp0 (fields[0].value, "1") == 0); } +static gboolean +domain_found (const gchar *domains, + const char *log_domain) +{ + guint len; + const gchar *found; + + len = strlen (log_domain); + + for (found = strstr (domains, log_domain); found; + found = strstr (found + 1, log_domain)) + { + if ((found == domains || found[-1] == ' ') + && (found[len] == 0 || found[len] == ' ')) + return TRUE; + } + + return FALSE; +} + +static struct { + GRWLock lock; + gchar *domains; + gboolean domains_set; +} g_log_global; + +/** + * g_log_writer_default_set_debug_domains: + * @domains: (nullable) (transfer none): `NULL`-terminated array with domains to be printed. + * `NULL` or an array with no values means none. Array with a single value `"all"` means all. + + * Reset the list of domains to be logged, that might be initially set by the + * `G_MESSAGES_DEBUG` environment variable. This function is thread-safe. + * + * Since: 2.80 + */ +void +g_log_writer_default_set_debug_domains (const gchar * const *domains) +{ + g_rw_lock_writer_lock (&g_log_global.lock); + + g_free (g_log_global.domains); + g_log_global.domains = domains ? + g_strjoinv (" ", (gchar **)domains) : NULL; + + g_log_global.domains_set = TRUE; + + g_rw_lock_writer_unlock (&g_log_global.lock); +} + /* * Internal version of g_log_writer_default_would_drop(), which can * read from either a log_domain or an array of fields. This avoids @@ -2643,14 +2534,22 @@ should_drop_message (GLogLevelFlags log_level, !(log_level >> G_LOG_LEVEL_USER_SHIFT) && !g_log_get_debug_enabled ()) { - const gchar *domains; gsize i; - domains = g_getenv ("G_MESSAGES_DEBUG"); + g_rw_lock_reader_lock (&g_log_global.lock); + + if (G_UNLIKELY (!g_log_global.domains_set)) + { + g_log_global.domains = g_strdup (g_getenv ("G_MESSAGES_DEBUG")); + g_log_global.domains_set = TRUE; + } if ((log_level & INFO_LEVELS) == 0 || - domains == NULL) - return TRUE; + g_log_global.domains == NULL) + { + g_rw_lock_reader_unlock (&g_log_global.lock); + return TRUE; + } if (log_domain == NULL) { @@ -2664,9 +2563,14 @@ should_drop_message (GLogLevelFlags log_level, } } - if (strcmp (domains, "all") != 0 && - (log_domain == NULL || !strstr (domains, log_domain))) - return TRUE; + if (strcmp (g_log_global.domains, "all") != 0 && + (log_domain == NULL || !domain_found (g_log_global.domains, log_domain))) + { + g_rw_lock_reader_unlock (&g_log_global.lock); + return TRUE; + } + + g_rw_lock_reader_unlock (&g_log_global.lock); } return FALSE; @@ -2683,7 +2587,7 @@ should_drop_message (GLogLevelFlags log_level, * * As with g_log_default_handler(), this function drops debug and informational * messages unless their log domain (or `all`) is listed in the space-separated - * `G_MESSAGES_DEBUG` environment variable. + * `G_MESSAGES_DEBUG` environment variable, or by g_log_writer_default_set_debug_domains(). * * This can be used when implementing log writers with the same filtering * behaviour as the default, but a different destination or output format: @@ -2740,7 +2644,7 @@ g_log_writer_default_would_drop (GLogLevelFlags log_level, * * As with g_log_default_handler(), this function drops debug and informational * messages unless their log domain (or `all`) is listed in the space-separated - * `G_MESSAGES_DEBUG` environment variable. + * `G_MESSAGES_DEBUG` environment variable, or set at runtime by g_log_writer_default_set_debug_domains(). * * g_log_writer_default() uses the mask set by g_log_set_always_fatal() to * determine which messages are fatal. When using a custom writer func instead it is @@ -2881,8 +2785,8 @@ _g_log_writer_fallback (GLogLevelFlags log_level, * other logging functions; it should only be used from %GLogWriterFunc * implementations. * - * Note also that the value of this does not depend on `G_MESSAGES_DEBUG`; see - * the docs for g_log_set_debug_enabled(). + * Note also that the value of this does not depend on `G_MESSAGES_DEBUG`, nor + * g_log_writer_default_set_debug_domains(); see the docs for g_log_set_debug_enabled(). * * Returns: %TRUE if debug output is enabled, %FALSE otherwise * @@ -2899,8 +2803,9 @@ g_log_get_debug_enabled (void) * @enabled: %TRUE to enable debug output, %FALSE otherwise * * Enable or disable debug output from the GLib logging system for all domains. - * This value interacts disjunctively with `G_MESSAGES_DEBUG` — if either of - * them would allow a debug message to be outputted, it will be. + * This value interacts disjunctively with `G_MESSAGES_DEBUG` and + * g_log_writer_default_set_debug_domains() — if any of them would allow + * a debug message to be outputted, it will be. * * Note that this should not be used from within library code to enable debug * output — it is intended for external use. @@ -3227,7 +3132,8 @@ escape_string (GString *string) * * - `G_MESSAGES_DEBUG`: A space-separated list of log domains for * which debug and informational messages are printed. By default - * these messages are not printed. + * these messages are not printed. If you need to set the allowed + * domains at runtime, use g_log_writer_default_set_debug_domains(). * * stderr is used for levels %G_LOG_LEVEL_ERROR, %G_LOG_LEVEL_CRITICAL, * %G_LOG_LEVEL_WARNING and %G_LOG_LEVEL_MESSAGE. stdout is used for @@ -3485,12 +3391,25 @@ g_printerr (const gchar *format, * Calculates the maximum space needed to store the output * of the sprintf() function. * - * Returns: the maximum space needed to store the formatted string + * If @format or @args are invalid, `0` is returned. This could happen if, for + * example, @format contains an `%lc` or `%ls` placeholder and @args contains a + * wide character which cannot be represented in multibyte encoding. `0` + * can also be returned legitimately if, for example, @format is `%s` and @args + * is an empty string. The caller is responsible for differentiating these two + * return cases if necessary. It is recommended to not use `%lc` or `%ls` + * placeholders in any case, as their behaviour is locale-dependent. + * + * Returns: the maximum space needed to store the formatted string, or `0` on error */ gsize g_printf_string_upper_bound (const gchar *format, va_list args) { gchar c; - return _g_vsnprintf (&c, 1, format, args) + 1; + int count = _g_vsnprintf (&c, 1, format, args); + + if (count < 0) + return 0; + + return count + 1; } diff --git a/glib/gmessages.h b/glib/gmessages.h index eab6d06..47ba067 100644 --- a/glib/gmessages.h +++ b/glib/gmessages.h @@ -250,6 +250,9 @@ void g_log_writer_default_set_use_stderr (gboolean use_stderr); GLIB_AVAILABLE_IN_2_68 gboolean g_log_writer_default_would_drop (GLogLevelFlags log_level, const char *log_domain); +GLIB_AVAILABLE_IN_2_80 +void g_log_writer_default_set_debug_domains (const gchar * const *domains); + /* G_MESSAGES_DEBUG enablement */ GLIB_AVAILABLE_IN_2_72 diff --git a/glib/gnode.c b/glib/gnode.c index b9a68c2..8e0187f 100644 --- a/glib/gnode.c +++ b/glib/gnode.c @@ -40,43 +40,6 @@ #include "gtestutils.h" /** - * SECTION:trees-nary - * @title: N-ary Trees - * @short_description: trees of data with any number of branches - * - * The #GNode struct and its associated functions provide a N-ary tree - * data structure, where nodes in the tree can contain arbitrary data. - * - * To create a new tree use g_node_new(). - * - * To insert a node into a tree use g_node_insert(), - * g_node_insert_before(), g_node_append() and g_node_prepend(). - * - * To create a new node and insert it into a tree use - * g_node_insert_data(), g_node_insert_data_after(), - * g_node_insert_data_before(), g_node_append_data() - * and g_node_prepend_data(). - * - * To reverse the children of a node use g_node_reverse_children(). - * - * To find a node use g_node_get_root(), g_node_find(), - * g_node_find_child(), g_node_child_index(), g_node_child_position(), - * g_node_first_child(), g_node_last_child(), g_node_nth_child(), - * g_node_first_sibling(), g_node_prev_sibling(), g_node_next_sibling() - * or g_node_last_sibling(). - * - * To get information about a node or tree use G_NODE_IS_LEAF(), - * G_NODE_IS_ROOT(), g_node_depth(), g_node_n_nodes(), - * g_node_n_children(), g_node_is_ancestor() or g_node_max_height(). - * - * To traverse a tree, calling a function for each node visited in the - * traversal, use g_node_traverse() or g_node_children_foreach(). - * - * To remove a node or subtree from a tree use g_node_unlink() or - * g_node_destroy(). - **/ - -/** * GNode: * @data: contains the actual data of the node. * @next: points to the node's next sibling (a sibling is another @@ -170,8 +133,8 @@ g_node_unlink (GNode *node) /** * g_node_copy_deep: * @node: a #GNode - * @copy_func: the function which is called to copy the data inside each node, - * or %NULL to use the original data. + * @copy_func: (scope call): the function which is called to copy the data + * inside each node, or %NULL to use the original data. * @data: data to pass to @copy_func * * Recursively copies a #GNode and its data. @@ -812,7 +775,7 @@ g_node_depth_traverse_level (GNode *node, * depth will not be visited. If max_depth is -1 all nodes in * the tree are visited. If depth is 1, only the root is visited. * If depth is 2, the root and its children are visited. And so on. - * @func: the function to call for each visited #GNode + * @func: (scope call): the function to call for each visited #GNode * @data: user data to pass to the function * * Traverses a tree starting at the given root #GNode. @@ -1235,7 +1198,7 @@ g_node_last_sibling (GNode *node) * @node: a #GNode * @flags: which types of children are to be visited, one of * %G_TRAVERSE_ALL, %G_TRAVERSE_LEAVES and %G_TRAVERSE_NON_LEAVES - * @func: the function to call for each visited node + * @func: (scope call): the function to call for each visited node * @data: user data to pass to the function * * Calls a function for each of the children of a #GNode. Note that it diff --git a/glib/goption.c b/glib/goption.c index 0f6f331..530e0cd 100644 --- a/glib/goption.c +++ b/glib/goption.c @@ -19,166 +19,6 @@ * along with this library; if not, see . */ -/** - * SECTION:goptioncontext - * @Short_description: parses commandline options - * @Title: Commandline option parser - * - * The GOption commandline parser is intended to be a simpler replacement - * for the popt library. It supports short and long commandline options, - * as shown in the following example: - * - * `testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2` - * - * The example demonstrates a number of features of the GOption - * commandline parser: - * - * - Options can be single letters, prefixed by a single dash. - * - * - Multiple short options can be grouped behind a single dash. - * - * - Long options are prefixed by two consecutive dashes. - * - * - Options can have an extra argument, which can be a number, a string or - * a filename. For long options, the extra argument can be appended with - * an equals sign after the option name, which is useful if the extra - * argument starts with a dash, which would otherwise cause it to be - * interpreted as another option. - * - * - Non-option arguments are returned to the application as rest arguments. - * - * - An argument consisting solely of two dashes turns off further parsing, - * any remaining arguments (even those starting with a dash) are returned - * to the application as rest arguments. - * - * Another important feature of GOption is that it can automatically - * generate nicely formatted help output. Unless it is explicitly turned - * off with g_option_context_set_help_enabled(), GOption will recognize - * the `--help`, `-?`, `--help-all` and `--help-groupname` options - * (where `groupname` is the name of a #GOptionGroup) and write a text - * similar to the one shown in the following example to stdout. - * - * |[ - * Usage: - * testtreemodel [OPTION...] - test tree model performance - * - * Help Options: - * -h, --help Show help options - * --help-all Show all help options - * --help-gtk Show GTK Options - * - * Application Options: - * -r, --repeats=N Average over N repetitions - * -m, --max-size=M Test up to 2^M items - * --display=DISPLAY X display to use - * -v, --verbose Be verbose - * -b, --beep Beep when done - * --rand Randomize the data - * ]| - * - * GOption groups options in #GOptionGroups, which makes it easy to - * incorporate options from multiple sources. The intended use for this is - * to let applications collect option groups from the libraries it uses, - * add them to their #GOptionContext, and parse all options by a single call - * to g_option_context_parse(). See gtk_get_option_group() for an example. - * - * If an option is declared to be of type string or filename, GOption takes - * care of converting it to the right encoding; strings are returned in - * UTF-8, filenames are returned in the GLib filename encoding. Note that - * this only works if setlocale() has been called before - * g_option_context_parse(). - * - * Here is a complete example of setting up GOption to parse the example - * commandline above and produce the example help output. - * |[ - * static gint repeats = 2; - * static gint max_size = 8; - * static gboolean verbose = FALSE; - * static gboolean beep = FALSE; - * static gboolean randomize = FALSE; - * - * static GOptionEntry entries[] = - * { - * { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" }, - * { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" }, - * { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL }, - * { "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL }, - * { "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL }, - * G_OPTION_ENTRY_NULL - * }; - * - * int - * main (int argc, char *argv[]) - * { - * GError *error = NULL; - * GOptionContext *context; - * - * context = g_option_context_new ("- test tree model performance"); - * g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE); - * g_option_context_add_group (context, gtk_get_option_group (TRUE)); - * if (!g_option_context_parse (context, &argc, &argv, &error)) - * { - * g_print ("option parsing failed: %s\n", error->message); - * exit (1); - * } - * - * ... - * - * } - * ]| - * - * On UNIX systems, the argv that is passed to main() has no particular - * encoding, even to the extent that different parts of it may have - * different encodings. In general, normal arguments and flags will be - * in the current locale and filenames should be considered to be opaque - * byte strings. Proper use of %G_OPTION_ARG_FILENAME vs - * %G_OPTION_ARG_STRING is therefore important. - * - * Note that on Windows, filenames do have an encoding, but using - * #GOptionContext with the argv as passed to main() will result in a - * program that can only accept commandline arguments with characters - * from the system codepage. This can cause problems when attempting to - * deal with filenames containing Unicode characters that fall outside - * of the codepage. - * - * A solution to this is to use g_win32_get_command_line() and - * g_option_context_parse_strv() which will properly handle full Unicode - * filenames. If you are using #GApplication, this is done - * automatically for you. - * - * The following example shows how you can use #GOptionContext directly - * in order to correctly deal with Unicode filenames on Windows: - * - * |[ - * int - * main (int argc, char **argv) - * { - * GError *error = NULL; - * GOptionContext *context; - * gchar **args; - * - * #ifdef G_OS_WIN32 - * args = g_win32_get_command_line (); - * #else - * args = g_strdupv (argv); - * #endif - * - * // set up context - * - * if (!g_option_context_parse_strv (context, &args, &error)) - * { - * // error happened - * } - * - * ... - * - * g_strfreev (args); - * - * ... - * } - * ]| - */ - #include "config.h" #include @@ -195,6 +35,7 @@ #include "gprintf.h" #include "glibintl.h" +#include "gutilsprivate.h" #if defined G_OS_WIN32 #include @@ -328,7 +169,7 @@ _g_utf8_strwidth (const gchar *p) G_DEFINE_QUARK (g-option-context-error-quark, g_option_error) /** - * g_option_context_new: + * g_option_context_new: (constructor) * @parameter_string: (nullable): a string which is displayed in * the first line of `--help` output, after the usage summary * `programname [OPTION...]` @@ -353,7 +194,7 @@ G_DEFINE_QUARK (g-option-context-error-quark, g_option_error) * function set with g_option_context_set_translate_func(), so * it should normally be passed untranslated. * - * Returns: a newly created #GOptionContext, which must be + * Returns: (transfer full): a newly created #GOptionContext, which must be * freed with g_option_context_free() after use. * * Since: 2.6 @@ -381,7 +222,7 @@ g_option_context_new (const gchar *parameter_string) /** * g_option_context_free: - * @context: a #GOptionContext + * @context: (transfer full): a #GOptionContext * * Frees context and all the groups which have been * added to it. @@ -1973,10 +1814,7 @@ g_option_context_parse (GOptionContext *context, else prgname = platform_get_argv0 (); - if (prgname) - g_set_prgname (prgname); - else - g_set_prgname (""); + g_set_prgname_once (prgname ? prgname : ""); g_free (prgname); } diff --git a/glib/gpathbuf.c b/glib/gpathbuf.c index c7cf048..e51f3f1 100644 --- a/glib/gpathbuf.c +++ b/glib/gpathbuf.c @@ -15,15 +15,13 @@ #include "gstrfuncs.h" /** - * SECTION:gpathbuf - * @Title: GPathBuf - * @Short_description: A mutable path builder + * GPathBuf: * * `GPathBuf` is a helper type that allows you to easily build paths from * individual elements, using the platform specific conventions for path * separators. * - * |[ + * ```c * g_auto (GPathBuf) path; * * g_path_buf_init (&path); @@ -34,11 +32,11 @@ * * g_autofree char *echo = g_path_buf_to_path (&path); * g_assert_cmpstr (echo, ==, "/usr/bin/echo"); - * ]| + * ``` * * You can also load a full path and then operate on its components: * - * |[ + * ```c * g_auto (GPathBuf) path; * * g_path_buf_init_from_path (&path, "/usr/bin/echo"); @@ -48,9 +46,9 @@ * * g_autofree char *sh = g_path_buf_to_path (&path); * g_assert_cmpstr (sh, ==, "/usr/bin/sh"); - * ]| + * ``` * - * `GPathBuf` is available since GLib 2.76. + * Since: 2.76 */ typedef struct { diff --git a/glib/gpathbuf.h b/glib/gpathbuf.h index b423419..1ea01f0 100644 --- a/glib/gpathbuf.h +++ b/glib/gpathbuf.h @@ -16,13 +16,6 @@ G_BEGIN_DECLS typedef struct _GPathBuf GPathBuf; -/** - * GPathBuf: (copy-func g_path_buf_copy) (free-func g_path_buf_free) - * - * A mutable path builder. - * - * Since: 2.76 - */ struct _GPathBuf { /*< private >*/ diff --git a/glib/gpattern.c b/glib/gpattern.c index 09bdd5a..bf61da3 100644 --- a/glib/gpattern.c +++ b/glib/gpattern.c @@ -31,32 +31,24 @@ #include "gutils.h" /** - * SECTION:patterns - * @title: Glob-style pattern matching - * @short_description: matches strings against patterns containing '*' - * (wildcard) and '?' (joker) - * - * The g_pattern_match* functions match a string - * against a pattern containing '*' and '?' wildcards with similar - * semantics as the standard glob() function: '*' matches an arbitrary, + * GPatternSpec: + * + * A `GPatternSpec` struct is the 'compiled' form of a glob-style pattern. + * + * The [func@GLib.pattern_match_simple] and [method@GLib.PatternSpec.match] functions + * match a string against a pattern containing '*' and '?' wildcards with similar + * semantics as the standard `glob()` function: '*' matches an arbitrary, * possibly empty, string, '?' matches an arbitrary character. * - * Note that in contrast to glob(), the '/' character can be matched by + * Note that in contrast to `glob()`, the '/' character can be matched by * the wildcards, there are no '[...]' character ranges and '*' and '?' * can not be escaped to include them literally in a pattern. * - * When multiple strings must be matched against the same pattern, it - * is better to compile the pattern to a #GPatternSpec using - * g_pattern_spec_new() and use g_pattern_match_string() instead of - * g_pattern_match_simple(). This avoids the overhead of repeated + * When multiple strings must be matched against the same pattern, it is better + * to compile the pattern to a [struct@GLib.PatternSpec] using + * [ctor@GLib.PatternSpec.new] and use [method@GLib.PatternSpec.match_string] + * instead of [func@GLib.pattern_match_simple]. This avoids the overhead of repeated * pattern compilation. - **/ - -/** - * GPatternSpec: - * - * A GPatternSpec struct is the 'compiled' form of a pattern. This - * structure is opaque and its fields cannot be accessed directly. */ /* keep enum and structure of gpattern.c and patterntest.c in sync */ diff --git a/glib/gprintf.c b/glib/gprintf.c index a0ccef9..7cf30d2 100644 --- a/glib/gprintf.c +++ b/glib/gprintf.c @@ -31,7 +31,7 @@ /** * g_printf: * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @...: the arguments to insert in the output. * * An implementation of the standard printf() function which supports @@ -65,7 +65,7 @@ g_printf (gchar const *format, * g_fprintf: * @file: (not nullable): the stream to write to. * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @...: the arguments to insert in the output. * * An implementation of the standard fprintf() function which supports @@ -98,7 +98,7 @@ g_fprintf (FILE *file, * is up to the caller to ensure that the allocated buffer is large * enough to hold the formatted result * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @...: the arguments to insert in the output. * * An implementation of the standard sprintf() function which supports @@ -136,7 +136,7 @@ g_sprintf (gchar *string, * @n: the maximum number of bytes to produce (including the * terminating nul character). * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @...: the arguments to insert in the output. * * A safer form of the standard sprintf() function. The output is guaranteed @@ -179,7 +179,7 @@ g_snprintf (gchar *string, /** * g_vprintf: * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of arguments to insert in the output. * * An implementation of the standard vprintf() function which supports @@ -204,7 +204,7 @@ g_vprintf (gchar const *format, * g_vfprintf: * @file: (not nullable): the stream to write to. * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of arguments to insert in the output. * * An implementation of the standard fprintf() function which supports @@ -230,7 +230,7 @@ g_vfprintf (FILE *file, * g_vsprintf: * @string: the buffer to hold the output. * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of arguments to insert in the output. * * An implementation of the standard vsprintf() function which supports @@ -259,7 +259,7 @@ g_vsprintf (gchar *string, * @n: the maximum number of bytes to produce (including the * terminating nul character). * @format: a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of arguments to insert in the output. * * A safer form of the standard vsprintf() function. The output is guaranteed @@ -300,7 +300,7 @@ g_vsnprintf (gchar *string, * @string: (not optional) (nullable): the return location for the newly-allocated string, * which will be %NULL if (and only if) this function fails * @format: (not nullable): a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of arguments to insert in the output. * * An implementation of the GNU vasprintf() function which supports @@ -359,19 +359,29 @@ g_vasprintf (gchar **string, { va_list args2; + char c; + int max_len; va_copy (args2, args); - *string = g_new (gchar, g_printf_string_upper_bound (format, args)); + max_len = _g_vsnprintf (&c, 1, format, args); + if (max_len < 0) + { + /* This can happen if @format contains `%ls` or `%lc` and @args contains + * something not representable in the current locale’s encoding (which + * should be UTF-8, but ymmv). Basically: don’t use `%ls` or `%lc`. */ + va_end (args2); + *string = NULL; + return -1; + } + + *string = g_new (gchar, (size_t) max_len + 1); len = _g_vsprintf (*string, format, args2); va_end (args2); - if (len < 0) - { - g_free (*string); - *string = NULL; - } + /* _g_vsprintf() should have exactly the same failure modes as _g_vsnprintf() */ + g_assert (len >= 0); } #endif diff --git a/glib/gqsort.c b/glib/gqsort.c index a0edcd4..9d6bb1e 100644 --- a/glib/gqsort.c +++ b/glib/gqsort.c @@ -286,7 +286,7 @@ msort_r (void *b, size_t n, size_t s, GCompareDataFunc cmp, void *arg) * @pbase: (not nullable): start of array to sort * @total_elems: elements in the array * @size: size of each element - * @compare_func: function to compare elements + * @compare_func: (scope call): function to compare elements * @user_data: data to pass to @compare_func * * This is just like the standard C qsort() function, but diff --git a/glib/gquark.c b/glib/gquark.c index 12ec34c..0b6863a 100644 --- a/glib/gquark.c +++ b/glib/gquark.c @@ -68,40 +68,34 @@ g_quark_init (void) } /** - * SECTION:quarks - * @title: Quarks - * @short_description: a 2-way association between a string and a - * unique integer identifier + * GQuark: + * + * A GQuark is a non-zero integer which uniquely identifies a + * particular string. * - * Quarks are associations between strings and integer identifiers. - * Given either the string or the #GQuark identifier it is possible to + * A GQuark value of zero is associated to `NULL`. + * + * Given either the string or the `GQuark` identifier it is possible to * retrieve the other. * - * Quarks are used for both [datasets][glib-Datasets] and - * [keyed data lists][glib-Keyed-Data-Lists]. + * Quarks are used for both + * [datasets and keyed data lists](datalist-and-dataset.html). * - * To create a new quark from a string, use g_quark_from_string() or - * g_quark_from_static_string(). + * To create a new quark from a string, use [func@GLib.quark_from_string] + * or [func@GLib.quark_from_static_string]. * - * To find the string corresponding to a given #GQuark, use - * g_quark_to_string(). + * To find the string corresponding to a given `GQuark`, use + * [func@GLib.quark_to_string]. * - * To find the #GQuark corresponding to a given string, use - * g_quark_try_string(). + * To find the `GQuark` corresponding to a given string, use + * [func@GLib.quark_try_string]. * * Another use for the string pool maintained for the quark functions - * is string interning, using g_intern_string() or - * g_intern_static_string(). An interned string is a canonical + * is string interning, using [func@GLib.intern_string] or + * [func@GLib.intern_static_string]. An interned string is a canonical * representation for a string. One important advantage of interned * strings is that they can be compared for equality by a simple - * pointer comparison, rather than using strcmp(). - */ - -/** - * GQuark: - * - * A GQuark is a non-zero integer which uniquely identifies a - * particular string. A GQuark value of zero is associated to %NULL. + * pointer comparison, rather than using `strcmp()`. */ /** diff --git a/glib/gqueue.c b/glib/gqueue.c index a5c4f18..07805ff 100644 --- a/glib/gqueue.c +++ b/glib/gqueue.c @@ -24,35 +24,6 @@ * MT safe */ -/** - * SECTION:queue - * @Title: Double-ended Queues - * @Short_description: double-ended queue data structure - * - * The #GQueue structure and its associated functions provide a standard - * queue data structure. Internally, GQueue uses the same data structure - * as #GList to store elements with the same complexity over - * insertion/deletion (O(1)) and access/search (O(n)) operations. - * - * The data contained in each element can be either integer values, by - * using one of the [Type Conversion Macros][glib-Type-Conversion-Macros], - * or simply pointers to any type of data. - * - * As with all other GLib data structures, #GQueue is not thread-safe. - * For a thread-safe queue, use #GAsyncQueue. - * - * To create a new GQueue, use g_queue_new(). - * - * To initialize a statically-allocated GQueue, use %G_QUEUE_INIT or - * g_queue_init(). - * - * To add elements, use g_queue_push_head(), g_queue_push_head_link(), - * g_queue_push_tail() and g_queue_push_tail_link(). - * - * To remove elements, use g_queue_pop_head() and g_queue_pop_tail(). - * - * To free the entire queue, use g_queue_free(). - */ #include "config.h" #include "gqueue.h" @@ -256,7 +227,7 @@ g_queue_copy (GQueue *queue) /** * g_queue_foreach: * @queue: a #GQueue - * @func: the function to call for each element's data + * @func: (scope call): the function to call for each element's data * @user_data: user data to pass to @func * * Calls @func for each element in the queue passing @user_data to the @@ -310,7 +281,7 @@ g_queue_find (GQueue *queue, * g_queue_find_custom: * @queue: a #GQueue * @data: user data passed to @func - * @func: a #GCompareFunc to call for each element. It should return 0 + * @func: (scope call): a #GCompareFunc to call for each element. It should return 0 * when the desired element is found * * Finds an element in a #GQueue, using a supplied function to find the @@ -337,7 +308,7 @@ g_queue_find_custom (GQueue *queue, /** * g_queue_sort: * @queue: a #GQueue - * @compare_func: the #GCompareDataFunc used to sort @queue. This function + * @compare_func: (scope call): the #GCompareDataFunc used to sort @queue. This function * is passed two elements of the queue and should return 0 if they are * equal, a negative value if the first comes before the second, and * a positive value if the second comes before the first. @@ -1150,7 +1121,7 @@ g_queue_insert_after_link (GQueue *queue, * g_queue_insert_sorted: * @queue: a #GQueue * @data: the data to insert - * @func: the #GCompareDataFunc used to compare elements in the queue. It is + * @func: (scope call): the #GCompareDataFunc used to compare elements in the queue. It is * called with two elements of the @queue and @user_data. It should * return 0 if the elements are equal, a negative value if the first * element comes before the second, and a positive value if the second diff --git a/glib/grand.c b/glib/grand.c index 5fb4457..302b74b 100644 --- a/glib/grand.c +++ b/glib/grand.c @@ -63,57 +63,6 @@ #endif /** - * SECTION:random_numbers - * @title: Random Numbers - * @short_description: pseudo-random number generator - * - * The following functions allow you to use a portable, fast and good - * pseudo-random number generator (PRNG). - * - * Do not use this API for cryptographic purposes such as key - * generation, nonces, salts or one-time pads. - * - * This PRNG is suitable for non-cryptographic use such as in games - * (shuffling a card deck, generating levels), generating data for - * a test suite, etc. If you need random data for cryptographic - * purposes, it is recommended to use platform-specific APIs such - * as `/dev/random` on UNIX, or CryptGenRandom() on Windows. - * - * GRand uses the Mersenne Twister PRNG, which was originally - * developed by Makoto Matsumoto and Takuji Nishimura. Further - * information can be found at - * [this page](http://www.math.sci.hiroshima-u.ac.jp/~m-mat/MT/emt.html). - * - * If you just need a random number, you simply call the g_random_* - * functions, which will create a globally used #GRand and use the - * according g_rand_* functions internally. Whenever you need a - * stream of reproducible random numbers, you better create a - * #GRand yourself and use the g_rand_* functions directly, which - * will also be slightly faster. Initializing a #GRand with a - * certain seed will produce exactly the same series of random - * numbers on all platforms. This can thus be used as a seed for - * e.g. games. - * - * The g_rand*_range functions will return high quality equally - * distributed random numbers, whereas for example the - * `(g_random_int()%max)` approach often - * doesn't yield equally distributed numbers. - * - * GLib changed the seeding algorithm for the pseudo-random number - * generator Mersenne Twister, as used by #GRand. This was necessary, - * because some seeds would yield very bad pseudo-random streams. - * Also the pseudo-random integers generated by g_rand*_int_range() - * will have a slightly better equal distribution with the new - * version of GLib. - * - * The original seeding and generation algorithms, as found in - * GLib 2.0.x, can be used instead of the new ones by setting the - * environment variable `G_RANDOM_VERSION` to the value of '2.0'. - * Use the GLib-2.0 algorithms only if you have sequences of numbers - * generated with Glib-2.0 that you need to reproduce exactly. - */ - -/** * GRand: * * The GRand struct is an opaque data structure. It should only be @@ -170,12 +119,12 @@ struct _GRand }; /** - * g_rand_new_with_seed: + * g_rand_new_with_seed: (constructor) * @seed: a value to initialize the random number generator * * Creates a new random number generator initialized with @seed. * - * Returns: the new #GRand + * Returns: (transfer full): the new #GRand **/ GRand* g_rand_new_with_seed (guint32 seed) @@ -186,14 +135,14 @@ g_rand_new_with_seed (guint32 seed) } /** - * g_rand_new_with_seed_array: + * g_rand_new_with_seed_array: (constructor) * @seed: an array of seeds to initialize the random number generator * @seed_length: an array of seeds to initialize the random number * generator * * Creates a new random number generator initialized with @seed. * - * Returns: the new #GRand + * Returns: (transfer full): the new #GRand * * Since: 2.4 */ @@ -207,7 +156,7 @@ g_rand_new_with_seed_array (const guint32 *seed, } /** - * g_rand_new: + * g_rand_new: (constructor) * * Creates a new random number generator initialized with a seed taken * either from `/dev/urandom` (if existing) or from the current time @@ -215,7 +164,7 @@ g_rand_new_with_seed_array (const guint32 *seed, * * On Windows, the seed is taken from rand_s(). * - * Returns: the new #GRand + * Returns: (transfer full): the new #GRand */ GRand* g_rand_new (void) @@ -310,7 +259,7 @@ g_rand_free (GRand *rand) * This way you can take a snapshot of the random number generator for * replaying later. * - * Returns: the new #GRand + * Returns: (transfer full): the new #GRand * * Since: 2.4 */ diff --git a/glib/grcbox.c b/glib/grcbox.c index 2538157..4238247 100644 --- a/glib/grcbox.c +++ b/glib/grcbox.c @@ -34,136 +34,6 @@ #include -/** - * SECTION:rcbox - * @Title: Reference counted data - * @Short_description: Allocated memory with reference counting semantics - * - * A "reference counted box", or "RcBox", is an opaque wrapper data type - * that is guaranteed to be as big as the size of a given data type, and - * which augments the given data type with reference counting semantics - * for its memory management. - * - * RcBox is useful if you have a plain old data type, like a structure - * typically placed on the stack, and you wish to provide additional API - * to use it on the heap; or if you want to implement a new type to be - * passed around by reference without necessarily implementing copy/free - * semantics or your own reference counting. - * - * The typical use is: - * - * |[ - * typedef struct { - * char *name; - * char *address; - * char *city; - * char *state; - * int age; - * } Person; - * - * Person * - * person_new (void) - * { - * return g_rc_box_new0 (Person); - * } - * ]| - * - * Every time you wish to acquire a reference on the memory, you should - * call g_rc_box_acquire(); similarly, when you wish to release a reference - * you should call g_rc_box_release(): - * - * |[ - * // Add a Person to the Database; the Database acquires ownership - * // of the Person instance - * void - * add_person_to_database (Database *db, Person *p) - * { - * db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p)); - * } - * - * // Removes a Person from the Database; the reference acquired by - * // add_person_to_database() is released here - * void - * remove_person_from_database (Database *db, Person *p) - * { - * db->persons = g_list_remove (db->persons, p); - * g_rc_box_release (p); - * } - * ]| - * - * If you have additional memory allocated inside the structure, you can - * use g_rc_box_release_full(), which takes a function pointer, which - * will be called if the reference released was the last: - * - * |[ - * void - * person_clear (Person *p) - * { - * g_free (p->name); - * g_free (p->address); - * g_free (p->city); - * g_free (p->state); - * } - * - * void - * remove_person_from_database (Database *db, Person *p) - * { - * db->persons = g_list_remove (db->persons, p); - * g_rc_box_release_full (p, (GDestroyNotify) person_clear); - * } - * ]| - * - * If you wish to transfer the ownership of a reference counted data - * type without increasing the reference count, you can use g_steal_pointer(): - * - * |[ - * Person *p = g_rc_box_new (Person); - * - * // fill_person_details() is defined elsewhere - * fill_person_details (p); - * - * // add_person_to_database_no_ref() is defined elsewhere; it adds - * // a Person to the Database without taking a reference - * add_person_to_database_no_ref (db, g_steal_pointer (&p)); - * ]| - * - * ## Thread safety - * - * The reference counting operations on data allocated using g_rc_box_alloc(), - * g_rc_box_new(), and g_rc_box_dup() are not thread safe; it is your code's - * responsibility to ensure that references are acquired are released on the - * same thread. - * - * If you need thread safe reference counting, see the [atomic reference counted - * data][arcbox] API. - * - * ## Automatic pointer clean up - * - * If you want to add g_autoptr() support to your plain old data type through - * reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and - * g_rc_box_release(): - * - * |[ - * G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release) - * ]| - * - * If you need to clear the contents of the data, you will need to use an - * ancillary function that calls g_rc_box_release_full(): - * - * |[ - * static void - * my_data_struct_release (MyDataStruct *data) - * { - * // my_data_struct_clear() is defined elsewhere - * g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear); - * } - * - * G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release) - * ]| - * - * Since: 2.58 - */ - /* We use the same alignment as GTypeInstance and GNU libc's malloc */ #define ALIGN_STRUCT(offset) ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT) diff --git a/glib/grefcount.c b/glib/grefcount.c index f682de7..aac7887 100644 --- a/glib/grefcount.c +++ b/glib/grefcount.c @@ -18,29 +18,6 @@ * License along with this library; if not, see . */ -/** - * SECTION:refcount - * @Title: Reference counting - * @Short_description: Reference counting types and functions - * - * Reference counting is a garbage collection mechanism that is based on - * assigning a counter to a data type, or any memory area; the counter is - * increased whenever a new reference to that data type is acquired, and - * decreased whenever the reference is released. Once the last reference - * is released, the resources associated to that data type are freed. - * - * GLib uses reference counting in many of its data types, and provides - * the #grefcount and #gatomicrefcount types to implement safe and atomic - * reference counting semantics in new data types. - * - * It is important to note that #grefcount and #gatomicrefcount should be - * considered completely opaque types; you should always use the provided - * API to increase and decrease the counters, and you should never check - * their content directly, or compare their content with other values. - * - * Since: 2.58 - */ - #include "config.h" #include "grefcount.h" diff --git a/glib/grefstring.c b/glib/grefstring.c index f201897..167c24a 100644 --- a/glib/grefstring.c +++ b/glib/grefstring.c @@ -18,74 +18,6 @@ * License along with this library; if not, see . */ -/** - * SECTION:refstring - * @Title: Reference counted strings - * @Short_description: Strings with reference counted memory management - * - * Reference counted strings are normal C strings that have been augmented - * with a reference counter to manage their resources. You allocate a new - * reference counted string and acquire and release references as needed, - * instead of copying the string among callers; when the last reference on - * the string is released, the resources allocated for it are freed. - * - * Typically, reference counted strings can be used when parsing data from - * files and storing them into data structures that are passed to various - * callers: - * - * |[ - * PersonDetails * - * person_details_from_data (const char *data) - * { - * // Use g_autoptr() to simplify error cases - * g_autoptr(GRefString) full_name = NULL; - * g_autoptr(GRefString) address = NULL; - * g_autoptr(GRefString) city = NULL; - * g_autoptr(GRefString) state = NULL; - * g_autoptr(GRefString) zip_code = NULL; - * - * // parse_person_details() is defined elsewhere; returns refcounted strings - * if (!parse_person_details (data, &full_name, &address, &city, &state, &zip_code)) - * return NULL; - * - * if (!validate_zip_code (zip_code)) - * return NULL; - * - * // add_address_to_cache() and add_full_name_to_cache() are defined - * // elsewhere; they add strings to various caches, using refcounted - * // strings to avoid copying data over and over again - * add_address_to_cache (address, city, state, zip_code); - * add_full_name_to_cache (full_name); - * - * // person_details_new() is defined elsewhere; it takes a reference - * // on each string - * PersonDetails *res = person_details_new (full_name, - * address, - * city, - * state, - * zip_code); - * - * return res; - * } - * ]| - * - * In the example above, we have multiple functions taking the same strings - * for different uses; with typical C strings, we'd have to copy the strings - * every time the life time rules of the data differ from the life time of - * the string parsed from the original buffer. With reference counted strings, - * each caller can take a reference on the data, and keep it as long as it - * needs to own the string. - * - * Reference counted strings can also be "interned" inside a global table - * owned by GLib; while an interned string has at least a reference, creating - * a new interned reference counted string with the same contents will return - * a reference to the existing string instead of creating a new reference - * counted string instance. Once the string loses its last reference, it will - * be automatically removed from the global interned strings table. - * - * Since: 2.58 - */ - #include "config.h" #include "grefstring.h" diff --git a/glib/gregex.c b/glib/gregex.c index 116ecac..d1633a8 100644 --- a/glib/gregex.c +++ b/glib/gregex.c @@ -40,14 +40,13 @@ #include "gthread.h" /** - * SECTION:gregex - * @title: Perl-compatible regular expressions - * @short_description: matches strings against regular expressions - * @see_also: [Regular expression syntax][glib-regex-syntax] + * GRegex: * - * The g_regex_*() functions implement regular - * expression pattern matching using syntax and semantics similar to - * Perl regular expression. + * A `GRegex` is the "compiled" form of a regular expression pattern. + * + * `GRegex` implements regular expression pattern matching using syntax and + * semantics similar to Perl regular expression. See the + * [PCRE documentation](man:pcrepattern(3)) for the syntax definition. * * Some functions accept a @start_position argument, setting it differs * from just passing over a shortened string and setting %G_REGEX_MATCH_NOTBOL @@ -81,23 +80,23 @@ * The behaviour of the dot, circumflex, and dollar metacharacters are * affected by newline characters, the default is to recognize any newline * character (the same characters recognized by "\R"). This can be changed - * with %G_REGEX_NEWLINE_CR, %G_REGEX_NEWLINE_LF and %G_REGEX_NEWLINE_CRLF - * compile options, and with %G_REGEX_MATCH_NEWLINE_ANY, - * %G_REGEX_MATCH_NEWLINE_CR, %G_REGEX_MATCH_NEWLINE_LF and - * %G_REGEX_MATCH_NEWLINE_CRLF match options. These settings are also - * relevant when compiling a pattern if %G_REGEX_EXTENDED is set, and an + * with `G_REGEX_NEWLINE_CR`, `G_REGEX_NEWLINE_LF` and `G_REGEX_NEWLINE_CRLF` + * compile options, and with `G_REGEX_MATCH_NEWLINE_ANY`, + * `G_REGEX_MATCH_NEWLINE_CR`, `G_REGEX_MATCH_NEWLINE_LF` and + * `G_REGEX_MATCH_NEWLINE_CRLF` match options. These settings are also + * relevant when compiling a pattern if `G_REGEX_EXTENDED` is set, and an * unescaped "#" outside a character class is encountered. This indicates * a comment that lasts until after the next newline. * - * Creating and manipulating the same #GRegex structure from different - * threads is not a problem as #GRegex does not modify its internal - * state between creation and destruction, on the other hand #GMatchInfo + * Creating and manipulating the same `GRegex` structure from different + * threads is not a problem as `GRegex` does not modify its internal + * state between creation and destruction, on the other hand `GMatchInfo` * is not threadsafe. * * The regular expressions low-level functionalities are obtained through - * the excellent - * [PCRE](http://www.pcre.org/) - * library written by Philip Hazel. + * the excellent [PCRE](http://www.pcre.org/) library written by Philip Hazel. + * + * Since: 2.14 */ #define G_REGEX_PCRE_GENERIC_MASK (PCRE2_ANCHORED | \ @@ -3396,7 +3395,7 @@ g_regex_replace_literal (const GRegex *regex, * @string_len: the length of @string, in bytes, or -1 if @string is nul-terminated * @start_position: starting index of the string to match, in bytes * @match_options: options for the match - * @eval: a function to call for each match + * @eval: (scope call): a function to call for each match * @user_data: user data to pass to the function * @error: location to store the error occurring, or %NULL to ignore errors * diff --git a/glib/gregex.h b/glib/gregex.h index 30eb387..fd2bf81 100644 --- a/glib/gregex.h +++ b/glib/gregex.h @@ -413,14 +413,6 @@ typedef enum G_REGEX_MATCH_NOTEMPTY_ATSTART = 1 << 28 } GRegexMatchFlags; -/** - * GRegex: - * - * A GRegex is the "compiled" form of a regular expression pattern. - * This structure is opaque and its fields cannot be accessed directly. - * - * Since: 2.14 - */ typedef struct _GRegex GRegex; diff --git a/glib/gscanner.c b/glib/gscanner.c index 451feb6..cb7e811 100644 --- a/glib/gscanner.c +++ b/glib/gscanner.c @@ -55,15 +55,6 @@ /** - * SECTION:scanner - * @title: Lexical Scanner - * @short_description: a general purpose lexical scanner - * - * The #GScanner and its associated functions provide a - * general purpose lexical scanner. - */ - -/** * GScannerMsgFunc: * @scanner: a #GScanner * @message: the message @@ -196,7 +187,7 @@ * @next_position: char number of the last token from g_scanner_peek_next_token() * @msg_handler: handler function for _warn and _error * - * The data structure representing a lexical scanner. + * `GScanner` provides a general-purpose lexical scanner. * * You should set @input_name after creating the scanner, since * it is used by the default message handler when displaying @@ -904,7 +895,7 @@ g_scanner_foreach_internal (gpointer _key, * g_scanner_scope_foreach_symbol: * @scanner: a #GScanner * @scope_id: the scope id - * @func: the function to call for each symbol/value pair + * @func: (scope call): the function to call for each symbol/value pair * @user_data: user data to pass to the function * * Calls the given function for each of the symbol/value pairs diff --git a/glib/gscripttable.h b/glib/gscripttable.h index 2cf4fd2..f639a04 100644 --- a/glib/gscripttable.h +++ b/glib/gscripttable.h @@ -2799,8 +2799,7 @@ static const struct { { 0x2e80, 26, G_UNICODE_SCRIPT_HAN }, { 0x2e9b, 89, G_UNICODE_SCRIPT_HAN }, { 0x2f00, 214, G_UNICODE_SCRIPT_HAN }, - { 0x2ff0, 12, G_UNICODE_SCRIPT_COMMON }, - { 0x3000, 5, G_UNICODE_SCRIPT_COMMON }, + { 0x2ff0, 21, G_UNICODE_SCRIPT_COMMON }, { 0x3005, 1, G_UNICODE_SCRIPT_HAN }, { 0x3006, 1, G_UNICODE_SCRIPT_COMMON }, { 0x3007, 1, G_UNICODE_SCRIPT_HAN }, @@ -2824,6 +2823,7 @@ static const struct { { 0x3190, 16, G_UNICODE_SCRIPT_COMMON }, { 0x31a0, 32, G_UNICODE_SCRIPT_BOPOMOFO }, { 0x31c0, 36, G_UNICODE_SCRIPT_COMMON }, + { 0x31ef, 1, G_UNICODE_SCRIPT_COMMON }, { 0x31f0, 16, G_UNICODE_SCRIPT_KATAKANA }, { 0x3200, 31, G_UNICODE_SCRIPT_HANGUL }, { 0x3220, 64, G_UNICODE_SCRIPT_COMMON }, @@ -3341,6 +3341,7 @@ static const struct { { 0x2b740, 222, G_UNICODE_SCRIPT_HAN }, { 0x2b820, 5762, G_UNICODE_SCRIPT_HAN }, { 0x2ceb0, 7473, G_UNICODE_SCRIPT_HAN }, + { 0x2ebf0, 622, G_UNICODE_SCRIPT_HAN }, { 0x2f800, 542, G_UNICODE_SCRIPT_HAN }, { 0x30000, 4939, G_UNICODE_SCRIPT_HAN }, { 0x31350, 4192, G_UNICODE_SCRIPT_HAN }, diff --git a/glib/gsequence.c b/glib/gsequence.c index ead827d..81f0d08 100644 --- a/glib/gsequence.c +++ b/glib/gsequence.c @@ -25,54 +25,6 @@ #include "gmem.h" #include "gtestutils.h" #include "gslice.h" -/** - * SECTION:sequence - * @title: Sequences - * @short_description: scalable lists - * - * The #GSequence data structure has the API of a list, but is - * implemented internally with a balanced binary tree. This means that - * most of the operations (access, search, insertion, deletion, ...) on - * #GSequence are O(log(n)) in average and O(n) in worst case for time - * complexity. But, note that maintaining a balanced sorted list of n - * elements is done in time O(n log(n)). - * The data contained in each element can be either integer values, by using - * of the [Type Conversion Macros][glib-Type-Conversion-Macros], or simply - * pointers to any type of data. - * - * A #GSequence is accessed through "iterators", represented by a - * #GSequenceIter. An iterator represents a position between two - * elements of the sequence. For example, the "begin" iterator - * represents the gap immediately before the first element of the - * sequence, and the "end" iterator represents the gap immediately - * after the last element. In an empty sequence, the begin and end - * iterators are the same. - * - * Some methods on #GSequence operate on ranges of items. For example - * g_sequence_foreach_range() will call a user-specified function on - * each element with the given range. The range is delimited by the - * gaps represented by the passed-in iterators, so if you pass in the - * begin and end iterators, the range in question is the entire - * sequence. - * - * The function g_sequence_get() is used with an iterator to access the - * element immediately following the gap that the iterator represents. - * The iterator is said to "point" to that element. - * - * Iterators are stable across most operations on a #GSequence. For - * example an iterator pointing to some element of a sequence will - * continue to point to that element even after the sequence is sorted. - * Even moving an element to another sequence using for example - * g_sequence_move_range() will not invalidate the iterators pointing - * to it. The only operation that will invalidate an iterator is when - * the element it points to is removed from any sequence. - * - * To sort the data, either use g_sequence_insert_sorted() or - * g_sequence_insert_sorted_iter() to add data to the #GSequence or, if - * you want to add a large amount of data, it is more efficient to call - * g_sequence_sort() or g_sequence_sort_iter() after doing unsorted - * insertions. - */ /** * GSequenceIter: @@ -303,7 +255,7 @@ g_sequence_free (GSequence *seq) * g_sequence_foreach_range: * @begin: a #GSequenceIter * @end: a #GSequenceIter - * @func: a #GFunc + * @func: (scope call): a #GFunc * @user_data: user data passed to @func * * Calls @func for each item in the range (@begin, @end) passing @@ -345,7 +297,7 @@ g_sequence_foreach_range (GSequenceIter *begin, /** * g_sequence_foreach: * @seq: a #GSequence - * @func: the function to call for each item in @seq + * @func: (scope call): the function to call for each item in @seq * @user_data: user data passed to @func * * Calls @func for each item in the sequence passing @user_data @@ -675,7 +627,7 @@ g_sequence_move_range (GSequenceIter *dest, /** * g_sequence_sort: * @seq: a #GSequence - * @cmp_func: the function used to sort the sequence + * @cmp_func: (scope call): the function used to sort the sequence * @cmp_data: user data passed to @cmp_func * * Sorts @seq using @cmp_func. @@ -707,7 +659,7 @@ g_sequence_sort (GSequence *seq, * g_sequence_insert_sorted: * @seq: a #GSequence * @data: the data to insert - * @cmp_func: the function used to compare items in the sequence + * @cmp_func: (scope call): the function used to compare items in the sequence * @cmp_data: user data passed to @cmp_func. * * Inserts @data into @seq using @cmp_func to determine the new @@ -749,7 +701,7 @@ g_sequence_insert_sorted (GSequence *seq, /** * g_sequence_sort_changed: * @iter: A #GSequenceIter - * @cmp_func: the function used to compare items in the sequence + * @cmp_func: (scope call): the function used to compare items in the sequence * @cmp_data: user data passed to @cmp_func. * * Moves the data pointed to by @iter to a new position as indicated by @@ -790,7 +742,7 @@ g_sequence_sort_changed (GSequenceIter *iter, * g_sequence_search: * @seq: a #GSequence * @data: data for the new item - * @cmp_func: the function used to compare items in the sequence + * @cmp_func: (scope call): the function used to compare items in the sequence * @cmp_data: user data passed to @cmp_func * * Returns an iterator pointing to the position where @data would @@ -834,7 +786,7 @@ g_sequence_search (GSequence *seq, * g_sequence_lookup: * @seq: a #GSequence * @data: data to look up - * @cmp_func: the function used to compare items in the sequence + * @cmp_func: (scope call): the function used to compare items in the sequence * @cmp_data: user data passed to @cmp_func * * Returns an iterator pointing to the position of the first item found @@ -878,7 +830,7 @@ g_sequence_lookup (GSequence *seq, /** * g_sequence_sort_iter: * @seq: a #GSequence - * @cmp_func: the function used to compare iterators in the sequence + * @cmp_func: (scope call): the function used to compare iterators in the sequence * @cmp_data: user data passed to @cmp_func * * Like g_sequence_sort(), but uses a #GSequenceIterCompareFunc instead @@ -932,7 +884,7 @@ g_sequence_sort_iter (GSequence *seq, /** * g_sequence_sort_changed_iter: * @iter: a #GSequenceIter - * @iter_cmp: the function used to compare iterators in the sequence + * @iter_cmp: (scope call): the function used to compare iterators in the sequence * @cmp_data: user data passed to @cmp_func * * Like g_sequence_sort_changed(), but uses @@ -997,7 +949,7 @@ g_sequence_sort_changed_iter (GSequenceIter *iter, * g_sequence_insert_sorted_iter: * @seq: a #GSequence * @data: data for the new item - * @iter_cmp: the function used to compare iterators in the sequence + * @iter_cmp: (scope call): the function used to compare iterators in the sequence * @cmp_data: user data passed to @iter_cmp * * Like g_sequence_insert_sorted(), but uses @@ -1064,7 +1016,7 @@ g_sequence_insert_sorted_iter (GSequence *seq, * g_sequence_search_iter: * @seq: a #GSequence * @data: data for the new item - * @iter_cmp: the function used to compare iterators in the sequence + * @iter_cmp: (scope call): the function used to compare iterators in the sequence * @cmp_data: user data passed to @iter_cmp * * Like g_sequence_search(), but uses a #GSequenceIterCompareFunc @@ -1122,7 +1074,7 @@ g_sequence_search_iter (GSequence *seq, * g_sequence_lookup_iter: * @seq: a #GSequence * @data: data to look up - * @iter_cmp: the function used to compare iterators in the sequence + * @iter_cmp: (scope call): the function used to compare iterators in the sequence * @cmp_data: user data passed to @iter_cmp * * Like g_sequence_lookup(), but uses a #GSequenceIterCompareFunc diff --git a/glib/gshell.c b/glib/gshell.c index 82e7bd7..040e2e4 100644 --- a/glib/gshell.c +++ b/glib/gshell.c @@ -34,20 +34,6 @@ #include "gthread.h" /** - * SECTION:shell - * @title: Shell-related Utilities - * @short_description: shell-like commandline handling - * - * GLib provides the functions g_shell_quote() and g_shell_unquote() - * to handle shell-like quoting in strings. The function g_shell_parse_argv() - * parses a string similar to the way a POSIX shell (/bin/sh) would. - * - * Note that string handling in shells has many obscure and historical - * corner-cases which these functions do not necessarily reproduce. They - * are good enough in practice, though. - */ - -/** * G_SHELL_ERROR: * * Error domain for shell functions. diff --git a/glib/gslice.c b/glib/gslice.c index 6bcb202..83b6708 100644 --- a/glib/gslice.c +++ b/glib/gslice.c @@ -30,65 +30,6 @@ #include "glib_trace.h" #include "gprintf.h" -/** - * SECTION:memory_slices - * @title: Memory Slices - * @short_description: efficient way to allocate groups of equal-sized - * chunks of memory - * - * GSlice was a space-efficient and multi-processing scalable way to allocate - * equal sized pieces of memory. Since GLib 2.76, its implementation has been - * removed and it calls g_malloc() and g_free_sized(), because the performance - * of the system-default allocators has improved on all platforms since GSlice - * was written. - * - * The GSlice APIs have not been deprecated, as they are widely in use and doing - * so would be very disruptive for little benefit. - * - * New code should be written using g_new()/g_malloc() and g_free_sized() or - * g_free(). There is no particular benefit in porting existing code away from - * g_slice_new()/g_slice_free() unless it’s being rewritten anyway. - * - * Here is an example for using the slice allocator: - * |[ - * gchar *mem[10000]; - * gint i; - * - * // Allocate 10000 blocks. - * for (i = 0; i < 10000; i++) - * { - * mem[i] = g_slice_alloc (50); - * - * // Fill in the memory with some junk. - * for (j = 0; j < 50; j++) - * mem[i][j] = i * j; - * } - * - * // Now free all of the blocks. - * for (i = 0; i < 10000; i++) - * g_slice_free1 (50, mem[i]); - * ]| - * - * And here is an example for using the using the slice allocator - * with data structures: - * |[ - * GRealArray *array; - * - * // Allocate one block, using the g_slice_new() macro. - * array = g_slice_new (GRealArray); - * - * // We can now use array just like a normal pointer to a structure. - * array->data = NULL; - * array->len = 0; - * array->alloc = 0; - * array->zero_terminated = (zero_terminated ? 1 : 0); - * array->clear = (clear ? 1 : 0); - * array->elt_size = elt_size; - * - * // We can free the block, so it can be reused. - * g_slice_free (GRealArray, array); - * ]| - */ /* --- auxiliary functions --- */ void diff --git a/glib/gslist.c b/glib/gslist.c index 7d4051c..68c0e40 100644 --- a/glib/gslist.c +++ b/glib/gslist.c @@ -36,57 +36,6 @@ #include "gslice.h" /** - * SECTION:linked_lists_single - * @title: Singly-Linked Lists - * @short_description: linked lists that can be iterated in one direction - * - * The #GSList structure and its associated functions provide a - * standard singly-linked list data structure. The benefit of this - * data-structure is to provide insertion/deletion operations in O(1) - * complexity where access/search operations are in O(n). The benefit - * of #GSList over #GList (doubly linked list) is that they are lighter - * in space as they only need to retain one pointer but it double the - * cost of the worst case access/search operations. - * - * Each element in the list contains a piece of data, together with a - * pointer which links to the next element in the list. Using this - * pointer it is possible to move through the list in one direction - * only (unlike the [double-linked lists][glib-Doubly-Linked-Lists], - * which allow movement in both directions). - * - * The data contained in each element can be either integer values, by - * using one of the [Type Conversion Macros][glib-Type-Conversion-Macros], - * or simply pointers to any type of data. - * - * List elements are allocated from the [slice allocator][glib-Memory-Slices], - * which is more efficient than allocating elements individually. - * - * Note that most of the #GSList functions expect to be passed a - * pointer to the first element in the list. The functions which insert - * elements return the new start of the list, which may have changed. - * - * There is no function to create a #GSList. %NULL is considered to be - * the empty list so you simply set a #GSList* to %NULL. - * - * To add elements, use g_slist_append(), g_slist_prepend(), - * g_slist_insert() and g_slist_insert_sorted(). - * - * To remove elements, use g_slist_remove(). - * - * To find elements in the list use g_slist_last(), g_slist_next(), - * g_slist_nth(), g_slist_nth_data(), g_slist_find() and - * g_slist_find_custom(). - * - * To find the index of an element use g_slist_position() and - * g_slist_index(). - * - * To call a function for each element in the list use - * g_slist_foreach(). - * - * To free the entire list, use g_slist_free(). - **/ - -/** * GSList: * @data: holds the element's data, which can be a pointer to any kind * of data, or any integer value using the @@ -572,7 +521,7 @@ g_slist_copy (GSList *list) /** * g_slist_copy_deep: * @list: a #GSList - * @func: a copy function used to copy every element in the list + * @func: (scope call): a copy function used to copy every element in the list * @user_data: user data passed to the copy function @func, or #NULL * * Makes a full (deep) copy of a #GSList. @@ -728,7 +677,7 @@ g_slist_find (GSList *list, * g_slist_find_custom: * @list: a #GSList * @data: user data passed to the function - * @func: the function to call for each element. + * @func: (scope call): the function to call for each element. * It should return 0 when the desired element is found * * Finds an element in a #GSList, using a supplied function to @@ -868,7 +817,7 @@ g_slist_length (GSList *list) /** * g_slist_foreach: * @list: a #GSList - * @func: the function to call with each element's data + * @func: (scope call): the function to call with each element's data * @user_data: user data to pass to the function * * Calls a function for each element of a #GSList. @@ -947,7 +896,7 @@ g_slist_insert_sorted_real (GSList *list, * g_slist_insert_sorted: * @list: a #GSList * @data: the data for the new element - * @func: the function to compare elements in the list. + * @func: (scope call): the function to compare elements in the list. * It should return a number > 0 if the first parameter * comes after the second parameter in the sort order. * @@ -968,7 +917,7 @@ g_slist_insert_sorted (GSList *list, * g_slist_insert_sorted_with_data: * @list: a #GSList * @data: the data for the new element - * @func: the function to compare elements in the list. + * @func: (scope call): the function to compare elements in the list. * It should return a number > 0 if the first parameter * comes after the second parameter in the sort order. * @user_data: data to pass to comparison function @@ -1053,7 +1002,7 @@ g_slist_sort_real (GSList *list, /** * g_slist_sort: * @list: a #GSList - * @compare_func: the comparison function used to sort the #GSList. + * @compare_func: (scope call): the comparison function used to sort the #GSList. * This function is passed the data from 2 elements of the #GSList * and should return 0 if they are equal, a negative value if the * first element comes before the second, or a positive value if @@ -1074,7 +1023,7 @@ g_slist_sort (GSList *list, /** * g_slist_sort_with_data: * @list: a #GSList - * @compare_func: comparison function + * @compare_func: (scope call): comparison function * @user_data: data to pass to comparison function * * Like g_slist_sort(), but the sort function accepts a user data argument. diff --git a/glib/gspawn.c b/glib/gspawn.c index 2f7465b..0720cc3 100644 --- a/glib/gspawn.c +++ b/glib/gspawn.c @@ -70,7 +70,7 @@ #include "glibintl.h" #include "glib-unix.h" -#ifdef __APPLE__ +#if defined(__APPLE__) && defined(HAVE_LIBPROC_H) #include #include #endif @@ -110,67 +110,6 @@ extern char **environ; #define HAVE_O_CLOEXEC 1 #endif -/** - * SECTION:spawn - * @Short_description: process launching - * @Title: Spawning Processes - * - * GLib supports spawning of processes with an API that is more - * convenient than the bare UNIX fork() and exec(). - * - * The g_spawn family of functions has synchronous (g_spawn_sync()) - * and asynchronous variants (g_spawn_async(), g_spawn_async_with_pipes()), - * as well as convenience variants that take a complete shell-like - * commandline (g_spawn_command_line_sync(), g_spawn_command_line_async()). - * - * See #GSubprocess in GIO for a higher-level API that provides - * stream interfaces for communication with child processes. - * - * An example of using g_spawn_async_with_pipes(): - * |[ - * const gchar * const argv[] = { "my-favourite-program", "--args", NULL }; - * gint child_stdout, child_stderr; - * GPid child_pid; - * g_autoptr(GError) error = NULL; - * - * // Spawn child process. - * g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL, - * NULL, &child_pid, NULL, &child_stdout, - * &child_stderr, &error); - * if (error != NULL) - * { - * g_error ("Spawning child failed: %s", error->message); - * return; - * } - * - * // Add a child watch function which will be called when the child process - * // exits. - * g_child_watch_add (child_pid, child_watch_cb, NULL); - * - * // You could watch for output on @child_stdout and @child_stderr using - * // #GUnixInputStream or #GIOChannel here. - * - * static void - * child_watch_cb (GPid pid, - * gint status, - * gpointer user_data) - * { - * g_message ("Child %" G_PID_FORMAT " exited %s", pid, - * g_spawn_check_wait_status (status, NULL) ? "normally" : "abnormally"); - * - * // Free any resources associated with the child here, such as I/O channels - * // on its stdout and stderr FDs. If you have no code to put in the - * // child_watch_cb() callback, you can remove it and the g_child_watch_add() - * // call, but you must also remove the G_SPAWN_DO_NOT_REAP_CHILD flag, - * // otherwise the child process will stay around as a zombie until this - * // process exits. - * - * g_spawn_close_pid (pid); - * } - * ]| - */ - - static gint g_execute (const gchar *file, gchar **argv, gchar **argv_buffer, @@ -263,23 +202,6 @@ g_spawn_async (const gchar *working_directory, error); } -/* Avoids a danger in threaded situations (calling close() - * on a file descriptor twice, and another thread has - * re-opened it since the first close) - * - * This function is called between fork() and exec() and hence must be - * async-signal-safe (see signal-safety(7)). - */ -static void -close_and_invalidate (gint *fd) -{ - if (*fd < 0) - return; - - g_close (*fd, NULL); - *fd = -1; -} - /* Some versions of OS X define READ_OK in public headers */ #undef READ_OK @@ -484,8 +406,7 @@ g_spawn_sync (const gchar *working_directory, failed = TRUE; break; case READ_EOF: - close_and_invalidate (&outpipe); - outpipe = -1; + g_clear_fd (&outpipe, NULL); break; default: break; @@ -503,8 +424,7 @@ g_spawn_sync (const gchar *working_directory, failed = TRUE; break; case READ_EOF: - close_and_invalidate (&errpipe); - errpipe = -1; + g_clear_fd (&errpipe, NULL); break; default: break; @@ -516,12 +436,9 @@ g_spawn_sync (const gchar *working_directory, } /* These should only be open still if we had an error. */ - - if (outpipe >= 0) - close_and_invalidate (&outpipe); - if (errpipe >= 0) - close_and_invalidate (&errpipe); - + g_clear_fd (&outpipe, NULL); + g_clear_fd (&errpipe, NULL); + /* Wait for child to exit, even if we have * an error pending. */ @@ -1556,7 +1473,7 @@ safe_fdwalk_with_invalid_fds (int (*cb)(void *data, int fd), void *data) if (open_max < 0) open_max = 4096; -#if defined(__APPLE__) +#if defined(__APPLE__) && defined(HAVE_LIBPROC_H) /* proc_pidinfo isn't documented as async-signal-safe but looking at the implementation * in the darwin tree here: * @@ -1822,7 +1739,7 @@ do_exec (gint child_err_report_fd, if (safe_dup2 (read_null, 0) < 0) write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED); - close_and_invalidate (&read_null); + g_clear_fd (&read_null, NULL); } /* Like with stdin above, it's possible the caller assigned @@ -1859,7 +1776,7 @@ do_exec (gint child_err_report_fd, if (safe_dup2 (write_null, 1) < 0) write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED); - close_and_invalidate (&write_null); + g_clear_fd (&write_null, NULL); } if (IS_STD_FILENO (stderr_fd) && stderr_fd != STDERR_FILENO) @@ -1891,7 +1808,7 @@ do_exec (gint child_err_report_fd, if (safe_dup2 (write_null, 2) < 0) write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED); - close_and_invalidate (&write_null); + g_clear_fd (&write_null, NULL); } /* Close all file descriptors but stdin, stdout and stderr, and any of source_fds, @@ -1982,7 +1899,7 @@ do_exec (gint child_err_report_fd, if (safe_dup2 (source_fds[i], target_fds[i]) < 0) write_err_and_exit (child_err_report_fd, CHILD_DUPFD_FAILED); - close_and_invalidate (&source_fds[i]); + g_clear_fd (&source_fds[i], NULL); } } } @@ -2272,12 +2189,12 @@ do_posix_spawn (const gchar * const *argv, out_close_fds: for (i = 0; i < num_parent_close_fds; i++) - close_and_invalidate (&parent_close_fds [i]); + g_clear_fd (&parent_close_fds[i], NULL); if (duped_source_fds != NULL) { for (i = 0; i < n_fds; i++) - close_and_invalidate (&duped_source_fds[i]); + g_clear_fd (&duped_source_fds[i], NULL); g_free (duped_source_fds); } @@ -2291,6 +2208,16 @@ out_free_spawnattr: #endif /* POSIX_SPAWN_AVAILABLE */ static gboolean +source_fds_collide_with_pipe (const GUnixPipe *pipefd, + const int *source_fds, + gsize n_fds, + GError **error) +{ + return (_g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_READ], source_fds, n_fds, error) || + _g_spawn_invalid_source_fd (pipefd->fds[G_UNIX_PIPE_END_WRITE], source_fds, n_fds, error)); +} + +static gboolean fork_exec (gboolean intermediate_child, const gchar *working_directory, const gchar * const *argv, @@ -2318,9 +2245,9 @@ fork_exec (gboolean intermediate_child, GError **error) { GPid pid = -1; - gint child_err_report_pipe[2] = { -1, -1 }; - gint child_pid_report_pipe[2] = { -1, -1 }; - guint pipe_flags = cloexec_pipes ? FD_CLOEXEC : 0; + GUnixPipe child_err_report_pipe = G_UNIX_PIPE_INIT; + GUnixPipe child_pid_report_pipe = G_UNIX_PIPE_INIT; + guint pipe_flags = cloexec_pipes ? O_CLOEXEC : 0; gint status; const gchar *chosen_search_path; gchar *search_path_buffer = NULL; @@ -2329,9 +2256,9 @@ fork_exec (gboolean intermediate_child, gchar **argv_buffer = NULL; gchar **argv_buffer_heap = NULL; gsize argv_buffer_len = 0; - gint stdin_pipe[2] = { -1, -1 }; - gint stdout_pipe[2] = { -1, -1 }; - gint stderr_pipe[2] = { -1, -1 }; + GUnixPipe stdin_pipe = G_UNIX_PIPE_INIT; + GUnixPipe stdout_pipe = G_UNIX_PIPE_INIT; + GUnixPipe stderr_pipe = G_UNIX_PIPE_INIT; gint child_close_fds[4] = { -1, -1, -1, -1 }; gint n_child_close_fds = 0; gint *source_fds_copy = NULL; @@ -2344,35 +2271,32 @@ fork_exec (gboolean intermediate_child, /* If pipes have been requested, open them */ if (stdin_pipe_out != NULL) { - if (!g_unix_open_pipe (stdin_pipe, pipe_flags, error)) + if (!g_unix_pipe_open (&stdin_pipe, pipe_flags, error)) goto cleanup_and_fail; - if (_g_spawn_invalid_source_fd (stdin_pipe[0], source_fds, n_fds, error) || - _g_spawn_invalid_source_fd (stdin_pipe[1], source_fds, n_fds, error)) + if (source_fds_collide_with_pipe (&stdin_pipe, source_fds, n_fds, error)) goto cleanup_and_fail; - child_close_fds[n_child_close_fds++] = stdin_pipe[1]; - stdin_fd = stdin_pipe[0]; + child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_WRITE); + stdin_fd = g_unix_pipe_get (&stdin_pipe, G_UNIX_PIPE_END_READ); } if (stdout_pipe_out != NULL) { - if (!g_unix_open_pipe (stdout_pipe, pipe_flags, error)) + if (!g_unix_pipe_open (&stdout_pipe, pipe_flags, error)) goto cleanup_and_fail; - if (_g_spawn_invalid_source_fd (stdout_pipe[0], source_fds, n_fds, error) || - _g_spawn_invalid_source_fd (stdout_pipe[1], source_fds, n_fds, error)) + if (source_fds_collide_with_pipe (&stdout_pipe, source_fds, n_fds, error)) goto cleanup_and_fail; - child_close_fds[n_child_close_fds++] = stdout_pipe[0]; - stdout_fd = stdout_pipe[1]; + child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_READ); + stdout_fd = g_unix_pipe_get (&stdout_pipe, G_UNIX_PIPE_END_WRITE); } if (stderr_pipe_out != NULL) { - if (!g_unix_open_pipe (stderr_pipe, pipe_flags, error)) + if (!g_unix_pipe_open (&stderr_pipe, pipe_flags, error)) goto cleanup_and_fail; - if (_g_spawn_invalid_source_fd (stderr_pipe[0], source_fds, n_fds, error) || - _g_spawn_invalid_source_fd (stderr_pipe[1], source_fds, n_fds, error)) + if (source_fds_collide_with_pipe (&stderr_pipe, source_fds, n_fds, error)) goto cleanup_and_fail; - child_close_fds[n_child_close_fds++] = stderr_pipe[0]; - stderr_fd = stderr_pipe[1]; + child_close_fds[n_child_close_fds++] = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_READ); + stderr_fd = g_unix_pipe_get (&stderr_pipe, G_UNIX_PIPE_END_WRITE); } child_close_fds[n_child_close_fds++] = -1; @@ -2510,18 +2434,16 @@ fork_exec (gboolean intermediate_child, if (n_fds > 0) memcpy (source_fds_copy, source_fds, sizeof (*source_fds) * n_fds); - if (!g_unix_open_pipe (child_err_report_pipe, pipe_flags, error)) + if (!g_unix_pipe_open (&child_err_report_pipe, pipe_flags, error)) goto cleanup_and_fail; - if (_g_spawn_invalid_source_fd (child_err_report_pipe[0], source_fds, n_fds, error) || - _g_spawn_invalid_source_fd (child_err_report_pipe[1], source_fds, n_fds, error)) + if (source_fds_collide_with_pipe (&child_err_report_pipe, source_fds, n_fds, error)) goto cleanup_and_fail; if (intermediate_child) { - if (!g_unix_open_pipe (child_pid_report_pipe, pipe_flags, error)) + if (!g_unix_pipe_open (&child_pid_report_pipe, pipe_flags, error)) goto cleanup_and_fail; - if (_g_spawn_invalid_source_fd (child_pid_report_pipe[0], source_fds, n_fds, error) || - _g_spawn_invalid_source_fd (child_pid_report_pipe[1], source_fds, n_fds, error)) + if (source_fds_collide_with_pipe (&child_pid_report_pipe, source_fds, n_fds, error)) goto cleanup_and_fail; } @@ -2560,13 +2482,13 @@ fork_exec (gboolean intermediate_child, * not needed in the close_descriptors case, * though */ - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[0]); + g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL); + g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL); if (child_close_fds[0] != -1) { int i = -1; while (child_close_fds[++i] != -1) - close_and_invalidate (&child_close_fds[i]); + g_clear_fd (&child_close_fds[i], NULL); } if (intermediate_child) @@ -2583,16 +2505,16 @@ fork_exec (gboolean intermediate_child, if (grandchild_pid < 0) { /* report -1 as child PID */ - write_all (child_pid_report_pipe[1], &grandchild_pid, - sizeof(grandchild_pid)); + write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE), + &grandchild_pid, sizeof(grandchild_pid)); - write_err_and_exit (child_err_report_pipe[1], + write_err_and_exit (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE), CHILD_FORK_FAILED); } else if (grandchild_pid == 0) { - close_and_invalidate (&child_pid_report_pipe[1]); - do_exec (child_err_report_pipe[1], + g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL); + do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE), stdin_fd, stdout_fd, stderr_fd, @@ -2617,8 +2539,9 @@ fork_exec (gboolean intermediate_child, } else { - write_all (child_pid_report_pipe[1], &grandchild_pid, sizeof(grandchild_pid)); - close_and_invalidate (&child_pid_report_pipe[1]); + write_all (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE), + &grandchild_pid, sizeof(grandchild_pid)); + g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL); _exit (0); } @@ -2628,7 +2551,7 @@ fork_exec (gboolean intermediate_child, /* Just run the child. */ - do_exec (child_err_report_pipe[1], + do_exec (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE), stdin_fd, stdout_fd, stderr_fd, @@ -2660,8 +2583,8 @@ fork_exec (gboolean intermediate_child, gint n_ints = 0; /* Close the uncared-about ends of the pipes */ - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&child_pid_report_pipe[1]); + g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_WRITE, NULL); + g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_WRITE, NULL); /* If we had an intermediate child, reap it */ if (intermediate_child) @@ -2679,7 +2602,7 @@ fork_exec (gboolean intermediate_child, } - if (!read_ints (child_err_report_pipe[0], + if (!read_ints (g_unix_pipe_get (&child_err_report_pipe, G_UNIX_PIPE_END_READ), buf, 2, &n_ints, error)) goto cleanup_and_fail; @@ -2760,7 +2683,7 @@ fork_exec (gboolean intermediate_child, { n_ints = 0; - if (!read_ints (child_pid_report_pipe[0], + if (!read_ints (g_unix_pipe_get (&child_pid_report_pipe, G_UNIX_PIPE_END_READ), buf, 1, &n_ints, error)) goto cleanup_and_fail; @@ -2783,8 +2706,8 @@ fork_exec (gboolean intermediate_child, } /* Success against all odds! return the information */ - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[0]); + g_unix_pipe_close (&child_err_report_pipe, G_UNIX_PIPE_END_READ, NULL); + g_unix_pipe_close (&child_pid_report_pipe, G_UNIX_PIPE_END_READ, NULL); g_free (search_path_buffer_heap); g_free (argv_buffer_heap); @@ -2798,18 +2721,18 @@ fork_exec (gboolean intermediate_child, success: /* Close the uncared-about ends of the pipes */ - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[1]); + g_unix_pipe_close (&stdin_pipe, G_UNIX_PIPE_END_READ, NULL); + g_unix_pipe_close (&stdout_pipe, G_UNIX_PIPE_END_WRITE, NULL); + g_unix_pipe_close (&stderr_pipe, G_UNIX_PIPE_END_WRITE, NULL); if (stdin_pipe_out != NULL) - *stdin_pipe_out = g_steal_fd (&stdin_pipe[1]); + *stdin_pipe_out = g_unix_pipe_steal (&stdin_pipe, G_UNIX_PIPE_END_WRITE); if (stdout_pipe_out != NULL) - *stdout_pipe_out = g_steal_fd (&stdout_pipe[0]); + *stdout_pipe_out = g_unix_pipe_steal (&stdout_pipe, G_UNIX_PIPE_END_READ); if (stderr_pipe_out != NULL) - *stderr_pipe_out = g_steal_fd (&stderr_pipe[0]); + *stderr_pipe_out = g_unix_pipe_steal (&stderr_pipe, G_UNIX_PIPE_END_READ); return TRUE; @@ -2833,17 +2756,11 @@ success: } } - close_and_invalidate (&stdin_pipe[0]); - close_and_invalidate (&stdin_pipe[1]); - close_and_invalidate (&stdout_pipe[0]); - close_and_invalidate (&stdout_pipe[1]); - close_and_invalidate (&stderr_pipe[0]); - close_and_invalidate (&stderr_pipe[1]); - - close_and_invalidate (&child_err_report_pipe[0]); - close_and_invalidate (&child_err_report_pipe[1]); - close_and_invalidate (&child_pid_report_pipe[0]); - close_and_invalidate (&child_pid_report_pipe[1]); + g_unix_pipe_clear (&stdin_pipe); + g_unix_pipe_clear (&stdout_pipe); + g_unix_pipe_clear (&stderr_pipe); + g_unix_pipe_clear (&child_err_report_pipe); + g_unix_pipe_clear (&child_pid_report_pipe); g_clear_pointer (&search_path_buffer_heap, g_free); g_clear_pointer (&argv_buffer_heap, g_free); diff --git a/glib/gstdio.h b/glib/gstdio.h index 7acdb9c..42c177b 100644 --- a/glib/gstdio.h +++ b/glib/gstdio.h @@ -57,7 +57,7 @@ typedef struct stat GStatBuf; #endif -#if defined(G_OS_UNIX) && !defined(G_STDIO_WRAP_ON_UNIX) +#if defined(G_OS_UNIX) && !defined(G_STDIO_WRAP_ON_UNIX) && !defined(__GI_SCANNER__) /* Just pass on to the system functions, so there's no potential for data * format mismatches, especially with large file interfaces. diff --git a/glib/gstrfuncs.c b/glib/gstrfuncs.c index 22a608d..8dd722a 100644 --- a/glib/gstrfuncs.c +++ b/glib/gstrfuncs.c @@ -57,45 +57,6 @@ #include "gprintfint.h" #include "glibintl.h" - -/** - * SECTION:string_utils - * @title: String Utility Functions - * @short_description: various string-related functions - * - * This section describes a number of utility functions for creating, - * duplicating, and manipulating strings. - * - * Note that the functions g_printf(), g_fprintf(), g_sprintf(), - * g_vprintf(), g_vfprintf(), g_vsprintf() and g_vasprintf() - * are declared in the header `gprintf.h` which is not included in `glib.h` - * (otherwise using `glib.h` would drag in `stdio.h`), so you'll have to - * explicitly include `` in order to use the GLib - * printf() functions. - * - * ## String precision pitfalls # {#string-precision} - * - * While you may use the printf() functions to format UTF-8 strings, - * notice that the precision of a \%Ns parameter is interpreted - * as the number of bytes, not characters to print. On top of that, - * the GNU libc implementation of the printf() functions has the - * "feature" that it checks that the string given for the \%Ns - * parameter consists of a whole number of characters in the current - * encoding. So, unless you are sure you are always going to be in an - * UTF-8 locale or your know your text is restricted to ASCII, avoid - * using \%Ns. If your intention is to format strings for a - * certain number of columns, then \%Ns is not a correct solution - * anyway, since it fails to take wide characters (see g_unichar_iswide()) - * into account. - * - * Note also that there are various printf() parameters which are platform - * dependent. GLib provides platform independent macros for these parameters - * which should be used instead. A common example is %G_GUINT64_FORMAT, which - * should be used instead of `%llu` or similar parameters for formatting - * 64-bit integers. These macros are all named `G_*_FORMAT`; see - * [Basic Types][glib-Basic-Types]. - */ - /** * g_ascii_isalnum: * @c: any character @@ -527,7 +488,7 @@ g_stpcpy (gchar *dest, /** * g_strdup_vprintf: * @format: (not nullable): a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @args: the list of parameters to insert into the format string * * Similar to the standard C vsprintf() function but safer, since it @@ -542,7 +503,7 @@ g_stpcpy (gchar *dest, * See also g_vasprintf(), which offers the same functionality, but * additionally returns the length of the allocated string. * - * Returns: a newly-allocated string holding the result + * Returns: (nullable) (transfer full): a newly-allocated string holding the result */ gchar* g_strdup_vprintf (const gchar *format, @@ -558,7 +519,7 @@ g_strdup_vprintf (const gchar *format, /** * g_strdup_printf: * @format: (not nullable): a standard printf() format string, but notice - * [string precision pitfalls][string-precision] + * [string precision pitfalls](string-utils.html#string-precision-pitfalls) * @...: the parameters to insert into the format string * * Similar to the standard C sprintf() function but safer, since it @@ -570,7 +531,7 @@ g_strdup_vprintf (const gchar *format, * contains `%lc` or `%ls` conversions, which can fail if no multibyte * representation is available for the given character. * - * Returns: a newly-allocated string holding the result + * Returns: (nullable) (transfer full): a newly-allocated string holding the result */ gchar* g_strdup_printf (const gchar *format, @@ -2572,7 +2533,7 @@ g_strsplit_set (const gchar *string, /** * g_strfreev: - * @str_array: (nullable): a %NULL-terminated array of strings to free + * @str_array: (nullable) (transfer full): a %NULL-terminated array of strings to free * * Frees a %NULL-terminated array of strings, as well as each * string it contains. @@ -2602,7 +2563,7 @@ g_strfreev (gchar **str_array) * the array itself. g_strfreev() does this for you. If called * on a %NULL value, g_strdupv() simply returns %NULL. * - * Returns: (nullable): a new %NULL-terminated array of strings. + * Returns: (nullable) (transfer full): a new %NULL-terminated array of strings. */ gchar** g_strdupv (gchar **str_array) diff --git a/glib/gstring.c b/glib/gstring.c index 9f04144..463bfec 100644 --- a/glib/gstring.c +++ b/glib/gstring.c @@ -43,25 +43,6 @@ /** - * SECTION:strings - * @title: Strings - * @short_description: text buffers which grow automatically - * as text is added - * - * A #GString is an object that handles the memory management of a C - * string for you. The emphasis of #GString is on text, typically - * UTF-8. Crucially, the "str" member of a #GString is guaranteed to - * have a trailing nul character, and it is therefore always safe to - * call functions such as strchr() or g_strdup() on it. - * - * However, a #GString can also hold arbitrary binary data, because it - * has a "len" member, which includes any possible embedded nul - * characters in the data. Conceptually then, #GString is like a - * #GByteArray with the addition of many convenience methods for text, - * and a guaranteed nul terminator. - */ - -/** * GString: * @str: points to the character data. It may move as text is added. * The @str field is null-terminated and so @@ -71,7 +52,16 @@ * @allocated_len: the number of bytes that can be stored in the * string before it needs to be reallocated. May be larger than @len. * - * The GString struct contains the public fields of a GString. + * A `GString` is an object that handles the memory management of a C string. + * + * The emphasis of `GString` is on text, typically UTF-8. Crucially, the "str" member + * of a `GString` is guaranteed to have a trailing nul character, and it is therefore + * always safe to call functions such as `strchr()` or `strdup()` on it. + * + * However, a `GString` can also hold arbitrary binary data, because it has a "len" member, + * which includes any possible embedded nul characters in the data. Conceptually then, + * `GString` is like a `GByteArray` with the addition of many convenience methods for + * text, and a guaranteed nul terminator. */ static void @@ -1231,6 +1221,10 @@ g_string_append_vprintf (GString *string, string->len += len; g_free (buf); } + else + { + g_critical ("Failed to append to string: invalid format/args passed to g_vasprintf()"); + } } /** diff --git a/glib/gstringchunk.c b/glib/gstringchunk.c index f4cf6cf..fb95146 100644 --- a/glib/gstringchunk.c +++ b/glib/gstringchunk.c @@ -42,40 +42,33 @@ #include "gutilsprivate.h" /** - * SECTION:string_chunks - * @title: String Chunks - * @short_description: efficient storage of groups of strings + * GStringChunk: + * + * `GStringChunk` provides efficient storage of groups of strings * * String chunks are used to store groups of strings. Memory is - * allocated in blocks, and as strings are added to the #GStringChunk + * allocated in blocks, and as strings are added to the `GStringChunk` * they are copied into the next free position in a block. When a block * is full a new block is allocated. * * When storing a large number of strings, string chunks are more - * efficient than using g_strdup() since fewer calls to malloc() are - * needed, and less memory is wasted in memory allocation overheads. + * efficient than using [func@GLib.strdup] since fewer calls to `malloc()` + * are needed, and less memory is wasted in memory allocation overheads. * - * By adding strings with g_string_chunk_insert_const() it is also + * By adding strings with [method@GLib.StringChunk.insert_const] it is also * possible to remove duplicates. * - * To create a new #GStringChunk use g_string_chunk_new(). + * To create a new `GStringChunk` use [func@GLib.StringChunk.new]. * - * To add strings to a #GStringChunk use g_string_chunk_insert(). + * To add strings to a `GStringChunk` use [method@GLib.StringChunk.insert]. * - * To add strings to a #GStringChunk, but without duplicating strings - * which are already in the #GStringChunk, use - * g_string_chunk_insert_const(). + * To add strings to a `GStringChunk`, but without duplicating strings + * which are already in the `GStringChunk`, use [method@GLib.StringChunk.insert_const]. * - * To free the entire #GStringChunk use g_string_chunk_free(). It is - * not possible to free individual strings. + * To free the entire `GStringChunk` use [method@GLib.StringChunk.free]. + * It is not possible to free individual strings. */ -/** - * GStringChunk: - * - * An opaque data structure representing String Chunks. - * It should only be accessed by using the following functions. - */ struct _GStringChunk { GHashTable *const_table; @@ -86,7 +79,7 @@ struct _GStringChunk }; /** - * g_string_chunk_new: + * g_string_chunk_new: (constructor) * @size: the default size of the blocks of memory which are * allocated to store the strings. If a particular string * is larger than this default size, a larger block of @@ -94,7 +87,7 @@ struct _GStringChunk * * Creates a new #GStringChunk. * - * Returns: a new #GStringChunk + * Returns: (transfer full): a new #GStringChunk */ GStringChunk * g_string_chunk_new (gsize size) @@ -115,7 +108,7 @@ g_string_chunk_new (gsize size) /** * g_string_chunk_free: - * @chunk: a #GStringChunk + * @chunk: (transfer full): a #GStringChunk * * Frees all memory allocated by the #GStringChunk. * After calling g_string_chunk_free() it is not safe to diff --git a/glib/gstrvbuilder.c b/glib/gstrvbuilder.c index 5ef7dcc..12d6a29 100644 --- a/glib/gstrvbuilder.c +++ b/glib/gstrvbuilder.c @@ -27,21 +27,18 @@ #include "gmessages.h" /** - * SECTION:gstrvbuilder - * @title: GStrvBuilder - * @short_description: Helper to create NULL-terminated string arrays. + * GStrvBuilder: * - * #GStrvBuilder is a method of easily building dynamically sized - * NULL-terminated string arrays. + * `GStrvBuilder` is a helper object to build a %NULL-terminated string arrays. * * The following example shows how to build a two element array: * - * |[ + * ```c * g_autoptr(GStrvBuilder) builder = g_strv_builder_new (); * g_strv_builder_add (builder, "hello"); * g_strv_builder_add (builder, "world"); * g_auto(GStrv) array = g_strv_builder_end (builder); - * ]| + * ``` * * Since: 2.68 */ @@ -160,6 +157,24 @@ g_strv_builder_add_many (GStrvBuilder *builder, } /** + * g_strv_builder_take: + * @builder: a #GStrvBuilder + * @value: (transfer full): a string. + * Ownership of the string is transferred to the #GStrvBuilder + * + * Add a string to the end of the array. After @value belongs to the + * #GStrvBuilder and may no longer be modified by the caller. + * + * Since 2.80 + */ +void +g_strv_builder_take (GStrvBuilder *builder, + char *value) +{ + g_ptr_array_add (&builder->array, value); +} + +/** * g_strv_builder_end: * @builder: a #GStrvBuilder * diff --git a/glib/gstrvbuilder.h b/glib/gstrvbuilder.h index c8acbaa..f96df30 100644 --- a/glib/gstrvbuilder.h +++ b/glib/gstrvbuilder.h @@ -30,14 +30,6 @@ G_BEGIN_DECLS -/** - * GStrvBuilder: - * - * A helper object to build a %NULL-terminated string array - * by appending. See g_strv_builder_new(). - * - * Since: 2.68 - */ typedef struct _GStrvBuilder GStrvBuilder; GLIB_AVAILABLE_IN_2_68 @@ -61,6 +53,10 @@ GLIB_AVAILABLE_IN_2_70 void g_strv_builder_add_many (GStrvBuilder *builder, ...) G_GNUC_NULL_TERMINATED; +GLIB_AVAILABLE_IN_2_80 +void g_strv_builder_take (GStrvBuilder *builder, + char *value); + GLIB_AVAILABLE_IN_2_68 GStrv g_strv_builder_end (GStrvBuilder *builder); diff --git a/glib/gtestutils.c b/glib/gtestutils.c index 483275a..704f5ce 100644 --- a/glib/gtestutils.c +++ b/glib/gtestutils.c @@ -68,193 +68,6 @@ #define TAP_SUBTEST_PREFIX "# " /* a 4-space indented line */ /** - * SECTION:testing - * @title: Testing - * @short_description: a test framework - * - * GLib provides a framework for writing and maintaining unit tests - * in parallel to the code they are testing. The API is designed according - * to established concepts found in the other test frameworks (JUnit, NUnit, - * RUnit), which in turn is based on smalltalk unit testing concepts. - * - * - Test case: Tests (test methods) are grouped together with their - * fixture into test cases. - * - * - Fixture: A test fixture consists of fixture data and setup and - * teardown methods to establish the environment for the test - * functions. We use fresh fixtures, i.e. fixtures are newly set - * up and torn down around each test invocation to avoid dependencies - * between tests. - * - * - Test suite: Test cases can be grouped into test suites, to allow - * subsets of the available tests to be run. Test suites can be - * grouped into other test suites as well. - * - * The API is designed to handle creation and registration of test suites - * and test cases implicitly. A simple call like - * |[ - * g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); - * - * g_test_add_func ("/misc/assertions", test_assertions); - * ]| - * creates a test suite called "misc" with a single test case named - * "assertions", which consists of running the test_assertions function. - * - * g_test_init() should be called before calling any other test functions. - * - * In addition to the traditional g_assert_true(), the test framework provides - * an extended set of assertions for comparisons: g_assert_cmpfloat(), - * g_assert_cmpfloat_with_epsilon(), g_assert_cmpint(), g_assert_cmpuint(), - * g_assert_cmphex(), g_assert_cmpstr(), g_assert_cmpmem() and - * g_assert_cmpvariant(). The - * advantage of these variants over plain g_assert_true() is that the assertion - * messages can be more elaborate, and include the values of the compared - * entities. - * - * Note that g_assert() should not be used in unit tests, since it is a no-op - * when compiling with `G_DISABLE_ASSERT`. Use g_assert() in production code, - * and g_assert_true() in unit tests. - * - * A full example of creating a test suite with two tests using fixtures: - * |[ - * #include - * #include - * - * typedef struct { - * MyObject *obj; - * OtherObject *helper; - * } MyObjectFixture; - * - * static void - * my_object_fixture_set_up (MyObjectFixture *fixture, - * gconstpointer user_data) - * { - * fixture->obj = my_object_new (); - * my_object_set_prop1 (fixture->obj, "some-value"); - * my_object_do_some_complex_setup (fixture->obj, user_data); - * - * fixture->helper = other_object_new (); - * } - * - * static void - * my_object_fixture_tear_down (MyObjectFixture *fixture, - * gconstpointer user_data) - * { - * g_clear_object (&fixture->helper); - * g_clear_object (&fixture->obj); - * } - * - * static void - * test_my_object_test1 (MyObjectFixture *fixture, - * gconstpointer user_data) - * { - * g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "initial-value"); - * } - * - * static void - * test_my_object_test2 (MyObjectFixture *fixture, - * gconstpointer user_data) - * { - * my_object_do_some_work_using_helper (fixture->obj, fixture->helper); - * g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "updated-value"); - * } - * - * int - * main (int argc, char *argv[]) - * { - * setlocale (LC_ALL, ""); - * - * g_test_init (&argc, &argv, NULL); - * - * // Define the tests. - * g_test_add ("/my-object/test1", MyObjectFixture, "some-user-data", - * my_object_fixture_set_up, test_my_object_test1, - * my_object_fixture_tear_down); - * g_test_add ("/my-object/test2", MyObjectFixture, "some-user-data", - * my_object_fixture_set_up, test_my_object_test2, - * my_object_fixture_tear_down); - * - * return g_test_run (); - * } - * ]| - * - * ## Integrating GTest in your project - * - * If you are using the [Meson](http://mesonbuild.com) build system, you will - * typically use the provided `test()` primitive to call the test binaries, - * e.g.: - * - * |[ - * test( - * 'foo', - * executable('foo', 'foo.c', dependencies: deps), - * env: [ - * 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - * 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), - * ], - * ) - * - * test( - * 'bar', - * executable('bar', 'bar.c', dependencies: deps), - * env: [ - * 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()), - * 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()), - * ], - * ) - * ]| - * - * If you are using Autotools, you're strongly encouraged to use the Automake - * [TAP](https://testanything.org/) harness; GLib provides template files for - * easily integrating with it: - * - * - [glib-tap.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk) - * - [tap-test](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test) - * - [tap-driver.sh](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh) - * - * You can copy these files in your own project's root directory, and then - * set up your `Makefile.am` file to reference them, for instance: - * - * |[ - * include $(top_srcdir)/glib-tap.mk - * - * # test binaries - * test_programs = \ - * foo \ - * bar - * - * # data distributed in the tarball - * dist_test_data = \ - * foo.data.txt \ - * bar.data.txt - * - * # data not distributed in the tarball - * test_data = \ - * blah.data.txt - * ]| - * - * Make sure to distribute the TAP files, using something like the following - * in your top-level `Makefile.am`: - * - * |[ - * EXTRA_DIST += \ - * tap-driver.sh \ - * tap-test - * ]| - * - * `glib-tap.mk` will be distributed implicitly due to being included in a - * `Makefile.am`. All three files should be added to version control. - * - * If you don't have access to the Autotools TAP harness, you can use the - * [gtester][gtester] and [gtester-report][gtester-report] tools, and use - * the [glib.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk) - * Automake template provided by GLib. Note, however, that since GLib 2.62, - * [gtester][gtester] and [gtester-report][gtester-report] have been deprecated - * in favour of using TAP. The `--tap` argument to tests is enabled by default - * as of GLib 2.62. - */ - -/** * g_test_initialized: * * Returns %TRUE if g_test_init() has been called. @@ -1102,10 +915,10 @@ g_test_log (GTestLogType lbit, unsigned subtest_level; gdouble timing; - if (g_once_init_enter (&g_default_print_func)) + if (g_once_init_enter_pointer (&g_default_print_func)) { - g_once_init_leave (&g_default_print_func, - g_set_print_handler (g_test_print_handler)); + g_once_init_leave_pointer (&g_default_print_func, + g_set_print_handler (g_test_print_handler)); g_assert_nonnull (g_default_print_func); } @@ -1844,8 +1657,8 @@ void test_run_seedstr = seedstr; } - if (!g_get_prgname() && !no_g_set_prgname) - g_set_prgname ((*argv)[0]); + if (!g_get_prgname () && !no_g_set_prgname) + g_set_prgname_once ((*argv)[0]); if (g_getenv ("G_TEST_ROOT_PROCESS")) { @@ -4037,6 +3850,32 @@ G_GNUC_END_IGNORE_DEPRECATIONS * @test_flags: Flags to modify subprocess behaviour. * * Respawns the test program to run only @test_path in a subprocess. + * + * This is equivalent to calling g_test_trap_subprocess_with_envp() with `envp` + * set to %NULL. See the documentation for that function for full details. + * + * Since: 2.38 + */ +void +g_test_trap_subprocess (const char *test_path, + guint64 usec_timeout, + GTestSubprocessFlags test_flags) +{ + g_test_trap_subprocess_with_envp (test_path, NULL, usec_timeout, test_flags); +} + +/** + * g_test_trap_subprocess_with_envp: + * @test_path: (nullable): Test to run in a subprocess + * @envp: (array zero-terminated=1) (nullable) (element-type filename): Environment + * to run the test in, or %NULL to inherit the parent’s environment. This must + * be in the GLib filename encoding. + * @usec_timeout: Timeout for the subprocess test in micro seconds. + * @test_flags: Flags to modify subprocess behaviour. + * + * Respawns the test program to run only @test_path in a subprocess with the + * given @envp environment. + * * This can be used for a test case that might not return, or that * might abort. * @@ -4050,6 +3889,8 @@ G_GNUC_END_IGNORE_DEPRECATIONS * tests with names of this form will automatically be skipped in the * parent process. * + * If @envp is %NULL, the parent process’ environment will be inherited. + * * If @usec_timeout is non-0, the test subprocess is aborted and * considered failing if its run time exceeds it. * @@ -4092,23 +3933,44 @@ G_GNUC_END_IGNORE_DEPRECATIONS * g_test_trap_assert_stderr ("*ERROR*too large*"); * } * + * static void + * test_different_username (void) + * { + * if (g_test_subprocess ()) + * { + * // Code under test goes here + * g_message ("Username is now simulated as %s", g_getenv ("USER")); + * return; + * } + * + * // Reruns this same test in a subprocess + * g_autoptr(GStrv) envp = g_get_environ (); + * envp = g_environ_setenv (g_steal_pointer (&envp), "USER", "charlie", TRUE); + * g_test_trap_subprocess_with_envp (NULL, envp, 0, G_TEST_SUBPROCESS_DEFAULT); + * g_test_trap_assert_passed (); + * g_test_trap_assert_stdout ("Username is now simulated as charlie"); + * } + * * int * main (int argc, char **argv) * { * g_test_init (&argc, &argv, NULL); * - * g_test_add_func ("/myobject/create_large_object", + * g_test_add_func ("/myobject/create-large-object", * test_create_large_object); + * g_test_add_func ("/myobject/different-username", + * test_different_username); * return g_test_run (); * } * ]| * - * Since: 2.38 + * Since: 2.80 */ void -g_test_trap_subprocess (const char *test_path, - guint64 usec_timeout, - GTestSubprocessFlags test_flags) +g_test_trap_subprocess_with_envp (const char *test_path, + const char * const *envp, + guint64 usec_timeout, + GTestSubprocessFlags test_flags) { GError *error = NULL; GPtrArray *argv; @@ -4167,7 +4029,7 @@ g_test_trap_subprocess (const char *test_path, if (!g_spawn_async_with_pipes (test_initial_cwd, (char **)argv->pdata, - NULL, flags, + (char **) envp, flags, NULL, NULL, &pid, NULL, &stdout_fd, &stderr_fd, &error)) diff --git a/glib/gtestutils.h b/glib/gtestutils.h index 30ede25..69ca9c9 100644 --- a/glib/gtestutils.h +++ b/glib/gtestutils.h @@ -515,6 +515,11 @@ GLIB_AVAILABLE_IN_2_38 void g_test_trap_subprocess (const char *test_path, guint64 usec_timeout, GTestSubprocessFlags test_flags); +GLIB_AVAILABLE_IN_2_80 +void g_test_trap_subprocess_with_envp (const char *test_path, + const char * const *envp, + guint64 usec_timeout, + GTestSubprocessFlags test_flags); GLIB_AVAILABLE_IN_ALL gboolean g_test_trap_has_passed (void); diff --git a/glib/gthread-win32.c b/glib/gthread-win32.c index 58e244e..fc5697d 100644 --- a/glib/gthread-win32.c +++ b/glib/gthread-win32.c @@ -424,28 +424,6 @@ g_system_thread_free (GRealThread *thread) void g_system_thread_exit (void) { - /* In static compilation, DllMain doesn't exist and so DLL_THREAD_DETACH - * case is never called and thread destroy notifications are not triggered. - * To ensure that notifications are correctly triggered in static - * compilation mode, we call directly the "detach" function here right - * before terminating the thread. - * As all win32 threads initialized through the glib API are run through - * the same proxy function g_thread_win32_proxy() which calls systematically - * g_system_thread_exit() when finishing, we obtain the same behavior as - * with dynamic compilation. - * - * WARNING: unfortunately this mechanism cannot work with threads created - * directly from the Windows API using CreateThread() or _beginthread/ex(). - * It only works with threads created by using the glib API with - * g_system_thread_new(). If users need absolutely to use a thread NOT - * created with glib API under Windows and in static compilation mode, they - * should not use glib functions within their thread or they may encounter - * memory leaks when the thread finishes. - */ -#ifdef GLIB_STATIC_COMPILATION - g_thread_win32_thread_detach (); -#endif - _endthreadex (0); } @@ -593,7 +571,7 @@ SetThreadName (DWORD dwThreadID, info.dwThreadID = dwThreadID; info.dwFlags = 0; - infosize = sizeof (info) / sizeof (DWORD); + infosize = sizeof (info) / sizeof (ULONG_PTR); #ifdef _MSC_VER __try @@ -601,14 +579,12 @@ SetThreadName (DWORD dwThreadID, RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (const ULONG_PTR *) &info); } - __except (EXCEPTION_EXECUTE_HANDLER) + __except (GetExceptionCode () == EXCEPTION_SET_THREAD_NAME ? + EXCEPTION_EXECUTE_HANDLER : EXCEPTION_CONTINUE_SEARCH) { } #else - /* Without a debugger we *must* have an exception handler, - * otherwise raising an exception will crash the process. - */ - if ((!IsDebuggerPresent ()) && (SetThreadName_VEH_handle == NULL)) + if ((!IsDebuggerPresent ()) || (SetThreadName_VEH_handle == NULL)) return; RaiseException (EXCEPTION_SET_THREAD_NAME, 0, infosize, (const ULONG_PTR *) &info); @@ -681,11 +657,15 @@ g_thread_win32_init (void) InitializeCriticalSection (&g_private_lock); #ifndef _MSC_VER - SetThreadName_VEH_handle = AddVectoredExceptionHandler (1, &SetThreadName_VEH); + /* Set the handler as last to not interfere with ASAN runtimes. + * Many ASAN implementations (currently all three of GCC, CLANG + * and MSVC) install a Vectored Exception Handler that must be + * first in the sequence to work well + */ + SetThreadName_VEH_handle = AddVectoredExceptionHandler (0, &SetThreadName_VEH); if (SetThreadName_VEH_handle == NULL) - { - /* This is bad, but what can we do? */ - } + g_critical ("%s failed with error code %u", + "AddVectoredExceptionHandler", (unsigned int) GetLastError ()); #endif } diff --git a/glib/gthread.c b/glib/gthread.c index eed7595..a64b1ce 100644 --- a/glib/gthread.c +++ b/glib/gthread.c @@ -62,104 +62,6 @@ #include "glib_trace.h" #include "gtrace-private.h" -/** - * SECTION:threads - * @title: Threads - * @short_description: portable support for threads, mutexes, locks, - * conditions and thread private data - * @see_also: #GThreadPool, #GAsyncQueue - * - * Threads act almost like processes, but unlike processes all threads - * of one process share the same memory. This is good, as it provides - * easy communication between the involved threads via this shared - * memory, and it is bad, because strange things (so called - * "Heisenbugs") might happen if the program is not carefully designed. - * In particular, due to the concurrent nature of threads, no - * assumptions on the order of execution of code running in different - * threads can be made, unless order is explicitly forced by the - * programmer through synchronization primitives. - * - * The aim of the thread-related functions in GLib is to provide a - * portable means for writing multi-threaded software. There are - * primitives for mutexes to protect the access to portions of memory - * (#GMutex, #GRecMutex and #GRWLock). There is a facility to use - * individual bits for locks (g_bit_lock()). There are primitives - * for condition variables to allow synchronization of threads (#GCond). - * There are primitives for thread-private data - data that every - * thread has a private instance of (#GPrivate). There are facilities - * for one-time initialization (#GOnce, g_once_init_enter()). Finally, - * there are primitives to create and manage threads (#GThread). - * - * The GLib threading system used to be initialized with g_thread_init(). - * This is no longer necessary. Since version 2.32, the GLib threading - * system is automatically initialized at the start of your program, - * and all thread-creation functions and synchronization primitives - * are available right away. - * - * Note that it is not safe to assume that your program has no threads - * even if you don't call g_thread_new() yourself. GLib and GIO can - * and will create threads for their own purposes in some cases, such - * as when using g_unix_signal_source_new() or when using GDBus. - * - * Originally, UNIX did not have threads, and therefore some traditional - * UNIX APIs are problematic in threaded programs. Some notable examples - * are - * - * - C library functions that return data in statically allocated - * buffers, such as strtok() or strerror(). For many of these, - * there are thread-safe variants with a _r suffix, or you can - * look at corresponding GLib APIs (like g_strsplit() or g_strerror()). - * - * - The functions setenv() and unsetenv() manipulate the process - * environment in a not thread-safe way, and may interfere with getenv() - * calls in other threads. Note that getenv() calls may be hidden behind - * other APIs. For example, GNU gettext() calls getenv() under the - * covers. In general, it is best to treat the environment as readonly. - * If you absolutely have to modify the environment, do it early in - * main(), when no other threads are around yet. - * - * - The setlocale() function changes the locale for the entire process, - * affecting all threads. Temporary changes to the locale are often made - * to change the behavior of string scanning or formatting functions - * like scanf() or printf(). GLib offers a number of string APIs - * (like g_ascii_formatd() or g_ascii_strtod()) that can often be - * used as an alternative. Or you can use the uselocale() function - * to change the locale only for the current thread. - * - * - The fork() function only takes the calling thread into the child's - * copy of the process image. If other threads were executing in critical - * sections they could have left mutexes locked which could easily - * cause deadlocks in the new child. For this reason, you should - * call exit() or exec() as soon as possible in the child and only - * make signal-safe library calls before that. - * - * - The daemon() function uses fork() in a way contrary to what is - * described above. It should not be used with GLib programs. - * - * GLib itself is internally completely thread-safe (all global data is - * automatically locked), but individual data structure instances are - * not automatically locked for performance reasons. For example, - * you must coordinate accesses to the same #GHashTable from multiple - * threads. The two notable exceptions from this rule are #GMainLoop - * and #GAsyncQueue, which are thread-safe and need no further - * application-level locking to be accessed from multiple threads. - * Most refcounting functions such as g_object_ref() are also thread-safe. - * - * A common use for #GThreads is to move a long-running blocking operation out - * of the main thread and into a worker thread. For GLib functions, such as - * single GIO operations, this is not necessary, and complicates the code. - * Instead, the `…_async()` version of the function should be used from the main - * thread, eliminating the need for locking and synchronisation between multiple - * threads. If an operation does need to be moved to a worker thread, consider - * using g_task_run_in_thread(), or a #GThreadPool. #GThreadPool is often a - * better choice than #GThread, as it handles thread reuse and task queueing; - * #GTask uses this internally. - * - * However, if multiple blocking operations need to be performed in sequence, - * and it is not possible to use #GTask for them, moving them to a worker thread - * can clarify the code. - */ - /* G_LOCK Documentation {{{1 ---------------------------------------------- */ /** @@ -663,7 +565,7 @@ g_once_impl (GOnce *once, /** * g_once_init_enter: - * @location: (not nullable): location of a static initializable variable + * @location: (inout) (not optional): location of a static initializable variable * containing 0 * * Function to be called when starting a critical initialization @@ -720,8 +622,56 @@ gboolean } /** - * g_once_init_leave: + * g_once_init_enter_pointer: * @location: (not nullable): location of a static initializable variable + * containing `NULL` + * + * This functions behaves in the same way as g_once_init_enter(), but can + * can be used to initialize pointers (or #guintptr) instead of #gsize. + * + * |[ + * static MyStruct *interesting_struct = NULL; + * + * if (g_once_init_enter_pointer (&interesting_struct)) + * { + * MyStruct *setup_value = allocate_my_struct (); // initialization code here + * + * g_once_init_leave_pointer (&interesting_struct, g_steal_pointer (&setup_value)); + * } + * + * // use interesting_struct here + * ]| + * + * Returns: %TRUE if the initialization section should be entered, + * %FALSE and blocks otherwise + * + * Since: 2.80 + */ +gboolean +(g_once_init_enter_pointer) (gpointer location) +{ + gpointer *value_location = (gpointer *) location; + gboolean need_init = FALSE; + g_mutex_lock (&g_once_mutex); + if (g_atomic_pointer_get (value_location) == 0) + { + if (!g_slist_find (g_once_init_list, (void *) value_location)) + { + need_init = TRUE; + g_once_init_list = g_slist_prepend (g_once_init_list, (void *) value_location); + } + else + do + g_cond_wait (&g_once_cond, &g_once_mutex); + while (g_slist_find (g_once_init_list, (void *) value_location)); + } + g_mutex_unlock (&g_once_mutex); + return need_init; +} + +/** + * g_once_init_leave: + * @location: (inout) (not optional): location of a static initializable variable * containing 0 * @result: new non-0 value for *@value_location * @@ -755,6 +705,42 @@ void g_mutex_unlock (&g_once_mutex); } +/** + * g_once_init_leave_pointer: + * @location: (not nullable): location of a static initializable variable + * containing `NULL` + * @result: new non-`NULL` value for `*location` + * + * Counterpart to g_once_init_enter_pointer(). Expects a location of a static + * `NULL`-initialized initialization variable, and an initialization value + * other than `NULL`. Sets the variable to the initialization value, and + * releases concurrent threads blocking in g_once_init_enter_pointer() on this + * initialization variable. + * + * This functions behaves in the same way as g_once_init_leave(), but + * can be used to initialize pointers (or #guintptr) instead of #gsize. + * + * Since: 2.80 + */ +void +(g_once_init_leave_pointer) (gpointer location, + gpointer result) +{ + gpointer *value_location = (gpointer *) location; + gpointer old_value; + + g_return_if_fail (result != 0); + + old_value = g_atomic_pointer_exchange (value_location, result); + g_return_if_fail (old_value == 0); + + g_mutex_lock (&g_once_mutex); + g_return_if_fail (g_once_init_list != NULL); + g_once_init_list = g_slist_remove (g_once_init_list, (void *) value_location); + g_cond_broadcast (&g_once_cond); + g_mutex_unlock (&g_once_mutex); +} + /* GThread {{{1 -------------------------------------------------------- */ /** diff --git a/glib/gthread.h b/glib/gthread.h index 14bb5a0..1b5a89a 100644 --- a/glib/gthread.h +++ b/glib/gthread.h @@ -236,6 +236,12 @@ GLIB_AVAILABLE_IN_ALL void g_once_init_leave (volatile void *location, gsize result); +GLIB_AVAILABLE_IN_2_80 +gboolean g_once_init_enter_pointer (void *location); +GLIB_AVAILABLE_IN_2_80 +void g_once_init_leave_pointer (void *location, + gpointer result); + /* Use C11-style atomic extensions to check the fast path for status=ready. If * they are not available, fall back to using a mutex and condition variable in * g_once_impl(). @@ -268,11 +274,30 @@ void g_once_init_leave (volatile void *location, 0 ? (void) (*(location) = (result)) : (void) 0; \ g_once_init_leave ((location), (gsize) (result)); \ })) +# define g_once_init_enter_pointer(location) \ + (G_GNUC_EXTENSION ({ \ + G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \ + (void) (0 ? (gpointer) * (location) : NULL); \ + (!g_atomic_pointer_get (location) && \ + g_once_init_enter_pointer (location)); \ + })) GLIB_AVAILABLE_MACRO_IN_2_80 +# define g_once_init_leave_pointer(location, result) \ + (G_GNUC_EXTENSION ({ \ + G_STATIC_ASSERT (sizeof *(location) == sizeof (gpointer)); \ + 0 ? (void) (*(location) = (result)) : (void) 0; \ + g_once_init_leave_pointer ((location), (gpointer) (guintptr) (result)); \ + })) GLIB_AVAILABLE_MACRO_IN_2_80 #else # define g_once_init_enter(location) \ (g_once_init_enter((location))) # define g_once_init_leave(location, result) \ (g_once_init_leave((location), (gsize) (result))) +# define g_once_init_enter_pointer(location) \ + (g_once_init_enter_pointer((location))) \ + GLIB_AVAILABLE_MACRO_IN_2_80 +# define g_once_init_leave_pointer(location, result) \ + (g_once_init_leave_pointer((location), (gpointer) (guintptr) (result))) \ + GLIB_AVAILABLE_MACRO_IN_2_80 #endif GLIB_AVAILABLE_IN_2_36 diff --git a/glib/gthreadpool.c b/glib/gthreadpool.c index c18de89..6ca051e 100644 --- a/glib/gthreadpool.c +++ b/glib/gthreadpool.c @@ -37,43 +37,6 @@ #include "gtimer.h" #include "gutils.h" -/** - * SECTION:thread_pools - * @title: Thread Pools - * @short_description: pools of threads to execute work concurrently - * @see_also: #GThread - * - * Sometimes you wish to asynchronously fork out the execution of work - * and continue working in your own thread. If that will happen often, - * the overhead of starting and destroying a thread each time might be - * too high. In such cases reusing already started threads seems like a - * good idea. And it indeed is, but implementing this can be tedious - * and error-prone. - * - * Therefore GLib provides thread pools for your convenience. An added - * advantage is, that the threads can be shared between the different - * subsystems of your program, when they are using GLib. - * - * To create a new thread pool, you use g_thread_pool_new(). - * It is destroyed by g_thread_pool_free(). - * - * If you want to execute a certain task within a thread pool, - * you call g_thread_pool_push(). - * - * To get the current number of running threads you call - * g_thread_pool_get_num_threads(). To get the number of still - * unprocessed tasks you call g_thread_pool_unprocessed(). To control - * the maximal number of threads for a thread pool, you use - * g_thread_pool_get_max_threads() and g_thread_pool_set_max_threads(). - * - * Finally you can control the number of unused threads, that are kept - * alive by GLib for future use. The current number can be fetched with - * g_thread_pool_get_num_unused_threads(). The maximal number can be - * controlled by g_thread_pool_get_max_unused_threads() and - * g_thread_pool_set_max_unused_threads(). All currently unused threads - * can be stopped by calling g_thread_pool_stop_unused_threads(). - */ - #define DEBUG_MSG(x) /* #define DEBUG_MSG(args) g_printerr args ; g_printerr ("\n"); */ @@ -85,9 +48,32 @@ typedef struct _GRealThreadPool GRealThreadPool; * @user_data: the user data for the threads of this pool * @exclusive: are all threads exclusive to this pool * - * The #GThreadPool struct represents a thread pool. It has three - * public read-only members, but the underlying struct is bigger, - * so you must not copy this struct. + * The `GThreadPool` struct represents a thread pool. + * + * A thread pool is useful when you wish to asynchronously fork out the execution of work + * and continue working in your own thread. If that will happen often, the overhead of starting + * and destroying a thread each time might be too high. In such cases reusing already started + * threads seems like a good idea. And it indeed is, but implementing this can be tedious + * and error-prone. + * + * Therefore GLib provides thread pools for your convenience. An added advantage is, that the + * threads can be shared between the different subsystems of your program, when they are using GLib. + * + * To create a new thread pool, you use [func@GLib.ThreadPool.new]. + * It is destroyed by [method@GLib.ThreadPool.free]. + * + * If you want to execute a certain task within a thread pool, use [method@GLib.ThreadPool.push]. + * + * To get the current number of running threads you call [method@GLib.ThreadPool.get_num_threads]. + * To get the number of still unprocessed tasks you call [method@GLib.ThreadPool.unprocessed]. + * To control the maximum number of threads for a thread pool, you use + * [method@GLib.ThreadPool.get_max_threads]. and [method@GLib.ThreadPool.set_max_threads]. + * + * Finally you can control the number of unused threads, that are kept alive by GLib for future use. + * The current number can be fetched with [func@GLib.ThreadPool.get_num_unused_threads]. + * The maximum number can be controlled by [func@GLib.ThreadPool.get_max_unused_threads] and + * [func@GLib.ThreadPool.set_max_unused_threads]. All currently unused threads + * can be stopped by calling [func@GLib.ThreadPool.stop_unused_threads]. */ struct _GRealThreadPool { diff --git a/glib/gtimer.c b/glib/gtimer.c index dde502a..be6d829 100644 --- a/glib/gtimer.c +++ b/glib/gtimer.c @@ -57,21 +57,14 @@ #include "gmain.h" /** - * SECTION:timers - * @title: Timers - * @short_description: keep track of elapsed time - * - * #GTimer records a start time, and counts microseconds elapsed since - * that time. This is done somewhat differently on different platforms, - * and can be tricky to get exactly right, so #GTimer provides a - * portable/convenient interface. - **/ - -/** * GTimer: * - * Opaque datatype that records a start time. - **/ + * `GTimer` records a start time, and counts microseconds elapsed since + * that time. + * + * This is done somewhat differently on different platforms, and can be + * tricky to get exactly right, so `GTimer` provides a portable/convenient interface. + */ struct _GTimer { guint64 start; @@ -81,12 +74,12 @@ struct _GTimer }; /** - * g_timer_new: + * g_timer_new: (constructor) * * Creates a new timer, and starts timing (i.e. g_timer_start() is * implicitly called for you). * - * Returns: a new #GTimer. + * Returns: (transfer full): a new #GTimer. **/ GTimer* g_timer_new (void) diff --git a/glib/gtimezone.c b/glib/gtimezone.c index 4a4a2d0..0c3cae3 100644 --- a/glib/gtimezone.c +++ b/glib/gtimezone.c @@ -53,25 +53,23 @@ #endif /** - * SECTION:timezone - * @title: GTimeZone - * @short_description: a structure representing a time zone - * @see_also: #GDateTime + * GTimeZone: + * + * A `GTimeZone` represents a time zone, at no particular point in time. * - * #GTimeZone is a structure that represents a time zone, at no - * particular point in time. It is refcounted and immutable. + * The `GTimeZone` struct is refcounted and immutable. * * Each time zone has an identifier (for example, ‘Europe/London’) which is - * platform dependent. See g_time_zone_new() for information on the identifier - * formats. The identifier of a time zone can be retrieved using - * g_time_zone_get_identifier(). + * platform dependent. See [ctor@GLib.TimeZone.new] for information on the + * identifier formats. The identifier of a time zone can be retrieved using + * [method@GLib.TimeZone.get_identifier]. * - * A time zone contains a number of intervals. Each interval has - * an abbreviation to describe it (for example, ‘PDT’), an offset to UTC and a - * flag indicating if the daylight savings time is in effect during that - * interval. A time zone always has at least one interval — interval 0. Note - * that interval abbreviations are not the same as time zone identifiers - * (apart from ‘UTC’), and cannot be passed to g_time_zone_new(). + * A time zone contains a number of intervals. Each interval has an abbreviation + * to describe it (for example, ‘PDT’), an offset to UTC and a flag indicating + * if the daylight savings time is in effect during that interval. A time zone + * always has at least one interval — interval 0. Note that interval abbreviations + * are not the same as time zone identifiers (apart from ‘UTC’), and cannot be + * passed to [ctor@GLib.TimeZone.new]. * * Every UTC time is contained within exactly one interval, but a given * local time may be contained within zero, one or two intervals (due to @@ -84,17 +82,8 @@ * that some properties (like the abbreviation) change between intervals * without other properties changing. * - * #GTimeZone is available since GLib 2.26. - */ - -/** - * GTimeZone: - * - * #GTimeZone is an opaque structure whose members cannot be accessed - * directly. - * * Since: 2.26 - **/ + */ /* IANA zoneinfo file format {{{1 */ @@ -103,6 +92,8 @@ typedef struct { gchar bytes[8]; } gint64_be; typedef struct { gchar bytes[4]; } gint32_be; typedef struct { gchar bytes[4]; } guint32_be; +#ifdef G_OS_UNIX + static inline gint64 gint64_from_be (const gint64_be be) { gint64 tmp; memcpy (&tmp, &be, sizeof tmp); return GINT64_FROM_BE (tmp); } @@ -115,6 +106,8 @@ static inline guint32 guint32_from_be (const guint32_be be) { guint32 tmp; memcpy (&tmp, &be, sizeof tmp); return GUINT32_FROM_BE (tmp); } +#endif + /* The layout of an IANA timezone file header */ struct tzhead { diff --git a/glib/gtrace.c b/glib/gtrace.c index 0ca1bb4..b59ee7d 100644 --- a/glib/gtrace.c +++ b/glib/gtrace.c @@ -20,10 +20,6 @@ */ /* - * SECTION:trace - * @Title: Performance tracing - * @Short_description: Functions for measuring and tracing performance - * * The performance tracing functions allow for the performance of code using * GLib to be measured by passing metrics from the current process to an * external measurement process such as `sysprof-cli` or `sysprofd`. diff --git a/glib/gtrashstack.c b/glib/gtrashstack.c index f734e24..3d94cc6 100644 --- a/glib/gtrashstack.c +++ b/glib/gtrashstack.c @@ -34,34 +34,26 @@ #include "gtrashstack.h" /** - * SECTION:trash_stack - * @title: Trash Stacks - * @short_description: maintain a stack of unused allocated memory chunks + * GTrashStack: + * @next: pointer to the previous element of the stack, + * gets stored in the first `sizeof (gpointer)` + * bytes of the element * - * A #GTrashStack is an efficient way to keep a stack of unused allocated + * A `GTrashStack` is an efficient way to keep a stack of unused allocated * memory chunks. Each memory chunk is required to be large enough to hold - * a #gpointer. This allows the stack to be maintained without any space + * a `gpointer`. This allows the stack to be maintained without any space * overhead, since the stack pointers can be stored inside the memory chunks. * - * There is no function to create a #GTrashStack. A %NULL #GTrashStack* + * There is no function to create a `GTrashStack`. A `NULL` `GTrashStack*` * is a perfectly valid empty stack. * - * There is no longer any good reason to use #GTrashStack. If you have - * extra pieces of memory, free() them and allocate them again later. - * - * Deprecated: 2.48: #GTrashStack is deprecated without replacement - */ - -/** - * GTrashStack: - * @next: pointer to the previous element of the stack, - * gets stored in the first `sizeof (gpointer)` - * bytes of the element + * Each piece of memory that is pushed onto the stack is cast to a + * `GTrashStack*`. * - * Each piece of memory that is pushed onto the stack - * is cast to a GTrashStack*. + * There is no longer any good reason to use `GTrashStack`. If you have + * extra pieces of memory, `free()` them and allocate them again later. * - * Deprecated: 2.48: #GTrashStack is deprecated without replacement + * Deprecated: 2.48: `GTrashStack` is deprecated without replacement */ /** diff --git a/glib/gtree.c b/glib/gtree.c index bfae639..b8d3877 100644 --- a/glib/gtree.c +++ b/glib/gtree.c @@ -36,38 +36,6 @@ #include "gtestutils.h" #include "gslice.h" -/** - * SECTION:trees-binary - * @title: Balanced Binary Trees - * @short_description: a sorted collection of key/value pairs optimized - * for searching and traversing in order - * - * The #GTree structure and its associated functions provide a sorted - * collection of key/value pairs optimized for searching and traversing - * in order. This means that most of the operations (access, search, - * insertion, deletion, ...) on #GTree are O(log(n)) in average and O(n) - * in worst case for time complexity. But, note that maintaining a - * balanced sorted #GTree of n elements is done in time O(n log(n)). - * - * To create a new #GTree use g_tree_new(). - * - * To insert a key/value pair into a #GTree use g_tree_insert() - * (O(n log(n))). - * - * To remove a key/value pair use g_tree_remove() (O(n log(n))). - * - * To look up the value corresponding to a given key, use - * g_tree_lookup() and g_tree_lookup_extended(). - * - * To find out the number of nodes in a #GTree, use g_tree_nnodes(). To - * get the height of a #GTree, use g_tree_height(). - * - * To traverse a #GTree, calling a function for each node visited in - * the traversal, use g_tree_foreach(). - * - * To destroy a #GTree, use g_tree_destroy(). - **/ - #define MAX_GTREE_HEIGHT 40 /* G_MAXUINT nodes will be covered by tree height of log2(G_MAXUINT) + 2. */ G_STATIC_ASSERT ((G_GUINT64_CONSTANT (1) << (MAX_GTREE_HEIGHT - 2)) >= G_MAXUINT); @@ -152,7 +120,7 @@ g_tree_node_new (gpointer key, } /** - * g_tree_new: + * g_tree_new: (constructor) * @key_compare_func: the function used to order the nodes in the #GTree. * It should return values similar to the standard strcmp() function - * 0 if the two arguments are equal, a negative value if the first argument @@ -1138,7 +1106,7 @@ g_tree_lookup_extended (GTree *tree, /** * g_tree_foreach: * @tree: a #GTree - * @func: the function to call for each node visited. + * @func: (scope call): the function to call for each node visited. * If this function returns %TRUE, the traversal is stopped. * @user_data: user data to pass to the function * @@ -1177,7 +1145,7 @@ g_tree_foreach (GTree *tree, /** * g_tree_foreach_node: * @tree: a #GTree - * @func: the function to call for each node visited. + * @func: (scope call): the function to call for each node visited. * If this function returns %TRUE, the traversal is stopped. * @user_data: user data to pass to the function * @@ -1218,7 +1186,7 @@ g_tree_foreach_node (GTree *tree, /** * g_tree_traverse: * @tree: a #GTree - * @traverse_func: the function to call for each node visited. If this + * @traverse_func: (scope call): the function to call for each node visited. If this * function returns %TRUE, the traversal is stopped. * @traverse_type: the order in which nodes are visited, one of %G_IN_ORDER, * %G_PRE_ORDER and %G_POST_ORDER @@ -1278,7 +1246,7 @@ g_tree_traverse (GTree *tree, /** * g_tree_search_node: * @tree: a #GTree - * @search_func: a function used to search the #GTree + * @search_func: (scope call): a function used to search the #GTree * @user_data: the data passed as the second argument to @search_func * * Searches a #GTree using @search_func. @@ -1312,7 +1280,7 @@ g_tree_search_node (GTree *tree, /** * g_tree_search: * @tree: a #GTree - * @search_func: a function used to search the #GTree + * @search_func: (scope call): a function used to search the #GTree * @user_data: the data passed as the second argument to @search_func * * Searches a #GTree using @search_func. diff --git a/glib/gunibreak.h b/glib/gunibreak.h index dc3151a..6a3e731 100644 --- a/glib/gunibreak.h +++ b/glib/gunibreak.h @@ -7,7 +7,7 @@ #include #include -#define G_UNICODE_DATA_VERSION "15.0.0" +#define G_UNICODE_DATA_VERSION "15.1.0" #define G_UNICODE_LAST_CHAR 0x10FFFF @@ -18,7 +18,7 @@ static const gint8 break_property_data[][256] = { { /* page 0, index 0 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -148,7 +148,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC }, { /* page 2, index 1 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -278,7 +278,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 3, index 2 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -408,7 +408,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 4, index 3 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -538,7 +538,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 5, index 4 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -668,9 +668,9 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 6, index 5 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_POSTFIX, @@ -778,7 +778,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -798,7 +798,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 7, index 6 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -928,7 +928,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_PREFIX, G_UNICODE_BREAK_PREFIX }, { /* page 8, index 7 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1000,7 +1000,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -1041,7 +1041,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -1058,7 +1058,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK }, { /* page 9, index 8 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1188,7 +1188,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 10, index 9 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1318,7 +1318,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK }, { /* page 11, index 10 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1448,7 +1448,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 12, index 11 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1578,7 +1578,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 13, index 12 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -1708,7 +1708,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 14, index 13 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMPLEX_CONTEXT, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, @@ -1837,7 +1837,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 15, index 14 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_BEFORE, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_NON_BREAKING_GLUE, @@ -1965,7 +1965,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 16, index 15 */ - G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, + G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, @@ -2095,7 +2095,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC }, { /* page 17, index 16 */ - G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, + G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, G_UNICODE_BREAK_HANGUL_L_JAMO, @@ -2225,7 +2225,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_T_JAMO, G_UNICODE_BREAK_HANGUL_T_JAMO }, { /* page 18, index 17 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -2355,7 +2355,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 19, index 18 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -2485,7 +2485,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 20, index 19 */ - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -2615,7 +2615,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 22, index 20 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -2745,7 +2745,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 23, index 21 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -2875,7 +2875,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 24, index 22 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_EXCLAMATION, G_UNICODE_BREAK_EXCLAMATION, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_EXCLAMATION, @@ -3005,7 +3005,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 25, index 23 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -3135,7 +3135,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 26, index 24 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -3265,33 +3265,25 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 27, index 25 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -3299,33 +3291,33 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_VIRAMA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, @@ -3359,32 +3351,32 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_VIRAMA_FINAL, G_UNICODE_BREAK_VIRAMA_FINAL, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -3393,7 +3385,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 28, index 26 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -3522,7 +3514,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 29, index 27 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -3652,7 +3644,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK }, { /* page 31, index 28 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -3782,7 +3774,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN }, { /* page 32, index 29 */ - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, @@ -3901,7 +3893,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 33, index 30 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -4031,7 +4023,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 34, index 31 */ - G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AMBIGUOUS, @@ -4161,7 +4153,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 35, index 32 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -4291,7 +4283,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 36, index 33 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -4421,7 +4413,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC }, { /* page 37, index 34 */ - G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, + G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, @@ -4551,7 +4543,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 38, index 35 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_ALPHABETIC, @@ -4681,7 +4673,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 39, index 36 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -4811,7 +4803,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 41, index 37 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -4941,7 +4933,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 43, index 38 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -5071,7 +5063,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 44, index 39 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -5201,7 +5193,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_AFTER }, { /* page 45, index 40 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -5331,7 +5323,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK }, { /* page 46, index 41 */ - G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, + G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, G_UNICODE_BREAK_QUOTATION, @@ -5455,7 +5447,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 47, index 42 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -5581,11 +5573,11 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 48, index 43 */ - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_CLOSE_PUNCTUATION, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_CLOSE_PUNCTUATION, G_UNICODE_BREAK_CLOSE_PUNCTUATION, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_NON_STARTER, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -5736,7 +5728,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 49, index 44 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -5855,7 +5847,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER, G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER, G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER, @@ -5874,7 +5866,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_CONDITIONAL_JAPANESE_STARTER }, { /* page 50, index 45 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -6004,7 +5996,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 77, index 46 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -6134,7 +6126,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 160, index 47 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -6264,7 +6256,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 164, index 48 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -6394,7 +6386,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER }, { /* page 166, index 49 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -6523,7 +6515,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 167, index 50 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -6653,7 +6645,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 168, index 51 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, @@ -6782,7 +6774,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK }, { /* page 169, index 52 */ - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, @@ -6847,52 +6839,45 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, + G_UNICODE_BREAK_VIRAMA, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, @@ -6911,27 +6896,27 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_UNKNOWN }, { /* page 170, index 53 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -6942,23 +6927,21 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMPLEX_CONTEXT, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, @@ -7008,6 +6991,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, + G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -7019,19 +7003,18 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, - G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -7041,7 +7024,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 171, index 54 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, @@ -7171,7 +7154,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 172, index 55 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7301,7 +7284,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 173, index 56 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7431,7 +7414,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 174, index 57 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7561,7 +7544,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 175, index 58 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7691,7 +7674,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 176, index 59 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7821,7 +7804,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 177, index 60 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -7951,7 +7934,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 178, index 61 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8081,7 +8064,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 179, index 62 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8211,7 +8194,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 180, index 63 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8341,7 +8324,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 181, index 64 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8471,7 +8454,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 182, index 65 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8601,7 +8584,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 183, index 66 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8731,7 +8714,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 184, index 67 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8861,7 +8844,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 185, index 68 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -8991,7 +8974,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 186, index 69 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9121,7 +9104,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 187, index 70 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9251,7 +9234,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 188, index 71 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9381,7 +9364,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 189, index 72 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9511,7 +9494,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 190, index 73 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9641,7 +9624,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 191, index 74 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9771,7 +9754,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 192, index 75 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -9901,7 +9884,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 193, index 76 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10031,7 +10014,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 194, index 77 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10161,7 +10144,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 195, index 78 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10291,7 +10274,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 196, index 79 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10421,7 +10404,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 197, index 80 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10551,7 +10534,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 198, index 81 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10681,7 +10664,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 199, index 82 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10811,7 +10794,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 200, index 83 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -10941,7 +10924,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 201, index 84 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11071,7 +11054,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 202, index 85 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11201,7 +11184,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 203, index 86 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11331,7 +11314,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 204, index 87 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11461,7 +11444,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 205, index 88 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11591,7 +11574,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 206, index 89 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11721,7 +11704,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 207, index 90 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11851,7 +11834,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 208, index 91 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -11981,7 +11964,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 209, index 92 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12111,7 +12094,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 210, index 93 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12241,7 +12224,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 211, index 94 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12371,7 +12354,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 212, index 95 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12501,7 +12484,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 213, index 96 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12631,7 +12614,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 214, index 97 */ - G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LV_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12761,7 +12744,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE }, { /* page 215, index 98 */ - G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, + G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, G_UNICODE_BREAK_HANGUL_LVT_SYLLABLE, @@ -12891,7 +12874,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 251, index 99 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, @@ -13021,7 +13004,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 253, index 100 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -13151,7 +13134,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 254, index 101 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -13281,7 +13264,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_WORD_JOINER }, { /* page 255, index 102 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_EXCLAMATION, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_EXCLAMATION, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_PREFIX, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -13416,7 +13399,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 256, index 103 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -13546,7 +13529,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 257, index 104 */ - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -13676,7 +13659,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 258, index 105 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -13806,7 +13789,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 259, index 106 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -13936,7 +13919,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 260, index 107 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14066,7 +14049,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 261, index 108 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14196,7 +14179,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 263, index 109 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14326,7 +14309,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 264, index 110 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -14456,7 +14439,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 265, index 111 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14586,7 +14569,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 266, index 112 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, @@ -14714,7 +14697,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 267, index 113 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14843,7 +14826,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 268, index 114 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -14973,7 +14956,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 269, index 115 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15103,7 +15086,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 270, index 116 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -15233,7 +15216,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK }, { /* page 271, index 117 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15338,48 +15321,13 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN - }, - { /* page 272, index 118 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15391,42 +15339,68 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN + }, + { /* page 272, index 118 */ G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AKSARA_PRE_BASE, + G_UNICODE_BREAK_AKSARA_PRE_BASE, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_VIRAMA, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15457,7 +15431,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -15465,7 +15439,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15493,7 +15467,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 273, index 119 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15621,7 +15595,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 274, index 120 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -15750,37 +15724,28 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 275, index 121 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -15788,17 +15753,17 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_VIRAMA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -15880,7 +15845,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 276, index 122 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -16009,7 +15974,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 277, index 123 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -16137,7 +16102,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 278, index 124 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -16265,7 +16230,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 279, index 125 */ - G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, + G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, G_UNICODE_BREAK_COMPLEX_CONTEXT, @@ -16395,7 +16360,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 280, index 126 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -16525,30 +16490,22 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC }, { /* page 281, index 127 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -16556,20 +16513,20 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_VIRAMA, G_UNICODE_BREAK_AKSARA_PRE_BASE, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AKSARA_PRE_BASE, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -16655,7 +16612,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 282, index 128 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -16783,7 +16740,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 283, index 129 */ - G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, + G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_BEFORE, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -16911,7 +16868,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 284, index 130 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17040,7 +16997,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 285, index 131 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, @@ -17170,7 +17127,6 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 286, index 132 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -17282,50 +17238,43 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, + G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN + G_UNICODE_BREAK_UNKNOWN }, { /* page 287, index 133 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA_PRE_BASE, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_AKSARA, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -17333,19 +17282,18 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_AFTER, - G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_VIRAMA, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_AFTER, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_AKSARA_START, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -17388,7 +17336,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -17396,6 +17344,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17410,9 +17359,8 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_POSTFIX, - G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_POSTFIX, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17421,16 +17369,16 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AFTER + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_AFTER }, { /* page 291, index 134 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17560,7 +17508,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 292, index 135 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17689,7 +17637,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 293, index 136 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -17819,7 +17767,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 303, index 137 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -17949,7 +17897,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 306, index 138 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18079,7 +18027,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 307, index 139 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18209,7 +18157,6 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 308, index 140 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18233,6 +18180,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_OPEN_PUNCTUATION, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_NON_BREAKING_GLUE, G_UNICODE_BREAK_NON_BREAKING_GLUE, @@ -18339,7 +18287,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 325, index 141 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18469,7 +18417,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 326, index 142 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18599,7 +18547,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 362, index 143 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18728,7 +18676,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 363, index 144 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -18858,7 +18806,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 366, index 145 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -18988,7 +18936,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN }, { /* page 367, index 146 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -19118,7 +19066,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 391, index 147 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -19248,7 +19196,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 396, index 148 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -19378,7 +19326,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 397, index 149 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -19508,7 +19456,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 431, index 150 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -19638,7 +19586,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN }, { /* page 433, index 151 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -19771,7 +19719,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 434, index 152 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -19901,7 +19849,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 444, index 153 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20031,7 +19979,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 463, index 154 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -20161,7 +20109,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 464, index 155 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20291,7 +20239,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 465, index 156 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20421,7 +20369,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 466, index 157 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20551,7 +20499,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 467, index 158 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20681,7 +20629,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 468, index 159 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -20811,7 +20759,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 469, index 160 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, @@ -20941,7 +20889,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 470, index 161 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -21071,7 +21019,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC }, { /* page 471, index 162 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -21201,7 +21149,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_NUMERIC, G_UNICODE_BREAK_NUMERIC }, { /* page 474, index 163 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, @@ -21330,7 +21278,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 479, index 164 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -21460,7 +21408,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 480, index 165 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, @@ -21590,7 +21538,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 481, index 166 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -21720,7 +21668,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 482, index 167 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -21850,7 +21798,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_PREFIX }, { /* page 484, index 168 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -21980,7 +21928,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 487, index 169 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -22110,7 +22058,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN }, { /* page 488, index 170 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -22240,7 +22188,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 489, index 171 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -22370,7 +22318,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 492, index 172 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -22500,7 +22448,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 493, index 173 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -22630,7 +22578,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 494, index 174 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -22760,7 +22708,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 497, index 175 */ - G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, + G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, G_UNICODE_BREAK_AMBIGUOUS, @@ -22890,7 +22838,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_REGIONAL_INDICATOR, G_UNICODE_BREAK_REGIONAL_INDICATOR }, { /* page 499, index 176 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -23020,7 +22968,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_EMOJI_MODIFIER, G_UNICODE_BREAK_EMOJI_MODIFIER }, { /* page 500, index 177 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -23150,7 +23098,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 501, index 178 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -23280,7 +23228,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 502, index 179 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -23410,7 +23358,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 503, index 180 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -23540,7 +23488,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 504, index 181 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -23670,7 +23618,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 505, index 182 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -23800,7 +23748,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 506, index 183 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -23930,7 +23878,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC }, { /* page 507, index 184 */ - G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, + G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, G_UNICODE_BREAK_ALPHABETIC, @@ -24060,7 +24008,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 511, index 185 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -24190,7 +24138,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 767, index 186 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -24320,7 +24268,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 1023, index 187 */ - G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, + G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, G_UNICODE_BREAK_IDEOGRAPHIC, @@ -24450,7 +24398,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 3584, index 188 */ - G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN, @@ -24580,7 +24528,7 @@ static const gint8 break_property_data[][256] = { G_UNICODE_BREAK_UNKNOWN, G_UNICODE_BREAK_UNKNOWN }, { /* page 3585, index 189 */ - G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, + G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, G_UNICODE_BREAK_COMBINING_MARK, diff --git a/glib/gunichartables.h b/glib/gunichartables.h index dde72ad..8beeab0 100644 --- a/glib/gunichartables.h +++ b/glib/gunichartables.h @@ -4,7 +4,7 @@ #ifndef CHARTABLES_H #define CHARTABLES_H -#define G_UNICODE_DATA_VERSION "15.0.0" +#define G_UNICODE_DATA_VERSION "15.1.0" #define G_UNICODE_LAST_CHAR 0x10ffff @@ -16,7 +16,7 @@ static const char type_data[][256] = { { /* page 0, index 0 */ - G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, + G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, G_UNICODE_CONTROL, @@ -134,7 +134,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 1, index 1 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -264,7 +264,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 2, index 2 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -394,7 +394,7 @@ static const char type_data[][256] = { G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL }, { /* page 3, index 3 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -522,7 +522,7 @@ static const char type_data[][256] = { G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER }, { /* page 4, index 4 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, @@ -652,7 +652,7 @@ static const char type_data[][256] = { G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER }, { /* page 5, index 5 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -772,7 +772,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 6, index 6 */ - G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, + G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_FORMAT, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -877,7 +877,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 7, index 7 */ - G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -978,7 +978,7 @@ static const char type_data[][256] = { G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_CURRENCY_SYMBOL }, { /* page 8, index 8 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1084,7 +1084,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK }, { /* page 9, index 9 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1183,7 +1183,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED }, { /* page 10, index 10 */ - G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1279,7 +1279,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK }, { /* page 11, index 11 */ - G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, + G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1372,7 +1372,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 12, index 12 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1468,7 +1468,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 13, index 13 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1561,7 +1561,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 14, index 14 */ - G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1659,7 +1659,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 15, index 15 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -1768,7 +1768,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 16, index 16 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1882,7 +1882,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 18, index 17 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -1970,7 +1970,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 19, index 18 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2075,7 +2075,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 20, index 19 */ - G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_LETTER, + G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2163,7 +2163,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, { /* page 22, index 20 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2253,7 +2253,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 23, index 21 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2349,7 +2349,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 24, index 22 */ - G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_DASH_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -2441,7 +2441,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 25, index 23 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2534,7 +2534,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL }, { /* page 26, index 24 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2639,7 +2639,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 27, index 25 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2741,7 +2741,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION }, { /* page 28, index 26 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -2852,7 +2852,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 29, index 27 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -2982,7 +2982,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK }, { /* page 30, index 28 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -3112,7 +3112,7 @@ static const char type_data[][256] = { G_UNICODE_UPPERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER }, { /* page 31, index 29 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -3238,7 +3238,7 @@ static const char type_data[][256] = { G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_UNASSIGNED }, { /* page 32, index 30 */ - G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, G_UNICODE_SPACE_SEPARATOR, @@ -3353,7 +3353,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 33, index 31 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_OTHER_SYMBOL, @@ -3457,7 +3457,7 @@ static const char type_data[][256] = { G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL }, { /* page 35, index 32 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OPEN_PUNCTUATION, G_UNICODE_CLOSE_PUNCTUATION, @@ -3546,7 +3546,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL }, { /* page 36, index 33 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -3634,7 +3634,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_NUMBER }, { /* page 37, index 34 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -3722,7 +3722,7 @@ static const char type_data[][256] = { G_UNICODE_MATH_SYMBOL }, { /* page 38, index 35 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -3810,7 +3810,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL }, { /* page 39, index 36 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -3903,7 +3903,7 @@ static const char type_data[][256] = { G_UNICODE_MATH_SYMBOL }, { /* page 41, index 37 */ - G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, + G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, G_UNICODE_MATH_SYMBOL, @@ -3996,7 +3996,7 @@ static const char type_data[][256] = { G_UNICODE_MATH_SYMBOL }, { /* page 43, index 38 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -4084,7 +4084,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL }, { /* page 44, index 39 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, @@ -4213,7 +4213,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_PUNCTUATION }, { /* page 45, index 40 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -4313,7 +4313,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK }, { /* page 46, index 41 */ - G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_FINAL_PUNCTUATION, G_UNICODE_INITIAL_PUNCTUATION, G_UNICODE_FINAL_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -4416,7 +4416,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 47, index 42 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -4500,11 +4500,11 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, - G_UNICODE_UNASSIGNED + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL }, { /* page 48, index 43 */ - G_UNICODE_SPACE_SEPARATOR, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_SPACE_SEPARATOR, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_SYMBOL, G_UNICODE_MODIFIER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_LETTER_NUMBER, @@ -4604,7 +4604,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 49, index 44 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -4683,7 +4683,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -4692,7 +4692,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 50, index 45 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -4780,7 +4780,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL }, { /* page 77, index 46 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -4868,7 +4868,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL }, { /* page 160, index 47 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -4956,7 +4956,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, { /* page 164, index 48 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5045,7 +5045,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION }, { /* page 166, index 49 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5154,7 +5154,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 167, index 50 */ - G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, + G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, G_UNICODE_MODIFIER_SYMBOL, @@ -5278,7 +5278,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, { /* page 168, index 51 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, @@ -5375,7 +5375,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK }, { /* page 169, index 52 */ - G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, + G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, G_UNICODE_DECIMAL_NUMBER, @@ -5478,7 +5478,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 170, index 53 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5577,7 +5577,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 171, index 54 */ - G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5691,7 +5691,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 215, index 55 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5779,7 +5779,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 250, index 56 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -5867,7 +5867,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 251, index 57 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -5960,7 +5960,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, { /* page 253, index 58 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -6049,7 +6049,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL }, { /* page 254, index 59 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -6153,7 +6153,7 @@ static const char type_data[][256] = { G_UNICODE_FORMAT }, { /* page 255, index 60 */ - G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_CURRENCY_SYMBOL, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -6260,7 +6260,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 256, index 61 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -6348,7 +6348,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 257, index 62 */ - G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, @@ -6444,7 +6444,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 258, index 63 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -6532,7 +6532,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 259, index 64 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -6622,7 +6622,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 260, index 65 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, @@ -6736,7 +6736,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 261, index 66 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -6837,7 +6837,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 263, index 67 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -6934,7 +6934,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 264, index 68 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7022,7 +7022,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER }, { /* page 265, index 69 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7110,7 +7110,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER }, { /* page 266, index 70 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -7203,7 +7203,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 267, index 71 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7293,7 +7293,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 268, index 72 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7398,7 +7398,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_NUMBER }, { /* page 269, index 73 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7488,7 +7488,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 270, index 74 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -7576,7 +7576,7 @@ static const char type_data[][256] = { G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK }, { /* page 271, index 75 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7668,7 +7668,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 272, index 76 */ - G_UNICODE_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7766,7 +7766,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 273, index 77 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7867,7 +7867,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 274, index 78 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -7962,7 +7962,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 275, index 79 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_SPACING_MARK, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8053,7 +8053,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 276, index 80 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8151,7 +8151,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 277, index 81 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -8245,7 +8245,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 278, index 82 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8343,7 +8343,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 279, index 83 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8435,7 +8435,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 280, index 84 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8537,7 +8537,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER }, { /* page 281, index 85 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -8629,7 +8629,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 282, index 86 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_OTHER_LETTER, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -8728,7 +8728,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 283, index 87 */ - G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, + G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, G_UNICODE_OTHER_PUNCTUATION, @@ -8817,7 +8817,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 284, index 88 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -8916,7 +8916,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 285, index 89 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, @@ -9009,7 +9009,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 286, index 90 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -9098,7 +9098,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 287, index 91 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_SPACING_MARK, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9192,7 +9192,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_PUNCTUATION }, { /* page 291, index 92 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9280,7 +9280,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 292, index 93 */ - G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, + G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, G_UNICODE_LETTER_NUMBER, @@ -9387,7 +9387,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, { /* page 293, index 94 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9475,7 +9475,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 303, index 95 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -9563,7 +9563,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 308, index 96 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9652,7 +9652,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 326, index 97 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9740,7 +9740,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 362, index 98 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9832,7 +9832,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 363, index 99 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -9924,7 +9924,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 366, index 100 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -10023,7 +10023,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 367, index 101 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10114,7 +10114,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 391, index 102 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10202,7 +10202,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 396, index 103 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10290,7 +10290,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 397, index 104 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -10378,7 +10378,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 431, index 105 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -10468,7 +10468,7 @@ static const char type_data[][256] = { G_UNICODE_MODIFIER_LETTER, G_UNICODE_UNASSIGNED }, { /* page 433, index 106 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10556,7 +10556,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 434, index 107 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10644,7 +10644,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 444, index 108 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -10732,7 +10732,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 463, index 109 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -10831,7 +10831,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 464, index 110 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -10919,7 +10919,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 465, index 111 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -11011,7 +11011,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 466, index 112 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -11099,7 +11099,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 467, index 113 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -11187,7 +11187,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 468, index 114 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, @@ -11316,7 +11316,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 469, index 115 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UPPERCASE_LETTER, @@ -11445,7 +11445,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 470, index 116 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -11575,7 +11575,7 @@ static const char type_data[][256] = { G_UNICODE_LOWERCASE_LETTER }, { /* page 471, index 117 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -11705,7 +11705,7 @@ static const char type_data[][256] = { G_UNICODE_DECIMAL_NUMBER }, { /* page 474, index 118 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -11816,7 +11816,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 479, index 119 */ - G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, + G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, G_UNICODE_LOWERCASE_LETTER, @@ -11910,7 +11910,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 480, index 120 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_UNASSIGNED, @@ -12014,7 +12014,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 481, index 121 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -12105,7 +12105,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 482, index 122 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -12195,7 +12195,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_CURRENCY_SYMBOL }, { /* page 484, index 123 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -12285,7 +12285,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 487, index 124 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -12373,7 +12373,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 488, index 125 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -12462,7 +12462,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 489, index 126 */ - G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, + G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, G_UNICODE_UPPERCASE_LETTER, @@ -12564,7 +12564,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 492, index 127 */ - G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -12652,7 +12652,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 493, index 128 */ - G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, @@ -12740,7 +12740,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 494, index 129 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -12828,7 +12828,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 496, index 130 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -12916,7 +12916,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 497, index 131 */ - G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, + G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, G_UNICODE_OTHER_NUMBER, @@ -13004,7 +13004,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_SYMBOL }, { /* page 498, index 132 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -13092,7 +13092,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 499, index 133 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13181,7 +13181,7 @@ static const char type_data[][256] = { G_UNICODE_MODIFIER_SYMBOL }, { /* page 502, index 134 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13269,7 +13269,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 503, index 135 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13357,7 +13357,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 504, index 136 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13445,7 +13445,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 506, index 137 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13533,7 +13533,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 507, index 138 */ - G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, + G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, G_UNICODE_OTHER_SYMBOL, @@ -13622,7 +13622,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, { /* page 678, index 139 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -13710,7 +13710,7 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED }, { /* page 695, index 140 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -13798,7 +13798,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 696, index 141 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -13886,7 +13886,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 718, index 142 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -13974,7 +13974,7 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER }, { /* page 747, index 143 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -14054,6 +14054,94 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER + }, + { /* page 750, index 144 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + G_UNICODE_OTHER_LETTER, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, + G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -14061,8 +14149,8 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 762, index 144 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + { /* page 762, index 145 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -14149,8 +14237,8 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 787, index 145 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + { /* page 787, index 146 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -14237,8 +14325,8 @@ static const char type_data[][256] = { G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER }, - { /* page 803, index 146 */ - G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, + { /* page 803, index 147 */ + G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, G_UNICODE_OTHER_LETTER, @@ -14325,8 +14413,8 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 3584, index 147 */ - G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT, G_UNICODE_UNASSIGNED, + { /* page 3584, index 148 */ + G_UNICODE_UNASSIGNED, G_UNICODE_FORMAT, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, @@ -14405,8 +14493,8 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 3585, index 148 */ - G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, + { /* page 3585, index 149 */ + G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, G_UNICODE_NON_SPACING_MARK, @@ -14533,8 +14621,8 @@ static const char type_data[][256] = { G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 4095, index 149 */ - G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + { /* page 4095, index 150 */ + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, @@ -14621,8 +14709,8 @@ static const char type_data[][256] = { G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_UNASSIGNED, G_UNICODE_UNASSIGNED }, - { /* page 4351, index 150 */ - G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, + { /* page 4351, index 151 */ + G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, G_UNICODE_PRIVATE_USE, @@ -15461,9 +15549,9 @@ static const gint16 type_table_part1[804] = { G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, 143 /* page 747 */, - G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, - G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, - G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, + 144 /* page 750 */, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, @@ -15475,7 +15563,7 @@ static const gint16 type_table_part1[804] = { G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, - 144 /* page 762 */, + 145 /* page 762 */, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, @@ -15500,7 +15588,7 @@ static const gint16 type_table_part1[804] = { G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, - 145 /* page 787 */, + 146 /* page 787 */, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, @@ -15516,13 +15604,13 @@ static const gint16 type_table_part1[804] = { G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_OTHER_LETTER + G_UNICODE_MAX_TABLE_INDEX, - 146 /* page 803 */ + 147 /* page 803 */ }; /* U+E0000 through U+10FFFF */ static const gint16 type_table_part2[768] = { - 147 /* page 3584 */, - 148 /* page 3585 */, + 148 /* page 3584 */, + 149 /* page 3585 */, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_UNASSIGNED + G_UNICODE_MAX_TABLE_INDEX, @@ -16032,7 +16120,7 @@ static const gint16 type_table_part2[768] = { G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, - 149 /* page 4095 */, + 150 /* page 4095 */, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, @@ -16288,12 +16376,12 @@ static const gint16 type_table_part2[768] = { G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, G_UNICODE_PRIVATE_USE + G_UNICODE_MAX_TABLE_INDEX, - 150 /* page 4351 */ + 151 /* page 4351 */ }; static const gunichar attr_data[][256] = { { /* page 0, index 0 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16324,7 +16412,7 @@ static const gunichar attr_data[][256] = { 0x00db, 0x00dc, 0x00dd, 0x00de, 0x0178 }, { /* page 1, index 1 */ - 0x0101, 0x0100, 0x0103, 0x0102, 0x0105, 0x0104, 0x0107, 0x0106, 0x0109, + 0x0101, 0x0100, 0x0103, 0x0102, 0x0105, 0x0104, 0x0107, 0x0106, 0x0109, 0x0108, 0x010b, 0x010a, 0x010d, 0x010c, 0x010f, 0x010e, 0x0111, 0x0110, 0x0113, 0x0112, 0x0115, 0x0114, 0x0117, 0x0116, 0x0119, 0x0118, 0x011b, 0x011a, 0x011d, 0x011c, 0x011f, 0x011e, 0x0121, 0x0120, 0x0123, 0x0122, @@ -16355,7 +16443,7 @@ static const gunichar attr_data[][256] = { 0x01f9, 0x01f8, 0x01fb, 0x01fa, 0x01fd, 0x01fc, 0x01ff, 0x01fe }, { /* page 2, index 2 */ - 0x0201, 0x0200, 0x0203, 0x0202, 0x0205, 0x0204, 0x0207, 0x0206, 0x0209, + 0x0201, 0x0200, 0x0203, 0x0202, 0x0205, 0x0204, 0x0207, 0x0206, 0x0209, 0x0208, 0x020b, 0x020a, 0x020d, 0x020c, 0x020f, 0x020e, 0x0211, 0x0210, 0x0213, 0x0212, 0x0215, 0x0214, 0x0217, 0x0216, 0x0219, 0x0218, 0x021b, 0x021a, 0x021d, 0x021c, 0x021f, 0x021e, 0x019e, 0x0000, 0x0223, 0x0222, @@ -16386,7 +16474,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 3, index 3 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16417,7 +16505,7 @@ static const gunichar attr_data[][256] = { 0x03fb, 0x03fa, 0x0000, 0x037b, 0x037c, 0x037d }, { /* page 4, index 4 */ - 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, + 0x0450, 0x0451, 0x0452, 0x0453, 0x0454, 0x0455, 0x0456, 0x0457, 0x0458, 0x0459, 0x045a, 0x045b, 0x045c, 0x045d, 0x045e, 0x045f, 0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043a, 0x043b, 0x043c, 0x043d, 0x043e, 0x043f, 0x0440, 0x0441, 0x0442, 0x0443, @@ -16448,7 +16536,7 @@ static const gunichar attr_data[][256] = { 0x04fd, 0x04fc, 0x04ff, 0x04fe }, { /* page 5, index 5 */ - 0x0501, 0x0500, 0x0503, 0x0502, 0x0505, 0x0504, 0x0507, 0x0506, 0x0509, + 0x0501, 0x0500, 0x0503, 0x0502, 0x0505, 0x0504, 0x0507, 0x0506, 0x0509, 0x0508, 0x050b, 0x050a, 0x050d, 0x050c, 0x050f, 0x050e, 0x0511, 0x0510, 0x0513, 0x0512, 0x0515, 0x0514, 0x0517, 0x0516, 0x0519, 0x0518, 0x051b, 0x051a, 0x051d, 0x051c, 0x051f, 0x051e, 0x0521, 0x0520, 0x0523, 0x0522, @@ -16479,7 +16567,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 6, index 6 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16510,7 +16598,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 7, index 7 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16541,7 +16629,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 9, index 8 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16572,7 +16660,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 10, index 9 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16603,7 +16691,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 11, index 10 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16634,7 +16722,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 12, index 11 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16665,7 +16753,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 13, index 12 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16696,7 +16784,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 14, index 13 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16727,7 +16815,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 15, index 14 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, @@ -16758,7 +16846,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 16, index 15 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16789,7 +16877,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x1cbd, 0x1cbe, 0x1cbf }, { /* page 19, index 16 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16820,7 +16908,7 @@ static const gunichar attr_data[][256] = { 0x13f4, 0x13f5, 0x0000, 0x0000 }, { /* page 23, index 17 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16851,7 +16939,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 24, index 18 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16882,7 +16970,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 25, index 19 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16913,7 +17001,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 26, index 20 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16944,7 +17032,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 27, index 21 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -16975,7 +17063,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 28, index 22 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17006,7 +17094,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 29, index 23 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17037,7 +17125,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 30, index 24 */ - 0x1e01, 0x1e00, 0x1e03, 0x1e02, 0x1e05, 0x1e04, 0x1e07, 0x1e06, 0x1e09, + 0x1e01, 0x1e00, 0x1e03, 0x1e02, 0x1e05, 0x1e04, 0x1e07, 0x1e06, 0x1e09, 0x1e08, 0x1e0b, 0x1e0a, 0x1e0d, 0x1e0c, 0x1e0f, 0x1e0e, 0x1e11, 0x1e10, 0x1e13, 0x1e12, 0x1e15, 0x1e14, 0x1e17, 0x1e16, 0x1e19, 0x1e18, 0x1e1b, 0x1e1a, 0x1e1d, 0x1e1c, 0x1e1f, 0x1e1e, 0x1e21, 0x1e20, 0x1e23, 0x1e22, @@ -17068,7 +17156,7 @@ static const gunichar attr_data[][256] = { 0x1efb, 0x1efa, 0x1efd, 0x1efc, 0x1eff, 0x1efe }, { /* page 31, index 25 */ - 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f00, + 0x1f08, 0x1f09, 0x1f0a, 0x1f0b, 0x1f0c, 0x1f0d, 0x1f0e, 0x1f0f, 0x1f00, 0x1f01, 0x1f02, 0x1f03, 0x1f04, 0x1f05, 0x1f06, 0x1f07, 0x1f18, 0x1f19, 0x1f1a, 0x1f1b, 0x1f1c, 0x1f1d, 0x0000, 0x0000, 0x1f10, 0x1f11, 0x1f12, 0x1f13, 0x1f14, 0x1f15, 0x0000, 0x0000, 0x1f28, 0x1f29, 0x1f2a, 0x1f2b, @@ -17103,7 +17191,7 @@ static const gunichar attr_data[][256] = { 0x1000415, 0x0000, 0x0000, 0x0000 }, { /* page 33, index 26 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17134,7 +17222,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 44, index 27 */ - 0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37, 0x2c38, + 0x2c30, 0x2c31, 0x2c32, 0x2c33, 0x2c34, 0x2c35, 0x2c36, 0x2c37, 0x2c38, 0x2c39, 0x2c3a, 0x2c3b, 0x2c3c, 0x2c3d, 0x2c3e, 0x2c3f, 0x2c40, 0x2c41, 0x2c42, 0x2c43, 0x2c44, 0x2c45, 0x2c46, 0x2c47, 0x2c48, 0x2c49, 0x2c4a, 0x2c4b, 0x2c4c, 0x2c4d, 0x2c4e, 0x2c4f, 0x2c50, 0x2c51, 0x2c52, 0x2c53, @@ -17165,7 +17253,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 45, index 28 */ - 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, + 0x10a0, 0x10a1, 0x10a2, 0x10a3, 0x10a4, 0x10a5, 0x10a6, 0x10a7, 0x10a8, 0x10a9, 0x10aa, 0x10ab, 0x10ac, 0x10ad, 0x10ae, 0x10af, 0x10b0, 0x10b1, 0x10b2, 0x10b3, 0x10b4, 0x10b5, 0x10b6, 0x10b7, 0x10b8, 0x10b9, 0x10ba, 0x10bb, 0x10bc, 0x10bd, 0x10be, 0x10bf, 0x10c0, 0x10c1, 0x10c2, 0x10c3, @@ -17196,7 +17284,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 166, index 29 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, @@ -17227,7 +17315,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 167, index 30 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xa723, 0xa722, @@ -17258,7 +17346,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 168, index 31 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17289,7 +17377,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 169, index 32 */ - 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, + 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17320,7 +17408,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 170, index 33 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17351,7 +17439,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 171, index 34 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17382,7 +17470,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 251, index 35 */ - 0x100000f, 0x1000016, 0x100001d, 0x1000024, 0x100002d, 0x1000036, + 0x100000f, 0x1000016, 0x100001d, 0x1000024, 0x100002d, 0x1000036, 0x100003d, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x100004f, 0x100005a, 0x1000065, 0x1000070, 0x100007b, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17414,7 +17502,7 @@ static const gunichar attr_data[][256] = { 0x0000 }, { /* page 255, index 36 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0001, 0x0002, 0x0003, 0x0004, 0x0005, 0x0006, 0x0007, 0x0008, 0x0009, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0xff41, 0xff42, 0xff43, @@ -17445,7 +17533,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 260, index 37 */ - 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, + 0x10428, 0x10429, 0x1042a, 0x1042b, 0x1042c, 0x1042d, 0x1042e, 0x1042f, 0x10430, 0x10431, 0x10432, 0x10433, 0x10434, 0x10435, 0x10436, 0x10437, 0x10438, 0x10439, 0x1043a, 0x1043b, 0x1043c, 0x1043d, 0x1043e, 0x1043f, 0x10440, 0x10441, 0x10442, 0x10443, 0x10444, 0x10445, 0x10446, 0x10447, @@ -17478,7 +17566,7 @@ static const gunichar attr_data[][256] = { 0x104d2, 0x104d3, 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 261, index 38 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17510,7 +17598,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 268, index 39 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17542,7 +17630,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 269, index 40 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17573,7 +17661,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 272, index 41 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17604,7 +17692,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 273, index 42 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17635,7 +17723,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 274, index 43 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17666,7 +17754,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 276, index 44 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17697,7 +17785,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 278, index 45 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17728,7 +17816,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 279, index 46 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17759,7 +17847,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 280, index 47 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17791,7 +17879,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000 }, { /* page 281, index 48 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17822,7 +17910,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 284, index 49 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17853,7 +17941,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 285, index 50 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17884,7 +17972,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 287, index 51 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17915,7 +18003,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 362, index 52 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17946,7 +18034,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 363, index 53 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -17977,7 +18065,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 366, index 54 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -18009,7 +18097,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000 }, { /* page 471, index 55 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -18040,7 +18128,7 @@ static const gunichar attr_data[][256] = { 0x0006, 0x0007, 0x0008, 0x0009 }, { /* page 481, index 56 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -18071,7 +18159,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 482, index 57 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -18102,7 +18190,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 484, index 58 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -18133,7 +18221,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 489, index 59 */ - 0x1e922, 0x1e923, 0x1e924, 0x1e925, 0x1e926, 0x1e927, 0x1e928, 0x1e929, + 0x1e922, 0x1e923, 0x1e924, 0x1e925, 0x1e926, 0x1e927, 0x1e928, 0x1e929, 0x1e92a, 0x1e92b, 0x1e92c, 0x1e92d, 0x1e92e, 0x1e92f, 0x1e930, 0x1e931, 0x1e932, 0x1e933, 0x1e934, 0x1e935, 0x1e936, 0x1e937, 0x1e938, 0x1e939, 0x1e93a, 0x1e93b, 0x1e93c, 0x1e93d, 0x1e93e, 0x1e93f, 0x1e940, 0x1e941, @@ -18165,7 +18253,7 @@ static const gunichar attr_data[][256] = { 0x0000, 0x0000, 0x0000, 0x0000 }, { /* page 507, index 60 */ - 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, + 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, @@ -20232,14 +20320,13 @@ static const struct Interval g_unicode_width_table_wide[] = { {0x2E80, 0x2E99}, {0x2E9B, 0x2EF3}, {0x2F00, 0x2FD5}, -{0x2FF0, 0x2FFB}, -{0x3000, 0x303E}, +{0x2FF0, 0x303E}, {0x3041, 0x3096}, {0x3099, 0x30FF}, {0x3105, 0x312F}, {0x3131, 0x318E}, {0x3190, 0x31E3}, -{0x31F0, 0x321E}, +{0x31EF, 0x321E}, {0x3220, 0x3247}, {0x3250, 0x4DBF}, {0x4E00, 0xA48C}, @@ -20319,6 +20406,7 @@ static const struct Interval g_unicode_width_table_wide[] = { {0x2B740, 0x2B81D}, {0x2B820, 0x2CEA1}, {0x2CEB0, 0x2EBE0}, +{0x2EBF0, 0x2EE5D}, {0x2F800, 0x2FA1D}, {0x30000, 0x3134A}, {0x31350, 0x323AF}, diff --git a/glib/gunicode.h b/glib/gunicode.h index 85b3e09..6f359e1 100644 --- a/glib/gunicode.h +++ b/glib/gunicode.h @@ -204,10 +204,15 @@ typedef enum * @G_UNICODE_BREAK_EMOJI_BASE: Emoji Base (EB). Since: 2.50 * @G_UNICODE_BREAK_EMOJI_MODIFIER: Emoji Modifier (EM). Since: 2.50 * @G_UNICODE_BREAK_ZERO_WIDTH_JOINER: Zero Width Joiner (ZWJ). Since: 2.50 + * @G_UNICODE_BREAK_AKSARA: Aksara (AK). Since: 2.80 + * @G_UNICODE_BREAK_AKSARA_PRE_BASE (AP). Since: 2.80 + * @G_UNICODE_BREAK_AKSARA_START (AS). Since: 2.80 + * @G_UNICODE_BREAK_VIRAMA_FINAL (VF). Since: 2.80 + * @G_UNICODE_BREAK_VIRAMA (VI). Since: 2.80 * * These are the possible line break classifications. * - * Since new unicode versions may add new types here, applications should be ready + * Since new Unicode versions may add new types here, applications should be ready * to handle unknown values. They may be regarded as %G_UNICODE_BREAK_UNKNOWN. * * See [Unicode Line Breaking Algorithm](https://www.unicode.org/reports/tr14/). @@ -257,7 +262,12 @@ typedef enum G_UNICODE_BREAK_REGIONAL_INDICATOR, G_UNICODE_BREAK_EMOJI_BASE, G_UNICODE_BREAK_EMOJI_MODIFIER, - G_UNICODE_BREAK_ZERO_WIDTH_JOINER + G_UNICODE_BREAK_ZERO_WIDTH_JOINER, + G_UNICODE_BREAK_AKSARA, + G_UNICODE_BREAK_AKSARA_PRE_BASE, + G_UNICODE_BREAK_AKSARA_START, + G_UNICODE_BREAK_VIRAMA_FINAL, + G_UNICODE_BREAK_VIRAMA } GUnicodeBreakType; /** diff --git a/glib/gunicomp.h b/glib/gunicomp.h index f2fd759..90fffb3 100644 --- a/glib/gunicomp.h +++ b/glib/gunicomp.h @@ -7,7 +7,7 @@ static const guint16 compose_data[][256] = { { /* page 0, index 0 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 149, 150, 151, 0, 0, 1, 2, 3, 4, 5, 152, 6, 7, 8, 153, 9, 10, 11, 12, 13, 14, 0, 15, 16, 17, 18, 19, 20, 21, @@ -21,7 +21,7 @@ static const guint16 compose_data[][256] = { 164, 0, 0, 0, 0, 58, 59, 165, 0, 166, 0, 0, 0, 60, 0, 0, 0 }, { /* page 1, index 1 */ - 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0, + 0, 0, 61, 62, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 63, 64, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 65, 66, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 167, 168, 0, @@ -35,7 +35,7 @@ static const guint16 compose_data[][256] = { 0 }, { /* page 2, index 2 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 179, 180, 181, 182, 0, 0, 0, 0, 183, 184, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -48,7 +48,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 3, index 3 */ - 378, 379, 380, 381, 382, 0, 383, 384, 385, 386, 387, 388, 389, 0, 0, 390, + 378, 379, 380, 381, 382, 0, 383, 384, 385, 386, 387, 388, 389, 0, 0, 390, 0, 391, 0, 392, 393, 0, 0, 0, 0, 0, 0, 394, 0, 0, 0, 0, 0, 0, 0, 395, 396, 397, 398, 399, 400, 0, 0, 0, 0, 401, 402, 0, 403, 404, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 405, 0, 0, 406, 0, 0, 0, 0, 0, 0, 0, @@ -62,7 +62,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 4, index 4 */ - 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 191, 0, 90, + 0, 0, 0, 0, 0, 0, 190, 0, 0, 0, 0, 0, 0, 0, 0, 0, 89, 0, 0, 191, 0, 90, 91, 192, 92, 0, 193, 0, 0, 0, 194, 0, 0, 0, 0, 93, 0, 0, 0, 195, 0, 0, 0, 196, 0, 197, 0, 0, 94, 0, 0, 198, 0, 95, 96, 199, 97, 0, 200, 0, 0, 0, 201, 0, 0, 0, 0, 98, 0, 0, 0, 202, 0, 0, 0, 203, 0, 204, 0, 0, 0, 0, 0, @@ -76,7 +76,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 6, index 5 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 99, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 212, 0, 213, 0, 0, 0, 0, 0, 0, 0, 0, 409, 410, 411, 0, 0, 0, 0, 0, 0, 0, @@ -89,7 +89,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 9, index 6 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 0, 0, 0, 0, 0, 0, 0, 218, 0, 0, 219, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -102,7 +102,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 11, index 7 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 414, 0, 0, 0, 0, 0, 0, 0, 0, 101, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 415, 416, 0, 0, 0, 0, 0, @@ -115,7 +115,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 12, index 8 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -128,7 +128,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 13, index 9 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 422, 0, 0, 0, 0, 0, 0, 0, 104, 225, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 423, 0, 0, 0, 0, 0, 0, @@ -141,7 +141,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 16, index 10 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 227, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -154,7 +154,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 27, index 11 */ - 0, 0, 0, 0, 0, 228, 0, 229, 0, 230, 0, 231, 0, 232, 0, 0, 0, 233, 0, 0, + 0, 0, 0, 0, 0, 228, 0, 229, 0, 230, 0, 231, 0, 232, 0, 0, 0, 233, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 234, 0, 235, 0, 236, 237, 0, 0, 238, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -167,7 +167,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 30, index 12 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 239, 240, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 241, 242, 0, 0, @@ -180,7 +180,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 31, index 13 */ - 108, 109, 249, 250, 251, 252, 253, 254, 110, 111, 255, 256, 257, 258, + 108, 109, 249, 250, 251, 252, 253, 254, 110, 111, 255, 256, 257, 258, 259, 260, 112, 113, 0, 0, 0, 0, 0, 0, 114, 115, 0, 0, 0, 0, 0, 0, 116, 117, 261, 262, 263, 264, 265, 266, 118, 119, 267, 268, 269, 270, 271, 272, 120, 121, 0, 0, 0, 0, 0, 0, 122, 123, 0, 0, 0, 0, 0, 0, 124, 125, 0, @@ -195,7 +195,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 290, 0, 0, 0, 0, 0, 0, 0, 136, 0 }, { /* page 33, index 14 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -208,7 +208,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 34, index 15 */ - 0, 0, 0, 297, 0, 0, 0, 0, 298, 0, 0, 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 297, 0, 0, 0, 0, 298, 0, 0, 299, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 300, 0, 301, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 302, 0, 0, 0, 0, 0, 0, 303, 0, 304, 0, 0, 305, 0, 0, 0, 0, 306, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -222,7 +222,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 48, index 16 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 332, 0, 0, 0, 0, 333, 0, 334, 0, 335, 0, 336, 0, 337, 0, 338, 0, 339, 0, 340, 0, @@ -236,7 +236,7 @@ static const guint16 compose_data[][256] = { 0, 0, 365, 366, 367, 368, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 369, 0, 0 }, { /* page 272, index 17 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -249,7 +249,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 273, index 18 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 373, 374, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -262,7 +262,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 275, index 19 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 427, 0, 0, 0, 0, 0, 0, 0, 0, 147, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 428, 0, 0, 0, 0, 0, 0, @@ -275,7 +275,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 276, index 20 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -288,7 +288,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 277, index 21 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -301,7 +301,7 @@ static const guint16 compose_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 281, index 22 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 377, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/glib/gunidecomp.c b/glib/gunidecomp.c index f149443..5c2d41b 100644 --- a/glib/gunidecomp.c +++ b/glib/gunidecomp.c @@ -19,43 +19,6 @@ * along with this library; if not, see . */ -/** - * SECTION:unicode - * @Title: Unicode Manipulation - * @Short_description: functions operating on Unicode characters and - * UTF-8 strings - * @See_also: g_locale_to_utf8(), g_locale_from_utf8() - * - * This section describes a number of functions for dealing with - * Unicode characters and strings. There are analogues of the - * traditional `ctype.h` character classification and case conversion - * functions, UTF-8 analogues of some string utility functions, - * functions to perform normalization, case conversion and collation - * on UTF-8 strings and finally functions to convert between the UTF-8, - * UTF-16 and UCS-4 encodings of Unicode. - * - * The implementations of the Unicode functions in GLib are based - * on the Unicode Character Data tables, which are available from - * [www.unicode.org](http://www.unicode.org/). - * - * * Unicode 4.0 was added in GLib 2.8 - * * Unicode 4.1 was added in GLib 2.10 - * * Unicode 5.0 was added in GLib 2.12 - * * Unicode 5.1 was added in GLib 2.16.3 - * * Unicode 6.0 was added in GLib 2.30 - * * Unicode 6.1 was added in GLib 2.32 - * * Unicode 6.2 was added in GLib 2.36 - * * Unicode 6.3 was added in GLib 2.40 - * * Unicode 7.0 was added in GLib 2.42 - * * Unicode 8.0 was added in GLib 2.48 - * * Unicode 9.0 was added in GLib 2.50.1 - * * Unicode 10.0 was added in GLib 2.54 - * * Unicode 11.10 was added in GLib 2.58 - * * Unicode 12.0 was added in GLib 2.62 - * * Unicode 12.1 was added in GLib 2.62 - * * Unicode 13.0 was added in GLib 2.66 - */ - #include "config.h" #include diff --git a/glib/gunidecomp.h b/glib/gunidecomp.h index a33d068..1c742fa 100644 --- a/glib/gunidecomp.h +++ b/glib/gunidecomp.h @@ -15,7 +15,7 @@ static const guchar cclass_data[][256] = { { /* page 3, index 0 */ - 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 232, 220, 220, 220, 220, 232, 216, 220, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 202, 202, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 220, 1, 1, 1, 1, 1, 220, @@ -31,7 +31,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 4, index 1 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -44,7 +44,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 5, index 2 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -58,7 +58,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 6, index 3 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 230, 30, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 27, 28, 29, 30, 31, 32, 33, 34, 230, 230, 220, @@ -72,7 +72,7 @@ static const guchar cclass_data[][256] = { 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 7, index 4 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 230, 230, 220, 230, 230, 220, 220, 220, 230, 220, 220, 230, 220, 230, 230, 230, 220, 230, 220, 230, 220, 230, 220, 230, 230, 0, 0, 0, @@ -86,7 +86,7 @@ static const guchar cclass_data[][256] = { 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, { /* page 8, index 5 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -101,7 +101,7 @@ static const guchar cclass_data[][256] = { 29, 230, 230, 230, 220, 230, 230, 220, 220, 230, 230, 230, 230, 230 }, { /* page 9, index 6 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 230, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -114,7 +114,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0 }, { /* page 10, index 7 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -127,7 +127,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 11, index 8 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -140,7 +140,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 12, index 9 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 84, 91, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -153,7 +153,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 13, index 10 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -166,7 +166,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 14, index 11 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 103, 103, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 107, 107, 107, 107, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -179,7 +179,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 15, index 12 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 220, 0, 216, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -193,7 +193,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0 }, { /* page 16, index 13 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -206,7 +206,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 19, index 14 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, @@ -219,7 +219,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 23, index 15 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -232,7 +232,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 24, index 16 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -245,7 +245,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 25, index 17 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 222, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -258,7 +258,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 26, index 18 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -272,7 +272,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 27, index 19 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -285,7 +285,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 28, index 20 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -299,7 +299,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0 }, { /* page 29, index 21 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -314,7 +314,7 @@ static const guchar cclass_data[][256] = { 228, 220, 218, 230, 233, 220, 230, 220 }, { /* page 32, index 22 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -328,7 +328,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0 }, { /* page 44, index 23 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -341,7 +341,7 @@ static const guchar cclass_data[][256] = { 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 45, index 24 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -355,7 +355,7 @@ static const guchar cclass_data[][256] = { 230, 230, 230, 230, 230, 230, 230, 230 }, { /* page 48, index 25 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 218, 228, 232, 222, 224, 224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -368,7 +368,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 166, index 26 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -382,7 +382,7 @@ static const guchar cclass_data[][256] = { 0 }, { /* page 168, index 27 */ - 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -396,7 +396,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0 }, { /* page 169, index 28 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -409,7 +409,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 170, index 29 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -422,7 +422,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 171, index 30 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -435,7 +435,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 251, index 31 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -448,7 +448,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 254, index 32 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 220, 220, 220, 220, 220, 220, 220, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -462,7 +462,7 @@ static const guchar cclass_data[][256] = { 0, 0 }, { /* page 257, index 33 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -475,7 +475,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 0 }, { /* page 258, index 34 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -488,7 +488,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 259, index 35 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -501,7 +501,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 266, index 36 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 0, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 1, 220, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -514,7 +514,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 269, index 37 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -527,7 +527,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 270, index 38 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -540,7 +540,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 220 }, { /* page 271, index 39 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 220, 220, 230, 230, 230, 220, 230, 220, 220, 220, 220, 0, 0, 0, 0, 0, 0, 0, 0, @@ -554,7 +554,7 @@ static const guchar cclass_data[][256] = { 0 }, { /* page 272, index 40 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -567,7 +567,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 273, index 41 */ - 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -580,7 +580,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 274, index 42 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -593,7 +593,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 275, index 43 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -606,7 +606,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 276, index 44 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 0, @@ -619,7 +619,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 277, index 45 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -632,7 +632,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 278, index 46 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -645,7 +645,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 279, index 47 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -658,7 +658,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 280, index 48 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -671,7 +671,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 281, index 49 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -684,7 +684,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 282, index 50 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -697,7 +697,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 284, index 51 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -710,7 +710,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 285, index 52 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -723,7 +723,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 287, index 53 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -736,7 +736,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 362, index 54 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -749,7 +749,7 @@ static const guchar cclass_data[][256] = { 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 363, index 55 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -762,7 +762,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 367, index 56 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -775,7 +775,7 @@ static const guchar cclass_data[][256] = { 6, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 444, index 57 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -788,7 +788,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 465, index 58 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -802,7 +802,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 466, index 59 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -815,7 +815,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 480, index 60 */ - 230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230, 230, 230, + 230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 230, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 230, 230, 0, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -829,7 +829,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 481, index 61 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -842,7 +842,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 482, index 62 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -855,7 +855,7 @@ static const guchar cclass_data[][256] = { 230, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 484, index 63 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -868,7 +868,7 @@ static const guchar cclass_data[][256] = { 220, 230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 488, index 64 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, @@ -881,7 +881,7 @@ static const guchar cclass_data[][256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }, { /* page 489, index 65 */ - 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 230, 230, 230, 230, 230, 230, 7, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, diff --git a/glib/guri.c b/glib/guri.c index 5872550..592b762 100644 --- a/glib/guri.c +++ b/glib/guri.c @@ -29,23 +29,74 @@ #include "guriprivate.h" /** - * SECTION:guri - * @short_description: URI-handling utilities - * @include: glib.h + * GUri: * - * The #GUri type and related functions can be used to parse URIs into + * The `GUri` type and related functions can be used to parse URIs into * their components, and build valid URIs from individual components. * - * Note that #GUri scope is to help manipulate URIs in various applications, + * Since `GUri` only represents absolute URIs, all `GUri`s will have a + * URI scheme, so [method@GLib.Uri.get_scheme] will always return a non-`NULL` + * answer. Likewise, by definition, all URIs have a path component, so + * [method@GLib.Uri.get_path] will always return a non-`NULL` string (which may + * be empty). + * + * If the URI string has an + * [‘authority’ component](https://tools.ietf.org/html/rfc3986#section-3) (that + * is, if the scheme is followed by `://` rather than just `:`), then the + * `GUri` will contain a hostname, and possibly a port and ‘userinfo’. + * Additionally, depending on how the `GUri` was constructed/parsed (for example, + * using the `G_URI_FLAGS_HAS_PASSWORD` and `G_URI_FLAGS_HAS_AUTH_PARAMS` flags), + * the userinfo may be split out into a username, password, and + * additional authorization-related parameters. + * + * Normally, the components of a `GUri` will have all `%`-encoded + * characters decoded. However, if you construct/parse a `GUri` with + * `G_URI_FLAGS_ENCODED`, then the `%`-encoding will be preserved instead in + * the userinfo, path, and query fields (and in the host field if also + * created with `G_URI_FLAGS_NON_DNS`). In particular, this is necessary if + * the URI may contain binary data or non-UTF-8 text, or if decoding + * the components might change the interpretation of the URI. + * + * For example, with the encoded flag: + * + * ```c + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_ENCODED, &err); + * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue"); + * ``` + * + * While the default `%`-decoding behaviour would give: + * + * ```c + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_NONE, &err); + * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http://host/path?param=value"); + * ``` + * + * During decoding, if an invalid UTF-8 string is encountered, parsing will fail + * with an error indicating the bad string location: + * + * ```c + * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fbad%3D%00alue", G_URI_FLAGS_NONE, &err); + * g_assert_error (err, G_URI_ERROR, G_URI_ERROR_BAD_QUERY); + * ``` + * + * You should pass `G_URI_FLAGS_ENCODED` or `G_URI_FLAGS_ENCODED_QUERY` if you + * need to handle that case manually. In particular, if the query string + * contains `=` characters that are `%`-encoded, you should let + * [func@GLib.Uri.parse_params] do the decoding once of the query. + * + * `GUri` is immutable once constructed, and can safely be accessed from + * multiple threads. Its reference counting is atomic. + * + * Note that the scope of `GUri` is to help manipulate URIs in various applications, * following [RFC 3986](https://tools.ietf.org/html/rfc3986). In particular, - * it doesn't intend to cover web browser needs, and doesn't implement the + * it doesn't intend to cover web browser needs, and doesn’t implement the * [WHATWG URL](https://url.spec.whatwg.org/) standard. No APIs are provided to * help prevent * [homograph attacks](https://en.wikipedia.org/wiki/IDN_homograph_attack), so - * #GUri is not suitable for formatting URIs for display to the user for making + * `GUri` is not suitable for formatting URIs for display to the user for making * security-sensitive decisions. * - * ## Relative and absolute URIs # {#relative-absolute-uris} + * ## Relative and absolute URIs * * As defined in [RFC 3986](https://tools.ietf.org/html/rfc3986#section-4), the * hierarchical nature of URIs means that they can either be ‘relative @@ -65,145 +116,85 @@ * * Absolute URIs have a scheme specified. Any other components of the URI which * are missing are specified as explicitly unset in the URI, rather than being - * resolved relative to a base URI using g_uri_parse_relative(). + * resolved relative to a base URI using [method@GLib.Uri.parse_relative]. * * For example, a valid absolute URI is `file:///home/bob` or * `https://search.com?query=string`. * - * A #GUri instance is always an absolute URI. A string may be an absolute URI + * A `GUri` instance is always an absolute URI. A string may be an absolute URI * or a relative reference; see the documentation for individual functions as to * what forms they accept. * * ## Parsing URIs * - * The most minimalist APIs for parsing URIs are g_uri_split() and - * g_uri_split_with_user(). These split a URI into its component + * The most minimalist APIs for parsing URIs are [func@GLib.Uri.split] and + * [func@GLib.Uri.split_with_user]. These split a URI into its component * parts, and return the parts; the difference between the two is that - * g_uri_split() treats the ‘userinfo’ component of the URI as a - * single element, while g_uri_split_with_user() can (depending on the - * #GUriFlags you pass) treat it as containing a username, password, - * and authentication parameters. Alternatively, g_uri_split_network() + * [func@GLib.Uri.split] treats the ‘userinfo’ component of the URI as a + * single element, while [func@GLib.Uri.split_with_user] can (depending on the + * [flags@GLib.UriFlags] you pass) treat it as containing a username, password, + * and authentication parameters. Alternatively, [func@GLib.Uri.split_network] * can be used when you are only interested in the components that are * needed to initiate a network connection to the service (scheme, * host, and port). * - * g_uri_parse() is similar to g_uri_split(), but instead of returning - * individual strings, it returns a #GUri structure (and it requires + * [func@GLib.Uri.parse] is similar to [func@GLib.Uri.split], but instead of + * returning individual strings, it returns a `GUri` structure (and it requires * that the URI be an absolute URI). * - * g_uri_resolve_relative() and g_uri_parse_relative() allow you to - * resolve a relative URI relative to a base URI. - * g_uri_resolve_relative() takes two strings and returns a string, - * and g_uri_parse_relative() takes a #GUri and a string and returns a - * #GUri. + * [func@GLib.Uri.resolve_relative] and [method@GLib.Uri.parse_relative] allow + * you to resolve a relative URI relative to a base URI. + * [func@GLib.Uri.resolve_relative] takes two strings and returns a string, + * and [method@GLib.Uri.parse_relative] takes a `GUri` and a string and returns a + * `GUri`. * - * All of the parsing functions take a #GUriFlags argument describing + * All of the parsing functions take a [flags@GLib.UriFlags] argument describing * exactly how to parse the URI; see the documentation for that type * for more details on the specific flags that you can pass. If you * need to choose different flags based on the type of URI, you can - * use g_uri_peek_scheme() on the URI string to check the scheme + * use [func@GLib.Uri.peek_scheme] on the URI string to check the scheme * first, and use that to decide what flags to parse it with. * - * For example, you might want to use %G_URI_PARAMS_WWW_FORM when parsing the - * params for a web URI, so compare the result of g_uri_peek_scheme() against - * `http` and `https`. + * For example, you might want to use `G_URI_PARAMS_WWW_FORM` when parsing the + * params for a web URI, so compare the result of [func@GLib.Uri.peek_scheme] + * against `http` and `https`. * * ## Building URIs * - * g_uri_join() and g_uri_join_with_user() can be used to construct + * [func@GLib.Uri.join] and [func@GLib.Uri.join_with_user] can be used to construct * valid URI strings from a set of component strings. They are the - * inverse of g_uri_split() and g_uri_split_with_user(). + * inverse of [func@GLib.Uri.split] and [func@GLib.Uri.split_with_user]. * - * Similarly, g_uri_build() and g_uri_build_with_user() can be used to - * construct a #GUri from a set of component strings. + * Similarly, [func@GLib.Uri.build] and [func@GLib.Uri.build_with_user] can be + * used to construct a `GUri` from a set of component strings. * * As with the parsing functions, the building functions take a - * #GUriFlags argument. In particular, it is important to keep in mind + * [flags@GLib.UriFlags] argument. In particular, it is important to keep in mind * whether the URI components you are using are already `%`-encoded. If so, - * you must pass the %G_URI_FLAGS_ENCODED flag. + * you must pass the `G_URI_FLAGS_ENCODED` flag. * * ## `file://` URIs * * Note that Windows and Unix both define special rules for parsing * `file://` URIs (involving non-UTF-8 character sets on Unix, and the - * interpretation of path separators on Windows). #GUri does not - * implement these rules. Use g_filename_from_uri() and - * g_filename_to_uri() if you want to properly convert between + * interpretation of path separators on Windows). `GUri` does not + * implement these rules. Use [func@GLib.filename_from_uri] and + * [func@GLib.filename_to_uri] if you want to properly convert between * `file://` URIs and local filenames. * * ## URI Equality * * Note that there is no `g_uri_equal ()` function, because comparing - * URIs usefully requires scheme-specific knowledge that #GUri does - * not have. #GUri can help with normalization if you use the various - * encoded #GUriFlags as well as %G_URI_FLAGS_SCHEME_NORMALIZE however - * it is not comprehensive. + * URIs usefully requires scheme-specific knowledge that `GUri` does + * not have. `GUri` can help with normalization if you use the various + * encoded [flags@GLib.UriFlags] as well as `G_URI_FLAGS_SCHEME_NORMALIZE` + * however it is not comprehensive. * For example, `data:,foo` and `data:;base64,Zm9v` resolve to the same * thing according to the `data:` URI specification which GLib does not * handle. * * Since: 2.66 */ - -/** - * GUri: - * - * A parsed absolute URI. - * - * Since #GUri only represents absolute URIs, all #GUris will have a - * URI scheme, so g_uri_get_scheme() will always return a non-%NULL - * answer. Likewise, by definition, all URIs have a path component, so - * g_uri_get_path() will always return a non-%NULL string (which may be empty). - * - * If the URI string has an - * [‘authority’ component](https://tools.ietf.org/html/rfc3986#section-3) (that - * is, if the scheme is followed by `://` rather than just `:`), then the - * #GUri will contain a hostname, and possibly a port and ‘userinfo’. - * Additionally, depending on how the #GUri was constructed/parsed (for example, - * using the %G_URI_FLAGS_HAS_PASSWORD and %G_URI_FLAGS_HAS_AUTH_PARAMS flags), - * the userinfo may be split out into a username, password, and - * additional authorization-related parameters. - * - * Normally, the components of a #GUri will have all `%`-encoded - * characters decoded. However, if you construct/parse a #GUri with - * %G_URI_FLAGS_ENCODED, then the `%`-encoding will be preserved instead in - * the userinfo, path, and query fields (and in the host field if also - * created with %G_URI_FLAGS_NON_DNS). In particular, this is necessary if - * the URI may contain binary data or non-UTF-8 text, or if decoding - * the components might change the interpretation of the URI. - * - * For example, with the encoded flag: - * - * |[ - * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_ENCODED, &err); - * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue"); - * ]| - * - * While the default `%`-decoding behaviour would give: - * - * |[ - * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fparam%3Dvalue", G_URI_FLAGS_NONE, &err); - * g_assert_cmpstr (g_uri_get_query (uri), ==, "query=http://host/path?param=value"); - * ]| - * - * During decoding, if an invalid UTF-8 string is encountered, parsing will fail - * with an error indicating the bad string location: - * - * |[ - * g_autoptr(GUri) uri = g_uri_parse ("http://host/path?query=http%3A%2F%2Fhost%2Fpath%3Fbad%3D%00alue", G_URI_FLAGS_NONE, &err); - * g_assert_error (err, G_URI_ERROR, G_URI_ERROR_BAD_QUERY); - * ]| - * - * You should pass %G_URI_FLAGS_ENCODED or %G_URI_FLAGS_ENCODED_QUERY if you - * need to handle that case manually. In particular, if the query string - * contains `=` characters that are `%`-encoded, you should let - * g_uri_parse_params() do the decoding once of the query. - * - * #GUri is immutable once constructed, and can safely be accessed from - * multiple threads. Its reference counting is atomic. - * - * Since: 2.66 - */ struct _GUri { gchar *scheme; gchar *userinfo; @@ -1072,7 +1063,7 @@ g_uri_split_internal (const gchar *uri_string, * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_ref (which can be an - * [absolute or relative URI][relative-absolute-uris]) according to @flags, and + * [absolute or relative URI](#relative-and-absolute-uris)) according to @flags, and * returns the pieces. Any component that doesn't appear in @uri_ref will be * returned as %NULL (but note that all URIs always have a path component, * though it may be the empty string). @@ -1139,7 +1130,7 @@ g_uri_split (const gchar *uri_ref, * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_ref (which can be an - * [absolute or relative URI][relative-absolute-uris]) according to @flags, and + * [absolute or relative URI](#relative-and-absolute-uris)) according to @flags, and * returns the pieces. Any component that doesn't appear in @uri_ref will be * returned as %NULL (but note that all URIs always have a path component, * though it may be the empty string). @@ -1191,7 +1182,7 @@ g_uri_split_with_user (const gchar *uri_ref, * port, or `-1` * @error: #GError for error reporting, or %NULL to ignore. * - * Parses @uri_string (which must be an [absolute URI][relative-absolute-uris]) + * Parses @uri_string (which must be an [absolute URI](#relative-and-absolute-uris)) * according to @flags, and returns the pieces relevant to connecting to a host. * See the documentation for g_uri_split() for more details; this is * mostly a wrapper around that function with simpler arguments. @@ -1260,7 +1251,7 @@ g_uri_split_network (const gchar *uri_string, * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_string according to @flags, to determine whether it is a valid - * [absolute URI][relative-absolute-uris], i.e. it does not need to be resolved + * [absolute URI](#relative-and-absolute-uris), i.e. it does not need to be resolved * relative to another URI using g_uri_parse_relative(). * * If it’s not a valid URI, an error is returned explaining how it’s invalid. @@ -1398,7 +1389,7 @@ remove_dot_segments (gchar *path) * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_string according to @flags. If the result is not a - * valid [absolute URI][relative-absolute-uris], it will be discarded, and an + * valid [absolute URI](#relative-and-absolute-uris), it will be discarded, and an * error returned. * * Return value: (transfer full): a new #GUri, or NULL on error. @@ -1424,7 +1415,7 @@ g_uri_parse (const gchar *uri_string, * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_ref according to @flags and, if it is a - * [relative URI][relative-absolute-uris], resolves it relative to @base_uri. + * [relative URI](#relative-and-absolute-uris), resolves it relative to @base_uri. * If the result is not a valid absolute URI, it will be discarded, and an error * returned. * @@ -1555,7 +1546,7 @@ g_uri_parse_relative (GUri *base_uri, * @error: #GError for error reporting, or %NULL to ignore. * * Parses @uri_ref according to @flags and, if it is a - * [relative URI][relative-absolute-uris], resolves it relative to + * [relative URI](#relative-and-absolute-uris), resolves it relative to * @base_uri_string. If the result is not a valid absolute URI, it will be * discarded, and an error returned. * diff --git a/glib/gutils.c b/glib/gutils.c index 362c55a..84912c0 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -79,14 +79,6 @@ #endif -/** - * SECTION:misc_utils - * @title: Miscellaneous Utility Functions - * @short_description: a selection of portable utility functions - * - * These are portable utility functions. - */ - #ifdef G_PLATFORM_WIN32 # include # ifndef GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS @@ -663,7 +655,7 @@ g_get_user_database_entry (void) { static UserDatabaseEntry *entry; - if (g_once_init_enter (&entry)) + if (g_once_init_enter_pointer (&entry)) { static UserDatabaseEntry e; @@ -787,7 +779,7 @@ g_get_user_database_entry (void) if (!e.real_name) e.real_name = g_strdup ("Unknown"); - g_once_init_leave (&entry, &e); + g_once_init_leave_pointer (&entry, &e); } return entry; @@ -1065,7 +1057,7 @@ g_get_host_name (void) { static gchar *hostname; - if (g_once_init_enter (&hostname)) + if (g_once_init_enter_pointer (&hostname)) { gboolean failed; gchar *utmp = NULL; @@ -1122,13 +1114,12 @@ g_get_host_name (void) failed = TRUE; #endif - g_once_init_leave (&hostname, failed ? g_strdup ("localhost") : utmp); + g_once_init_leave_pointer (&hostname, failed ? g_strdup ("localhost") : utmp); } return hostname; } -G_LOCK_DEFINE_STATIC (g_prgname); static const gchar *g_prgname = NULL; /* always a quark */ /** @@ -1150,13 +1141,7 @@ static const gchar *g_prgname = NULL; /* always a quark */ const gchar* g_get_prgname (void) { - const gchar* retval; - - G_LOCK (g_prgname); - retval = g_prgname; - G_UNLOCK (g_prgname); - - return retval; + return g_atomic_pointer_get (&g_prgname); } /** @@ -1179,13 +1164,29 @@ g_get_prgname (void) void g_set_prgname (const gchar *prgname) { - GQuark qprgname = g_quark_from_string (prgname); - G_LOCK (g_prgname); - g_prgname = g_quark_to_string (qprgname); - G_UNLOCK (g_prgname); + prgname = g_intern_string (prgname); + g_atomic_pointer_set (&g_prgname, prgname); +} + +/** + * g_set_prgname_once: + * @prgname: the name of the program. + * + * If g_get_prgname() is not set, this is the same as setting + * the name via g_set_prgname() and %TRUE is returned. Otherwise, + * does nothing and returns %FALSE. This is thread-safe. + * + * Returns: whether g_prgname was initialized by the call. + */ +gboolean +g_set_prgname_once (const gchar *prgname) +{ + /* if @prgname is NULL, then this has the same effect as calling + * (g_get_prgname()==NULL). */ + prgname = g_intern_string (prgname); + return g_atomic_pointer_compare_and_exchange (&g_prgname, NULL, prgname); } -G_LOCK_DEFINE_STATIC (g_application_name); static gchar *g_application_name = NULL; /** @@ -1207,16 +1208,14 @@ static gchar *g_application_name = NULL; const gchar * g_get_application_name (void) { - gchar* retval; + const char *retval; - G_LOCK (g_application_name); - retval = g_application_name; - G_UNLOCK (g_application_name); + retval = g_atomic_pointer_get (&g_application_name); - if (retval == NULL) - return g_get_prgname (); - - return retval; + if (retval) + return retval; + + return g_get_prgname (); } /** @@ -1240,17 +1239,17 @@ g_get_application_name (void) void g_set_application_name (const gchar *application_name) { - gboolean already_set = FALSE; - - G_LOCK (g_application_name); - if (g_application_name) - already_set = TRUE; - else - g_application_name = g_strdup (application_name); - G_UNLOCK (g_application_name); + char *name; + + g_return_if_fail (application_name); - if (already_set) - g_warning ("g_set_application_name() called multiple times"); + name = g_strdup (application_name); + + if (!g_atomic_pointer_compare_and_exchange (&g_application_name, NULL, name)) + { + g_warning ("g_set_application_name() called multiple times"); + g_free (name); + } } #ifdef G_OS_WIN32 @@ -1876,6 +1875,7 @@ g_build_user_data_dir (void) if (!data_dir || !data_dir[0]) { gchar *home_dir = g_build_home_dir (); + g_free (data_dir); data_dir = g_build_filename (home_dir, ".local", "share", NULL); g_free (home_dir); } @@ -2913,7 +2913,7 @@ g_format_size (guint64 size) * a strong "power of 2" basis, like RAM sizes or RAID stripe sizes. * Network and storage sizes should be reported in the normal SI units. * @G_FORMAT_SIZE_BITS: set the size as a quantity in bits, rather than - * bytes, and return units in bits. For example, ‘Mb’ rather than ‘MB’. + * bytes, and return units in bits. For example, ‘Mbit’ rather than ‘MB’. * @G_FORMAT_SIZE_ONLY_VALUE: return only value, without unit; this should * not be used together with @G_FORMAT_SIZE_LONG_FORMAT * nor @G_FORMAT_SIZE_ONLY_UNIT. Since: 2.74 @@ -2990,32 +2990,32 @@ g_format_size_full (guint64 size, { EXBIBYTE_FACTOR, N_("EiB") } }, { - /* Translators: A unit symbol for size formatting, showing for example: "13.0 kb" */ - { KILOBYTE_FACTOR, N_("kb") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mb" */ - { MEGABYTE_FACTOR, N_("Mb") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gb" */ - { GIGABYTE_FACTOR, N_("Gb") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tb" */ - { TERABYTE_FACTOR, N_("Tb") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pb" */ - { PETABYTE_FACTOR, N_("Pb") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Eb" */ - { EXABYTE_FACTOR, N_("Eb") } + /* Translators: A unit symbol for size formatting, showing for example: "13.0 kbit" */ + { KILOBYTE_FACTOR, N_("kbit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mbit" */ + { MEGABYTE_FACTOR, N_("Mbit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gbit" */ + { GIGABYTE_FACTOR, N_("Gbit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tbit" */ + { TERABYTE_FACTOR, N_("Tbit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pbit" */ + { PETABYTE_FACTOR, N_("Pbit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Ebit" */ + { EXABYTE_FACTOR, N_("Ebit") } }, { - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Kib" */ - { KIBIBYTE_FACTOR, N_("Kib") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mib" */ - { MEBIBYTE_FACTOR, N_("Mib") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gib" */ - { GIBIBYTE_FACTOR, N_("Gib") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tib" */ - { TEBIBYTE_FACTOR, N_("Tib") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pib" */ - { PEBIBYTE_FACTOR, N_("Pib") }, - /* Translators: A unit symbol for size formatting, showing for example: "13.0 Eib" */ - { EXBIBYTE_FACTOR, N_("Eib") } + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Kibit" */ + { KIBIBYTE_FACTOR, N_("Kibit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Mibit" */ + { MEBIBYTE_FACTOR, N_("Mibit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Gibit" */ + { GIBIBYTE_FACTOR, N_("Gibit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Tibit" */ + { TEBIBYTE_FACTOR, N_("Tibit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Pibit" */ + { PEBIBYTE_FACTOR, N_("Pibit") }, + /* Translators: A unit symbol for size formatting, showing for example: "13.0 Eibit" */ + { EXBIBYTE_FACTOR, N_("Eibit") } } }; diff --git a/glib/gutilsprivate.h b/glib/gutilsprivate.h index b4f1b98..7bbde71 100644 --- a/glib/gutilsprivate.h +++ b/glib/gutilsprivate.h @@ -59,6 +59,8 @@ void _g_unset_cached_tmp_dir (void); gboolean _g_localtime (time_t timet, struct tm *tm); +gboolean g_set_prgname_once (const gchar *prgname); + G_END_DECLS #endif /* __G_UTILS_PRIVATE_H__ */ diff --git a/glib/guuid.c b/glib/guuid.c index 5368465..f2d632b 100644 --- a/glib/guuid.c +++ b/glib/guuid.c @@ -35,28 +35,6 @@ typedef struct { guint8 bytes[16]; } GUuid; -/** - * SECTION:uuid - * @title: GUuid - * @short_description: a universally unique identifier - * - * A UUID, or Universally unique identifier, is intended to uniquely - * identify information in a distributed environment. For the - * definition of UUID, see [RFC 4122](https://tools.ietf.org/html/rfc4122.html). - * - * The creation of UUIDs does not require a centralized authority. - * - * UUIDs are of relatively small size (128 bits, or 16 bytes). The - * common string representation (ex: - * 1d6c0810-2bd6-45f3-9890-0268422a6f14) needs 37 bytes. - * - * The UUID specification defines 5 versions, and calling - * g_uuid_string_random() will generate a unique (or rather random) - * UUID of the most common version, version 4. - * - * Since: 2.52 - */ - /* * g_uuid_to_string: * @uuid: a #GUuid diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c index 06e857b..d22299e 100644 --- a/glib/gvariant-core.c +++ b/glib/gvariant-core.c @@ -49,14 +49,6 @@ * Most GVariant API functions are in gvariant.c. */ -/** - * GVariant: - * - * #GVariant is an opaque data structure and can only be accessed - * using the following functions. - * - * Since: 2.24 - **/ struct _GVariant /* see below for field member documentation */ { diff --git a/glib/gvariant.c b/glib/gvariant.c index b7e4241..8316184 100644 --- a/glib/gvariant.c +++ b/glib/gvariant.c @@ -36,115 +36,114 @@ #include /** - * SECTION:gvariant - * @title: GVariant - * @short_description: strongly typed value datatype - * @see_also: GVariantType + * GVariant: * - * #GVariant is a variant datatype; it can contain one or more values + * `GVariant` is a variant datatype; it can contain one or more values * along with information about the type of the values. * - * A #GVariant may contain simple types, like an integer, or a boolean value; + * A `GVariant` may contain simple types, like an integer, or a boolean value; * or complex types, like an array of two strings, or a dictionary of key - * value pairs. A #GVariant is also immutable: once it's been created neither + * value pairs. A `GVariant` is also immutable: once it’s been created neither * its type nor its content can be modified further. * - * GVariant is useful whenever data needs to be serialized, for example when - * sending method parameters in D-Bus, or when saving settings using GSettings. + * `GVariant` is useful whenever data needs to be serialized, for example when + * sending method parameters in D-Bus, or when saving settings using + * [class@Gio.Settings]. * - * When creating a new #GVariant, you pass the data you want to store in it + * When creating a new `GVariant`, you pass the data you want to store in it * along with a string representing the type of data you wish to pass to it. * - * For instance, if you want to create a #GVariant holding an integer value you + * For instance, if you want to create a `GVariant` holding an integer value you * can use: * - * |[ - * GVariant *v = g_variant_new ("u", 40); - * ]| + * ```c + * GVariant *v = g_variant_new ("u", 40); + * ``` * - * The string "u" in the first argument tells #GVariant that the data passed to - * the constructor (40) is going to be an unsigned integer. + * The string `u` in the first argument tells `GVariant` that the data passed to + * the constructor (`40`) is going to be an unsigned integer. * - * More advanced examples of #GVariant in use can be found in documentation for - * [GVariant format strings][gvariant-format-strings-pointers]. + * More advanced examples of `GVariant` in use can be found in documentation for + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * The range of possible values is determined by the type. * - * The type system used by #GVariant is #GVariantType. + * The type system used by `GVariant` is [type@GLib.VariantType]. * - * #GVariant instances always have a type and a value (which are given - * at construction time). The type and value of a #GVariant instance - * can never change other than by the #GVariant itself being - * destroyed. A #GVariant cannot contain a pointer. + * `GVariant` instances always have a type and a value (which are given + * at construction time). The type and value of a `GVariant` instance + * can never change other than by the `GVariant` itself being + * destroyed. A `GVariant` cannot contain a pointer. * - * #GVariant is reference counted using g_variant_ref() and - * g_variant_unref(). #GVariant also has floating reference counts -- - * see g_variant_ref_sink(). + * `GVariant` is reference counted using [method@GLib.Variant.ref] and + * [method@GLib.Variant.unref]. `GVariant` also has floating reference counts — + * see [method@GLib.Variant.ref_sink]. * - * #GVariant is completely threadsafe. A #GVariant instance can be + * `GVariant` is completely threadsafe. A `GVariant` instance can be * concurrently accessed in any way from any number of threads without * problems. * - * #GVariant is heavily optimised for dealing with data in serialized + * `GVariant` is heavily optimised for dealing with data in serialized * form. It works particularly well with data located in memory-mapped * files. It can perform nearly all deserialization operations in a * small constant time, usually touching only a single memory page. - * Serialized #GVariant data can also be sent over the network. + * Serialized `GVariant` data can also be sent over the network. * - * #GVariant is largely compatible with D-Bus. Almost all types of - * #GVariant instances can be sent over D-Bus. See #GVariantType for - * exceptions. (However, #GVariant's serialization format is not the same - * as the serialization format of a D-Bus message body: use #GDBusMessage, - * in the gio library, for those.) + * `GVariant` is largely compatible with D-Bus. Almost all types of + * `GVariant` instances can be sent over D-Bus. See [type@GLib.VariantType] for + * exceptions. (However, `GVariant`’s serialization format is not the same + * as the serialization format of a D-Bus message body: use + * [class@Gio.DBusMessage], in the GIO library, for those.) * - * For space-efficiency, the #GVariant serialization format does not - * automatically include the variant's length, type or endianness, + * For space-efficiency, the `GVariant` serialization format does not + * automatically include the variant’s length, type or endianness, * which must either be implied from context (such as knowledge that a * particular file format always contains a little-endian - * %G_VARIANT_TYPE_VARIANT which occupies the whole length of the file) + * `G_VARIANT_TYPE_VARIANT` which occupies the whole length of the file) * or supplied out-of-band (for instance, a length, type and/or endianness * indicator could be placed at the beginning of a file, network message * or network stream). * - * A #GVariant's size is limited mainly by any lower level operating - * system constraints, such as the number of bits in #gsize. For + * A `GVariant`’s size is limited mainly by any lower level operating + * system constraints, such as the number of bits in `gsize`. For * example, it is reasonable to have a 2GB file mapped into memory - * with #GMappedFile, and call g_variant_new_from_data() on it. + * with [struct@GLib.MappedFile], and call [ctor@GLib.Variant.new_from_data] on + * it. * - * For convenience to C programmers, #GVariant features powerful + * For convenience to C programmers, `GVariant` features powerful * varargs-based value construction and destruction. This feature is * designed to be embedded in other libraries. * - * There is a Python-inspired text language for describing #GVariant - * values. #GVariant includes a printer for this language and a parser + * There is a Python-inspired text language for describing `GVariant` + * values. `GVariant` includes a printer for this language and a parser * with type inferencing. * * ## Memory Use * - * #GVariant tries to be quite efficient with respect to memory use. + * `GVariant` tries to be quite efficient with respect to memory use. * This section gives a rough idea of how much memory is used by the * current implementation. The information here is subject to change * in the future. * - * The memory allocated by #GVariant can be grouped into 4 broad + * The memory allocated by `GVariant` can be grouped into 4 broad * purposes: memory for serialized data, memory for the type * information cache, buffer management memory and memory for the - * #GVariant structure itself. + * `GVariant` structure itself. * * ## Serialized Data Memory * - * This is the memory that is used for storing GVariant data in + * This is the memory that is used for storing `GVariant` data in * serialized form. This is what would be sent over the network or * what would end up on disk, not counting any indicator of the * endianness, or of the length or type of the top-level variant. * * The amount of memory required to store a boolean is 1 byte. 16, * 32 and 64 bit integers and double precision floating point numbers - * use their "natural" size. Strings (including object path and + * use their ‘natural’ size. Strings (including object path and * signature strings) are stored with a nul terminator, and as such * use the length of the string plus 1 byte. * - * Maybe types use no space at all to represent the null value and + * ‘Maybe’ types use no space at all to represent the null value and * use the same amount of space (sometimes plus one byte) as the * equivalent non-maybe-typed value to represent the non-null case. * @@ -170,39 +169,39 @@ * In the case that the dictionary is empty, 0 bytes are required for * the serialization. * - * If we add an item "width" that maps to the int32 value of 500 then - * we will use 4 byte to store the int32 (so 6 for the variant + * If we add an item ‘width’ that maps to the int32 value of 500 then + * we will use 4 bytes to store the int32 (so 6 for the variant * containing it) and 6 bytes for the string. The variant must be - * aligned to 8 after the 6 bytes of the string, so that's 2 extra + * aligned to 8 after the 6 bytes of the string, so that’s 2 extra * bytes. 6 (string) + 2 (padding) + 6 (variant) is 14 bytes used * for the dictionary entry. An additional 1 byte is added to the * array as a framing offset making a total of 15 bytes. * - * If we add another entry, "title" that maps to a nullable string + * If we add another entry, ‘title’ that maps to a nullable string * that happens to have a value of null, then we use 0 bytes for the * null value (and 3 bytes for the variant to contain it along with * its type string) plus 6 bytes for the string. Again, we need 2 * padding bytes. That makes a total of 6 + 2 + 3 = 11 bytes. * * We now require extra padding between the two items in the array. - * After the 14 bytes of the first item, that's 2 bytes required. + * After the 14 bytes of the first item, that’s 2 bytes required. * We now require 2 framing offsets for an extra two * bytes. 14 + 2 + 11 + 2 = 29 bytes to encode the entire two-item * dictionary. * * ## Type Information Cache * - * For each GVariant type that currently exists in the program a type + * For each `GVariant` type that currently exists in the program a type * information structure is kept in the type information cache. The * type information structure is required for rapid deserialization. * - * Continuing with the above example, if a #GVariant exists with the - * type "a{sv}" then a type information struct will exist for - * "a{sv}", "{sv}", "s", and "v". Multiple uses of the same type + * Continuing with the above example, if a `GVariant` exists with the + * type `a{sv}` then a type information struct will exist for + * `a{sv}`, `{sv}`, `s`, and `v`. Multiple uses of the same type * will share the same type information. Additionally, all * single-digit types are stored in read-only static memory and do * not contribute to the writable memory footprint of a program using - * #GVariant. + * `GVariant`. * * Aside from the type information structures stored in read-only * memory, there are two forms of type information. One is used for @@ -210,23 +209,23 @@ * maybe types. The other is used for container types where there * are multiple element types: tuples and dictionary entries. * - * Array type info structures are 6 * sizeof (void *), plus the + * Array type info structures are `6 * sizeof (void *)`, plus the * memory required to store the type string itself. This means that - * on 32-bit systems, the cache entry for "a{sv}" would require 30 - * bytes of memory (plus malloc overhead). + * on 32-bit systems, the cache entry for `a{sv}` would require 30 + * bytes of memory (plus allocation overhead). * - * Tuple type info structures are 6 * sizeof (void *), plus 4 * - * sizeof (void *) for each item in the tuple, plus the memory + * Tuple type info structures are `6 * sizeof (void *)`, plus `4 * + * sizeof (void *)` for each item in the tuple, plus the memory * required to store the type string itself. A 2-item tuple, for * example, would have a type information structure that consumed - * writable memory in the size of 14 * sizeof (void *) (plus type + * writable memory in the size of `14 * sizeof (void *)` (plus type * string) This means that on 32-bit systems, the cache entry for - * "{sv}" would require 61 bytes of memory (plus malloc overhead). + * `{sv}` would require 61 bytes of memory (plus allocation overhead). * - * This means that in total, for our "a{sv}" example, 91 bytes of + * This means that in total, for our `a{sv}` example, 91 bytes of * type information would be allocated. * - * The type information cache, additionally, uses a #GHashTable to + * The type information cache, additionally, uses a [struct@GLib.HashTable] to * store and look up the cached items and stores a pointer to this * hash table in static storage. The hash table is freed when there * are zero items in the type cache. @@ -238,34 +237,34 @@ * * ## Buffer Management Memory * - * #GVariant uses an internal buffer management structure to deal + * `GVariant` uses an internal buffer management structure to deal * with the various different possible sources of serialized data * that it uses. The buffer is responsible for ensuring that the * correct call is made when the data is no longer in use by - * #GVariant. This may involve a g_free() or a g_slice_free() or - * even g_mapped_file_unref(). + * `GVariant`. This may involve a [func@GLib.free] or + * even [method@GLib.MappedFile.unref]. * * One buffer management structure is used for each chunk of * serialized data. The size of the buffer management structure - * is 4 * (void *). On 32-bit systems, that's 16 bytes. + * is `4 * (void *)`. On 32-bit systems, that’s 16 bytes. * * ## GVariant structure * - * The size of a #GVariant structure is 6 * (void *). On 32-bit - * systems, that's 24 bytes. + * The size of a `GVariant` structure is `6 * (void *)`. On 32-bit + * systems, that’s 24 bytes. * - * #GVariant structures only exist if they are explicitly created - * with API calls. For example, if a #GVariant is constructed out of + * `GVariant` structures only exist if they are explicitly created + * with API calls. For example, if a `GVariant` is constructed out of * serialized data for the example given above (with the dictionary) * then although there are 9 individual values that comprise the * entire dictionary (two keys, two values, two variants containing * the values, two dictionary entries, plus the dictionary itself), - * only 1 #GVariant instance exists -- the one referring to the + * only 1 `GVariant` instance exists — the one referring to the * dictionary. * * If calls are made to start accessing the other values then - * #GVariant instances will exist for those values only for as long - * as they are in use (ie: until you call g_variant_unref()). The + * `GVariant` instances will exist for those values only for as long + * as they are in use (ie: until you call [method@GLib.Variant.unref]). The * type information is shared. The serialized data and the buffer * management structure for that serialized data is shared by the * child. @@ -276,13 +275,15 @@ * strings to variants (with two entries, as given above), we are * using 91 bytes of memory for type information, 29 bytes of memory * for the serialized data, 16 bytes for buffer management and 24 - * bytes for the #GVariant instance, or a total of 160 bytes, plus - * malloc overhead. If we were to use g_variant_get_child_value() to - * access the two dictionary entries, we would use an additional 48 + * bytes for the `GVariant` instance, or a total of 160 bytes, plus + * allocation overhead. If we were to use [method@GLib.Variant.get_child_value] + * to access the two dictionary entries, we would use an additional 48 * bytes. If we were to have other dictionaries of the same type, we * would use more memory for the serialized data and buffer * management for those dictionaries, but the type information would * be shared. + * + * Since: 2.24 */ /* definition of GVariant structure is in gvariant-core.c */ @@ -964,7 +965,7 @@ g_variant_new_dict_entry (GVariant *key, * @format_string determines the C types that are used for unpacking * the values and also determines if the values are copied or borrowed, * see the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * This function is currently implemented with a linear scan. If you * plan to do many lookups then #GVariantDict may be more efficient. @@ -4045,7 +4046,7 @@ g_variant_dict_init (GVariantDict *dict, * * @format_string determines the C types that are used for unpacking the * values and also determines if the values are copied or borrowed, see the - * section on [GVariant format strings][gvariant-format-strings-pointers]. + * section on [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Returns: %TRUE if a value was unpacked * @@ -5505,7 +5506,7 @@ g_variant_new_va (const gchar *format_string, * @format_string determines the C types that are used for unpacking * the values and also determines if the values are copied or borrowed, * see the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Since: 2.24 **/ @@ -5559,7 +5560,7 @@ g_variant_get (GVariant *value, * @format_string determines the C types that are used for unpacking * the values and also determines if the values are copied or borrowed, * see the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Since: 2.24 **/ @@ -5654,7 +5655,7 @@ g_variant_builder_add (GVariantBuilder *builder, * @format_string determines the C types that are used for unpacking * the values and also determines if the values are copied or borrowed, * see the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Since: 2.24 **/ @@ -5727,7 +5728,7 @@ g_variant_get_child (GVariant *value, * the values and also determines if the values are copied or borrowed. * * See the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Returns: %TRUE if a value was unpacked, or %FALSE if there as no value * @@ -5826,7 +5827,7 @@ g_variant_iter_next (GVariantIter *iter, * the values and also determines if the values are copied or borrowed. * * See the section on - * [GVariant format strings][gvariant-format-strings-pointers]. + * [`GVariant` format strings](gvariant-format-strings.html#pointers). * * Returns: %TRUE if a value was unpacked, or %FALSE if there was no * value diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c index 58a4a59..948f391 100644 --- a/glib/gvarianttype.c +++ b/glib/gvarianttype.c @@ -32,158 +32,160 @@ /** - * SECTION:gvarianttype - * @title: GVariantType - * @short_description: introduction to the GVariant type system - * @see_also: #GVariantType, #GVariant + * GVariantType: * - * This section introduces the GVariant type system. It is based, in + * A type in the [type@GLib.Variant] type system. + * + * This section introduces the [type@GLib.Variant] type system. It is based, in * large part, on the D-Bus type system, with two major changes and * some minor lifting of restrictions. The * [D-Bus specification](http://dbus.freedesktop.org/doc/dbus-specification.html), * therefore, provides a significant amount of - * information that is useful when working with GVariant. + * information that is useful when working with [type@GLib.Variant]. * * The first major change with respect to the D-Bus type system is the - * introduction of maybe (or "nullable") types. Any type in GVariant can be - * converted to a maybe type, in which case, "nothing" (or "null") becomes a - * valid value. Maybe types have been added by introducing the - * character "m" to type strings. + * introduction of maybe (or ‘nullable’) types. Any type in [type@GLib.Variant] + * can be converted to a maybe type, in which case, `nothing` (or `null`) + * becomes a valid value. Maybe types have been added by introducing the + * character `m` to type strings. * - * The second major change is that the GVariant type system supports the - * concept of "indefinite types" -- types that are less specific than + * The second major change is that the [type@GLib.Variant] type system supports + * the concept of ‘indefinite types’ — types that are less specific than * the normal types found in D-Bus. For example, it is possible to speak - * of "an array of any type" in GVariant, where the D-Bus type system - * would require you to speak of "an array of integers" or "an array of - * strings". Indefinite types have been added by introducing the - * characters "*", "?" and "r" to type strings. + * of ‘an array of any type’ in [type@GLib.Variant], where the D-Bus type system + * would require you to speak of ‘an array of integers’ or ‘an array of + * strings’. Indefinite types have been added by introducing the + * characters `*`, `?` and `r` to type strings. * * Finally, all arbitrary restrictions relating to the complexity of * types are lifted along with the restriction that dictionary entries * may only appear nested inside of arrays. * - * Just as in D-Bus, GVariant types are described with strings ("type - * strings"). Subject to the differences mentioned above, these strings + * Just as in D-Bus, [type@GLib.Variant] types are described with strings (‘type + * strings’). Subject to the differences mentioned above, these strings * are of the same form as those found in D-Bus. Note, however: D-Bus * always works in terms of messages and therefore individual type - * strings appear nowhere in its interface. Instead, "signatures" + * strings appear nowhere in its interface. Instead, ‘signatures’ * are a concatenation of the strings of the type of each argument in a - * message. GVariant deals with single values directly so GVariant type - * strings always describe the type of exactly one value. This means - * that a D-Bus signature string is generally not a valid GVariant type - * string -- except in the case that it is the signature of a message - * containing exactly one argument. + * message. [type@GLib.Variant] deals with single values directly so + * [type@GLib.Variant] type strings always describe the type of exactly one + * value. This means that a D-Bus signature string is generally not a valid + * [type@GLib.Variant] type string — except in the case that it is the signature + * of a message containing exactly one argument. * * An indefinite type is similar in spirit to what may be called an * abstract type in other type systems. No value can exist that has an * indefinite type as its type, but values can exist that have types * that are subtypes of indefinite types. That is to say, - * g_variant_get_type() will never return an indefinite type, but - * calling g_variant_is_of_type() with an indefinite type may return - * %TRUE. For example, you cannot have a value that represents "an - * array of no particular type", but you can have an "array of integers" - * which certainly matches the type of "an array of no particular type", - * since "array of integers" is a subtype of "array of no particular - * type". + * [method@GLib.Variant.get_type] will never return an indefinite type, but + * calling [method@GLib.Variant.is_of_type] with an indefinite type may return + * true. For example, you cannot have a value that represents ‘an + * array of no particular type’, but you can have an ‘array of integers’ + * which certainly matches the type of ‘an array of no particular type’, + * since ‘array of integers’ is a subtype of ‘array of no particular + * type’. * * This is similar to how instances of abstract classes may not * directly exist in other type systems, but instances of their * non-abstract subtypes may. For example, in GTK, no object that has - * the type of #GtkBin can exist (since #GtkBin is an abstract class), - * but a #GtkWindow can certainly be instantiated, and you would say - * that the #GtkWindow is a #GtkBin (since #GtkWindow is a subclass of - * #GtkBin). + * the type of [class@Gtk.Widget] can exist (since [class@Gtk.Widget] is an + * abstract class), but a [class@Gtk.Window] can certainly be instantiated, and + * you would say that the [class@Gtk.Window] is a [class@Gtk.Widget] (since + * [class@Gtk.Window] is a subclass of [class@Gtk.Widget]). + * + * Two types may not be compared by value; use [method@GLib.VariantType.equal] + * or [method@GLib.VariantType.is_subtype_of] May be copied using + * [method@GLib.VariantType.copy] and freed using [method@GLib.VariantType.free]. * * ## GVariant Type Strings * - * A GVariant type string can be any of the following: + * A [type@GLib.Variant] type string can be any of the following: * * - any basic type string (listed below) - * - * - "v", "r" or "*" - * - * - one of the characters 'a' or 'm', followed by another type string - * - * - the character '(', followed by a concatenation of zero or more other - * type strings, followed by the character ')' - * - * - the character '{', followed by a basic type string (see below), - * followed by another type string, followed by the character '}' + * - `v`, `r` or `*` + * - one of the characters `a` or `m`, followed by another type string + * - the character `(`, followed by a concatenation of zero or more other + * type strings, followed by the character `)` + * - the character `{`, followed by a basic type string (see below), + * followed by another type string, followed by the character `}` * * A basic type string describes a basic type (as per - * g_variant_type_is_basic()) and is always a single character in length. - * The valid basic type strings are "b", "y", "n", "q", "i", "u", "x", "t", - * "h", "d", "s", "o", "g" and "?". + * [method@GLib.VariantType.is_basic]) and is always a single character in + * length. The valid basic type strings are `b`, `y`, `n`, `q`, `i`, `u`, `x`, + * `t`, `h`, `d`, `s`, `o`, `g` and `?`. * - * The above definition is recursive to arbitrary depth. "aaaaai" and - * "(ui(nq((y)))s)" are both valid type strings, as is - * "a(aa(ui)(qna{ya(yd)}))". In order to not hit memory limits, #GVariant - * imposes a limit on recursion depth of 65 nested containers. This is the - * limit in the D-Bus specification (64) plus one to allow a #GDBusMessage to - * be nested in a top-level tuple. + * The above definition is recursive to arbitrary depth. `aaaaai` and + * `(ui(nq((y)))s)` are both valid type strings, as is + * `a(aa(ui)(qna{ya(yd)}))`. In order to not hit memory limits, + * [type@GLib.Variant] imposes a limit on recursion depth of 65 nested + * containers. This is the limit in the D-Bus specification (64) plus one to + * allow a [class@Gio.DBusMessage] to be nested in a top-level tuple. * * The meaning of each of the characters is as follows: - * - `b`: the type string of %G_VARIANT_TYPE_BOOLEAN; a boolean value. - * - `y`: the type string of %G_VARIANT_TYPE_BYTE; a byte. - * - `n`: the type string of %G_VARIANT_TYPE_INT16; a signed 16 bit integer. - * - `q`: the type string of %G_VARIANT_TYPE_UINT16; an unsigned 16 bit integer. - * - `i`: the type string of %G_VARIANT_TYPE_INT32; a signed 32 bit integer. - * - `u`: the type string of %G_VARIANT_TYPE_UINT32; an unsigned 32 bit integer. - * - `x`: the type string of %G_VARIANT_TYPE_INT64; a signed 64 bit integer. - * - `t`: the type string of %G_VARIANT_TYPE_UINT64; an unsigned 64 bit integer. - * - `h`: the type string of %G_VARIANT_TYPE_HANDLE; a signed 32 bit value + * + * - `b`: the type string of `G_VARIANT_TYPE_BOOLEAN`; a boolean value. + * - `y`: the type string of `G_VARIANT_TYPE_BYTE`; a byte. + * - `n`: the type string of `G_VARIANT_TYPE_INT16`; a signed 16 bit integer. + * - `q`: the type string of `G_VARIANT_TYPE_UINT16`; an unsigned 16 bit integer. + * - `i`: the type string of `G_VARIANT_TYPE_INT32`; a signed 32 bit integer. + * - `u`: the type string of `G_VARIANT_TYPE_UINT32`; an unsigned 32 bit integer. + * - `x`: the type string of `G_VARIANT_TYPE_INT64`; a signed 64 bit integer. + * - `t`: the type string of `G_VARIANT_TYPE_UINT64`; an unsigned 64 bit integer. + * - `h`: the type string of `G_VARIANT_TYPE_HANDLE`; a signed 32 bit value * that, by convention, is used as an index into an array of file * descriptors that are sent alongside a D-Bus message. - * - `d`: the type string of %G_VARIANT_TYPE_DOUBLE; a double precision + * - `d`: the type string of `G_VARIANT_TYPE_DOUBLE`; a double precision * floating point value. - * - `s`: the type string of %G_VARIANT_TYPE_STRING; a string. - * - `o`: the type string of %G_VARIANT_TYPE_OBJECT_PATH; a string in the form + * - `s`: the type string of `G_VARIANT_TYPE_STRING`; a string. + * - `o`: the type string of `G_VARIANT_TYPE_OBJECT_PATH`; a string in the form * of a D-Bus object path. - * - `g`: the type string of %G_VARIANT_TYPE_SIGNATURE; a string in the form of + * - `g`: the type string of `G_VARIANT_TYPE_SIGNATURE`; a string in the form of * a D-Bus type signature. - * - `?`: the type string of %G_VARIANT_TYPE_BASIC; an indefinite type that + * - `?`: the type string of `G_VARIANT_TYPE_BASIC`; an indefinite type that * is a supertype of any of the basic types. - * - `v`: the type string of %G_VARIANT_TYPE_VARIANT; a container type that + * - `v`: the type string of `G_VARIANT_TYPE_VARIANT`; a container type that * contain any other type of value. * - `a`: used as a prefix on another type string to mean an array of that - * type; the type string "ai", for example, is the type of an array of + * type; the type string `ai`, for example, is the type of an array of * signed 32-bit integers. - * - `m`: used as a prefix on another type string to mean a "maybe", or - * "nullable", version of that type; the type string "ms", for example, + * - `m`: used as a prefix on another type string to mean a ‘maybe’, or + * ‘nullable’, version of that type; the type string `ms`, for example, * is the type of a value that maybe contains a string, or maybe contains * nothing. * - `()`: used to enclose zero or more other concatenated type strings to - * create a tuple type; the type string "(is)", for example, is the type of + * create a tuple type; the type string `(is)`, for example, is the type of * a pair of an integer and a string. - * - `r`: the type string of %G_VARIANT_TYPE_TUPLE; an indefinite type that is + * - `r`: the type string of `G_VARIANT_TYPE_TUPLE`; an indefinite type that is * a supertype of any tuple type, regardless of the number of items. * - `{}`: used to enclose a basic type string concatenated with another type * string to create a dictionary entry type, which usually appears inside of - * an array to form a dictionary; the type string "a{sd}", for example, is + * an array to form a dictionary; the type string `a{sd}`, for example, is * the type of a dictionary that maps strings to double precision floating * point values. * * The first type (the basic type) is the key type and the second type is * the value type. The reason that the first type is restricted to being a * basic type is so that it can easily be hashed. - * - `*`: the type string of %G_VARIANT_TYPE_ANY; the indefinite type that is + * - `*`: the type string of `G_VARIANT_TYPE_ANY`; the indefinite type that is * a supertype of all types. Note that, as with all type strings, this * character represents exactly one type. It cannot be used inside of tuples - * to mean "any number of items". + * to mean ‘any number of items’. * * Any type string of a container that contains an indefinite type is, - * itself, an indefinite type. For example, the type string "a*" - * (corresponding to %G_VARIANT_TYPE_ARRAY) is an indefinite type - * that is a supertype of every array type. "(*s)" is a supertype + * itself, an indefinite type. For example, the type string `a*` + * (corresponding to `G_VARIANT_TYPE_ARRAY`) is an indefinite type + * that is a supertype of every array type. `(*s)` is a supertype * of all tuples that contain exactly two items where the second * item is a string. * - * "a{?*}" is an indefinite type that is a supertype of all arrays + * `a{?*}` is an indefinite type that is a supertype of all arrays * containing dictionary entries where the key is any basic type and * the value is any type at all. This is, by definition, a dictionary, - * so this type string corresponds to %G_VARIANT_TYPE_DICTIONARY. Note + * so this type string corresponds to `G_VARIANT_TYPE_DICTIONARY`. Note * that, due to the restriction that the key of a dictionary entry must - * be a basic type, "{**}" is not a valid type string. + * be a basic type, `{**}` is not a valid type string. + * + * Since: 2.24 */ diff --git a/glib/gvarianttype.h b/glib/gvarianttype.h index 6374957..0fc751b 100644 --- a/glib/gvarianttype.h +++ b/glib/gvarianttype.h @@ -31,15 +31,6 @@ G_BEGIN_DECLS -/** - * GVariantType: - * - * A type in the GVariant type system. - * - * Two types may not be compared by value; use g_variant_type_equal() or - * g_variant_type_is_subtype_of(). May be copied using - * g_variant_type_copy() and freed using g_variant_type_free(). - **/ typedef struct _GVariantType GVariantType; /** @@ -375,7 +366,7 @@ GVariantType * g_variant_type_new_dict_entry (const G /*< private >*/ GLIB_AVAILABLE_IN_ALL -const GVariantType * g_variant_type_checked_ (const gchar *); +const GVariantType * g_variant_type_checked_ (const gchar *type_string); GLIB_AVAILABLE_IN_2_60 gsize g_variant_type_string_get_depth_ (const gchar *type_string); diff --git a/glib/gversion.c b/glib/gversion.c index b12929b..ade16fc 100644 --- a/glib/gversion.c +++ b/glib/gversion.c @@ -29,28 +29,6 @@ #include "gversion.h" /** - * SECTION:version - * @Title: Version Information - * @Short_description: variables and functions to check the GLib version - * - * GLib provides version information, primarily useful in configure - * checks for builds that have a configure script. Applications will - * not typically use the features described here. - * - * The GLib headers annotate deprecated APIs in a way that produces - * compiler warnings if these deprecated APIs are used. The warnings - * can be turned off by defining the macro %GLIB_DISABLE_DEPRECATION_WARNINGS - * before including the glib.h header. - * - * GLib also provides support for building applications against - * defined subsets of deprecated or new GLib APIs. Define the macro - * %GLIB_VERSION_MIN_REQUIRED to specify up to what version of GLib - * you want to receive warnings about deprecated APIs. Define the - * macro %GLIB_VERSION_MAX_ALLOWED to specify the newest version of - * GLib whose API you want to use. - */ - -/** * glib_major_version: * * The major version of the GLib library. diff --git a/glib/gwakeup.c b/glib/gwakeup.c index 6ce401e..8208042 100644 --- a/glib/gwakeup.c +++ b/glib/gwakeup.c @@ -38,11 +38,9 @@ #include "gwakeup.h" /*< private > - * SECTION:gwakeup - * @title: GWakeup - * @short_description: portable cross-thread event signal mechanism + * GWakeup: * - * #GWakeup is a simple and portable way of signaling events between + * `GWakeup` is a simple and portable way of signaling events between * different threads in a way that integrates nicely with g_poll(). * GLib uses it internally for cross-thread signalling in the * implementation of #GMainContext and #GCancellable. @@ -59,7 +57,7 @@ * is implemented with a pair of pipes. * * Since: 2.30 - **/ + */ #ifdef _WIN32 #include @@ -124,7 +122,7 @@ struct _GWakeup gint fds[2]; }; -/** +/*< private > * g_wakeup_new: * * Creates a new #GWakeup. @@ -170,7 +168,7 @@ g_wakeup_new (void) return wakeup; } -/** +/*< private > * g_wakeup_get_pollfd: * @wakeup: a #GWakeup * @poll_fd: a #GPollFD @@ -190,7 +188,7 @@ g_wakeup_get_pollfd (GWakeup *wakeup, poll_fd->events = G_IO_IN; } -/** +/*< private > * g_wakeup_acknowledge: * @wakeup: a #GWakeup * @@ -229,7 +227,7 @@ g_wakeup_acknowledge (GWakeup *wakeup) } } -/** +/*< private > * g_wakeup_signal: * @wakeup: a #GWakeup * @@ -270,7 +268,7 @@ g_wakeup_signal (GWakeup *wakeup) } } -/** +/*< private > * g_wakeup_free: * @wakeup: a #GWakeup * diff --git a/glib/gwin32.h b/glib/gwin32.h index e38a7f9..a44c4c8 100644 --- a/glib/gwin32.h +++ b/glib/gwin32.h @@ -33,7 +33,7 @@ #include -#ifdef G_PLATFORM_WIN32 +#if defined(G_PLATFORM_WIN32) || defined(__GI_SCANNER__) G_BEGIN_DECLS @@ -41,7 +41,7 @@ G_BEGIN_DECLS #define MAXPATHLEN 1024 #endif -#ifdef G_OS_WIN32 +#if defined(G_OS_WIN32) || defined(__GI_SCANNER__) /* * To get prototypes for the following POSIXish functions, you have to @@ -68,7 +68,7 @@ G_BEGIN_DECLS GLIB_AVAILABLE_IN_ALL gint g_win32_ftruncate (gint f, guint size); -#endif /* G_OS_WIN32 */ +#endif /* G_OS_WIN32 || __GI_SCANNER__ */ /* The MS setlocale uses locale names of the form "English_United * States.1252" etc. We want the Unixish standard form "en", "zh_TW" @@ -137,6 +137,6 @@ gboolean g_win32_check_windows_version (const gint major, G_END_DECLS -#endif /* G_PLATFORM_WIN32 */ +#endif /* G_PLATFORM_WIN32 || __GI_SCANNER__ */ #endif /* __G_WIN32_H__ */ diff --git a/glib/meson.build b/glib/meson.build index c26a35e..95e863e 100644 --- a/glib/meson.build +++ b/glib/meson.build @@ -253,7 +253,7 @@ glib_sub_headers = files( install_headers(glib_sub_headers, install_dir : glib_sub_includedir) -deprecated_sources = files( +glib_deprecated_sources = files( 'deprecated/gallocator.c', 'deprecated/gcache.c', 'deprecated/gcompletion.c', @@ -277,6 +277,7 @@ glib_sources += files( 'gdataset.c', 'gdate.c', 'gdatetime.c', + 'gdatetime-private.c', 'gdir.c', 'genviron.c', 'gerror.c', @@ -407,7 +408,7 @@ endif glib_c_args = ['-DG_LOG_DOMAIN="GLib"'] + glib_c_args_internal + pcre2_static_args libglib = library('glib-2.0', glib_dtrace_obj, glib_dtrace_hdr, - sources : [deprecated_sources, glib_sources], + sources : [glib_deprecated_sources, glib_sources], version : library_version, soversion : soversion, darwin_versions : darwin_versions, @@ -445,8 +446,6 @@ pkg.generate(libglib, subdirs : ['glib-2.0'], extra_cflags : ['-I${libdir}/glib-2.0/include'] + win32_cflags, variables : [ - 'bindir=' + '${prefix}' / get_option('bindir'), - 'datadir=' + '${prefix}' / get_option('datadir'), 'glib_genmarshal=' + '${bindir}' / 'glib-genmarshal', 'gobject_query=' + '${bindir}' / 'gobject-query', 'glib_mkenums=' + '${bindir}' / 'glib-mkenums', diff --git a/glib/tests/atomic.c b/glib/tests/atomic.c index 614d5aa..9d57d21 100644 --- a/glib/tests/atomic.c +++ b/glib/tests/atomic.c @@ -31,7 +31,7 @@ test_types (void) const char *str = "Hello"; const char *old_str; int *ip, *ip2; - gsize gs, gs2; + guintptr gu, gu2; gboolean res; csp = &s; @@ -158,36 +158,36 @@ test_types (void) res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, &s, &ip2); g_assert_true (res); g_assert_true (ip == &s); - g_assert_cmpuint ((gsize) ip2, ==, 0); + g_assert_cmpuint ((guintptr) ip2, ==, 0); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &ip2); g_assert_false (res); g_assert_true (ip == &s); g_assert_true (ip2 == &s); - g_atomic_pointer_set (&gs, 0); - vp2 = (gpointer) g_atomic_pointer_get (&gs); - gs2 = (gsize) vp2; - g_assert_cmpuint (gs2, ==, 0); - res = g_atomic_pointer_compare_and_exchange (&gs, NULL, (gsize) NULL); + g_atomic_pointer_set (&gu, 0); + vp2 = (gpointer) g_atomic_pointer_get (&gu); + gu2 = (guintptr) vp2; + g_assert_cmpuint (gu2, ==, 0); + res = g_atomic_pointer_compare_and_exchange (&gu, NULL, (guintptr) NULL); g_assert_true (res); - g_assert_cmpuint (gs, ==, 0); - res = g_atomic_pointer_compare_and_exchange_full (&gs, (gsize) NULL, (gsize) NULL, &gs2); + g_assert_cmpuint (gu, ==, 0); + res = g_atomic_pointer_compare_and_exchange_full (&gu, (guintptr) NULL, (guintptr) NULL, &gu2); g_assert_true (res); - g_assert_cmpuint (gs, ==, 0); - g_assert_cmpuint (gs2, ==, 0); - gs2 = (gsize) g_atomic_pointer_add (&gs, 5); - g_assert_cmpuint (gs2, ==, 0); - g_assert_cmpuint (gs, ==, 5); - gs2 = g_atomic_pointer_and (&gs, 6); - g_assert_cmpuint (gs2, ==, 5); - g_assert_cmpuint (gs, ==, 4); - gs2 = g_atomic_pointer_or (&gs, 8); - g_assert_cmpuint (gs2, ==, 4); - g_assert_cmpuint (gs, ==, 12); - gs2 = g_atomic_pointer_xor (&gs, 4); - g_assert_cmpuint (gs2, ==, 12); - g_assert_cmpuint (gs, ==, 8); + g_assert_cmpuint (gu, ==, 0); + g_assert_cmpuint (gu2, ==, 0); + gu2 = (guintptr) g_atomic_pointer_add (&gu, 5); + g_assert_cmpuint (gu2, ==, 0); + g_assert_cmpuint (gu, ==, 5); + gu2 = g_atomic_pointer_and (&gu, 6); + g_assert_cmpuint (gu2, ==, 5); + g_assert_cmpuint (gu, ==, 4); + gu2 = g_atomic_pointer_or (&gu, 8); + g_assert_cmpuint (gu2, ==, 4); + g_assert_cmpuint (gu, ==, 12); + gu2 = g_atomic_pointer_xor (&gu, 4); + g_assert_cmpuint (gu2, ==, 12); + g_assert_cmpuint (gu, ==, 8); vp_str2 = g_atomic_pointer_exchange (&vp_str, str); g_assert_cmpstr (vp_str, ==, str); g_assert_null (vp_str2); @@ -340,41 +340,41 @@ G_GNUC_END_IGNORE_DEPRECATIONS res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, (gpointer) 1, &cp); g_assert_true (res); - g_assert_cmpint ((gsize) ip, ==, 1); - g_assert_cmpuint ((gsize) cp, ==, 0); + g_assert_cmpint ((guintptr) ip, ==, 1); + g_assert_cmpuint ((guintptr) cp, ==, 0); res = g_atomic_pointer_compare_and_exchange_full (&ip, NULL, NULL, &cp); g_assert_false (res); - g_assert_cmpuint ((gsize) ip, ==, 1); - g_assert_cmpuint ((gsize) cp, ==, 1); - - g_atomic_pointer_set (&gs, 0); - vp = g_atomic_pointer_get (&gs); - gs2 = (gsize) vp; - g_assert_cmpuint (gs2, ==, 0); - res = g_atomic_pointer_compare_and_exchange (&gs, NULL, NULL); + g_assert_cmpuint ((guintptr) ip, ==, 1); + g_assert_cmpuint ((guintptr) cp, ==, 1); + + g_atomic_pointer_set (&gu, 0); + vp = g_atomic_pointer_get (&gu); + gu2 = (guintptr) vp; + g_assert_cmpuint (gu2, ==, 0); + res = g_atomic_pointer_compare_and_exchange (&gu, NULL, NULL); g_assert_true (res); - g_assert_cmpuint (gs, ==, 0); - res = g_atomic_pointer_compare_and_exchange_full (&gs, NULL, NULL, &cp); + g_assert_cmpuint (gu, ==, 0); + res = g_atomic_pointer_compare_and_exchange_full (&gu, NULL, NULL, &cp); g_assert_true (res); - g_assert_cmpuint (gs, ==, 0); - g_assert_cmpuint ((gsize) cp, ==, 0); - gs2 = (gsize) g_atomic_pointer_add (&gs, 5); - g_assert_cmpuint (gs2, ==, 0); - g_assert_cmpuint (gs, ==, 5); - gs2 = g_atomic_pointer_and (&gs, 6); - g_assert_cmpuint (gs2, ==, 5); - g_assert_cmpuint (gs, ==, 4); - gs2 = g_atomic_pointer_or (&gs, 8); - g_assert_cmpuint (gs2, ==, 4); - g_assert_cmpuint (gs, ==, 12); - gs2 = g_atomic_pointer_xor (&gs, 4); - g_assert_cmpuint (gs2, ==, 12); - g_assert_cmpuint (gs, ==, 8); - vp2 = g_atomic_pointer_exchange (&gs, NULL); - gs2 = (gsize) vp2; - g_assert_cmpuint (gs2, ==, 8); - g_assert_null ((gpointer) gs); + g_assert_cmpuint (gu, ==, 0); + g_assert_cmpuint ((guintptr) cp, ==, 0); + gu2 = (guintptr) g_atomic_pointer_add (&gu, 5); + g_assert_cmpuint (gu2, ==, 0); + g_assert_cmpuint (gu, ==, 5); + gu2 = g_atomic_pointer_and (&gu, 6); + g_assert_cmpuint (gu2, ==, 5); + g_assert_cmpuint (gu, ==, 4); + gu2 = g_atomic_pointer_or (&gu, 8); + g_assert_cmpuint (gu2, ==, 4); + g_assert_cmpuint (gu, ==, 12); + gu2 = g_atomic_pointer_xor (&gu, 4); + g_assert_cmpuint (gu2, ==, 12); + g_assert_cmpuint (gu, ==, 8); + vp2 = g_atomic_pointer_exchange (&gu, NULL); + gu2 = (guintptr) vp2; + g_assert_cmpuint (gu2, ==, 8); + g_assert_null ((gpointer) gu); g_assert_cmpint (g_atomic_int_get (csp), ==, s); g_assert_true (g_atomic_pointer_get (cspp) == csp); diff --git a/glib/tests/casefold.txt b/glib/tests/casefold.txt index bcfa515..c9fa68b 100644 --- a/glib/tests/casefold.txt +++ b/glib/tests/casefold.txt @@ -1,4 +1,4 @@ -# Test cases generated from Unicode 15.0.0 data +# Test cases generated from Unicode 15.1.0 data # by gen-casefold-txt.py. Do not edit. # # Some special hand crafted tests diff --git a/glib/tests/casemap.txt b/glib/tests/casemap.txt index b4dce7b..6fe7020 100644 --- a/glib/tests/casemap.txt +++ b/glib/tests/casemap.txt @@ -1,4 +1,4 @@ -# Test cases generated from Unicode 15.0.0 data +# Test cases generated from Unicode 15.1.0 data # by gen-casemap-txt.py. Do not edit. # # Some special hand crafted tests diff --git a/glib/tests/constructor-helper.c b/glib/tests/constructor-helper.c new file mode 100644 index 0000000..33e2c7d --- /dev/null +++ b/glib/tests/constructor-helper.c @@ -0,0 +1,239 @@ +/* constructor-helpers.c - Helper library for the constructor test + * + * Copyright © 2023 Luca Bacci + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +/* This helper library manages a set of strings. Strings can be added, + * removed and checked for presence. This library does not call into + * libc, so can be used from module constructors in a safe manner on + * a wide range of operating systems. + * + * GLib is used only for assertions or hard errors; in such cases we + * don't really care about supported libc calls, as the test ought to + * fail anyway. + */ + +#include /* for size_t */ + +#include + +#if defined (_MSC_VER) +# pragma optimize ("", off) +#else +# if defined (__clang__) +# pragma clang optimize off +# elif defined (__GNUC__) +# pragma GCC optimize ("O0") +# endif +#endif + +#if defined(_WIN32) + #define MODULE_EXPORT \ + __declspec (dllexport) +#elif defined (__GNUC__) + #define MODULE_EXPORT \ + __attribute__((visibility("default"))) +#else + #define MODULE_EXPORT +#endif + +char buffer[500]; +size_t position; + +MODULE_EXPORT +void string_add (const char *string); + +MODULE_EXPORT +void string_add_exclusive (const char *string); + +MODULE_EXPORT +int string_remove (const char *string); + +MODULE_EXPORT +int string_find (const char *string); + +MODULE_EXPORT +void string_check (const char *string); + +static size_t +strlen_ (const char *string) +{ + size_t i = 0; + + g_assert_nonnull (string); + + while (string[i] != 0) + i++; + + return i; +} + +static void +memmove_ (char *buf, + size_t from, + size_t size, + size_t to) +{ + g_assert_true (to <= from); + + for (size_t i = 0; i < size; i++) + buffer[to + i] = buffer[from + i]; +} + +static void +memcpy_ (char *dst, + const char *src, + size_t size) +{ + for (size_t i = 0; i < size; i++) + dst[i] = src[i]; +} + +static void +memset_ (char *dst, + char val, + size_t size) +{ + for (size_t i = 0; i < size; i++) + dst[i] = val; +} + +static size_t +string_find_index_ (const char *string) +{ + size_t string_len; + size_t i = 0; + + g_assert_nonnull (string); + g_assert_true ((string_len = strlen_ (string)) > 0); + + for (i = 0; (i < sizeof (buffer) - position) && (buffer[i] != 0);) + { + const char *iter = &buffer[i]; + size_t len = strlen_ (iter); + + if (len == string_len && strcmp (iter, string) == 0) + return i; + + i += len + 1; + } + + return sizeof (buffer); +} + +/**< private > + * string_add: + * + * @string: NULL-terminated string. Must not be empty + * + * Adds @string to the set + */ +MODULE_EXPORT +void +string_add (const char *string) +{ + size_t len, size; + + g_assert_nonnull (string); + g_assert_true ((len = strlen_ (string)) > 0); + + size = len + 1; + + if (size > sizeof (buffer) - position) + g_error ("Not enough space in the buffer"); + + memcpy_ (buffer + position, string, size); + + position += size; +} + +/**< private > + * string_add_exclusive: + * + * @string: NULL-terminated string. Must not be empty + * + * Adds @string to the set, asserting that it's not already present. + */ +MODULE_EXPORT +void +string_add_exclusive (const char *string) +{ + if (string_find_index_ (string) < sizeof (buffer)) + g_error ("string %s already set", string); + + string_add (string); +} + +/**< private > + * string_remove: + * + * @string: NULL-terminated string. Must not be empty + * + * Removes the first occurrence of @string from the set. + * + * Returns: 1 if the string was removed, 0 otherwise. + */ +MODULE_EXPORT +int +string_remove (const char *string) +{ + size_t index = string_find_index_ (string); + size_t len, size; + + if (index >= sizeof (buffer)) + return 0; + + g_assert_true ((len = strlen_ (string)) > 0); + size = len + 1; + + memmove_ (buffer, index + size, index, position - (index + size)); + + position -= size; + + memset_ (buffer + position, 0, size); + + return 1; +} + +/**< private > + * string_find: + * + * @string: NULL-terminated string. Must not be empty + * + * Returns 1 if the string is present, 0 otherwise + */ +MODULE_EXPORT +int string_find (const char *string) +{ + return string_find_index_ (string) < sizeof (buffer); +} + +/**< private > + * string_check: + * + * @string: NULL-terminated string. Must not be empty + * + * Asserts that @string is present in the set + */ +MODULE_EXPORT +void +string_check (const char *string) +{ + if (string_find_index_ (string) >= sizeof (buffer)) + g_error ("String %s not present", string); +} diff --git a/glib/tests/constructor.c b/glib/tests/constructor.c new file mode 100644 index 0000000..001d754 --- /dev/null +++ b/glib/tests/constructor.c @@ -0,0 +1,260 @@ +/* constructor.c - Test for constructors + * + * Copyright © 2023 Luca Bacci + * + * SPDX-License-Identifier: LGPL-2.1-or-later + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with this library; if not, see . + */ + +#include +#include "../gconstructorprivate.h" + +#ifndef _WIN32 +#include +#else +#include +#endif + +#if defined(_WIN32) + #define MODULE_IMPORT \ + __declspec (dllimport) +#else + #define MODULE_IMPORT +#endif + +MODULE_IMPORT +void string_add_exclusive (const char *string); + +MODULE_IMPORT +void string_check (const char *string); + +MODULE_IMPORT +int string_find (const char *string); + +#if G_HAS_CONSTRUCTORS + +#ifdef G_DEFINE_CONSTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_CONSTRUCTOR_PRAGMA_ARGS (ctor) +#endif + +G_DEFINE_CONSTRUCTOR (ctor) + +static void +ctor (void) +{ + string_add_exclusive (G_STRINGIFY (PREFIX) "_" "ctor"); +} + +#ifdef G_DEFINE_DESTRUCTOR_NEEDS_PRAGMA +#pragma G_DEFINE_DESTRUCTOR_PRAGMA_ARGS (dtor) +#endif + +G_DEFINE_DESTRUCTOR (dtor) + +static void +dtor (void) +{ + string_add_exclusive (G_STRINGIFY (PREFIX) "_" "dtor"); + + if (string_find ("app_dtor") && string_find ("lib_dtor")) + { + /* All destructors were invoked, this is the last. + * Call _Exit (EXIT_SUCCESS) to exit immediately + * with a success code */ + _Exit (EXIT_SUCCESS); + } +} + +#endif /* G_HAS_CONSTRUCTORS */ + + +#if defined (_WIN32) && defined (G_HAS_TLS_CALLBACKS) + +extern IMAGE_DOS_HEADER __ImageBase; + +static inline HMODULE +this_module (void) +{ + return (HMODULE) &__ImageBase; +} + +G_DEFINE_TLS_CALLBACK (tls_callback) + +static void NTAPI +tls_callback (PVOID hInstance, + DWORD dwReason, + LPVOID lpvReserved) +{ + /* The HINSTANCE we get must match the address of __ImageBase */ + g_assert_true (hInstance == this_module ()); + +#ifdef BUILD_TEST_EXECUTABLE + /* Yes, we can call GetModuleHandle (NULL) with the loader lock */ + g_assert_true (hInstance == GetModuleHandle (NULL)); +#endif + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + { +#ifndef BUILD_TEST_EXECUTABLE + /* the library is explicitly loaded */ + g_assert_null (lpvReserved); +#endif + string_add_exclusive (G_STRINGIFY (PREFIX) "_" "tlscb_process_attach"); + } + break; + + case DLL_THREAD_ATTACH: + break; + + case DLL_THREAD_DETACH: + break; + + case DLL_PROCESS_DETACH: + { +#ifndef BUILD_TEST_EXECUTABLE + /* the library is explicitly unloaded */ + g_assert_null (lpvReserved); +#endif + string_add_exclusive (G_STRINGIFY (PREFIX) "_" "tlscb_process_detach"); + } + break; + + default: + g_assert_not_reached (); + break; + } +} + +#endif /* _WIN32 && G_HAS_TLS_CALLBACKS */ + +#ifdef BUILD_TEST_EXECUTABLE + +void *library; + +static void +load_library (const char *path) +{ +#ifndef _WIN32 + library = dlopen (path, RTLD_NOW); + if (!library) + { + g_error ("%s (%s) failed: %s", "dlopen", path, dlerror ()); + } +#else + wchar_t *path_utf16 = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL); + g_assert_nonnull (path_utf16); + + library = LoadLibraryW (path_utf16); + if (!library) + { + g_error ("%s (%s) failed with error code %u", + "FreeLibrary", path, (unsigned int) GetLastError ()); + } + + g_free (path_utf16); +#endif +} + +static void +unload_library (void) +{ +#ifndef _WIN32 + if (dlclose (library) != 0) + { + g_error ("%s failed: %s", "dlclose", dlerror ()); + } +#else + if (!FreeLibrary (library)) + { + g_error ("%s failed with error code %u", + "FreeLibrary", (unsigned int) GetLastError ()); + } +#endif +} + +static void +test_app (void) +{ +#if G_HAS_CONSTRUCTORS + string_check ("app_" "ctor"); +#endif +#if defined (_WIN32) && defined (G_HAS_TLS_CALLBACKS) + string_check ("app_" "tlscb_process_attach"); +#endif +} + +static void +test_lib (gconstpointer data) +{ + const char *library_path = (const char*) data; + + /* Constructors */ + load_library (library_path); + +#if G_HAS_CONSTRUCTORS + string_check ("lib_" "ctor"); +#endif +#if defined (_WIN32) && defined (G_HAS_TLS_CALLBACKS) + string_check ("lib_" "tlscb_process_attach"); +#endif + + /* Destructors */ + unload_library (); + +#if G_HAS_DESTRUCTORS + /* Destructors in dynamically-loaded libraries do not + * necessarily run on dlclose. On some systems dlclose + * is effectively a no-op (e.g with the Musl LibC) and + * destructors run at program exit */ + g_test_message ("Destructors run on module unload: %s\n", + string_find ("lib_" "dtor") ? "yes" : "no"); +#endif +#if defined (_WIN32) && defined (G_HAS_TLS_CALLBACKS) + string_check ("lib_" "tlscb_process_detach"); +#endif +} + +int +main (int argc, char *argv[]) +{ + + const char *libname = G_STRINGIFY (LIB_NAME); + const char *builddir; + char *path; + int ret; + + g_assert_nonnull ((builddir = g_getenv ("G_TEST_BUILDDIR"))); + + path = g_build_filename (builddir, libname, NULL); + + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/constructor/application", test_app); + g_test_add_data_func ("/constructor/library", path, test_lib); + + ret = g_test_run (); + g_assert_cmpint (ret, ==, 0); + + g_free (path); + + /* Return EXIT_FAILURE from main. The last destructor will + * call _Exit (EXIT_SUCCESS) if everything went well. This + * is a way to test that destructors get invoked */ + return EXIT_FAILURE; +} + +#endif /* BUILD_TEST_EXECUTABLE */ diff --git a/glib/tests/convert.c b/glib/tests/convert.c index 6a7bfaf..6cf19ad 100644 --- a/glib/tests/convert.c +++ b/glib/tests/convert.c @@ -950,35 +950,42 @@ test_no_conv (void) } static void -test_filename_from_uri_query_is_ignored (void) +test_filename_from_uri_helper (const gchar *uri, + const gchar *expected_filename) { gchar *filename; + gchar *expected_platform_filename; GError *error = NULL; - filename = g_filename_from_uri ("file:///tmp/foo?bar", NULL, &error); - g_assert_no_error (error); + expected_platform_filename = g_strdup (expected_filename); #ifdef G_OS_WIN32 - g_assert_cmpstr (filename, ==, "\\tmp\\foo"); -#else - g_assert_cmpstr (filename, ==, "/tmp/foo"); + for (gchar *p = expected_platform_filename; *p; p++) + { + if (*p == '/') + *p = '\\'; + } #endif + + filename = g_filename_from_uri (uri, NULL, &error); + g_assert_no_error (error); + g_assert_cmpstr (filename, ==, expected_platform_filename); g_free (filename); + g_free (expected_platform_filename); } static void -test_filename_from_uri_fragment_is_ignored (void) +test_filename_from_uri_query_is_ignored (void) { - gchar *filename; - GError *error = NULL; + test_filename_from_uri_helper ("file:///tmp/foo?bar", "/tmp/foo"); + test_filename_from_uri_helper ("file:///tmp/foo?bar#baz", "/tmp/foo"); +} - filename = g_filename_from_uri ("file:///tmp/foo#bar", NULL, &error); - g_assert_no_error (error); -#ifdef G_OS_WIN32 - g_assert_cmpstr (filename, ==, "\\tmp\\foo"); -#else - g_assert_cmpstr (filename, ==, "/tmp/foo"); -#endif - g_free (filename); +static void +test_filename_from_uri_fragment_is_ignored (void) +{ + test_filename_from_uri_helper ("file:///tmp/foo#bar", "/tmp/foo"); + /* this doesn't have a query, only a bizarre anchor */ + test_filename_from_uri_helper ("file:///tmp/foo#bar?baz", "/tmp/foo"); } int diff --git a/glib/tests/cxx.cpp b/glib/tests/cxx.cpp index bc7967c..5198621 100644 --- a/glib/tests/cxx.cpp +++ b/glib/tests/cxx.cpp @@ -536,7 +536,7 @@ int main (int argc, char *argv[]) { #if G_CXX_STD_CHECK_VERSION (11) - g_test_init (&argc, &argv, NULL); + g_test_init (&argc, &argv, nullptr); #else g_test_init (&argc, &argv, static_cast(NULL)); #endif diff --git a/glib/tests/dir.c b/glib/tests/dir.c index 74dbe14..641cee8 100644 --- a/glib/tests/dir.c +++ b/glib/tests/dir.c @@ -41,6 +41,29 @@ test_dir_nonexisting (void) g_error_free (error); } +static void +test_dir_refcounting (void) +{ + GDir *dir; + GError *local_error = NULL; + + g_test_summary ("Test refcounting interactions with g_dir_close()"); + + /* Try keeping the `GDir` struct alive after closing it. */ + dir = g_dir_open (".", 0, &local_error); + g_assert_no_error (local_error); + + g_dir_ref (dir); + g_dir_close (dir); + g_dir_unref (dir); + + /* Test that dropping the last ref closes it. Any leak here should be caught + * when the test is run under valgrind. */ + dir = g_dir_open (".", 0, &local_error); + g_assert_no_error (local_error); + g_dir_unref (dir); +} + int main (int argc, char *argv[]) { @@ -48,6 +71,7 @@ main (int argc, char *argv[]) g_test_add_func ("/dir/read", test_dir_read); g_test_add_func ("/dir/nonexisting", test_dir_nonexisting); + g_test_add_func ("/dir/refcounting", test_dir_refcounting); return g_test_run (); } diff --git a/glib/tests/fileutils.c b/glib/tests/fileutils.c index 8f5a482..56be804 100644 --- a/glib/tests/fileutils.c +++ b/glib/tests/fileutils.c @@ -60,6 +60,8 @@ #define G_TEST_DIR_MODE (S_IWRITE | S_IREAD) #endif +#include "testutils.h" + #define S G_DIR_SEPARATOR_S static void @@ -979,17 +981,17 @@ test_format_size_for_display (void) check_string (g_format_size_full (2, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_ONLY_VALUE), "2"); check_string (g_format_size_full (2, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_ONLY_UNIT), "bits"); - check_string (g_format_size_full (2000ULL, G_FORMAT_SIZE_BITS), "2.0\302\240kb"); - check_string (g_format_size_full (2000ULL * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Mb"); - check_string (g_format_size_full (2000ULL * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Gb"); - check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Tb"); - check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Pb"); - check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Eb"); + check_string (g_format_size_full (2000ULL, G_FORMAT_SIZE_BITS), "2.0\302\240kbit"); + check_string (g_format_size_full (2000ULL * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Mbit"); + check_string (g_format_size_full (2000ULL * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Gbit"); + check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Tbit"); + check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Pbit"); + check_string (g_format_size_full (2000ULL * 1000 * 1000 * 1000 * 1000 * 1000, G_FORMAT_SIZE_BITS), "2.0\302\240Ebit"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS), "238.5\302\240Mb"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_LONG_FORMAT), "238.5\302\240Mb (238472938 bits)"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS), "238.5\302\240Mbit"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_LONG_FORMAT), "238.5\302\240Mbit (238472938 bits)"); check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_ONLY_VALUE), "238.5"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_ONLY_UNIT), "Mb"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_ONLY_UNIT), "Mbit"); check_string (g_format_size_full (0, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "0 bits"); @@ -1002,17 +1004,17 @@ test_format_size_for_display (void) check_string (g_format_size_full (2, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_ONLY_VALUE), "2"); check_string (g_format_size_full (2, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_ONLY_UNIT), "bits"); - check_string (g_format_size_full (2048ULL, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Kib"); - check_string (g_format_size_full (2048ULL * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Mib"); - check_string (g_format_size_full (2048ULL * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Gib"); - check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Tib"); - check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Pib"); - check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Eib"); + check_string (g_format_size_full (2048ULL, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Kibit"); + check_string (g_format_size_full (2048ULL * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Mibit"); + check_string (g_format_size_full (2048ULL * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Gibit"); + check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Tibit"); + check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Pibit"); + check_string (g_format_size_full (2048ULL * 1024 * 1024 * 1024 * 1024 * 1024, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "2.0\302\240Eibit"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "227.4\302\240Mib"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_LONG_FORMAT), "227.4\302\240Mib (238472938 bits)"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS), "227.4\302\240Mibit"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_LONG_FORMAT), "227.4\302\240Mibit (238472938 bits)"); check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_ONLY_VALUE), "227.4"); - check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_ONLY_UNIT), "Mib"); + check_string (g_format_size_full (238472938, G_FORMAT_SIZE_BITS | G_FORMAT_SIZE_IEC_UNITS | G_FORMAT_SIZE_ONLY_UNIT), "Mibit"); } static void @@ -1472,6 +1474,124 @@ test_get_contents (void) g_remove (filename); } +static gboolean +resize_file (const gchar *filename, + gint64 size) +{ + int fd; + int retval; + + fd = g_open (filename, O_CREAT | O_RDWR | O_TRUNC, 0666); + g_assert_cmpint (fd, >=, 0); + +#ifdef G_OS_WIN32 + retval = _chsize_s (fd, size); +#elif HAVE_FTRUNCATE64 + retval = ftruncate64 (fd, size); +#else + errno = ENOSYS; + retval = -1; +#endif + if (retval != 0) + { + g_test_message ("Error trying to resize file (%s)", strerror (errno)); + close (fd); + return FALSE; + } + + close (fd); + return TRUE; +} + +static gboolean +is_error_in_list (GFileError error_code, + const GFileError ok_list[], + size_t ok_count) +{ + for (size_t i = 0; i < ok_count; i++) + { + if (ok_list[i] == error_code) + return TRUE; + } + return FALSE; +} + +static void +get_largefile_check_len (const gchar *filename, + gint64 large_len, + const GFileError ok_list[], + size_t ok_count) +{ + gboolean get_ok; + gsize len; + gchar *contents; + GError *error = NULL; + + get_ok = g_file_get_contents (filename, &contents, &len, &error); + if (get_ok) + { + g_assert_cmpint ((gint64) len, ==, large_len); + g_free (contents); + } + else + { + g_assert_cmpint (error->domain, ==, G_FILE_ERROR); + if (is_error_in_list ((GFileError)error->code, ok_list, ok_count)) + { + g_test_message ("Error reading file of size 0x%" G_GINT64_MODIFIER "x, but with acceptable error type (%s)", large_len, error->message); + } + else + { + /* fail for other errors */ + g_assert_no_error (error); + } + g_clear_error (&error); + } +} + +static void +test_get_contents_largefile (void) +{ + if (!g_test_slow ()) + { + g_test_skip ("Skipping slow largefile test"); + return; + } + + const gchar *filename = "file-test-get-contents-large"; + gint64 large_len; + + /* error OK if couldn't allocate large buffer, or if file is too large */ + const GFileError too_large_errors[] = { G_FILE_ERROR_NOMEM, G_FILE_ERROR_FAILED }; + /* error OK if couldn't allocate large buffer */ + const GFileError nomem_errors[] = { G_FILE_ERROR_NOMEM }; + + /* OK to fail to read this, but don't silently under-read */ + large_len = (G_GINT64_CONSTANT (1) << 32) + 16; + if (!resize_file (filename, large_len)) + goto failed_resize; + get_largefile_check_len (filename, large_len, too_large_errors, G_N_ELEMENTS (too_large_errors)); + + /* OK to fail to read this size, but don't silently under-read */ + large_len = (G_GINT64_CONSTANT (1) << 32) - 1; + if (!resize_file (filename, large_len)) + goto failed_resize; + get_largefile_check_len (filename, large_len, too_large_errors, G_N_ELEMENTS (too_large_errors)); + + /* OK to fail memory allocation, but don't otherwise fail this size */ + large_len = (G_GINT64_CONSTANT (1) << 31) - 1; + if (!resize_file (filename, large_len)) + goto failed_resize; + get_largefile_check_len (filename, large_len, nomem_errors, G_N_ELEMENTS (nomem_errors)); + + g_remove (filename); + return; + +failed_resize: + g_test_incomplete ("Failed to resize large file, unable to complete large file tests."); + g_remove (filename); +} + static void test_file_test (void) { @@ -2476,26 +2596,6 @@ test_win32_zero_terminate_symlink (void) #endif static void -assert_fd_was_closed (int fd) -{ - /* We can't tell a fd was really closed without behaving as though it - * was still valid */ - if (g_test_undefined ()) - { - int result, errsv; - GWin32InvalidParameterHandler handler; - - GLIB_PRIVATE_CALL (g_win32_push_empty_invalid_parameter_handler) (&handler); - result = g_fsync (fd); - errsv = errno; - GLIB_PRIVATE_CALL (g_win32_pop_invalid_parameter_handler) (&handler); - - g_assert_cmpint (result, !=, 0); - g_assert_cmpint (errsv, ==, EBADF); - } -} - -static void test_clear_fd_ebadf (void) { char *name = NULL; @@ -2666,6 +2766,7 @@ main (int argc, g_test_add_func ("/fileutils/mkstemp", test_mkstemp); g_test_add_func ("/fileutils/mkdtemp", test_mkdtemp); g_test_add_func ("/fileutils/get-contents", test_get_contents); + g_test_add_func ("/fileutils/get-contents-large-file", test_get_contents_largefile); g_test_add_func ("/fileutils/set-contents", test_set_contents); g_test_add_func ("/fileutils/set-contents-full", test_set_contents_full); g_test_add_func ("/fileutils/set-contents-full/read-only-file", test_set_contents_full_read_only_file); diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c index 49390c9..f60368d 100644 --- a/glib/tests/gdatetime.c +++ b/glib/tests/gdatetime.c @@ -1,6 +1,7 @@ /* gdatetime-tests.c * * Copyright (C) 2009-2010 Christian Hergert + * Copyright 2023 GNOME Foundation Inc. * * SPDX-License-Identifier: LGPL-2.1-or-later * @@ -16,6 +17,10 @@ * * You should have received a copy of the GNU Lesser General Public License * along with this library; if not, see . + * + * Authors: + * - Christian Hergert + * - Philip Withnall */ #include "config.h" @@ -28,6 +33,8 @@ #include #include +#include "gdatetime-private.h" + #ifdef G_OS_WIN32 #define WIN32_LEAN_AND_MEAN #include @@ -1536,15 +1543,8 @@ test_GDateTime_get_day_of_year (void) static void test_GDateTime_printf (void) { -/* 64 seems big, but one zoneinfo file, Factory, has an abbreviation - * that long, and it will cause the test to fail if dst isn't big - * enough. - */ gchar *old_lc_all; gchar *old_lc_messages; - gchar dst[64]; - struct tm tt; - time_t t; #ifdef G_OS_WIN32 gchar *current_tz = NULL; @@ -1552,14 +1552,14 @@ test_GDateTime_printf (void) #endif #define TEST_PRINTF(f,o) G_STMT_START { \ -GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\ +GDateTime *__dt = g_date_time_new_utc (2009, 10, 24, 0, 0, 0);\ gchar *__p = g_date_time_format (__dt, (f)); \ g_assert_cmpstr (__p, ==, (o)); \ g_date_time_unref (__dt); \ g_free (__p); } G_STMT_END #define TEST_PRINTF_DATE(y,m,d,f,o) G_STMT_START { \ - GDateTime *dt = g_date_time_new_local (y, m, d, 0, 0, 0); \ + GDateTime *dt = g_date_time_new_utc (y, m, d, 0, 0, 0); \ gchar *p = g_date_time_format (dt, (f)); \ gchar *o_casefold = g_utf8_casefold (o, -1); \ gchar *p_casefold = g_utf8_casefold (p, -1); \ @@ -1570,7 +1570,7 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\ g_free (p); } G_STMT_END #define TEST_PRINTF_TIME(h,m,s,f,o) G_STMT_START { \ - GDateTime *dt = g_date_time_new_local (2009, 10, 24, (h), (m), (s)); \ + GDateTime *dt = g_date_time_new_utc (2009, 10, 24, (h), (m), (s)); \ gchar *p = g_date_time_format (dt, (f)); \ g_assert_cmpstr (p, ==, (o)); \ g_date_time_unref (dt); \ @@ -1582,22 +1582,6 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\ old_lc_messages = g_strdup (g_getenv ("LC_MESSAGES")); g_setenv ("LC_MESSAGES", "C", TRUE); - /* - * This is a little helper to make sure we can compare timezones to - * that of the generated timezone. - */ - t = time (NULL); - g_assert_cmpint (t, !=, (time_t) -1); - memset (&tt, 0, sizeof(tt)); - get_localtime_tm (t, &tt); - tt.tm_year = 2009 - 1900; - tt.tm_mon = 9; /* 0 indexed */ - tt.tm_mday = 24; - t = mktime (&tt); - memset (&tt, 0, sizeof(tt)); - get_localtime_tm (t, &tt); - strftime (dst, sizeof(dst), "%Z", &tt); - TEST_PRINTF ("%a", "Sat"); TEST_PRINTF ("%A", "Saturday"); TEST_PRINTF ("%b", "Oct"); @@ -1642,7 +1626,7 @@ GDateTime *__dt = g_date_time_new_local (2009, 10, 24, 0, 0, 0);\ TEST_PRINTF ("%", ""); TEST_PRINTF ("%9", NULL); #ifdef G_OS_UNIX - TEST_PRINTF ("%Z", dst); + TEST_PRINTF ("%Z", "UTC"); #elif defined G_OS_WIN32 g_assert (GetDynamicTimeZoneInformation (&dtz_info) != TIME_ZONE_ID_INVALID); if (wcscmp (dtz_info.StandardName, L"") != 0) @@ -1741,6 +1725,21 @@ test_non_utf8_printf (void) TEST_PRINTF ("%%", "%"); TEST_PRINTF ("%", ""); TEST_PRINTF ("%9", NULL); +#ifdef HAVE_LANGINFO_ERA + TEST_PRINTF ("%Ec", "平成21年10月24日 00時00分00秒"); + TEST_PRINTF ("%EC", "平成"); + TEST_PRINTF ("%Ex", "平成21年10月24日"); + TEST_PRINTF ("%EX", "00時00分00秒"); + TEST_PRINTF ("%Ey", "21"); + TEST_PRINTF ("%EY", "平成21年"); +#else + TEST_PRINTF ("%Ec", "平成21年10月24日 00時00分00秒"); + TEST_PRINTF ("%EC", "平成"); + TEST_PRINTF ("%Ex", "2009\345\271\26410\346\234\21024\346\227\245"); + TEST_PRINTF ("%EX", "00\346\231\20200\345\210\20600\347\247\222"); + TEST_PRINTF ("%Ey", "09"); + TEST_PRINTF ("%EY", "2009"); +#endif setlocale (LC_ALL, oldlocale); g_free (oldlocale); @@ -1792,6 +1791,30 @@ test_modifiers (void) TEST_PRINTF_DATE (2009, 1, 21, "%-e", "21"); TEST_PRINTF_DATE (2009, 1, 21, "%0e", "21"); + TEST_PRINTF_DATE (2009, 1, 1, "%a", "Thu"); + TEST_PRINTF_DATE (2009, 1, 1, "%^a", "THU"); + TEST_PRINTF_DATE (2009, 1, 1, "%#a", "THU"); + + TEST_PRINTF_DATE (2009, 1, 1, "%A", "Thursday"); + TEST_PRINTF_DATE (2009, 1, 1, "%^A", "THURSDAY"); + TEST_PRINTF_DATE (2009, 1, 1, "%#A", "THURSDAY"); + + TEST_PRINTF_DATE (2009, 1, 1, "%b", "Jan"); + TEST_PRINTF_DATE (2009, 1, 1, "%^b", "JAN"); + TEST_PRINTF_DATE (2009, 1, 1, "%#b", "JAN"); + + TEST_PRINTF_DATE (2009, 1, 1, "%B", "January"); + TEST_PRINTF_DATE (2009, 1, 1, "%^B", "JANUARY"); + TEST_PRINTF_DATE (2009, 1, 1, "%#B", "JANUARY"); + + TEST_PRINTF_DATE (2009, 1, 1, "%h", "Jan"); + TEST_PRINTF_DATE (2009, 1, 1, "%^h", "JAN"); + TEST_PRINTF_DATE (2009, 1, 1, "%#h", "JAN"); + + TEST_PRINTF_DATE (2009, 1, 1, "%Z", "UTC"); + TEST_PRINTF_DATE (2009, 1, 1, "%^Z", "UTC"); + TEST_PRINTF_DATE (2009, 1, 1, "%#Z", "utc"); + TEST_PRINTF_TIME ( 1, 0, 0, "%H", "01"); TEST_PRINTF_TIME ( 1, 0, 0, "%_H", " 1"); TEST_PRINTF_TIME ( 1, 0, 0, "%-H", "1"); @@ -1824,7 +1847,16 @@ test_modifiers (void) TEST_PRINTF_TIME (23, 0, 0, "%-l", "11"); TEST_PRINTF_TIME (23, 0, 0, "%0l", "11"); + TEST_PRINTF_TIME (1, 0, 0, "%p", "AM"); + TEST_PRINTF_TIME (1, 0, 0, "%^p", "AM"); + TEST_PRINTF_TIME (1, 0, 0, "%#p", "am"); + + TEST_PRINTF_TIME (1, 0, 0, "%P", "am"); + TEST_PRINTF_TIME (1, 0, 0, "%^P", "AM"); + TEST_PRINTF_TIME (1, 0, 0, "%#P", "am"); + oldlocale = g_strdup (setlocale (LC_ALL, NULL)); + setlocale (LC_ALL, "fa_IR.utf-8"); #ifdef HAVE_LANGINFO_OUTDIGIT if (strstr (setlocale (LC_ALL, NULL), "fa_IR") != NULL) @@ -1843,6 +1875,61 @@ test_modifiers (void) #else g_test_skip ("langinfo not available, skipping O modifier tests"); #endif + + setlocale (LC_ALL, "gu_IN.utf-8"); +#ifdef HAVE_LANGINFO_OUTDIGIT + if (strstr (setlocale (LC_ALL, NULL), "gu_IN") != NULL) + { + TEST_PRINTF_TIME (23, 0, 0, "%OH", "૨૩"); /* '23' */ + TEST_PRINTF_TIME (23, 0, 0, "%OI", "૧૧"); /* '11' */ + TEST_PRINTF_TIME (23, 0, 0, "%OM", "૦૦"); /* '00' */ + + TEST_PRINTF_DATE (2011, 7, 1, "%Om", "૦૭"); /* '07' */ + TEST_PRINTF_DATE (2011, 7, 1, "%0Om", "૦૭"); /* '07' */ + TEST_PRINTF_DATE (2011, 7, 1, "%-Om", "૭"); /* '7' */ + TEST_PRINTF_DATE (2011, 7, 1, "%_Om", " ૭"); /* ' 7' */ + } + else + g_test_skip ("locale gu_IN not available, skipping O modifier tests"); +#else + g_test_skip ("langinfo not available, skipping O modifier tests"); +#endif + + setlocale (LC_ALL, "en_GB.utf-8"); + if (strstr (setlocale (LC_ALL, NULL), "en_GB") != NULL) + { +#ifndef __APPLE__ + TEST_PRINTF_DATE (2009, 1, 1, "%c", "thu 01 jan 2009 00:00:00 utc"); + TEST_PRINTF_DATE (2009, 1, 1, "%Ec", "thu 01 jan 2009 00:00:00 utc"); +#else + /* macOS uses a figure space (U+2007) to pad the day */ + TEST_PRINTF_DATE (2009, 1, 1, "%c", "thu " "\xe2\x80\x87" "1 jan 00:00:00 2009"); + TEST_PRINTF_DATE (2009, 1, 1, "%Ec", "thu " "\xe2\x80\x87" "1 jan 00:00:00 2009"); +#endif + + TEST_PRINTF_DATE (2009, 1, 1, "%C", "20"); + TEST_PRINTF_DATE (2009, 1, 1, "%EC", "20"); + +#ifndef __APPLE__ + TEST_PRINTF_DATE (2009, 1, 2, "%x", "02/01/09"); + TEST_PRINTF_DATE (2009, 1, 2, "%Ex", "02/01/09"); +#else + TEST_PRINTF_DATE (2009, 1, 2, "%x", "02/01/2009"); + TEST_PRINTF_DATE (2009, 1, 2, "%Ex", "02/01/2009"); +#endif + + TEST_PRINTF_TIME (1, 2, 3, "%X", "01:02:03"); + TEST_PRINTF_TIME (1, 2, 3, "%EX", "01:02:03"); + + TEST_PRINTF_DATE (2009, 1, 1, "%y", "09"); + TEST_PRINTF_DATE (2009, 1, 1, "%Ey", "09"); + + TEST_PRINTF_DATE (2009, 1, 1, "%Y", "2009"); + TEST_PRINTF_DATE (2009, 1, 1, "%EY", "2009"); + } + else + g_test_skip ("locale en_GB not available, skipping E modifier tests"); + setlocale (LC_ALL, oldlocale); g_free (oldlocale); } @@ -2183,6 +2270,172 @@ test_all_dates (void) } static void +test_date_time_eras_japan (void) +{ +#ifdef HAVE_LANGINFO_ERA + gchar *oldlocale; + + oldlocale = g_strdup (setlocale (LC_ALL, NULL)); + setlocale (LC_ALL, "ja_JP.utf-8"); + if (strstr (setlocale (LC_ALL, NULL), "ja_JP") == NULL) + { + g_test_skip ("locale ja_JP.utf-8 not available, skipping Japanese era tests"); + g_free (oldlocale); + return; + } + + /* See https://en.wikipedia.org/wiki/Japanese_era_name + * First test the Reiwa era (令和) */ + TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "令和05年06月01日 00時00分00秒"); + TEST_PRINTF_DATE (2023, 06, 01, "%EC", "令和"); + TEST_PRINTF_DATE (2023, 06, 01, "%Ex", "令和05年06月01日"); + TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00時00分00秒"); + TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "05"); + TEST_PRINTF_DATE (2023, 06, 01, "%EY", "令和05年"); + + /* Heisei era (平成) */ + TEST_PRINTF_DATE (2019, 04, 30, "%Ec", "平成31年04月30日 00時00分00秒"); + TEST_PRINTF_DATE (2019, 04, 30, "%EC", "平成"); + TEST_PRINTF_DATE (2019, 04, 30, "%Ex", "平成31年04月30日"); + TEST_PRINTF_DATE (2019, 04, 30, "%EX", "00時00分00秒"); + TEST_PRINTF_DATE (2019, 04, 30, "%Ey", "31"); + TEST_PRINTF_DATE (2019, 04, 30, "%EY", "平成31年"); + + /* Shōwa era (昭和) */ + TEST_PRINTF_DATE (1926, 12, 25, "%Ec", "昭和元年12月25日 00時00分00秒"); + TEST_PRINTF_DATE (1926, 12, 25, "%EC", "昭和"); + TEST_PRINTF_DATE (1926, 12, 25, "%Ex", "昭和元年12月25日"); + TEST_PRINTF_DATE (1926, 12, 25, "%EX", "00時00分00秒"); + TEST_PRINTF_DATE (1926, 12, 25, "%Ey", "01"); + TEST_PRINTF_DATE (1926, 12, 25, "%EY", "昭和元年"); + + setlocale (LC_ALL, oldlocale); + g_free (oldlocale); +#else + g_test_skip ("nl_langinfo(ERA) not supported, skipping era tests"); +#endif +} + +static void +test_date_time_eras_thailand (void) +{ +#ifdef HAVE_LANGINFO_ERA + gchar *oldlocale; + + oldlocale = g_strdup (setlocale (LC_ALL, NULL)); + setlocale (LC_ALL, "th_TH.utf-8"); + if (strstr (setlocale (LC_ALL, NULL), "th_TH") == NULL) + { + g_test_skip ("locale th_TH.utf-8 not available, skipping Thai era tests"); + g_free (oldlocale); + return; + } + + /* See https://en.wikipedia.org/wiki/Thai_solar_calendar */ + TEST_PRINTF_DATE (2023, 06, 01, "%Ec", "วันพฤหัสบดีที่  1 มิถุนายน พ.ศ. 2566, 00.00.00 น."); + TEST_PRINTF_DATE (2023, 06, 01, "%EC", "พ.ศ."); + TEST_PRINTF_DATE (2023, 06, 01, "%Ex", " 1 มิ.ย. 2566"); + TEST_PRINTF_DATE (2023, 06, 01, "%EX", "00.00.00 น."); + TEST_PRINTF_DATE (2023, 06, 01, "%Ey", "2566"); + TEST_PRINTF_DATE (2023, 06, 01, "%EY", "พ.ศ. 2566"); + + TEST_PRINTF_DATE (01, 06, 01, "%Ex", " 1 มิ.ย. 544"); + + setlocale (LC_ALL, oldlocale); + g_free (oldlocale); +#else + g_test_skip ("nl_langinfo(ERA) not supported, skipping era tests"); +#endif +} + +static void +test_date_time_eras_parsing (void) +{ + struct + { + const char *desc; + gboolean expected_success; + size_t expected_n_segments; + } + vectors[] = + { + /* Some successful parsing: */ + { "", TRUE, 0 }, + /* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/th_TH#L233: */ + { "+:1:-543/01/01:+*:พ.ศ.:%EC %Ey", TRUE, 1 }, + /* From https://github.com/bminor/glibc/blob/9fd3409842b3e2d31cff5dbd6f96066c430f0aa2/localedata/locales/ja_JP#L14967C5-L14977C60: */ + { "+:2:2020/01/01:+*:令和:%EC%Ey年;" + "+:1:2019/05/01:2019/12/31:令和:%EC元年;" + "+:2:1990/01/01:2019/04/30:平成:%EC%Ey年;" + "+:1:1989/01/08:1989/12/31:平成:%EC元年;" + "+:2:1927/01/01:1989/01/07:昭和:%EC%Ey年;" + "+:1:1926/12/25:1926/12/31:昭和:%EC元年;" + "+:2:1913/01/01:1926/12/24:大正:%EC%Ey年;" + "+:1:1912/07/30:1912/12/31:大正:%EC元年;" + "+:6:1873/01/01:1912/07/29:明治:%EC%Ey年;" + "+:1:0001/01/01:1872/12/31:西暦:%EC%Ey年;" + "+:1:-0001/12/31:-*:紀元前:%EC%Ey年", TRUE, 11 }, + { "-:2:2020/01/01:-*:令和:%EC%Ey年", TRUE, 1 }, + { "+:2:2020/01/01:2020/01/01:令和:%EC%Ey年", TRUE, 1 }, + { "+:2:+2020/01/01:+*:令和:%EC%Ey年", TRUE, 1 }, + /* Some errors: */ + { ".:2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+.2:2020/01/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+", FALSE, 0 }, + { "+:", FALSE, 0 }, + { "+::", FALSE, 0 }, + { "+:200", FALSE, 0 }, + { "+:2nonsense", FALSE, 0 }, + { "+:2nonsense:", FALSE, 0 }, + { "+:2:", FALSE, 0 }, + { "+:2::", FALSE, 0 }, + { "+:2:2020-01/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020nonsense/01/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:18446744073709551615/01/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01-01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01nonsense/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/00/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/13/01:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01/00:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01/32:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01/01nonsense:+*:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01/01", FALSE, 0 }, + { "+:2:2020/01/01:", FALSE, 0 }, + { "+:2:2020/01/01::", FALSE, 0 }, + { "+:2:2020/01/01:2021-01-01:令和:%EC%Ey年", FALSE, 0 }, + { "+:2:2020/01/01:+*", FALSE, 0 }, + { "+:2:2020/01/01:+*:", FALSE, 0 }, + { "+:2:2020/01/01:+*::", FALSE, 0 }, + { "+:2:2020/01/01:+*:令和", FALSE, 0 }, + { "+:2:2020/01/01:+*:令和:", FALSE, 0 }, + { "+:2:2020/01/01:+*:令和:;", FALSE, 0 }, + }; + + for (size_t i = 0; i < G_N_ELEMENTS (vectors); i++) + { + GPtrArray *segments = NULL; + + g_test_message ("Vector %" G_GSIZE_FORMAT ": %s", i, vectors[i].desc); + + segments = _g_era_description_parse (vectors[i].desc); + + if (vectors[i].expected_success) + { + g_assert_nonnull (segments); + g_assert_cmpuint (segments->len, ==, vectors[i].expected_n_segments); + } + else + { + g_assert_null (segments); + } + + g_clear_pointer (&segments, g_ptr_array_unref); + } +} + +static void test_z (void) { GTimeZone *tz; @@ -3139,6 +3392,38 @@ test_time_zone_caching (void) g_assert_true (tz1 == tz2); } +static void +test_date_time_unix_usec (void) +{ + gint64 usecs = g_get_real_time (); + gint64 secs = usecs / G_USEC_PER_SEC; + GDateTime *dt; + GDateTime *local; + + dt = g_date_time_new_from_unix_utc (secs); + g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, secs * G_USEC_PER_SEC); + g_assert_cmpint (g_date_time_to_unix (dt), ==, secs); + g_date_time_unref (dt); + + dt = g_date_time_new_from_unix_utc_usec (usecs); + g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, usecs); + g_assert_cmpint (g_date_time_to_unix (dt), ==, secs); + g_date_time_unref (dt); + + local = g_date_time_new_from_unix_local (secs); + dt = g_date_time_to_utc (local); + g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, secs * G_USEC_PER_SEC); + g_assert_cmpint (g_date_time_to_unix (dt), ==, secs); + g_date_time_unref (dt); + g_date_time_unref (local); + + local = g_date_time_new_from_unix_local_usec (usecs); + dt = g_date_time_to_utc (local); + g_assert_cmpint (g_date_time_to_unix_usec (dt), ==, usecs); + g_assert_cmpint (g_date_time_to_unix (dt), ==, secs); + g_date_time_unref (dt); + g_date_time_unref (local); +} gint main (gint argc, @@ -3152,6 +3437,7 @@ main (gint argc, * categories. Unset it to avoid interference with tests. */ g_unsetenv ("CHARSET"); + setlocale (LC_ALL, "C.UTF-8"); g_test_init (&argc, &argv, NULL); /* GDateTime Tests */ @@ -3219,6 +3505,11 @@ main (gint argc, g_test_add_func ("/GDateTime/dst", test_GDateTime_dst); g_test_add_func ("/GDateTime/test_z", test_z); g_test_add_func ("/GDateTime/test-all-dates", test_all_dates); + g_test_add_func ("/GDateTime/eras/japan", test_date_time_eras_japan); + g_test_add_func ("/GDateTime/eras/thailand", test_date_time_eras_thailand); + g_test_add_func ("/GDateTime/eras/parsing", test_date_time_eras_parsing); + g_test_add_func ("/GDateTime/unix_usec", test_date_time_unix_usec); + g_test_add_func ("/GTimeZone/find-interval", test_find_interval); g_test_add_func ("/GTimeZone/adjust-time", test_adjust_time); g_test_add_func ("/GTimeZone/no-header", test_no_header); diff --git a/glib/tests/io-channel-basic.c b/glib/tests/io-channel-basic.c index c1a46cd..695df6d 100644 --- a/glib/tests/io-channel-basic.c +++ b/glib/tests/io-channel-basic.c @@ -270,12 +270,12 @@ spawn_process (int children_nb) wcl.hCursor = NULL; wcl.hbrBackground = NULL; wcl.lpszMenuName = NULL; - wcl.lpszClassName = "io-channel-basic"; + wcl.lpszClassName = L"io-channel-basic"; klass = RegisterClass (&wcl); g_assert_cmpint (klass, !=, 0); - hwnd = CreateWindow (MAKEINTATOM(klass), "io-channel-basic", 0, 0, 0, 10, 10, + hwnd = CreateWindow (MAKEINTATOM (klass), L"io-channel-basic", 0, 0, 0, 10, 10, NULL, NULL, wcl.hInstance, NULL); g_assert_nonnull (hwnd); diff --git a/glib/tests/keyfile.c b/glib/tests/keyfile.c index bc125c1..92f8010 100644 --- a/glib/tests/keyfile.c +++ b/glib/tests/keyfile.c @@ -589,8 +589,9 @@ test_string (void) "key6=trailing space \n" "[invalid]\n" "key1=\\a\\b\\0800xff\n" - "key2=blabla\\\n" - "key3=foo\\i\\\n"; + "key2=blabla\\\n" /* escape at end of line */ + "key3=\\ifoo\n" /* invalid escape */ + "key4=\\i\\hfoo\n"; /* invalid escape with multiple stacked errors */ keyfile = load_data (data, 0); @@ -613,6 +614,10 @@ test_string (void) check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); g_free (value); + value = g_key_file_get_string (keyfile, "invalid", "key4", &error); + check_error (&error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_INVALID_VALUE); + g_free (value); + g_key_file_set_string (keyfile, "inserted", "key1", "simple"); g_key_file_set_string (keyfile, "inserted", "key2", " leading space"); g_key_file_set_string (keyfile, "inserted", "key3", "\tleading tab"); diff --git a/glib/tests/logging.c b/glib/tests/logging.c index ea9dcb8..858cad8 100644 --- a/glib/tests/logging.c +++ b/glib/tests/logging.c @@ -202,9 +202,46 @@ test_default_handler_debug_stderr (void) } static void -test_default_handler_would_drop (void) +test_default_handler_would_drop_env5 (void) { - g_unsetenv ("G_MESSAGES_DEBUG"); + g_setenv ("G_MESSAGES_DEBUG", "foobar", TRUE); + + g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo")); + g_assert_true (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "bar")); +} + +static void +test_default_handler_would_drop_env4 (void) +{ + g_setenv ("G_MESSAGES_DEBUG", "all", TRUE); + + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_ERROR, "foo")); + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_CRITICAL, "foo")); + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_WARNING, "foo")); + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_MESSAGE, "foo")); + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_INFO, "foo")); + g_assert_false (g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, "foo")); + g_assert_false (g_log_writer_default_would_drop (1< 0) + g_log_writer_default_would_drop (G_LOG_LEVEL_DEBUG, test_would_drop_robustness_random_domain ()); + + g_atomic_int_set (&test_would_drop_robustness_stopping, TRUE); + for (i = 0; i < G_N_ELEMENTS (threads); i++) + g_thread_join (threads[i]); +} + static void test_default_handler_0x400 (void) { @@ -338,6 +517,24 @@ test_default_handler (void) g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop", 0, G_TEST_SUBPROCESS_DEFAULT); g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-env1", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-env2", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-env3", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-env4", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-env5", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_subprocess ("/logging/default-handler/subprocess/would-drop-robustness", 0, + G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); } static void @@ -871,6 +1068,12 @@ main (int argc, char *argv[]) g_test_add_func ("/logging/default-handler/subprocess/debug-stderr", test_default_handler_debug_stderr); g_test_add_func ("/logging/default-handler/subprocess/0x400", test_default_handler_0x400); g_test_add_func ("/logging/default-handler/subprocess/would-drop", test_default_handler_would_drop); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-env1", test_default_handler_would_drop_env1); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-env2", test_default_handler_would_drop_env2); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-env3", test_default_handler_would_drop_env3); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-env4", test_default_handler_would_drop_env4); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-env5", test_default_handler_would_drop_env5); + g_test_add_func ("/logging/default-handler/subprocess/would-drop-robustness", test_default_handler_would_drop_robustness); g_test_add_func ("/logging/warnings", test_warnings); g_test_add_func ("/logging/fatal-log-mask", test_fatal_log_mask); g_test_add_func ("/logging/set-handler", test_set_handler); diff --git a/glib/tests/meson.build b/glib/tests/meson.build index d80c86e..f6efc59 100644 --- a/glib/tests/meson.build +++ b/glib/tests/meson.build @@ -12,14 +12,25 @@ glib_tests = { 'cache' : {}, 'charset' : {}, 'checksum' : {}, - 'collate' : {}, + 'collate' : { + # musl: collate fail due to missing collation support in musl libc + # From https://wiki.musl-libc.org/roadmap#Open_future_goals + # "LC_COLLATE support for collation orders other than simple codepoint order" + 'can_fail' : linux_libc == 'musl', + }, 'completion' : {}, 'cond' : {}, - 'convert' : {}, + 'convert' : { + # FIXME: musl: /conversion/illegal-sequence: https://gitlab.gnome.org/GNOME/glib/-/issues/3182 + 'can_fail' : linux_libc == 'musl', + }, 'dataset' : {}, 'date' : { - # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 - 'can_fail' : host_system == 'darwin', + # FIXME: darwin: https://gitlab.gnome.org/GNOME/glib/-/issues/1392 + # musl: /date/month_substring should be skipped but it's not. The fix should + # be on musl side: https://www.openwall.com/lists/musl/2023/08/10/3 + # FIXME: musl: /date/strftime: https://gitlab.gnome.org/GNOME/glib/-/issues/3171 + 'can_fail' : host_system == 'darwin' or linux_libc == 'musl', }, 'dir' : {}, 'environment' : { @@ -29,8 +40,12 @@ glib_tests = { 'error' : {}, 'fileutils' : {}, 'gdatetime' : { + 'source' : ['gdatetime.c', '../gdatetime-private.c'], 'suite' : ['slow'], - 'can_fail' : host_system == 'windows', + # musl: GDateTime/format_mixed/non_utf8_time_non_utf8_messages should be + # skipped but it's not. The fix should be on musl side: + # https://www.openwall.com/lists/musl/2023/08/10/3 + 'can_fail' : host_system == 'windows' or linux_libc == 'musl', }, 'guuid' : {}, 'gvariant' : { @@ -70,7 +85,11 @@ glib_tests = { 'node' : {}, 'once' : {}, 'onceinit' : {}, - 'option-context' : {}, + 'option-context' : { + # musl: /option/arg/repetition/locale should be skipped but it's not. The + # fix should be on musl side: https://www.openwall.com/lists/musl/2023/08/10/3 + 'can_fail' : linux_libc == 'musl', + }, 'option-argv0' : {}, 'overflow' : {}, 'overflow-fallback' : { @@ -127,23 +146,14 @@ glib_tests = { 'extra_programs' : host_machine.system() == 'windows' ? ['spawn-test-win32-gui'] : [], }, 'strfuncs' : {}, - 'string' : {}, - 'string-macro' : { - 'source' : 'string.c', + 'string' : { 'c_args' : cc.get_id() == 'gcc' ? ['-Werror=sign-conversion'] : [], - 'install' : false, }, 'strvbuilder' : {}, 'testing' : { 'args': [ '--verbose' ], 'extra_programs' : ['testing-helper'], - }, - 'testing-macro' : { - 'args': [ '--verbose' ], - 'extra_programs' : ['testing-helper'], - 'source' : 'testing.c', 'c_args' : cc.get_id() == 'gcc' ? ['-Werror=sign-conversion'] : [], - 'install' : false, }, 'test-printf' : {}, 'thread' : {}, @@ -318,6 +328,29 @@ if host_machine.system() == 'windows' } endif +if host_machine.system() == 'windows' or have_dlopen_dlsym + constructor_helper = shared_library('constructor-helper', + 'constructor-helper.c', + dependencies: [libglib_dep], + install : false) + constructor_lib = shared_library('constructor-lib', + 'constructor.c', + c_args: ['-DPREFIX=lib'], + dependencies: [libglib_dep], + link_with: [constructor_helper], + install : false) + glib_tests += { + 'constructor' : { + 'install': false, + 'c_args': ['-DLIB_NAME=' + fs.name(constructor_lib.full_path()), + '-DBUILD_TEST_EXECUTABLE', + '-DPREFIX=app'], + 'dependencies' : libdl_dep, + 'link_with': [constructor_helper] + } + } +endif + foreach test_name, extra_args : glib_tests foreach std: extra_args.get('c_standards', []) if c_standards.has_key(std) @@ -398,6 +431,7 @@ foreach test_name, extra_args : glib_tests link_args : extra_args.get('link_args', []), override_options : extra_args.get('override_options', []), dependencies : test_deps + extra_args.get('dependencies', []), + link_with : extra_args.get('link_with', []), install_dir: installed_tests_execdir, install_tag: 'tests', install: install, diff --git a/glib/tests/messages-low-memory.py b/glib/tests/messages-low-memory.py index 8e071b1..eb80369 100644 --- a/glib/tests/messages-low-memory.py +++ b/glib/tests/messages-low-memory.py @@ -63,6 +63,7 @@ class TestMessagesLowMemory(unittest.TestCase): env = os.environ.copy() env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" print("Environment:", env) # We want to ensure consistent line endings... diff --git a/glib/tests/once.c b/glib/tests/once.c index 0bcaea4..d851ad1 100644 --- a/glib/tests/once.c +++ b/glib/tests/once.c @@ -199,8 +199,8 @@ test_once_init_string (void) g_test_summary ("Test g_once_init_{enter,leave}() usage with a string"); - if (g_once_init_enter (&val)) - g_once_init_leave (&val, "foo"); + if (g_once_init_enter_pointer (&val)) + g_once_init_leave_pointer (&val, "foo"); g_assert_cmpstr (val, ==, "foo"); } diff --git a/glib/tests/onceinit.c b/glib/tests/onceinit.c index 4d10b4f..1e60b63 100644 --- a/glib/tests/onceinit.c +++ b/glib/tests/onceinit.c @@ -71,14 +71,14 @@ initializer1 (void) static gpointer initializer2 (void) { - static gsize initialized = 0; - if (g_once_init_enter (&initialized)) + static void *initialized = NULL; + if (g_once_init_enter_pointer (&initialized)) { void *pointer_value = &dummy_value; assert_singleton_execution2 (); - g_once_init_leave (&initialized, (gsize) pointer_value); + g_once_init_leave_pointer (&initialized, pointer_value); } - return (void*) initialized; + return initialized; } static void diff --git a/glib/tests/private.c b/glib/tests/private.c index 37f7761..424c34b 100644 --- a/glib/tests/private.c +++ b/glib/tests/private.c @@ -148,19 +148,6 @@ test_private3 (void) thread = (HANDLE) _beginthreadex (NULL, 0, private3_func, NULL, 0, &ignore); WaitForSingleObject (thread, INFINITE); CloseHandle (thread); - - /* FIXME: with static compilation on Windows this test will fail because - * it is mixing up glib threads with Microsoft native thread API. See - * comment in gthread-win32.c for g_system_thread_exit() implementation. - * Fix is not straightforward, possible solution could be to use FLS - * functions (instead of TLS) as proposed in - * https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1655 - */ - if (!private3_freed) - { - g_test_skip ("FIXME: GPrivate with native win32 thread"); - return; - } } #else { diff --git a/glib/tests/regex.c b/glib/tests/regex.c index d7a698e..1082526 100644 --- a/glib/tests/regex.c +++ b/glib/tests/regex.c @@ -1885,6 +1885,16 @@ test_lookbehind (void) g_match_info_free (match); g_regex_unref (regex); + regex = g_regex_new ("(?str, ==, "firsthalfsome format placeholders"); diff --git a/glib/tests/strvbuilder.c b/glib/tests/strvbuilder.c index 595a684..ed0cfa3 100644 --- a/glib/tests/strvbuilder.c +++ b/glib/tests/strvbuilder.c @@ -93,6 +93,25 @@ test_strvbuilder_add_many (void) } static void +test_strvbuilder_take (void) +{ + GStrvBuilder *builder; + GStrv result; + const gchar *expected[] = { "one", "two", "three", NULL }; + + builder = g_strv_builder_new (); + g_strv_builder_take (builder, g_strdup ("one")); + g_strv_builder_add (builder, "two"); + g_strv_builder_take (builder, g_strdup ("three")); + result = g_strv_builder_end (builder); + g_assert_nonnull (result); + g_assert_true (g_strv_equal ((const gchar *const *) result, expected)); + + g_strfreev (result); + g_strv_builder_unref (builder); +} + +static void test_strvbuilder_ref (void) { GStrvBuilder *builder; @@ -113,6 +132,7 @@ main (int argc, g_test_add_func ("/strvbuilder/add", test_strvbuilder_add); g_test_add_func ("/strvbuilder/addv", test_strvbuilder_addv); g_test_add_func ("/strvbuilder/add_many", test_strvbuilder_add_many); + g_test_add_func ("/strvbuilder/take", test_strvbuilder_take); g_test_add_func ("/strvbuilder/ref", test_strvbuilder_ref); return g_test_run (); diff --git a/glib/tests/test-printf.c b/glib/tests/test-printf.c index 261b038..432685e 100644 --- a/glib/tests/test-printf.c +++ b/glib/tests/test-printf.c @@ -897,6 +897,9 @@ test_upper_bound (void) res = upper_bound ("bla %s %d: %g\n", "bla", 123, 0.123); g_assert_cmpint (res, ==, 20); + + res = upper_bound ("Invalid case: %ls", L"\xD800" /* incomplete surrogate pair */); + g_assert_cmpint (res, ==, 0); } #if !defined(__APPLE__) && !defined(__FreeBSD__) @@ -945,6 +948,30 @@ test_vasprintf_invalid_format_placeholder (void) #endif } +static void +test_vasprintf_invalid_wide_string (void) +{ +#if !defined(__APPLE__) && !defined(__FreeBSD__) + gint len = 0; + gchar *buf = "some non-null string"; +#endif + + g_test_summary ("Test error handling for invalid wide strings in g_vasprintf()"); + +#if !defined(__APPLE__) && !defined(__FreeBSD__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat" +#pragma GCC diagnostic ignored "-Wformat-extra-args" + len = test_vasprintf_va (&buf, "%ls", L"\xD800" /* incomplete surrogate pair */); +#pragma GCC diagnostic pop + + g_assert_cmpint (len, ==, -1); + g_assert_null (buf); +#else + g_test_skip ("vasprintf() placeholder checks on BSDs are less strict"); +#endif +} + int main (int argc, char *argv[]) @@ -986,6 +1013,7 @@ main (int argc, g_test_add_func ("/sprintf/upper-bound", test_upper_bound); g_test_add_func ("/vasprintf/invalid-format-placeholder", test_vasprintf_invalid_format_placeholder); + g_test_add_func ("/vasprintf/invalid-wide-string", test_vasprintf_invalid_wide_string); return g_test_run(); } diff --git a/glib/tests/testing.c b/glib/tests/testing.c index acbc1be..83aaad9 100644 --- a/glib/tests/testing.c +++ b/glib/tests/testing.c @@ -404,6 +404,25 @@ test_subprocess_timeout (void) g_assert_true (g_test_trap_reached_timeout ()); } +static void +test_subprocess_envp (void) +{ + char **envp = NULL; + + if (g_test_subprocess ()) + { + g_assert_cmpstr (g_getenv ("TEST_SUBPROCESS_VARIABLE"), ==, "definitely set"); + return; + } + + envp = g_get_environ (); + envp = g_environ_setenv (g_steal_pointer (&envp), "TEST_SUBPROCESS_VARIABLE", "definitely set", TRUE); + g_test_trap_subprocess_with_envp (NULL, (const gchar * const *) envp, + 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_strfreev (envp); +} + /* run a test with fixture setup and teardown */ typedef struct { guint seed; @@ -2909,6 +2928,7 @@ main (int argc, g_test_add_func ("/trap_subprocess/no-such-test", test_subprocess_no_such_test); if (g_test_slow ()) g_test_add_func ("/trap_subprocess/timeout", test_subprocess_timeout); + g_test_add_func ("/trap_subprocess/envp", test_subprocess_envp); g_test_add_func ("/trap_subprocess/patterns", test_subprocess_patterns); diff --git a/glib/tests/testutils.h b/glib/tests/testutils.h new file mode 100644 index 0000000..4a26b28 --- /dev/null +++ b/glib/tests/testutils.h @@ -0,0 +1,50 @@ +/* + * Copyright 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * Copyright 2023 Collabora Ltd. + * + * SPDX-License-Identifier: LicenseRef-old-glib-tests + * + * This work is provided "as is"; redistribution and modification + * in whole or in part, in any medium, physical or electronic is + * permitted without restriction. + * + * This work is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * + * In no event shall the authors or contributors be liable for any + * direct, indirect, incidental, special, exemplary, or consequential + * damages (including, but not limited to, procurement of substitute + * goods or services; loss of use, data, or profits; or business + * interruption) however caused and on any theory of liability, whether + * in contract, strict liability, or tort (including negligence or + * otherwise) arising in any way out of the use of this software, even + * if advised of the possibility of such damage. + */ + +#include "config.h" + +#include + +#include "glib-private.h" +#include "gstdio.h" + +static inline void +assert_fd_was_closed (int fd) +{ + /* We can't tell a fd was really closed without behaving as though it + * was still valid */ + if (g_test_undefined ()) + { + int result, errsv; + GWin32InvalidParameterHandler handler; + + GLIB_PRIVATE_CALL (g_win32_push_empty_invalid_parameter_handler) (&handler); + result = g_fsync (fd); + errsv = errno; + GLIB_PRIVATE_CALL (g_win32_pop_invalid_parameter_handler) (&handler); + + g_assert_cmpint (result, !=, 0); + g_assert_cmpint (errsv, ==, EBADF); + } +} diff --git a/glib/tests/thread-pool-slow.c b/glib/tests/thread-pool-slow.c index f4a4ad7..7b69373 100644 --- a/glib/tests/thread-pool-slow.c +++ b/glib/tests/thread-pool-slow.c @@ -16,20 +16,10 @@ static gulong abs_thread_counter = 0; static gulong running_thread_counter = 0; static gulong leftover_task_counter = 0; -G_LOCK_DEFINE_STATIC (last_thread); - -static guint last_thread_id = 0; - -G_LOCK_DEFINE_STATIC (thread_counter_sort); - -static gulong sort_thread_counter = 0; - static GThreadPool *idle_pool = NULL; -static GMainLoop *main_loop = NULL; - static void -test_thread_functions (void) +test_threadpool_functions (void) { gint max_unused_threads; guint max_idle_time; @@ -62,7 +52,7 @@ test_thread_functions (void) } static void -test_thread_stop_unused (void) +test_threadpool_stop_unused (void) { GThreadPool *pool; guint i; @@ -99,7 +89,7 @@ test_thread_stop_unused (void) } static void -test_thread_stop_unused_multiple (void) +test_threadpool_stop_unused_multiple (void) { GThreadPool *pools[10]; guint i, j; @@ -144,7 +134,7 @@ test_thread_stop_unused_multiple (void) } static void -test_thread_pools_entry_func (gpointer data, gpointer user_data) +test_threadpool_pools_entry_func (gpointer data, gpointer user_data) { G_LOCK (thread_counter_pools); abs_thread_counter++; @@ -161,15 +151,15 @@ test_thread_pools_entry_func (gpointer data, gpointer user_data) } static void -test_thread_pools (void) +test_threadpool_pools (void) { GThreadPool *pool1, *pool2, *pool3; guint runs; guint i; - pool1 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 3, FALSE, NULL); - pool2 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 5, TRUE, NULL); - pool3 = g_thread_pool_new ((GFunc)test_thread_pools_entry_func, NULL, 7, TRUE, NULL); + pool1 = g_thread_pool_new ((GFunc) test_threadpool_pools_entry_func, NULL, 3, FALSE, NULL); + pool2 = g_thread_pool_new ((GFunc) test_threadpool_pools_entry_func, NULL, 5, TRUE, NULL); + pool3 = g_thread_pool_new ((GFunc) test_threadpool_pools_entry_func, NULL, 7, TRUE, NULL); runs = 300; for (i = 0; i < runs; i++) @@ -192,7 +182,7 @@ test_thread_pools (void) } static gint -test_thread_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_data) +test_threadpool_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_data) { guint32 id1, id2; @@ -203,49 +193,40 @@ test_thread_sort_compare_func (gconstpointer a, gconstpointer b, gpointer user_d } static void -test_thread_sort_entry_func (gpointer data, gpointer user_data) +test_threadpool_sort_entry_func (gpointer data, gpointer user_data) { guint thread_id; gboolean is_sorted; + static GMutex last_thread_mutex; + static guint last_thread_id = 0; - G_LOCK (last_thread); + g_mutex_lock (&last_thread_mutex); thread_id = GPOINTER_TO_UINT (data); is_sorted = GPOINTER_TO_INT (user_data); - if (is_sorted) { - static gboolean last_failed = FALSE; - - if (last_thread_id > thread_id) { - if (last_failed) { - g_assert_cmpint (last_thread_id, <=, thread_id); - } - - /* Here we remember one fail and if it concurrently fails, it - * can not be sorted. the last thread id might be < this thread - * id if something is added to the queue since threads were - * created - */ - last_failed = TRUE; - } else { - last_failed = FALSE; - } + if (is_sorted) + { + if (last_thread_id != 0) + g_assert_cmpint (last_thread_id, <=, thread_id); - last_thread_id = thread_id; - } + last_thread_id = thread_id; + } - G_UNLOCK (last_thread); + g_mutex_unlock (&last_thread_mutex); g_usleep (WAIT * 1000); } static void -test_thread_sort (gboolean sort) +test_threadpool_sort (gconstpointer data) { + gboolean sort = GPOINTER_TO_UINT (data); GThreadPool *pool; guint limit; guint max_threads; guint i; + GError *local_error = NULL; limit = MAX_THREADS * 10; @@ -261,11 +242,16 @@ test_thread_sort (gboolean sort) * Threads are scheduled by the operating system and are executed at * random. It cannot be assumed that threads are executed in the * order they are created. This was discussed in bug #334943. + * + * However, if testing sorting, we start with max-threads=0 so that all the + * work can be enqueued before starting the pool. This prevents a race between + * new work being enqueued out of sorted order, and work being pulled off the + * queue. */ - pool = g_thread_pool_new (test_thread_sort_entry_func, + pool = g_thread_pool_new (test_threadpool_sort_entry_func, GINT_TO_POINTER (sort), - max_threads, + sort ? 0 : max_threads, FALSE, NULL); @@ -273,7 +259,7 @@ test_thread_sort (gboolean sort) if (sort) { g_thread_pool_set_sort_function (pool, - test_thread_sort_compare_func, + test_threadpool_sort_compare_func, NULL); } @@ -290,6 +276,13 @@ test_thread_sort (gboolean sort) g_thread_pool_unprocessed (pool)); } + if (sort) + { + g_test_message ("Starting thread pool processing"); + g_thread_pool_set_max_threads (pool, max_threads, &local_error); + g_assert_no_error (local_error); + } + g_assert_cmpint (g_thread_pool_get_max_threads (pool), ==, (gint) max_threads); g_assert_cmpuint (g_thread_pool_get_num_threads (pool), <=, (guint) g_thread_pool_get_max_threads (pool)); @@ -297,31 +290,47 @@ test_thread_sort (gboolean sort) } static void -test_thread_idle_time_entry_func (gpointer data, gpointer user_data) +test_threadpool_idle_time_entry_func (gpointer data, gpointer user_data) { g_usleep (WAIT * 1000); } static gboolean -test_thread_idle_timeout (gpointer data) +test_threadpool_idle_timeout (gpointer data) { + gboolean *idle_timeout_called = data; gint i; + *idle_timeout_called = TRUE; + for (i = 0; i < 2; i++) { g_thread_pool_push (idle_pool, GUINT_TO_POINTER (100 + i), NULL); } - return FALSE; + g_main_context_wakeup (NULL); + + return G_SOURCE_REMOVE; +} + +static gboolean +poll_cb (gpointer data) +{ + g_main_context_wakeup (NULL); + return G_SOURCE_CONTINUE; } static void -test_thread_idle_time (void) +test_threadpool_idle_time (void) { guint limit = 50; guint interval = 10000; guint i; + guint idle; + gboolean idle_timeout_called = FALSE; + GSource *timeout_source = NULL; + GSource *poll_source = NULL; - idle_pool = g_thread_pool_new (test_thread_idle_time_entry_func, + idle_pool = g_thread_pool_new (test_threadpool_idle_time_entry_func, NULL, 0, FALSE, @@ -343,105 +352,32 @@ test_thread_idle_time (void) g_assert_cmpint (g_thread_pool_unprocessed (idle_pool), <=, limit); - g_timeout_add ((interval - 1000), - test_thread_idle_timeout, - GUINT_TO_POINTER (interval)); -} + timeout_source = g_timeout_source_new (interval - 1000); + g_source_set_callback (timeout_source, test_threadpool_idle_timeout, &idle_timeout_called, NULL); + g_source_attach (timeout_source, NULL); -static gboolean -test_check_start_and_stop (gpointer user_data) -{ - static guint test_number = 0; - static gboolean run_next = FALSE; - gboolean continue_timeout = TRUE; - gboolean quit = TRUE; - - if (test_number == 0) { - run_next = TRUE; - g_test_message ("***** RUNNING TEST %2.2d *****", test_number); - } + /* Wait until the idle timeout has been called at least once and there are no + * unused threads. We need a second timeout for this, to periodically wake + * the main context up, as there’s no way to be notified of changes to `idle`. + */ + poll_source = g_timeout_source_new (500); + g_source_set_callback (poll_source, poll_cb, NULL, NULL); + g_source_attach (poll_source, NULL); - if (run_next) { - test_number++; - - switch (test_number) { - case 1: - test_thread_functions (); - break; - case 2: - test_thread_stop_unused (); - break; - case 3: - test_thread_pools (); - break; - case 4: - test_thread_sort (FALSE); - break; - case 5: - test_thread_sort (TRUE); - break; - case 6: - test_thread_stop_unused (); - break; - case 7: - test_thread_stop_unused_multiple (); - break; - case 8: - test_thread_idle_time (); - break; - default: - g_test_message ("***** END OF TESTS *****"); - g_main_loop_quit (main_loop); - continue_timeout = FALSE; - break; + idle = g_thread_pool_get_num_unused_threads (); + while (!idle_timeout_called || idle > 0) + { + g_test_message ("Pool idle thread count: %d, unprocessed jobs: %d", + idle, g_thread_pool_unprocessed (idle_pool)); + g_main_context_iteration (NULL, TRUE); + idle = g_thread_pool_get_num_unused_threads (); } - run_next = FALSE; - return continue_timeout; - } - - if (test_number == 3) { - G_LOCK (thread_counter_pools); - quit &= running_thread_counter <= 0; - g_test_message ("***** POOL RUNNING THREAD COUNT:%ld", - running_thread_counter); - G_UNLOCK (thread_counter_pools); - } - - if (test_number == 4 || test_number == 5) { - G_LOCK (thread_counter_sort); - quit &= sort_thread_counter <= 0; - g_test_message ("***** POOL SORT THREAD COUNT:%ld", - sort_thread_counter); - G_UNLOCK (thread_counter_sort); - } - - if (test_number == 8) { - guint idle; - - idle = g_thread_pool_get_num_unused_threads (); - quit &= idle < 1; - g_test_message ("***** POOL IDLE THREAD COUNT:%d, UNPROCESSED JOBS:%d", - idle, g_thread_pool_unprocessed (idle_pool)); - } - - if (quit) { - run_next = TRUE; - } - - return continue_timeout; -} - -static void -test_threadpool_basics (void) -{ - g_timeout_add (1000, test_check_start_and_stop, NULL); - - main_loop = g_main_loop_new (NULL, FALSE); - g_main_loop_run (main_loop); - g_main_loop_unref (main_loop); - g_thread_pool_free (idle_pool, FALSE, TRUE); + g_source_destroy (poll_source); + g_source_unref (poll_source); + g_source_destroy (timeout_source); + g_source_unref (timeout_source); } int @@ -449,7 +385,13 @@ main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); - g_test_add_func ("/threadpool/basics", test_threadpool_basics); + g_test_add_func ("/threadpool/functions", test_threadpool_functions); + g_test_add_func ("/threadpool/stop-unused", test_threadpool_stop_unused); + g_test_add_func ("/threadpool/pools", test_threadpool_pools); + g_test_add_data_func ("/threadpool/no-sort", GUINT_TO_POINTER (FALSE), test_threadpool_sort); + g_test_add_data_func ("/threadpool/sort", GUINT_TO_POINTER (TRUE), test_threadpool_sort); + g_test_add_func ("/threadpool/stop-unused-multiple", test_threadpool_stop_unused_multiple); + g_test_add_func ("/threadpool/idle-time", test_threadpool_idle_time); return g_test_run (); } diff --git a/glib/tests/unicode.c b/glib/tests/unicode.c index 5d66977..e91425a 100644 --- a/glib/tests/unicode.c +++ b/glib/tests/unicode.c @@ -173,6 +173,11 @@ test_unichar_break_type (void) { G_UNICODE_BREAK_EMOJI_BASE, 0x1F466 }, { G_UNICODE_BREAK_EMOJI_MODIFIER, 0x1F3FB }, { G_UNICODE_BREAK_ZERO_WIDTH_JOINER, 0x200D }, + { G_UNICODE_BREAK_AKSARA, 0x1B45 }, + { G_UNICODE_BREAK_AKSARA_PRE_BASE, 0x1193F }, + { G_UNICODE_BREAK_AKSARA_START, 0x11F50 }, + { G_UNICODE_BREAK_VIRAMA_FINAL, 0x1BF3 }, + { G_UNICODE_BREAK_VIRAMA, 0xA9C0 }, }; for (i = 0; i < G_N_ELEMENTS (examples); i++) diff --git a/glib/tests/unix.c b/glib/tests/unix.c index ab6efaa..e4003f7 100644 --- a/glib/tests/unix.c +++ b/glib/tests/unix.c @@ -1,5 +1,6 @@ /* * Copyright (C) 2011 Red Hat, Inc. + * Copyright 2023 Collabora Ltd. * * SPDX-License-Identifier: LicenseRef-old-glib-tests * @@ -25,6 +26,7 @@ #include "config.h" +#include "glib-private.h" #include "glib-unix.h" #include "gstdio.h" @@ -32,6 +34,8 @@ #include #include +#include "testutils.h" + static void test_pipe (void) { @@ -123,6 +127,116 @@ test_pipe_stdio_overwrite (void) } static void +test_pipe_struct (void) +{ + GError *error = NULL; + GUnixPipe pair = G_UNIX_PIPE_INIT; + char buf[1024]; + gssize bytes_read; + gboolean res; + int read_end = -1; /* owned */ + int write_end = -1; /* unowned */ + int errsv; + + g_test_summary ("Test GUnixPipe structure"); + + res = g_unix_pipe_open (&pair, FD_CLOEXEC, &error); + g_assert_no_error (error); + g_assert_true (res); + + read_end = g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ); + g_assert_cmpint (read_end, >=, 0); + g_assert_cmpint (g_unix_pipe_steal (&pair, G_UNIX_PIPE_END_READ), ==, -1); + g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_READ), ==, -1); + write_end = g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE); + g_assert_cmpint (write_end, >=, 0); + g_assert_cmpint (g_unix_pipe_get (&pair, G_UNIX_PIPE_END_WRITE), ==, write_end); + + g_assert_cmpint (write (write_end, "hello", sizeof ("hello")), ==, sizeof ("hello")); + memset (buf, 0, sizeof (buf)); + bytes_read = read (read_end, buf, sizeof(buf) - 1); + g_assert_cmpint (bytes_read, ==, sizeof ("hello")); + buf[bytes_read] = '\0'; + + /* This is one of the few errno values guaranteed by Standard C. + * We set it here to check that g_unix_pipe_clear doesn't alter errno. */ + errno = EILSEQ; + + g_unix_pipe_clear (&pair); + errsv = errno; + g_assert_cmpint (errsv, ==, EILSEQ); + + g_assert_cmpint (pair.fds[0], ==, -1); + g_assert_cmpint (pair.fds[1], ==, -1); + + /* The read end wasn't closed, because it was stolen first */ + g_clear_fd (&read_end, &error); + g_assert_no_error (error); + + /* The write end was closed, because it wasn't stolen */ + assert_fd_was_closed (write_end); + + g_assert_cmpstr (buf, ==, "hello"); +} + +static void +test_pipe_struct_auto (void) +{ +#ifdef g_autofree + int i; + + g_test_summary ("Test g_auto(GUnixPipe)"); + + /* Let g_auto close the read end, the write end, neither, or both */ + for (i = 0; i < 4; i++) + { + int read_end = -1; /* unowned */ + int write_end = -1; /* unowned */ + int errsv; + + { + g_auto(GUnixPipe) pair = G_UNIX_PIPE_INIT; + GError *error = NULL; + gboolean res; + + res = g_unix_pipe_open (&pair, FD_CLOEXEC, &error); + g_assert_no_error (error); + g_assert_true (res); + + read_end = pair.fds[G_UNIX_PIPE_END_READ]; + g_assert_cmpint (read_end, >=, 0); + write_end = pair.fds[G_UNIX_PIPE_END_WRITE]; + g_assert_cmpint (write_end, >=, 0); + + if (i & 1) + { + /* This also exercises g_unix_pipe_close() with error */ + res = g_unix_pipe_close (&pair, G_UNIX_PIPE_END_READ, &error); + g_assert_no_error (error); + g_assert_true (res); + } + + /* This also exercises g_unix_pipe_close() without error */ + if (i & 2) + g_unix_pipe_close (&pair, G_UNIX_PIPE_END_WRITE, NULL); + + /* This is one of the few errno values guaranteed by Standard C. + * We set it here to check that a g_auto(GUnixPipe) close doesn't + * alter errno. */ + errno = EILSEQ; + } + + errsv = errno; + g_assert_cmpint (errsv, ==, EILSEQ); + assert_fd_was_closed (read_end); + assert_fd_was_closed (write_end); + } +#else + g_test_skip ("g_auto not supported by compiler"); +#endif +} + +static void test_error (void) { GError *error = NULL; @@ -502,6 +616,8 @@ main (int argc, g_test_add_func ("/glib-unix/pipe", test_pipe); g_test_add_func ("/glib-unix/pipe/fd-cloexec", test_pipe_fd_cloexec); g_test_add_func ("/glib-unix/pipe-stdio-overwrite", test_pipe_stdio_overwrite); + g_test_add_func ("/glib-unix/pipe-struct", test_pipe_struct); + g_test_add_func ("/glib-unix/pipe-struct-auto", test_pipe_struct_auto); g_test_add_func ("/glib-unix/error", test_error); g_test_add_func ("/glib-unix/nonblocking", test_nonblocking); g_test_add_func ("/glib-unix/sighup", test_sighup); diff --git a/glib/tests/uri.c b/glib/tests/uri.c index 94a0d5d..5e12ab2 100644 --- a/glib/tests/uri.c +++ b/glib/tests/uri.c @@ -132,6 +132,8 @@ file_from_uri_tests[] = { { "file://%E5%E4%F6/etc", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file:///some/file?query", "/some/file", NULL, 0 }, { "file:///some/file#bad", "/some/file", NULL, 0 }, + { "file:///some/file?query#frag", "/some/file", NULL, 0 }, + { "file:///some/file#fr?ag", "/some/file", NULL, 0 }, { "file://some", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, { "file:test", NULL, NULL, G_CONVERT_ERROR_BAD_URI}, diff --git a/glib/tests/utils.c b/glib/tests/utils.c index 3abef93..e71d9a6 100644 --- a/glib/tests/utils.c +++ b/glib/tests/utils.c @@ -211,8 +211,27 @@ test_prgname_thread_safety (void) static void test_tmpdir (void) { + char **envp = NULL; + g_test_bug ("https://bugzilla.gnome.org/show_bug.cgi?id=627969"); - g_assert_cmpstr (g_get_tmp_dir (), !=, ""); + g_test_summary ("Test that g_get_tmp_dir() returns a correct default if TMPDIR is set to the empty string"); + + if (g_test_subprocess ()) + { + g_assert_cmpstr (g_get_tmp_dir (), !=, ""); + return; + } + + envp = g_get_environ (); + + envp = g_environ_setenv (g_steal_pointer (&envp), "TMPDIR", "", TRUE); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "TMP"); + envp = g_environ_unsetenv (g_steal_pointer (&envp), "TEMP"); + + g_test_trap_subprocess_with_envp (NULL, (const gchar * const *) envp, + 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_strfreev (envp); } #if defined(__GNUC__) && (__GNUC__ >= 4) @@ -1309,11 +1328,6 @@ main (int argc, { argv0 = argv[0]; - /* for tmpdir test, need to do this early before g_get_any_init */ - g_setenv ("TMPDIR", "", TRUE); - g_unsetenv ("TMP"); - g_unsetenv ("TEMP"); - /* g_test_init() only calls g_set_prgname() if g_get_prgname() * returns %NULL, but g_get_prgname() on Windows never returns NULL. * So we need to do this by hand to make test_appname() work on diff --git a/glib/tests/win32.c b/glib/tests/win32.c index 748692d..18772c1 100644 --- a/glib/tests/win32.c +++ b/glib/tests/win32.c @@ -44,7 +44,7 @@ test_subst_pid_and_event (void) char *debugger_big_utf8; gchar *output; guintptr be = (guintptr) 0xFFFFFFFF; - DWORD bp = G_MAXSIZE; + DWORD bp = MAXDWORD; /* %f is not valid */ g_assert_false (_g_win32_subst_pid_and_event_w (debugger_3, G_N_ELEMENTS (debugger_3), diff --git a/glib/valgrind.h b/glib/valgrind.h index a7f1f56..6f1c452 100644 --- a/glib/valgrind.h +++ b/glib/valgrind.h @@ -93,6 +93,7 @@ #include +#include /* Nb: this file might be included in a file compiled with -ansi. So we can't use C++ style "//" comments nor the "asm" keyword (instead @@ -411,14 +412,14 @@ typedef _zzq_default, _zzq_request, \ _zzq_arg1, _zzq_arg2, _zzq_arg3, _zzq_arg4, _zzq_arg5) \ __extension__ \ - ({ volatile unsigned long int _zzq_args[6]; \ + ({ volatile uintptr_t _zzq_args[6]; \ volatile unsigned long int _zzq_result; \ - _zzq_args[0] = (unsigned long int)(_zzq_request); \ - _zzq_args[1] = (unsigned long int)(_zzq_arg1); \ - _zzq_args[2] = (unsigned long int)(_zzq_arg2); \ - _zzq_args[3] = (unsigned long int)(_zzq_arg3); \ - _zzq_args[4] = (unsigned long int)(_zzq_arg4); \ - _zzq_args[5] = (unsigned long int)(_zzq_arg5); \ + _zzq_args[0] = (uintptr_t)(_zzq_request); \ + _zzq_args[1] = (uintptr_t)(_zzq_arg1); \ + _zzq_args[2] = (uintptr_t)(_zzq_arg2); \ + _zzq_args[3] = (uintptr_t)(_zzq_arg3); \ + _zzq_args[4] = (uintptr_t)(_zzq_arg4); \ + _zzq_args[5] = (uintptr_t)(_zzq_arg5); \ __asm__ volatile(__SPECIAL_INSTRUCTION_PREAMBLE \ /* %RDX = client_request ( %RAX ) */ \ "xchgq %%rbx,%%rbx" \ diff --git a/gmodule/gmodule-dl.c b/gmodule/gmodule-dl.c index 81b1b9f..85062d0 100644 --- a/gmodule/gmodule-dl.c +++ b/gmodule/gmodule-dl.c @@ -167,7 +167,7 @@ _g_module_self (void) * NULL is given, dlsym returns an appropriate pointer. */ lock_dlerror (); -#if defined(__BIONIC__) || defined(__NetBSD__) +#if defined(__BIONIC__) || defined(__NetBSD__) || defined(__FreeBSD__) handle = RTLD_DEFAULT; #else handle = dlopen (NULL, RTLD_GLOBAL | RTLD_LAZY); @@ -182,7 +182,7 @@ _g_module_self (void) static void _g_module_close (gpointer handle) { -#if defined(__BIONIC__) || defined(__NetBSD__) +#if defined(__BIONIC__) || defined(__NetBSD__) || defined(__FreeBSD__) if (handle != RTLD_DEFAULT) #endif { diff --git a/gmodule/gmodule.c b/gmodule/gmodule.c index aafaaf0..87f6784 100644 --- a/gmodule/gmodule.c +++ b/gmodule/gmodule.c @@ -52,84 +52,6 @@ #include "gmoduleconf.h" #include "gstdio.h" -/** - * SECTION:modules - * @title: Dynamic Loading of Modules - * @short_description: portable method for dynamically loading 'plug-ins' - * - * These functions provide a portable way to dynamically load object files - * (commonly known as 'plug-ins'). The current implementation supports all - * systems that provide an implementation of dlopen() (e.g. Linux/Sun), as - * well as Windows platforms via DLLs. - * - * A program which wants to use these functions must be linked to the - * libraries output by the command `pkg-config --libs gmodule-2.0`. - * - * To use them you must first determine whether dynamic loading - * is supported on the platform by calling g_module_supported(). - * If it is, you can open a module with g_module_open(), - * find the module's symbols (e.g. function names) with g_module_symbol(), - * and later close the module with g_module_close(). - * g_module_name() will return the file name of a currently opened module. - * - * If any of the above functions fail, the error status can be found with - * g_module_error(). - * - * The #GModule implementation features reference counting for opened modules, - * and supports hook functions within a module which are called when the - * module is loaded and unloaded (see #GModuleCheckInit and #GModuleUnload). - * - * If your module introduces static data to common subsystems in the running - * program, e.g. through calling - * `g_quark_from_static_string ("my-module-stuff")`, - * it must ensure that it is never unloaded, by calling g_module_make_resident(). - * - * Example: Calling a function defined in a GModule - * |[ - * // the function signature for 'say_hello' - * typedef void (* SayHelloFunc) (const char *message); - * - * gboolean - * just_say_hello (const char *filename, GError **error) - * { - * SayHelloFunc say_hello; - * GModule *module; - * - * module = g_module_open (filename, G_MODULE_BIND_LAZY); - * if (!module) - * { - * g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH, - * "%s", g_module_error ()); - * return FALSE; - * } - * - * if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello)) - * { - * g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, - * "%s: %s", filename, g_module_error ()); - * if (!g_module_close (module)) - * g_warning ("%s: %s", filename, g_module_error ()); - * return FALSE; - * } - * - * if (say_hello == NULL) - * { - * g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN, - * "symbol say_hello is NULL"); - * if (!g_module_close (module)) - * g_warning ("%s: %s", filename, g_module_error ()); - * return FALSE; - * } - * - * // call our function in the module - * say_hello ("Hello world!"); - * - * if (!g_module_close (module)) - * g_warning ("%s: %s", filename, g_module_error ()); - * return TRUE; - * } - * ]| - */ /** * GModule: diff --git a/gmodule/meson.build b/gmodule/meson.build index da4d06c..bbe0a08 100644 --- a/gmodule/meson.build +++ b/gmodule/meson.build @@ -65,6 +65,7 @@ gmoduleconf_h = configure_file(input : 'gmoduleconf.h.in', # when it includes GLib as a subproject gmodule_h = files('gmodule.h') gmodule_c = files('gmodule.c') +gmodule_deprecated_c = files('gmodule-deprecated.c') install_headers([gmodule_h], install_dir : glib_includedir) @@ -77,7 +78,7 @@ gmodule_visibility_h = custom_target( install_tag: 'devel', ) -gmodule_sources = [gmodule_c, gmodule_visibility_h, 'gmodule-deprecated.c'] +gmodule_sources = [gmodule_c, gmodule_visibility_h, gmodule_deprecated_c] if host_system == 'windows' gmodule_win_rc = configure_file( diff --git a/gobject/gbinding.c b/gobject/gbinding.c index 204dc44..8c242e3 100644 --- a/gobject/gbinding.c +++ b/gobject/gbinding.c @@ -21,36 +21,33 @@ */ /** - * SECTION:gbinding - * @Title: GBinding - * @Short_Description: Bind two object properties + * GBinding: * - * #GBinding is the representation of a binding between a property on a - * #GObject instance (or source) and another property on another #GObject + * `GObject` instance (or source) and another property on another `GObject` * instance (or target). * * Whenever the source property changes, the same value is applied to the * target property; for instance, the following binding: * - * |[ + * ```c * g_object_bind_property (object1, "property-a", * object2, "property-b", * G_BINDING_DEFAULT); - * ]| + * ``` * * will cause the property named "property-b" of @object2 to be updated - * every time g_object_set() or the specific accessor changes the value of + * every time [method@GObject.set] or the specific accessor changes the value of * the property "property-a" of @object1. * * It is possible to create a bidirectional binding between two properties - * of two #GObject instances, so that if either property changes, the + * of two `GObject` instances, so that if either property changes, the * other is updated as well, for instance: * - * |[ + * ```c * g_object_bind_property (object1, "property-a", * object2, "property-b", * G_BINDING_BIDIRECTIONAL); - * ]| + * ``` * * will keep the two properties in sync. * @@ -59,14 +56,14 @@ * transformation from the source value to the target value before * applying it; for instance, the following binding: * - * |[ + * ```c * g_object_bind_property_full (adjustment1, "value", * adjustment2, "value", * G_BINDING_BIDIRECTIONAL, * celsius_to_fahrenheit, * fahrenheit_to_celsius, * NULL, NULL); - * ]| + * ``` * * will keep the "value" property of the two adjustments in sync; the * @celsius_to_fahrenheit function will be called whenever the "value" @@ -80,29 +77,29 @@ * * Note that #GBinding does not resolve cycles by itself; a cycle like * - * |[ + * ``` * object1:propertyA -> object2:propertyB * object2:propertyB -> object3:propertyC * object3:propertyC -> object1:propertyA - * ]| + * ``` * * might lead to an infinite loop. The loop, in this particular case, - * can be avoided if the objects emit the #GObject::notify signal only + * can be avoided if the objects emit the `GObject::notify` signal only * if the value has effectively been changed. A binding is implemented - * using the #GObject::notify signal, so it is susceptible to all the - * various ways of blocking a signal emission, like g_signal_stop_emission() - * or g_signal_handler_block(). + * using the `GObject::notify` signal, so it is susceptible to all the + * various ways of blocking a signal emission, like [func@GObject.signal_stop_emission] + * or [func@GObject.signal_handler_block]. * * A binding will be severed, and the resources it allocates freed, whenever - * either one of the #GObject instances it refers to are finalized, or when + * either one of the `GObject` instances it refers to are finalized, or when * the #GBinding instance loses its last reference. * * Bindings for languages with garbage collection can use - * g_binding_unbind() to explicitly release a binding between the source + * [method@GObject.Binding.unbind] to explicitly release a binding between the source * and target properties, instead of relying on the last reference on the * binding, source, and target instances to drop. * - * #GBinding is available since GObject 2.26 + * Since: 2.26 */ #include "config.h" @@ -123,9 +120,9 @@ GType g_binding_flags_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { static const GFlagsValue values[] = { { G_BINDING_DEFAULT, "G_BINDING_DEFAULT", "default" }, @@ -136,7 +133,7 @@ g_binding_flags_get_type (void) }; GType g_define_type_id = g_flags_register_static (g_intern_static_string ("GBindingFlags"), values); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; @@ -889,9 +886,7 @@ g_binding_class_init (GBindingClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_SOURCE, - g_param_spec_object ("source", - P_("Source"), - P_("The source of the binding"), + g_param_spec_object ("source", NULL, NULL, G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | @@ -904,9 +899,7 @@ g_binding_class_init (GBindingClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_TARGET, - g_param_spec_object ("target", - P_("Target"), - P_("The target of the binding"), + g_param_spec_object ("target", NULL, NULL, G_TYPE_OBJECT, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | @@ -923,9 +916,7 @@ g_binding_class_init (GBindingClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_SOURCE_PROPERTY, - g_param_spec_string ("source-property", - P_("Source Property"), - P_("The property on the source to bind"), + g_param_spec_string ("source-property", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | @@ -942,9 +933,7 @@ g_binding_class_init (GBindingClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_TARGET_PROPERTY, - g_param_spec_string ("target-property", - P_("Target Property"), - P_("The property on the target to bind"), + g_param_spec_string ("target-property", NULL, NULL, NULL, G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | @@ -957,9 +946,7 @@ g_binding_class_init (GBindingClass *klass) * Since: 2.26 */ g_object_class_install_property (gobject_class, PROP_FLAGS, - g_param_spec_flags ("flags", - P_("Flags"), - P_("The binding flags"), + g_param_spec_flags ("flags", NULL, NULL, G_TYPE_BINDING_FLAGS, G_BINDING_DEFAULT, G_PARAM_CONSTRUCT_ONLY | diff --git a/gobject/gbinding.h b/gobject/gbinding.h index 8504de2..4c7da7e 100644 --- a/gobject/gbinding.h +++ b/gobject/gbinding.h @@ -38,14 +38,6 @@ G_BEGIN_DECLS #define G_BINDING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), G_TYPE_BINDING, GBinding)) #define G_IS_BINDING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_BINDING)) -/** - * GBinding: - * - * GBinding is an opaque structure whose members - * cannot be accessed directly. - * - * Since: 2.26 - */ typedef struct _GBinding GBinding; /** diff --git a/gobject/gbindinggroup.c b/gobject/gbindinggroup.c index e5c8980..55e691b 100644 --- a/gobject/gbindinggroup.c +++ b/gobject/gbindinggroup.c @@ -27,18 +27,15 @@ #include "gparamspecs.h" /** - * SECTION:gbindinggroup - * @Title: GBindingGroup - * @Short_description: Binding multiple properties as a group - * @include: glib-object.h + * GBindingGroup: * - * The #GBindingGroup can be used to bind multiple properties + * `GBindingGroup` can be used to bind multiple properties * from an object collectively. * * Use the various methods to bind properties from a single source * object to multiple destination objects. Properties can be bound * bidirectionally and are connected when the source object is set - * with g_binding_group_set_source(). + * with [method@GObject.BindingGroup.set_source]. * * Since: 2.72 */ @@ -341,16 +338,14 @@ g_binding_group_class_init (GBindingGroupClass *klass) object_class->set_property = g_binding_group_set_property; /** - * GBindingGroup:source: (nullable) + * GBindingGroup:source: * * The source object used for binding properties. * * Since: 2.72 */ properties[PROP_SOURCE] = - g_param_spec_object ("source", - "Source", - "The source GObject used for binding properties.", + g_param_spec_object ("source", NULL, NULL, G_TYPE_OBJECT, (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); diff --git a/gobject/gbindinggroup.h b/gobject/gbindinggroup.h index 4cbdfe4..3985791 100644 --- a/gobject/gbindinggroup.h +++ b/gobject/gbindinggroup.h @@ -36,14 +36,6 @@ G_BEGIN_DECLS #define G_IS_BINDING_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_BINDING_GROUP)) #define G_TYPE_BINDING_GROUP (g_binding_group_get_type()) -/** - * GBindingGroup: - * - * GBindingGroup is an opaque structure whose members - * cannot be accessed directly. - * - * Since: 2.72 - */ typedef struct _GBindingGroup GBindingGroup; GOBJECT_AVAILABLE_IN_2_72 diff --git a/gobject/gboxed.c b/gobject/gboxed.c index 242ba09..5a9cff8 100644 --- a/gobject/gboxed.c +++ b/gobject/gboxed.c @@ -33,35 +33,6 @@ #include "gvaluearray.h" #include "gvaluecollector.h" - -/** - * SECTION:gboxed - * @short_description: A mechanism to wrap opaque C structures registered - * by the type system - * @see_also: #GParamSpecBoxed, g_param_spec_boxed() - * @title: Boxed Types - * - * #GBoxed is a generic wrapper mechanism for arbitrary C structures. - * - * The only thing the type system needs to know about the structures is how to - * copy them (a #GBoxedCopyFunc) and how to free them (a #GBoxedFreeFunc); - * beyond that, they are treated as opaque chunks of memory. - * - * Boxed types are useful for simple value-holder structures like rectangles or - * points. They can also be used for wrapping structures defined in non-#GObject - * based libraries. They allow arbitrary structures to be handled in a uniform - * way, allowing uniform copying (or referencing) and freeing (or unreferencing) - * of them, and uniform representation of the type of the contained structure. - * In turn, this allows any type which can be boxed to be set as the data in a - * #GValue, which allows for polymorphic handling of a much wider range of data - * types, and hence usage of such types as #GObject property values. - * - * #GBoxed is designed so that reference counted types can be boxed. Use the - * type’s ‘ref’ function as the #GBoxedCopyFunc, and its ‘unref’ function as the - * #GBoxedFreeFunc. For example, for #GBytes, the #GBoxedCopyFunc is - * g_bytes_ref(), and the #GBoxedFreeFunc is g_bytes_unref(). - */ - static inline void /* keep this function in sync with gvalue.c */ value_meminit (GValue *value, GType value_type) @@ -167,6 +138,8 @@ G_DEFINE_BOXED_TYPE (GTimeZone, g_time_zone, g_time_zone_ref, g_time_zone_unref) G_DEFINE_BOXED_TYPE (GKeyFile, g_key_file, g_key_file_ref, g_key_file_unref) G_DEFINE_BOXED_TYPE (GMappedFile, g_mapped_file, g_mapped_file_ref, g_mapped_file_unref) G_DEFINE_BOXED_TYPE (GBookmarkFile, g_bookmark_file, g_bookmark_file_copy, g_bookmark_file_free) +G_DEFINE_BOXED_TYPE (GHmac, g_hmac, g_hmac_ref, g_hmac_unref) +G_DEFINE_BOXED_TYPE (GDir, g_dir, g_dir_ref, g_dir_unref) G_DEFINE_BOXED_TYPE (GMainLoop, g_main_loop, g_main_loop_ref, g_main_loop_unref) G_DEFINE_BOXED_TYPE (GMainContext, g_main_context, g_main_context_ref, g_main_context_unref) @@ -181,20 +154,22 @@ G_DEFINE_BOXED_TYPE (GUri, g_uri, g_uri_ref, g_uri_unref) G_DEFINE_BOXED_TYPE (GOptionGroup, g_option_group, g_option_group_ref, g_option_group_unref) G_DEFINE_BOXED_TYPE (GPatternSpec, g_pattern_spec, g_pattern_spec_copy, g_pattern_spec_free); +G_DEFINE_BOXED_TYPE (GStrvBuilder, g_strv_builder, g_strv_builder_ref, g_strv_builder_unref); + /* This one can't use G_DEFINE_BOXED_TYPE (GStrv, g_strv, g_strdupv, g_strfreev) */ GType g_strv_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { GType g_define_type_id = g_boxed_type_register_static (g_intern_static_string ("GStrv"), (GBoxedCopyFunc) g_strdupv, (GBoxedFreeFunc) g_strfreev); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; @@ -280,8 +255,8 @@ boxed_proxy_lcopy_value (const GValue *value, /** * g_boxed_type_register_static: * @name: Name of the new boxed type. - * @boxed_copy: Boxed structure copy function. - * @boxed_free: Boxed structure free function. + * @boxed_copy: (scope forever): Boxed structure copy function. + * @boxed_free: (scope forever): Boxed structure free function. * * This function creates a new %G_TYPE_BOXED derived type id for a new * boxed type with name @name. diff --git a/gobject/gclosure.c b/gobject/gclosure.c index 8d5d88d..af219c2 100644 --- a/gobject/gclosure.c +++ b/gobject/gclosure.c @@ -39,11 +39,13 @@ /** - * SECTION:gclosure - * @short_description: Functions as first-class objects - * @title: Closures + * GClosure: + * @in_marshal: Indicates whether the closure is currently being invoked with + * g_closure_invoke() + * @is_invalid: Indicates whether the closure has been invalidated by + * g_closure_invalidate() * - * A #GClosure represents a callback supplied by the programmer. + * A `GClosure` represents a callback supplied by the programmer. * * It will generally comprise a function of some kind and a marshaller * used to call it. It is the responsibility of the marshaller to @@ -76,7 +78,7 @@ * * Using closures has a number of important advantages over a simple * callback function/data pointer combination: - * + * * - Closures allow the callee to get the types of the callback parameters, * which means that language bindings don't have to write individual glue * for each callback type. @@ -1173,7 +1175,7 @@ g_signal_type_cclosure_new (GType itype, g_return_val_if_fail (G_TYPE_IS_CLASSED (itype) || G_TYPE_IS_INTERFACE (itype), NULL); g_return_val_if_fail (struct_offset >= sizeof (GTypeClass), NULL); - closure = g_closure_new_simple (sizeof (GClosure), (gpointer) itype); + closure = g_closure_new_simple (sizeof (GClosure), GTYPE_TO_POINTER (itype)); if (G_TYPE_IS_INTERFACE (itype)) { g_closure_set_meta_marshal (closure, GUINT_TO_POINTER (struct_offset), g_type_iface_meta_marshal); @@ -1673,320 +1675,3 @@ g_cclosure_marshal_generic_va (GClosure *closure, if (return_value && G_VALUE_TYPE (return_value)) value_from_ffi_type (return_value, rvalue); } - -/** - * g_cclosure_marshal_VOID__VOID: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 1 - * @param_values: a #GValue array holding only the instance - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__BOOLEAN: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gboolean parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gboolean arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__CHAR: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gchar parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gchar arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__UCHAR: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #guchar parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, guchar arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__INT: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gint parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gint arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__UINT: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #guint parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, guint arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__LONG: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #glong parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, glong arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__ULONG: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gulong parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gulong arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__ENUM: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the enumeration parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gint arg1, gpointer user_data)` where the #gint parameter denotes an enumeration type.. - */ - -/** - * g_cclosure_marshal_VOID__FLAGS: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the flags parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gint arg1, gpointer user_data)` where the #gint parameter denotes a flags type. - */ - -/** - * g_cclosure_marshal_VOID__FLOAT: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gfloat parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gfloat arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__DOUBLE: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gdouble parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gdouble arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__STRING: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gchar* parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, const gchar *arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__PARAM: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #GParamSpec* parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, GParamSpec *arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__BOXED: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #GBoxed* parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, GBoxed *arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__POINTER: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #gpointer parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, gpointer arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__OBJECT: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #GObject* parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, GObject *arg1, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_VOID__VARIANT: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 2 - * @param_values: a #GValue array holding the instance and the #GVariant* parameter - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, GVariant *arg1, gpointer user_data)`. - * - * Since: 2.26 - */ - -/** - * g_cclosure_marshal_VOID__UINT_POINTER: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: ignored - * @n_param_values: 3 - * @param_values: a #GValue array holding instance, arg1 and arg2 - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `void (*callback) (gpointer instance, guint arg1, gpointer arg2, gpointer user_data)`. - */ - -/** - * g_cclosure_marshal_BOOLEAN__FLAGS: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: a #GValue which can store the returned #gboolean - * @n_param_values: 2 - * @param_values: a #GValue array holding instance and arg1 - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `gboolean (*callback) (gpointer instance, gint arg1, gpointer user_data)` where the #gint parameter - * denotes a flags type. - */ - -/** - * g_cclosure_marshal_BOOL__FLAGS: - * - * Another name for g_cclosure_marshal_BOOLEAN__FLAGS(). - */ -/** - * g_cclosure_marshal_STRING__OBJECT_POINTER: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: a #GValue, which can store the returned string - * @n_param_values: 3 - * @param_values: a #GValue array holding instance, arg1 and arg2 - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `gchar* (*callback) (gpointer instance, GObject *arg1, gpointer arg2, gpointer user_data)`. - */ -/** - * g_cclosure_marshal_BOOLEAN__OBJECT_BOXED_BOXED: - * @closure: the #GClosure to which the marshaller belongs - * @return_value: a #GValue, which can store the returned string - * @n_param_values: 3 - * @param_values: a #GValue array holding instance, arg1 and arg2 - * @invocation_hint: the invocation hint given as the last argument - * to g_closure_invoke() - * @marshal_data: additional data specified when registering the marshaller - * - * A marshaller for a #GCClosure with a callback of type - * `gboolean (*callback) (gpointer instance, GBoxed *arg1, GBoxed *arg2, gpointer user_data)`. - * - * Since: 2.26 - */ diff --git a/gobject/gclosure.h b/gobject/gclosure.h index 3b139b0..2462bce 100644 --- a/gobject/gclosure.h +++ b/gobject/gclosure.h @@ -169,15 +169,7 @@ struct _GClosureNotifyData gpointer data; GClosureNotify notify; }; -/** - * GClosure: - * @in_marshal: Indicates whether the closure is currently being invoked with - * g_closure_invoke() - * @is_invalid: Indicates whether the closure has been invalidated by - * g_closure_invalidate() - * - * A #GClosure represents a callback supplied by the programmer. - */ + struct _GClosure { /*< private >*/ diff --git a/gobject/genums.c b/gobject/genums.c index 1fe7f72..96b367d 100644 --- a/gobject/genums.c +++ b/gobject/genums.c @@ -31,43 +31,6 @@ #include "gvaluecollector.h" -/** - * SECTION:enumerations_flags - * @short_description: Enumeration and flags types - * @title: Enumeration and Flag Types - * @see_also:#GParamSpecEnum, #GParamSpecFlags, g_param_spec_enum(), - * g_param_spec_flags() - * - * The GLib type system provides fundamental types for enumeration and - * flags types. (Flags types are like enumerations, but allow their - * values to be combined by bitwise or). A registered enumeration or - * flags type associates a name and a nickname with each allowed - * value, and the methods g_enum_get_value_by_name(), - * g_enum_get_value_by_nick(), g_flags_get_value_by_name() and - * g_flags_get_value_by_nick() can look up values by their name or - * nickname. When an enumeration or flags type is registered with the - * GLib type system, it can be used as value type for object - * properties, using g_param_spec_enum() or g_param_spec_flags(). - * - * GObject ships with a utility called [glib-mkenums][glib-mkenums], - * that can construct suitable type registration functions from C enumeration - * definitions. - * - * Example of how to get a string representation of an enum value: - * |[ - * GEnumClass *enum_class; - * GEnumValue *enum_value; - * - * enum_class = g_type_class_ref (MAMAN_TYPE_MY_ENUM); - * enum_value = g_enum_get_value (enum_class, MAMAN_MY_ENUM_FOO); - * - * g_print ("Name: %s\n", enum_value->value_name); - * - * g_type_class_unref (enum_class); - * ]| - */ - - /* --- prototypes --- */ static void g_enum_class_init (GEnumClass *class, gpointer class_data); diff --git a/gobject/glib-enumtypes.c.template b/gobject/glib-enumtypes.c.template index 42f9c34..ab59828 100644 --- a/gobject/glib-enumtypes.c.template +++ b/gobject/glib-enumtypes.c.template @@ -22,9 +22,9 @@ G_GNUC_END_IGNORE_DEPRECATIONS GType @enum_name@_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { static const G@Type@Value values[] = { /*** END value-header ***/ @@ -38,7 +38,7 @@ GType }; GType g_define_type_id = g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; diff --git a/gobject/glib-mkenums.in b/gobject/glib-mkenums.in index 353e53a..e10b910 100755 --- a/gobject/glib-mkenums.in +++ b/gobject/glib-mkenums.in @@ -223,6 +223,8 @@ def parse_entries(file, file_name): (\w+)\s* # name (\s+[A-Z]+_(?:AVAILABLE|DEPRECATED)_ENUMERATOR_IN_[0-9_]+(?:_FOR\s*\(\s*\w+\s*\))?\s*)? # availability (?:=( # value + \s*'[^']*'\s* # char + | # OR \s*\w+\s*\(.*\)\s* # macro with multiple args | # OR (?:[^,/]|/(?!\*))* # anything but a comma or comment @@ -728,6 +730,10 @@ def process_file(curfilename): # approximation to C constant folding inum = eval(num, {}, c_namespace) + # Support character literals + if isinstance(inum, str) and len(inum) == 1: + inum = ord(inum) + # make sure it parsed to an integer if not isinstance(inum, int): sys.exit("Unable to parse enum value '%s'" % num) diff --git a/gobject/glib-types.h b/gobject/glib-types.h index 87065b9..76f746c 100644 --- a/gobject/glib-types.h +++ b/gobject/glib-types.h @@ -336,6 +336,33 @@ typedef gsize GType; */ #define G_TYPE_BOOKMARK_FILE (g_bookmark_file_get_type ()) +/** + * G_TYPE_HMAC: + * + * The #GType for a boxed type holding a #GHmac. + * + * Since: 2.80 + */ +#define G_TYPE_HMAC (g_hmac_get_type ()) + +/** + * G_TYPE_DIR: + * + * The #GType for a boxed type holding a #GDir. + * + * Since: 2.80 + */ +#define G_TYPE_DIR (g_dir_get_type ()) + +/** + * G_TYPE_STRV_BUILDER: + * + * The #GType for a boxed type holding a #GStrvBuilder. + * + * Since: 2.80 + */ +#define G_TYPE_STRV_BUILDER (g_strv_builder_get_type ()) + GOBJECT_AVAILABLE_IN_ALL GType g_date_get_type (void) G_GNUC_CONST; GOBJECT_AVAILABLE_IN_ALL @@ -400,6 +427,12 @@ GOBJECT_AVAILABLE_IN_2_70 GType g_pattern_spec_get_type (void) G_GNUC_CONST; GOBJECT_AVAILABLE_IN_2_76 GType g_bookmark_file_get_type (void) G_GNUC_CONST; +GOBJECT_AVAILABLE_IN_2_80 +GType g_hmac_get_type (void) G_GNUC_CONST; +GOBJECT_AVAILABLE_IN_2_80 +GType g_dir_get_type (void) G_GNUC_CONST; +GOBJECT_AVAILABLE_IN_2_80 +GType g_strv_builder_get_type (void) G_GNUC_CONST; GOBJECT_DEPRECATED_FOR('G_TYPE_VARIANT') GType g_variant_get_gtype (void) G_GNUC_CONST; diff --git a/gobject/gobject-autocleanups.h b/gobject/gobject-autocleanups.h index bddb3f2..23d4f6d 100644 --- a/gobject/gobject-autocleanups.h +++ b/gobject/gobject-autocleanups.h @@ -23,6 +23,8 @@ #error "Only can be included directly." #endif +#ifndef __GI_SCANNER__ + G_DEFINE_AUTOPTR_CLEANUP_FUNC(GClosure, g_closure_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GEnumClass, g_type_class_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GFlagsClass, g_type_class_unref) @@ -31,3 +33,5 @@ G_DEFINE_AUTOPTR_CLEANUP_FUNC(GInitiallyUnowned, g_object_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GParamSpec, g_param_spec_unref) G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTypeClass, g_type_class_unref) G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GValue, g_value_unset) + +#endif /* __GI_SCANNER__ */ diff --git a/gobject/gobject.c b/gobject/gobject.c index 518285d..1154517 100644 --- a/gobject/gobject.c +++ b/gobject/gobject.c @@ -38,102 +38,30 @@ #include "gconstructor.h" /** - * SECTION:objects - * @title: GObject - * @short_description: The base object type - * @see_also: #GParamSpecObject, g_param_spec_object() + * GObject: * - * GObject is the fundamental type providing the common attributes and + * The base object type. + * + * `GObject` is the fundamental type providing the common attributes and * methods for all object types in GTK, Pango and other libraries - * based on GObject. The GObject class provides methods for object + * based on GObject. The `GObject` class provides methods for object * construction and destruction, property access methods, and signal - * support. Signals are described in detail [here][gobject-Signals]. - * - * For a tutorial on implementing a new GObject class, see [How to define and - * implement a new GObject][howto-gobject]. For a list of naming conventions for - * GObjects and their methods, see the [GType conventions][gtype-conventions]. - * For the high-level concepts behind GObject, read [Instantiatable classed types: - * Objects][gtype-instantiatable-classed]. - * - * ## Floating references # {#floating-ref} - * - * **Note**: Floating references are a C convenience API and should not be - * used in modern GObject code. Language bindings in particular find the - * concept highly problematic, as floating references are not identifiable - * through annotations, and neither are deviations from the floating reference - * behavior, like types that inherit from #GInitiallyUnowned and still return - * a full reference from g_object_new(). - * - * GInitiallyUnowned is derived from GObject. The only difference between - * the two is that the initial reference of a GInitiallyUnowned is flagged - * as a "floating" reference. This means that it is not specifically - * claimed to be "owned" by any code portion. The main motivation for - * providing floating references is C convenience. In particular, it - * allows code to be written as: - * - * |[ - * container = create_container (); - * container_add_child (container, create_child()); - * ]| - * - * If container_add_child() calls g_object_ref_sink() on the passed-in child, - * no reference of the newly created child is leaked. Without floating - * references, container_add_child() can only g_object_ref() the new child, - * so to implement this code without reference leaks, it would have to be - * written as: + * support. Signals are described in detail [here][gobject-Signals]. * - * |[ - * Child *child; - * container = create_container (); - * child = create_child (); - * container_add_child (container, child); - * g_object_unref (child); - * ]| - * - * The floating reference can be converted into an ordinary reference by - * calling g_object_ref_sink(). For already sunken objects (objects that - * don't have a floating reference anymore), g_object_ref_sink() is equivalent - * to g_object_ref() and returns a new reference. - * - * Since floating references are useful almost exclusively for C convenience, - * language bindings that provide automated reference and memory ownership - * maintenance (such as smart pointers or garbage collection) should not - * expose floating references in their API. The best practice for handling - * types that have initially floating references is to immediately sink those - * references after g_object_new() returns, by checking if the #GType - * inherits from #GInitiallyUnowned. For instance: - * - * |[ - * GObject *res = g_object_new_with_properties (gtype, - * n_props, - * prop_names, - * prop_values); - * - * // or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED)) - * if (G_IS_INITIALLY_UNOWNED (res)) - * g_object_ref_sink (res); - * - * return res; - * ]| + * For a tutorial on implementing a new `GObject` class, see [How to define and + * implement a new GObject](tutorial.html#how-to-define-and-implement-a-new-gobject). + * For a list of naming conventions for GObjects and their methods, see the + * [GType conventions](concepts.html#conventions). For the high-level concepts + * behind GObject, read + * [Instantiatable classed types: Objects](concepts.html#instantiatable-classed-types-objects). * - * Some object implementations may need to save an objects floating state - * across certain code portions (an example is #GtkMenu), to achieve this, - * the following sequence can be used: - * - * |[ - * // save floating state - * gboolean was_floating = g_object_is_floating (object); - * g_object_ref_sink (object); - * // protected code portion - * - * ... - * - * // restore floating state - * if (was_floating) - * g_object_force_floating (object); - * else - * g_object_unref (object); // release previously acquired reference - * ]| + * Since GLib 2.72, all `GObject`s are guaranteed to be aligned to at least the + * alignment of the largest basic GLib type (typically this is `guint64` or + * `gdouble`). If you need larger alignment for an element in a `GObject`, you + * should allocate it on the heap (aligned), or arrange for your `GObject` to be + * appropriately padded. This guarantee applies to the `GObject` (or derived) + * struct, the `GObjectClass` (or derived) struct, and any private data allocated + * by `G_ADD_PRIVATE()`. */ /* --- macros --- */ @@ -260,6 +188,7 @@ G_LOCK_DEFINE_STATIC (weak_refs_mutex); G_LOCK_DEFINE_STATIC (toggle_refs_mutex); static GQuark quark_closure_array = 0; static GQuark quark_weak_refs = 0; +static GQuark quark_weak_notifies = 0; static GQuark quark_toggle_refs = 0; static GQuark quark_notify_queue; #ifndef HAVE_OPTIONAL_FLAGS @@ -281,12 +210,28 @@ g_object_notify_queue_free (gpointer data) GObjectNotifyQueue *nqueue = data; g_slist_free (nqueue->pspecs); - g_slice_free (GObjectNotifyQueue, nqueue); + g_free_sized (nqueue, sizeof (GObjectNotifyQueue)); +} + +static GObjectNotifyQueue * +g_object_notify_queue_create_queue_frozen (GObject *object) +{ + GObjectNotifyQueue *nqueue; + + nqueue = g_new0 (GObjectNotifyQueue, 1); + + *nqueue = (GObjectNotifyQueue){ + .freeze_count = 1, + }; + + g_datalist_id_set_data_full (&object->qdata, quark_notify_queue, + nqueue, g_object_notify_queue_free); + + return nqueue; } -static GObjectNotifyQueue* -g_object_notify_queue_freeze (GObject *object, - gboolean conditional) +static GObjectNotifyQueue * +g_object_notify_queue_freeze (GObject *object) { GObjectNotifyQueue *nqueue; @@ -294,15 +239,8 @@ g_object_notify_queue_freeze (GObject *object, nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); if (!nqueue) { - if (conditional) - { - G_UNLOCK(notify_lock); - return NULL; - } - - nqueue = g_slice_new0 (GObjectNotifyQueue); - g_datalist_id_set_data_full (&object->qdata, quark_notify_queue, - nqueue, g_object_notify_queue_free); + nqueue = g_object_notify_queue_create_queue_frozen (object); + goto out; } if (nqueue->freeze_count >= 65535) @@ -313,6 +251,7 @@ g_object_notify_queue_freeze (GObject *object, else nqueue->freeze_count++; +out: G_UNLOCK(notify_lock); return nqueue; @@ -320,7 +259,8 @@ g_object_notify_queue_freeze (GObject *object, static void g_object_notify_queue_thaw (GObject *object, - GObjectNotifyQueue *nqueue) + GObjectNotifyQueue *nqueue, + gboolean take_ref) { GParamSpec *pspecs_mem[16], **pspecs, **free_me = NULL; GSList *slist; @@ -328,8 +268,14 @@ g_object_notify_queue_thaw (GObject *object, G_LOCK(notify_lock); + if (!nqueue) + { + /* Caller didn't look up the queue yet. Do it now. */ + nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); + } + /* Just make sure we never get into some nasty race condition */ - if (G_UNLIKELY (nqueue->freeze_count == 0)) + if (G_UNLIKELY (!nqueue || nqueue->freeze_count == 0)) { G_UNLOCK (notify_lock); g_critical ("%s: property-changed notification for %s(%p) is not frozen", @@ -355,17 +301,53 @@ g_object_notify_queue_thaw (GObject *object, G_UNLOCK(notify_lock); if (n_pspecs) - G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); + { + if (take_ref) + g_object_ref (object); + + G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs); + + if (take_ref) + g_object_unref (object); + } g_free (free_me); } -static void +static gboolean g_object_notify_queue_add (GObject *object, GObjectNotifyQueue *nqueue, - GParamSpec *pspec) + GParamSpec *pspec, + gboolean in_init) { G_LOCK(notify_lock); + if (!nqueue) + { + /* We are called without an nqueue. Figure out whether a notification + * should be queued. */ + nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); + + if (!nqueue) + { + if (!in_init) + { + /* We don't have a notify queue and are not in_init. The event + * is not to be queued. The caller will dispatch directly. */ + G_UNLOCK (notify_lock); + return FALSE; + } + + /* We are "in_init", but did not freeze the queue in g_object_init + * yet. Instead, we gained a notify handler in instance init, so now + * we need to freeze just-in-time. + * + * Note that this freeze will be balanced at the end of object + * initialization. + */ + nqueue = g_object_notify_queue_create_queue_frozen (object); + } + } + g_assert (nqueue->n_pspecs < 65535); if (g_slist_find (nqueue->pspecs, pspec) == NULL) @@ -375,6 +357,8 @@ g_object_notify_queue_add (GObject *object, } G_UNLOCK(notify_lock); + + return TRUE; } #ifdef G_ENABLE_DEBUG @@ -474,6 +458,26 @@ _g_object_type_init (void) #endif /* G_ENABLE_DEBUG */ } +/* Initialize the global GParamSpecPool; this function needs to be + * called whenever we access the GParamSpecPool and we cannot guarantee + * that g_object_do_class_init() has been called: for instance, by the + * interface property API. + * + * To avoid yet another global lock, we use atomic pointer checks: the + * first caller of this function will win the race. Any other access to + * the GParamSpecPool is done under its own mutex. + */ +static inline void +g_object_init_pspec_pool (void) +{ + if (G_UNLIKELY (g_atomic_pointer_get (&pspec_pool) == NULL)) + { + GParamSpecPool *pool = g_param_spec_pool_new (TRUE); + if (!g_atomic_pointer_compare_and_exchange (&pspec_pool, NULL, pool)) + g_param_spec_pool_free (pool); + } +} + static void g_object_base_class_init (GObjectClass *class) { @@ -523,13 +527,15 @@ g_object_do_class_init (GObjectClass *class) quark_closure_array = g_quark_from_static_string ("GObject-closure-array"); quark_weak_refs = g_quark_from_static_string ("GObject-weak-references"); + quark_weak_notifies = g_quark_from_static_string ("GObject-weak-notifies"); quark_weak_locations = g_quark_from_static_string ("GObject-weak-locations"); quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references"); quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue"); #ifndef HAVE_OPTIONAL_FLAGS quark_in_construction = g_quark_from_static_string ("GObject-in-construction"); #endif - pspec_pool = g_param_spec_pool_new (TRUE); + + g_object_init_pspec_pool (); class->constructor = g_object_constructor; class->constructed = g_object_constructed; @@ -595,11 +601,13 @@ install_property_internal (GType g_type, { g_param_spec_ref_sink (pspec); + g_object_init_pspec_pool (); + if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE)) { g_critical ("When installing property: type '%s' already has a property named '%s'", - g_type_name (g_type), - pspec->name); + g_type_name (g_type), + pspec->name); g_param_spec_unref (pspec); return FALSE; } @@ -819,13 +827,13 @@ find_pspec (GObjectClass *class, * GObjectClass *gobject_class = G_OBJECT_CLASS (klass); * * obj_properties[PROP_FOO] = - * g_param_spec_int ("foo", "Foo", "Foo", + * g_param_spec_int ("foo", NULL, NULL, * -1, G_MAXINT, * 0, * G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); * * obj_properties[PROP_BAR] = - * g_param_spec_string ("bar", "Bar", "Bar", + * g_param_spec_string ("bar", NULL, NULL, * NULL, * G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); * @@ -1020,7 +1028,9 @@ g_object_interface_find_property (gpointer g_iface, g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); g_return_val_if_fail (property_name != NULL, NULL); - + + g_object_init_pspec_pool (); + return g_param_spec_pool_lookup (pspec_pool, property_name, iface_class->g_type, @@ -1146,10 +1156,10 @@ g_object_class_list_properties (GObjectClass *class, * Since: 2.4 * * Returns: (array length=n_properties_p) (transfer container): a - * pointer to an array of pointers to #GParamSpec - * structures. The paramspecs are owned by GLib, but the - * array should be freed with g_free() when you are done with - * it. + * pointer to an array of pointers to #GParamSpec + * structures. The paramspecs are owned by GLib, but the + * array should be freed with g_free() when you are done with + * it. */ GParamSpec** g_object_interface_list_properties (gpointer g_iface, @@ -1161,6 +1171,8 @@ g_object_interface_list_properties (gpointer g_iface, g_return_val_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type), NULL); + g_object_init_pspec_pool (); + pspecs = g_param_spec_pool_list (pspec_pool, iface_class->g_type, &n); @@ -1312,7 +1324,7 @@ g_object_init (GObject *object, if (CLASS_HAS_PROPS (class) && CLASS_NEEDS_NOTIFY (class)) { /* freeze object's notification queue, g_object_new_internal() preserves pairedness */ - g_object_notify_queue_freeze (object, FALSE); + g_object_notify_queue_freeze (object); } /* mark object in-construction for notify_queue_thaw() and to allow construct-only properties */ @@ -1359,9 +1371,16 @@ static void g_object_real_dispose (GObject *object) { g_signal_handlers_destroy (object); - g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); + + /* GWeakRef and weak_pointer do not call into user code. Clear those first + * so that user code can rely on the state of their weak pointers. + */ g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); g_datalist_id_set_data (&object->qdata, quark_weak_locations, NULL); + + /* GWeakNotify and GClosure can call into user code */ + g_datalist_id_set_data (&object->qdata, quark_weak_notifies, NULL); + g_datalist_id_set_data (&object->qdata, quark_closure_array, NULL); } #ifdef G_ENABLE_DEBUG @@ -1469,7 +1488,7 @@ g_object_freeze_notify (GObject *object) g_return_if_fail (G_IS_OBJECT (object)); #ifndef G_DISABLE_CHECKS - if (G_UNLIKELY (g_atomic_int_get (&object->ref_count) == 0)) + if (G_UNLIKELY (g_atomic_int_get (&object->ref_count) <= 0)) { g_critical ("Attempting to freeze the notification queue for object %s[%p]; " "Property notification does not work during instance finalization.", @@ -1479,9 +1498,7 @@ g_object_freeze_notify (GObject *object) } #endif - g_object_ref (object); - g_object_notify_queue_freeze (object, FALSE); - g_object_unref (object); + g_object_notify_queue_freeze (object); } static inline void @@ -1512,29 +1529,7 @@ g_object_notify_by_spec_internal (GObject *object, if (pspec != NULL && needs_notify) { - GObjectNotifyQueue *nqueue; - gboolean need_thaw = TRUE; - - /* conditional freeze: only increase freeze count if already frozen */ - nqueue = g_object_notify_queue_freeze (object, TRUE); - if (in_init && !nqueue) - { - /* We did not freeze the queue in g_object_init, but - * we gained a notify handler in instance init, so - * now we need to freeze just-in-time - */ - nqueue = g_object_notify_queue_freeze (object, FALSE); - need_thaw = FALSE; - } - - if (nqueue != NULL) - { - /* we're frozen, so add to the queue and release our freeze */ - g_object_notify_queue_add (object, nqueue, pspec); - if (need_thaw) - g_object_notify_queue_thaw (object, nqueue); - } - else + if (!g_object_notify_queue_add (object, NULL, pspec, in_init)) { /* * Coverity doesn’t understand the paired ref/unref here and seems to @@ -1628,7 +1623,7 @@ g_object_notify (GObject *object, * static void * my_object_class_init (MyObjectClass *klass) * { - * properties[PROP_FOO] = g_param_spec_int ("foo", "Foo", "The foo", + * properties[PROP_FOO] = g_param_spec_int ("foo", NULL, NULL, * 0, 100, * 50, * G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS); @@ -1674,12 +1669,10 @@ g_object_notify_by_pspec (GObject *object, void g_object_thaw_notify (GObject *object) { - GObjectNotifyQueue *nqueue; - g_return_if_fail (G_IS_OBJECT (object)); #ifndef G_DISABLE_CHECKS - if (G_UNLIKELY (g_atomic_int_get (&object->ref_count) == 0)) + if (G_UNLIKELY (g_atomic_int_get (&object->ref_count) <= 0)) { g_critical ("Attempting to thaw the notification queue for object %s[%p]; " "Property notification does not work during instance finalization.", @@ -1689,17 +1682,7 @@ g_object_thaw_notify (GObject *object) } #endif - - g_object_ref (object); - - /* FIXME: Freezing is the only way to get at the notify queue. - * So we freeze once and then thaw twice. - */ - nqueue = g_object_notify_queue_freeze (object, FALSE); - g_object_notify_queue_thaw (object, nqueue); - g_object_notify_queue_thaw (object, nqueue); - - g_object_unref (object); + g_object_notify_queue_thaw (object, NULL, TRUE); } static void @@ -1710,14 +1693,14 @@ maybe_issue_property_deprecation_warning (const GParamSpec *pspec) static GMutex already_warned_lock; gboolean already; - if (g_once_init_enter (&enable_diagnostic)) + if (g_once_init_enter_pointer (&enable_diagnostic)) { const gchar *value = g_getenv ("G_ENABLE_DIAGNOSTIC"); if (!value) value = "0"; - g_once_init_leave (&enable_diagnostic, value); + g_once_init_leave_pointer (&enable_diagnostic, value); } if (enable_diagnostic[0] == '0') @@ -1843,7 +1826,7 @@ object_set_property (GObject *object, if ((pspec->flags & (G_PARAM_EXPLICIT_NOTIFY | G_PARAM_READABLE)) == G_PARAM_READABLE && nqueue != NULL) - g_object_notify_queue_add (object, nqueue, pspec); + g_object_notify_queue_add (object, nqueue, pspec, FALSE); } static void @@ -2210,7 +2193,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, */ nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); if (!nqueue) - nqueue = g_object_notify_queue_freeze (object, FALSE); + nqueue = g_object_notify_queue_freeze (object); } } @@ -2225,7 +2208,7 @@ g_object_new_with_custom_constructor (GObjectClass *class, /* If nqueue is non-NULL then we are frozen. Thaw it. */ if (nqueue) - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); return object; } @@ -2259,7 +2242,7 @@ g_object_new_internal (GObjectClass *class, */ nqueue = g_datalist_id_get_data (&object->qdata, quark_notify_queue); if (!nqueue) - nqueue = g_object_notify_queue_freeze (object, FALSE); + nqueue = g_object_notify_queue_freeze (object); } /* We will set exactly n_construct_properties construct @@ -2303,7 +2286,7 @@ g_object_new_internal (GObjectClass *class, object_set_property (object, params[i].pspec, params[i].value, nqueue, TRUE); if (nqueue) - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); return object; } @@ -2622,7 +2605,7 @@ g_object_constructor (GType type, /* set construction parameters */ if (n_construct_properties) { - GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object, FALSE); + GObjectNotifyQueue *nqueue = g_object_notify_queue_freeze (object); /* set construct properties */ while (n_construct_properties--) @@ -2633,7 +2616,7 @@ g_object_constructor (GType type, construct_params++; object_set_property (object, pspec, value, nqueue, TRUE); } - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); /* the notification queue is still frozen from g_object_init(), so * we don't need to handle it here, g_object_newv() takes * care of that @@ -2710,7 +2693,7 @@ g_object_setv (GObject *object, class = G_OBJECT_GET_CLASS (object); if (_g_object_has_notify_handler (object)) - nqueue = g_object_notify_queue_freeze (object, FALSE); + nqueue = g_object_notify_queue_freeze (object); for (i = 0; i < n_properties; i++) { @@ -2723,7 +2706,7 @@ g_object_setv (GObject *object, } if (nqueue) - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); g_object_unref (object); } @@ -2751,7 +2734,7 @@ g_object_set_valist (GObject *object, g_object_ref (object); if (_g_object_has_notify_handler (object)) - nqueue = g_object_notify_queue_freeze (object, FALSE); + nqueue = g_object_notify_queue_freeze (object); class = G_OBJECT_GET_CLASS (object); @@ -2789,7 +2772,7 @@ g_object_set_valist (GObject *object, } if (nqueue) - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); g_object_unref (object); } @@ -3316,7 +3299,7 @@ g_object_weak_ref (GObject *object, g_return_if_fail (g_atomic_int_get (&object->ref_count) >= 1); G_LOCK (weak_refs_mutex); - wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_refs); + wstack = g_datalist_id_remove_no_notify (&object->qdata, quark_weak_notifies); if (wstack) { i = wstack->n_weak_refs++; @@ -3331,7 +3314,7 @@ g_object_weak_ref (GObject *object, } wstack->weak_refs[i].notify = notify; wstack->weak_refs[i].data = data; - g_datalist_id_set_data_full (&object->qdata, quark_weak_refs, wstack, weak_refs_notify); + g_datalist_id_set_data_full (&object->qdata, quark_weak_notifies, wstack, weak_refs_notify); G_UNLOCK (weak_refs_mutex); } @@ -3355,7 +3338,7 @@ g_object_weak_unref (GObject *object, g_return_if_fail (notify != NULL); G_LOCK (weak_refs_mutex); - wstack = g_datalist_id_get_data (&object->qdata, quark_weak_refs); + wstack = g_datalist_id_get_data (&object->qdata, quark_weak_notifies); if (wstack) { guint i; @@ -3438,7 +3421,7 @@ object_floating_flag_handler (GObject *object, oldvalue = g_atomic_pointer_get (&object->qdata); while (!g_atomic_pointer_compare_and_exchange_full ( (void**) &object->qdata, oldvalue, - (void *) ((gsize) oldvalue | OBJECT_FLOATING_FLAG), + (void *) ((guintptr) oldvalue | OBJECT_FLOATING_FLAG), &oldvalue)) ; return (gsize) oldvalue & OBJECT_FLOATING_FLAG; @@ -3446,7 +3429,7 @@ object_floating_flag_handler (GObject *object, oldvalue = g_atomic_pointer_get (&object->qdata); while (!g_atomic_pointer_compare_and_exchange_full ( (void**) &object->qdata, oldvalue, - (void *) ((gsize) oldvalue & ~(gsize) OBJECT_FLOATING_FLAG), + (void *) ((guintptr) oldvalue & ~(gsize) OBJECT_FLOATING_FLAG), &oldvalue)) ; return (gsize) oldvalue & OBJECT_FLOATING_FLAG; @@ -3887,7 +3870,7 @@ g_object_unref (gpointer _object) * drained when g_object_finalize() is reached and * the qdata is cleared. */ - nqueue = g_object_notify_queue_freeze (object, FALSE); + nqueue = g_object_notify_queue_freeze (object); /* we are about to remove the last reference */ TRACE (GOBJECT_OBJECT_DISPOSE(object,G_TYPE_FROM_INSTANCE(object), 1)); @@ -3909,7 +3892,7 @@ g_object_unref (gpointer _object) TRACE (GOBJECT_OBJECT_UNREF (object, G_TYPE_FROM_INSTANCE (object), old_ref)); /* emit all notifications that have been queued during dispose() */ - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); /* if we went from 2->1 we need to notify toggle refs if any */ if (old_ref == 2 && OBJECT_HAS_TOGGLE_REF (object) && @@ -3927,6 +3910,7 @@ g_object_unref (gpointer _object) g_signal_handlers_destroy (object); g_datalist_id_set_data (&object->qdata, quark_weak_refs, NULL); g_datalist_id_set_data (&object->qdata, quark_weak_locations, NULL); + g_datalist_id_set_data (&object->qdata, quark_weak_notifies, NULL); /* decrement the last reference */ old_ref = g_atomic_int_add (&object->ref_count, -1); @@ -3961,7 +3945,7 @@ g_object_unref (gpointer _object) /* The instance acquired a reference between dispose() and * finalize(), so we need to thaw the notification queue */ - g_object_notify_queue_thaw (object, nqueue); + g_object_notify_queue_thaw (object, nqueue, FALSE); } } } diff --git a/gobject/gobject.h b/gobject/gobject.h index ea0157c..7d987c4 100644 --- a/gobject/gobject.h +++ b/gobject/gobject.h @@ -248,22 +248,7 @@ typedef void (*GObjectFinalizeFunc) (GObject *object); */ typedef void (*GWeakNotify) (gpointer data, GObject *where_the_object_was); -/** - * GObject: - * - * The base object type. - * - * All the fields in the `GObject` structure are private to the implementation - * and should never be accessed directly. - * - * Since GLib 2.72, all #GObjects are guaranteed to be aligned to at least the - * alignment of the largest basic GLib type (typically this is #guint64 or - * #gdouble). If you need larger alignment for an element in a #GObject, you - * should allocate it on the heap (aligned), or arrange for your #GObject to be - * appropriately padded. This guarantee applies to the #GObject (or derived) - * struct, the #GObjectClass (or derived) struct, and any private data allocated - * by G_ADD_PRIVATE(). - */ + struct _GObject { GTypeInstance g_type_instance; diff --git a/gobject/gparam.c b/gobject/gparam.c index 9af9e9b..1571b34 100644 --- a/gobject/gparam.c +++ b/gobject/gparam.c @@ -31,29 +31,27 @@ #include "gtype-private.h" /** - * SECTION:gparamspec - * @short_description: Metadata for parameter specifications - * @see_also: g_object_class_install_property(), g_object_set(), - * g_object_get(), g_object_set_property(), g_object_get_property(), - * g_value_register_transform_func() - * @title: GParamSpec + * GParamSpec: (ref-func g_param_spec_ref_sink) (unref-func g_param_spec_unref) (set-value-func g_value_set_param) (get-value-func g_value_get_param) + * @g_type_instance: private `GTypeInstance` portion + * @name: name of this parameter: always an interned string + * @flags: `GParamFlags` flags for this parameter + * @value_type: the `GValue` type for this parameter + * @owner_type: `GType` type that uses (introduces) this parameter * - * #GParamSpec is an object structure that encapsulates the metadata - * required to specify parameters, such as e.g. #GObject properties. + * `GParamSpec` encapsulates the metadata required to specify parameters, such as `GObject` properties. * - * ## Parameter names # {#canonical-parameter-names} + * ## Parameter names * * A property name consists of one or more segments consisting of ASCII letters * and digits, separated by either the `-` or `_` character. The first * character of a property name must be a letter. These are the same rules as - * for signal naming (see g_signal_new()). + * for signal naming (see [func@GObject.signal_new]). * - * When creating and looking up a #GParamSpec, either separator can be + * When creating and looking up a `GParamSpec`, either separator can be * used, but they cannot be mixed. Using `-` is considerably more * efficient, and is the ‘canonical form’. Using `_` is discouraged. */ - /* --- defines --- */ #define PARAM_FLOATING_FLAG 0x2 #define G_PARAM_USER_MASK (~0U << G_PARAM_USER_SHIFT) @@ -257,7 +255,7 @@ g_param_spec_unref (GParamSpec *pspec) void g_param_spec_sink (GParamSpec *pspec) { - gsize oldvalue; + guintptr oldvalue; g_return_if_fail (G_IS_PARAM_SPEC (pspec)); oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG); @@ -277,7 +275,7 @@ g_param_spec_sink (GParamSpec *pspec) GParamSpec* g_param_spec_ref_sink (GParamSpec *pspec) { - gsize oldvalue; + guintptr oldvalue; g_return_val_if_fail (G_IS_PARAM_SPEC (pspec), NULL); oldvalue = g_atomic_pointer_and (&pspec->qdata, ~(gsize)PARAM_FLOATING_FLAG); @@ -996,12 +994,33 @@ g_param_spec_pool_new (gboolean type_prefixing) memcpy (&pool->mutex, &init_mutex, sizeof (init_mutex)); pool->type_prefixing = type_prefixing != FALSE; - pool->hash_table = g_hash_table_new (param_spec_pool_hash, param_spec_pool_equals); + pool->hash_table = g_hash_table_new_full (param_spec_pool_hash, + param_spec_pool_equals, + (GDestroyNotify) g_param_spec_unref, + NULL); return pool; } /** + * g_param_spec_pool_free: + * @pool: (transfer full): a #GParamSpecPool + * + * Frees the resources allocated by a #GParamSpecPool. + * + * Since: 2.80 + */ +void +g_param_spec_pool_free (GParamSpecPool *pool) +{ + g_mutex_lock (&pool->mutex); + g_hash_table_unref (pool->hash_table); + g_mutex_unlock (&pool->mutex); + g_mutex_clear (&pool->mutex); + g_free (pool); +} + +/** * g_param_spec_pool_insert: * @pool: a #GParamSpecPool. * @pspec: (transfer none) (not nullable): the #GParamSpec to insert @@ -1055,9 +1074,7 @@ g_param_spec_pool_remove (GParamSpecPool *pool, if (pool && pspec) { g_mutex_lock (&pool->mutex); - if (g_hash_table_remove (pool->hash_table, pspec)) - g_param_spec_unref (pspec); - else + if (!g_hash_table_remove (pool->hash_table, pspec)) g_critical (G_STRLOC ": attempt to remove unknown pspec '%s' from pool", pspec->name); g_mutex_unlock (&pool->mutex); } @@ -1236,7 +1253,7 @@ g_param_spec_pool_list_owned (GParamSpecPool *pool, g_mutex_lock (&pool->mutex); data[0] = NULL; - data[1] = (gpointer) owner_type; + data[1] = GTYPE_TO_POINTER (owner_type); g_hash_table_foreach (pool->hash_table, pool_list, &data); g_mutex_unlock (&pool->mutex); @@ -1375,7 +1392,7 @@ g_param_spec_pool_list (GParamSpecPool *pool, d = g_type_depth (owner_type); slists = g_new0 (GSList*, d); data[0] = slists; - data[1] = (gpointer) owner_type; + data[1] = GTYPE_TO_POINTER (owner_type); data[2] = pool->hash_table; data[3] = &n_pspecs; @@ -1631,7 +1648,7 @@ g_param_spec_get_default_value (GParamSpec *pspec) * done before a g_once_init_enter() could take the fast path in * another thread. */ - if (g_once_init_enter (&priv->default_value.g_type)) + if (g_once_init_enter_pointer (&priv->default_value.g_type)) { GValue default_value = G_VALUE_INIT; @@ -1641,7 +1658,7 @@ g_param_spec_get_default_value (GParamSpec *pspec) /* store all but the type */ memcpy (priv->default_value.data, default_value.data, sizeof (default_value.data)); - g_once_init_leave (&priv->default_value.g_type, pspec->value_type); + g_once_init_leave_pointer (&priv->default_value.g_type, pspec->value_type); } return &priv->default_value; diff --git a/gobject/gparam.h b/gobject/gparam.h index 6454e69..89374fe 100644 --- a/gobject/gparam.h +++ b/gobject/gparam.h @@ -203,17 +203,7 @@ typedef struct _GParamSpec GParamSpec; typedef struct _GParamSpecClass GParamSpecClass; typedef struct _GParameter GParameter GOBJECT_DEPRECATED_TYPE_IN_2_54; typedef struct _GParamSpecPool GParamSpecPool; -/** - * GParamSpec: (ref-func g_param_spec_ref_sink) (unref-func g_param_spec_unref) (set-value-func g_value_set_param) (get-value-func g_value_get_param) - * @g_type_instance: private #GTypeInstance portion - * @name: name of this parameter: always an interned string - * @flags: #GParamFlags flags for this parameter - * @value_type: the #GValue type for this parameter - * @owner_type: #GType type that uses (introduces) this parameter - * - * All other fields of the GParamSpec struct are private and - * should not be used directly. - */ + struct _GParamSpec { GTypeInstance g_type_instance; @@ -453,7 +443,8 @@ GOBJECT_AVAILABLE_IN_ALL GParamSpec** g_param_spec_pool_list (GParamSpecPool *pool, GType owner_type, guint *n_pspecs_p); - +GOBJECT_AVAILABLE_IN_2_80 +void g_param_spec_pool_free (GParamSpecPool *pool); /* contracts: * diff --git a/gobject/gparamspecs.c b/gobject/gparamspecs.c index 17b8606..cf50df7 100644 --- a/gobject/gparamspecs.c +++ b/gobject/gparamspecs.c @@ -37,29 +37,6 @@ #include "gvaluearray.h" -/** - * SECTION:param_value_types - * @short_description: Standard Parameter and Value Types - * @see_also: #GParamSpec, #GValue, g_object_class_install_property(). - * @title: Parameters and Values - * - * #GValue provides an abstract container structure which can be - * copied, transformed and compared while holding a value of any - * (derived) type, which is registered as a #GType with a - * #GTypeValueTable in its #GTypeInfo structure. Parameter - * specifications for most value types can be created as #GParamSpec - * derived instances, to implement e.g. #GObject properties which - * operate on #GValue containers. - * - * Parameter names need to start with a letter (a-z or A-Z). Subsequent - * characters can be letters, numbers or a '-'. - * All other characters are replaced by a '-' during construction. - * - * See also #GValue for more information. - * - */ - - #define G_FLOAT_EPSILON (1e-30) #define G_DOUBLE_EPSILON (1e-90) @@ -1245,7 +1222,7 @@ param_gtype_set_default (GParamSpec *pspec, { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - value->data[0].v_pointer = GSIZE_TO_POINTER (tspec->is_a_type); + value->data[0].v_pointer = GTYPE_TO_POINTER (tspec->is_a_type); } static gboolean @@ -1253,7 +1230,7 @@ param_gtype_is_valid (GParamSpec *pspec, const GValue *value) { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - GType gtype = GPOINTER_TO_SIZE (value->data[0].v_pointer); + GType gtype = GPOINTER_TO_TYPE (value->data[0].v_pointer); return tspec->is_a_type == G_TYPE_NONE || g_type_is_a (gtype, tspec->is_a_type); @@ -1264,12 +1241,12 @@ param_gtype_validate (GParamSpec *pspec, GValue *value) { GParamSpecGType *tspec = G_PARAM_SPEC_GTYPE (pspec); - GType gtype = GPOINTER_TO_SIZE (value->data[0].v_pointer); + GType gtype = GPOINTER_TO_TYPE (value->data[0].v_pointer); guint changed = 0; if (tspec->is_a_type != G_TYPE_NONE && !g_type_is_a (gtype, tspec->is_a_type)) { - value->data[0].v_pointer = GSIZE_TO_POINTER (tspec->is_a_type); + value->data[0].v_pointer = GTYPE_TO_POINTER (tspec->is_a_type); changed++; } @@ -1281,8 +1258,8 @@ param_gtype_values_cmp (GParamSpec *pspec, const GValue *value1, const GValue *value2) { - GType p1 = GPOINTER_TO_SIZE (value1->data[0].v_pointer); - GType p2 = GPOINTER_TO_SIZE (value2->data[0].v_pointer); + GType p1 = GPOINTER_TO_TYPE (value1->data[0].v_pointer); + GType p2 = GPOINTER_TO_TYPE (value2->data[0].v_pointer); /* not much to compare here, try to at least provide stable lesser/greater result */ diff --git a/gobject/gsignal.c b/gobject/gsignal.c index 1a2051f..04456ce 100644 --- a/gobject/gsignal.c +++ b/gobject/gsignal.c @@ -39,99 +39,6 @@ #include "gobject_trace.h" -/** - * SECTION:signals - * @short_description: A means for customization of object behaviour - * and a general purpose notification mechanism - * @title: Signals - * - * The basic concept of the signal system is that of the emission - * of a signal. Signals are introduced per-type and are identified - * through strings. Signals introduced for a parent type are available - * in derived types as well, so basically they are a per-type facility - * that is inherited. - * - * A signal emission mainly involves invocation of a certain set of - * callbacks in precisely defined manner. There are two main categories - * of such callbacks, per-object ones and user provided ones. - * (Although signals can deal with any kind of instantiatable type, I'm - * referring to those types as "object types" in the following, simply - * because that is the context most users will encounter signals in.) - * The per-object callbacks are most often referred to as "object method - * handler" or "default (signal) handler", while user provided callbacks are - * usually just called "signal handler". - * - * The object method handler is provided at signal creation time (this most - * frequently happens at the end of an object class' creation), while user - * provided handlers are frequently connected and disconnected to/from a - * certain signal on certain object instances. - * - * A signal emission consists of five stages, unless prematurely stopped: - * - * 1. Invocation of the object method handler for %G_SIGNAL_RUN_FIRST signals - * - * 2. Invocation of normal user-provided signal handlers (where the @after - * flag is not set) - * - * 3. Invocation of the object method handler for %G_SIGNAL_RUN_LAST signals - * - * 4. Invocation of user provided signal handlers (where the @after flag is set) - * - * 5. Invocation of the object method handler for %G_SIGNAL_RUN_CLEANUP signals - * - * The user-provided signal handlers are called in the order they were - * connected in. - * - * All handlers may prematurely stop a signal emission, and any number of - * handlers may be connected, disconnected, blocked or unblocked during - * a signal emission. - * - * There are certain criteria for skipping user handlers in stages 2 and 4 - * of a signal emission. - * - * First, user handlers may be blocked. Blocked handlers are omitted during - * callback invocation, to return from the blocked state, a handler has to - * get unblocked exactly the same amount of times it has been blocked before. - * - * Second, upon emission of a %G_SIGNAL_DETAILED signal, an additional - * @detail argument passed in to g_signal_emit() has to match the detail - * argument of the signal handler currently subject to invocation. - * Specification of no detail argument for signal handlers (omission of the - * detail part of the signal specification upon connection) serves as a - * wildcard and matches any detail argument passed in to emission. - * - * While the @detail argument is typically used to pass an object property name - * (as with #GObject::notify), no specific format is mandated for the detail - * string, other than that it must be non-empty. - * - * ## Memory management of signal handlers # {#signal-memory-management} - * - * If you are connecting handlers to signals and using a #GObject instance as - * your signal handler user data, you should remember to pair calls to - * g_signal_connect() with calls to g_signal_handler_disconnect() or - * g_signal_handlers_disconnect_by_func(). While signal handlers are - * automatically disconnected when the object emitting the signal is finalised, - * they are not automatically disconnected when the signal handler user data is - * destroyed. If this user data is a #GObject instance, using it from a - * signal handler after it has been finalised is an error. - * - * There are two strategies for managing such user data. The first is to - * disconnect the signal handler (using g_signal_handler_disconnect() or - * g_signal_handlers_disconnect_by_func()) when the user data (object) is - * finalised; this has to be implemented manually. For non-threaded programs, - * g_signal_connect_object() can be used to implement this automatically. - * Currently, however, it is unsafe to use in threaded programs. - * - * The second is to hold a strong reference on the user data until after the - * signal is disconnected for other reasons. This can be implemented - * automatically using g_signal_connect_data(). - * - * The first approach is recommended, as the second approach can result in - * effective memory leaks of the user data if the signal handler is never - * disconnected for some reason. - */ - - #define REPORT_BUG "please report occurrence circumstances to https://gitlab.gnome.org/GNOME/glib/issues/new" /* --- typedefs --- */ @@ -1326,8 +1233,8 @@ g_signal_lookup (const gchar *name, { /* give elaborate warnings */ if (!g_type_name (itype)) - g_critical (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GSIZE_FORMAT"'", - name, itype); + g_critical (G_STRLOC ": unable to look up signal \"%s\" for invalid type id '%"G_GUINTPTR_FORMAT"'", + name, (guintptr) itype); else if (!g_signal_is_valid_name (name)) g_critical (G_STRLOC ": unable to look up invalid signal name \"%s\" on type '%s'", name, g_type_name (itype)); @@ -1375,8 +1282,8 @@ g_signal_list_ids (GType itype, { /* give elaborate warnings */ if (!g_type_name (itype)) - g_critical (G_STRLOC ": unable to list signals for invalid type id '%"G_GSIZE_FORMAT"'", - itype); + g_critical (G_STRLOC ": unable to list signals for invalid type id '%"G_GUINTPTR_FORMAT"'", + (guintptr) itype); else if (!G_TYPE_IS_INSTANTIATABLE (itype) && !G_TYPE_IS_INTERFACE (itype)) g_critical (G_STRLOC ": unable to list signals of non instantiatable type '%s'", g_type_name (itype)); @@ -1461,7 +1368,7 @@ g_signal_query (guint signal_id, * @class_offset: The offset of the function pointer in the class structure * for this type. Used to invoke a class method generically. Pass 0 to * not associate a class method slot with this signal. - * @accumulator: (nullable): the accumulator for this signal; may be %NULL. + * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL. * @accu_data: (nullable) (closure accumulator): user data for the @accumulator. * @c_marshaller: (nullable): the function to translate arrays of parameter * values to signal emissions into C language callback invocations or %NULL. @@ -1534,10 +1441,10 @@ g_signal_new (const gchar *signal_name, * @signal_flags: a combination of #GSignalFlags specifying detail of when * the default handler is to be invoked. You should at least specify * %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST. - * @class_handler: (nullable): a #GCallback which acts as class implementation of + * @class_handler: (nullable) (scope forever): a #GCallback which acts as class implementation of * this signal. Used to invoke a class method generically. Pass %NULL to * not associate a class method with this signal. - * @accumulator: (nullable): the accumulator for this signal; may be %NULL. + * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL. * @accu_data: (nullable) (closure accumulator): user data for the @accumulator. * @c_marshaller: (nullable): the function to translate arrays of parameter * values to signal emissions into C language callback invocations or %NULL. @@ -1674,7 +1581,7 @@ signal_add_class_closure (SignalNode *node, * %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST * @class_closure: (nullable): The closure to invoke on signal emission; * may be %NULL - * @accumulator: (nullable): the accumulator for this signal; may be %NULL + * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL * @accu_data: (nullable) (closure accumulator): user data for the @accumulator * @c_marshaller: (nullable): the function to translate arrays of * parameter values to signal emissions into C language callback @@ -1935,7 +1842,7 @@ g_signal_set_va_marshaller (guint signal_id, * the default handler is to be invoked. You should at least specify * %G_SIGNAL_RUN_FIRST or %G_SIGNAL_RUN_LAST. * @class_closure: (nullable): The closure to invoke on signal emission; may be %NULL. - * @accumulator: (nullable): the accumulator for this signal; may be %NULL. + * @accumulator: (nullable) (scope forever): the accumulator for this signal; may be %NULL. * @accu_data: (nullable) (closure accumulator): user data for the @accumulator. * @c_marshaller: (nullable): the function to translate arrays of parameter * values to signal emissions into C language callback invocations or %NULL. @@ -2097,7 +2004,7 @@ g_signal_override_class_closure (guint signal_id, * @signal_name: the name for the signal * @instance_type: the instance type on which to override the class handler * for the signal. - * @class_handler: the handler. + * @class_handler: (scope forever): the handler. * * Overrides the class closure (i.e. the default handler) for the * given signal for emissions on instances of @instance_type with @@ -2127,14 +2034,14 @@ g_signal_override_class_handler (const gchar *signal_name, g_signal_override_class_closure (signal_id, instance_type, g_cclosure_new (class_handler, NULL, NULL)); else - g_critical ("%s: signal name '%s' is invalid for type id '%"G_GSIZE_FORMAT"'", - G_STRLOC, signal_name, instance_type); + g_critical ("%s: signal name '%s' is invalid for type id '%"G_GUINTPTR_FORMAT"'", + G_STRLOC, signal_name, (guintptr) instance_type); } /** * g_signal_chain_from_overridden: - * @instance_and_params: (array) the argument list of the signal emission. + * @instance_and_params: (array): the argument list of the signal emission. * The first element in the array is a #GValue for the instance the signal * is being emitted on. The rest are any arguments to be passed to the signal. * @return_value: Location for the return value. diff --git a/gobject/gsignal.h b/gobject/gsignal.h index 312055b..5522b72 100644 --- a/gobject/gsignal.h +++ b/gobject/gsignal.h @@ -504,7 +504,7 @@ void g_signal_chain_from_overridden_handler (gpointer instance, * * The handler will be called synchronously, before the default handler of the signal. g_signal_emit() will not return control until all handlers are called. * - * See [memory management of signal handlers][signal-memory-management] for + * See [memory management of signal handlers][signals.html#Memory_management_of_signal_handlers] for * details on how to handle the return value and memory management of @data. * * Returns: the handler ID, of type #gulong (always greater than 0 for successful connections) diff --git a/gobject/gsignalgroup.c b/gobject/gsignalgroup.c index 6cf9cc9..5372e8c 100644 --- a/gobject/gsignalgroup.c +++ b/gobject/gsignalgroup.c @@ -28,13 +28,12 @@ #include "gvaluetypes.h" /** - * SECTION:gsignalgroup - * @Title: GSignalGroup - * @Short_description: Manage a collection of signals on a GObject + * GSignalGroup: * - * #GSignalGroup manages to simplify the process of connecting - * many signals to a #GObject as a group. As such there is no API - * to disconnect a signal from the group. + * `GSignalGroup` manages a collection of signals on a `GObject`. + * + * `GSignalGroup` simplifies the process of connecting many signals to a `GObject` + * as a group. As such there is no API to disconnect a signal from the group. * * In particular, this allows you to: * @@ -43,12 +42,12 @@ * - Block and unblock signals as a group * - Ensuring that blocked state transfers across target instances. * - * One place you might want to use such a structure is with #GtkTextView and - * #GtkTextBuffer. Often times, you'll need to connect to many signals on - * #GtkTextBuffer from a #GtkTextView subclass. This allows you to create a + * One place you might want to use such a structure is with `GtkTextView` and + * `GtkTextBuffer`. Often times, you'll need to connect to many signals on + * `GtkTextBuffer` from a `GtkTextView` subclass. This allows you to create a * signal group during instance construction, simply bind the - * #GtkTextView:buffer property to #GSignalGroup:target and connect - * all the signals you need. When the #GtkTextView:buffer property changes + * `GtkTextView:buffer` property to `GSignalGroup:target` and connect + * all the signals you need. When the `GtkTextView:buffer` property changes * all of the signals will be transitioned correctly. * * Since: 2.72 @@ -611,9 +610,7 @@ g_signal_group_class_init (GSignalGroupClass *klass) * Since: 2.72 */ properties[PROP_TARGET] = - g_param_spec_object ("target", - "Target", - "The target instance used when connecting signals.", + g_param_spec_object ("target", NULL, NULL, G_TYPE_OBJECT, (G_PARAM_READWRITE | G_PARAM_EXPLICIT_NOTIFY | G_PARAM_STATIC_STRINGS)); @@ -625,9 +622,7 @@ g_signal_group_class_init (GSignalGroupClass *klass) * Since: 2.72 */ properties[PROP_TARGET_TYPE] = - g_param_spec_gtype ("target-type", - "Target Type", - "The GType of the target property.", + g_param_spec_gtype ("target-type", NULL, NULL, G_TYPE_OBJECT, (G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | G_PARAM_STATIC_STRINGS)); diff --git a/gobject/gsignalgroup.h b/gobject/gsignalgroup.h index 6aa151c..38fd2e0 100644 --- a/gobject/gsignalgroup.h +++ b/gobject/gsignalgroup.h @@ -36,14 +36,6 @@ G_BEGIN_DECLS #define G_IS_SIGNAL_GROUP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), G_TYPE_SIGNAL_GROUP)) #define G_TYPE_SIGNAL_GROUP (g_signal_group_get_type()) -/** - * GSignalGroup: - * - * #GSignalGroup is an opaque structure whose members - * cannot be accessed directly. - * - * Since: 2.72 - */ typedef struct _GSignalGroup GSignalGroup; GOBJECT_AVAILABLE_IN_2_72 diff --git a/gobject/gsourceclosure.c b/gobject/gsourceclosure.c index 6a42f77..3ca5e45 100644 --- a/gobject/gsourceclosure.c +++ b/gobject/gsourceclosure.c @@ -36,7 +36,7 @@ g_io_condition_get_type (void) { static GType etype = 0; - if (g_once_init_enter (&etype)) + if (g_once_init_enter_pointer (&etype)) { static const GFlagsValue values[] = { { G_IO_IN, "G_IO_IN", "in" }, @@ -48,7 +48,7 @@ g_io_condition_get_type (void) { 0, NULL, NULL } }; GType type_id = g_flags_register_static ("GIOCondition", values); - g_once_init_leave (&etype, type_id); + g_once_init_leave_pointer (&etype, type_id); } return etype; } diff --git a/gobject/gtype.c b/gobject/gtype.c index e2e0c38..8222fc4 100644 --- a/gobject/gtype.c +++ b/gobject/gtype.c @@ -44,65 +44,6 @@ #define IF_DEBUG(debug_type) if (_g_type_debug_flags & G_TYPE_DEBUG_ ## debug_type) #endif -/** - * SECTION:gtype - * @short_description: The GLib Runtime type identification and - * management system - * @title:Type Information - * - * The GType API is the foundation of the GObject system. It provides the - * facilities for registering and managing all fundamental data types, - * user-defined object and interface types. - * - * For type creation and registration purposes, all types fall into one of - * two categories: static or dynamic. Static types are never loaded or - * unloaded at run-time as dynamic types may be. Static types are created - * with g_type_register_static() that gets type specific information passed - * in via a #GTypeInfo structure. - * - * Dynamic types are created with g_type_register_dynamic() which takes a - * #GTypePlugin structure instead. The remaining type information (the - * #GTypeInfo structure) is retrieved during runtime through #GTypePlugin - * and the g_type_plugin_*() API. - * - * These registration functions are usually called only once from a - * function whose only purpose is to return the type identifier for a - * specific class. Once the type (or class or interface) is registered, - * it may be instantiated, inherited, or implemented depending on exactly - * what sort of type it is. - * - * There is also a third registration function for registering fundamental - * types called g_type_register_fundamental() which requires both a #GTypeInfo - * structure and a #GTypeFundamentalInfo structure but it is seldom used - * since most fundamental types are predefined rather than user-defined. - * - * Type instance and class structs are limited to a total of 64 KiB, - * including all parent types. Similarly, type instances' private data - * (as created by G_ADD_PRIVATE()) are limited to a total of - * 64 KiB. If a type instance needs a large static buffer, allocate it - * separately (typically by using #GArray or #GPtrArray) and put a pointer - * to the buffer in the structure. - * - * As mentioned in the [GType conventions][gtype-conventions], type names must - * be at least three characters long. There is no upper length limit. The first - * character must be a letter (a–z or A–Z) or an underscore (‘_’). Subsequent - * characters can be letters, numbers or any of ‘-_+’. - * - * # Runtime Debugging - * - * When `G_ENABLE_DEBUG` is defined during compilation, the GObject library - * supports an environment variable `GOBJECT_DEBUG` that can be set to a - * combination of flags to trigger debugging messages about - * object bookkeeping and signal emissions during runtime. - * - * The currently supported flags are: - * - `objects`: Tracks all #GObject instances in a global hash table called - * `debug_objects_ht`, and prints the still-alive objects on exit. - * - `instance-count`: Tracks the number of instances of every #GType and makes - * it available via the g_type_get_instance_count() function. - * - `signals`: Currently unused. - */ - /* NOTE: some functions (some internal variants and exported ones) * invalidate data portions of the TypeNodes. if external functions/callbacks @@ -155,6 +96,9 @@ #define g_assert_type_system_initialized() \ g_assert (static_quark_type_flags) +/* Make sure G_TYPE_IS_*() macros still end up inlined */ +#define g_type_test_flags(t,f) _g_type_test_flags(t,f) + #define TYPE_FUNDAMENTAL_FLAG_MASK (G_TYPE_FLAG_CLASSED | \ G_TYPE_FLAG_INSTANTIATABLE | \ G_TYPE_FLAG_DERIVABLE | \ @@ -163,7 +107,9 @@ /* List the flags that are directly accessible via the TypeNode struct flags */ #define NODE_FLAG_MASK ( \ + G_TYPE_FLAG_ABSTRACT | \ G_TYPE_FLAG_CLASSED | \ + G_TYPE_FLAG_DEPRECATED | \ G_TYPE_FLAG_INSTANTIATABLE | \ G_TYPE_FLAG_FINAL) @@ -198,6 +144,8 @@ typedef struct _IFaceHolder IFaceHolder; /* --- prototypes --- */ +static inline gboolean _g_type_test_flags (GType type, + guint flags); static inline GTypeFundamentalInfo* type_node_fundamental_info_I (TypeNode *node); static void type_add_flags_W (TypeNode *node, GTypeFlags flags); @@ -252,7 +200,9 @@ struct _TypeNode guint n_children; /* writable with lock */ guint n_supers : 8; guint n_prerequisites : 9; + guint is_abstract : 1; guint is_classed : 1; + guint is_deprecated : 1; guint is_instantiatable : 1; guint is_final : 1; guint mutatable_check_cache : 1; /* combines some common path checks */ @@ -472,7 +422,7 @@ type_node_any_new_W (TypeNode *pnode, #endif } else - type = (GType) node; + type = GPOINTER_TO_TYPE (node); g_assert ((type & TYPE_ID_MASK) == 0); @@ -482,7 +432,9 @@ type_node_any_new_W (TypeNode *pnode, node->supers[0] = type; node->supers[1] = 0; + node->is_abstract = (type_flags & G_TYPE_FLAG_ABSTRACT) != 0; node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0; + node->is_deprecated = (type_flags & G_TYPE_FLAG_DEPRECATED) != 0; node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0; if (NODE_IS_IFACE (node)) @@ -498,9 +450,13 @@ type_node_any_new_W (TypeNode *pnode, node->supers[0] = type; memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1)); + node->is_abstract = (type_flags & G_TYPE_FLAG_ABSTRACT) != 0; node->is_classed = pnode->is_classed; + node->is_deprecated = (type_flags & G_TYPE_FLAG_DEPRECATED) != 0; node->is_instantiatable = pnode->is_instantiatable; - + + node->is_deprecated |= pnode->is_deprecated; + if (NODE_IS_IFACE (node)) { IFACE_NODE_N_PREREQUISITES (node) = 0; @@ -541,7 +497,7 @@ type_node_any_new_W (TypeNode *pnode, node->global_gdata = NULL; g_hash_table_insert (static_type_nodes_ht, (gpointer) g_quark_to_string (node->qname), - (gpointer) type); + GTYPE_TO_POINTER (type)); g_atomic_int_inc ((gint *)&type_registration_serial); @@ -566,20 +522,18 @@ type_node_fundamental_new_W (GType ftype, { GTypeFundamentalInfo *finfo; TypeNode *node; - + g_assert ((ftype & TYPE_ID_MASK) == 0); g_assert (ftype <= G_TYPE_FUNDAMENTAL_MAX); - + if (ftype >> G_TYPE_FUNDAMENTAL_SHIFT == static_fundamental_next) static_fundamental_next++; - - type_flags &= TYPE_FUNDAMENTAL_FLAG_MASK; - + node = type_node_any_new_W (NULL, ftype, name, NULL, type_flags); - + finfo = type_node_fundamental_info_I (node); - finfo->type_flags = type_flags; - + finfo->type_flags = type_flags & TYPE_FUNDAMENTAL_FLAG_MASK; + return node; } @@ -1854,14 +1808,14 @@ maybe_issue_deprecation_warning (GType type) gboolean already; const char *name; - if (g_once_init_enter (&enable_diagnostic)) + if (g_once_init_enter_pointer (&enable_diagnostic)) { const gchar *value = g_getenv ("G_ENABLE_DIAGNOSTIC"); if (!value) value = "0"; - g_once_init_leave (&enable_diagnostic, value); + g_once_init_leave_pointer (&enable_diagnostic, value); } if (enable_diagnostic[0] == '0') @@ -2767,9 +2721,9 @@ g_type_register_fundamental (GType type_id, if ((type_id & TYPE_ID_MASK) || type_id > G_TYPE_FUNDAMENTAL_MAX) { - g_critical ("attempt to register fundamental type '%s' with invalid type id (%" G_GSIZE_FORMAT ")", + g_critical ("attempt to register fundamental type '%s' with invalid type id (%" G_GUINTPTR_FORMAT ")", type_name, - type_id); + (guintptr) type_id); return 0; } if ((finfo->type_flags & G_TYPE_FLAG_INSTANTIATABLE) && @@ -3490,7 +3444,7 @@ g_type_from_name (const gchar *name) g_return_val_if_fail (name != NULL, 0); G_READ_LOCK (&type_rw_lock); - type = (GType) g_hash_table_lookup (static_type_nodes_ht, name); + type = GPOINTER_TO_TYPE (g_hash_table_lookup (static_type_nodes_ht, name)); G_READ_UNLOCK (&type_rw_lock); return type; @@ -3919,6 +3873,8 @@ type_add_flags_W (TypeNode *node, dflags |= flags; type_set_qdata_W (node, static_quark_type_flags, GUINT_TO_POINTER (dflags)); + node->is_abstract = (flags & G_TYPE_FLAG_ABSTRACT) != 0; + node->is_deprecated |= (flags & G_TYPE_FLAG_DEPRECATED) != 0; node->is_final = (flags & G_TYPE_FLAG_FINAL) != 0; } @@ -3995,9 +3951,9 @@ g_type_get_instance_count (GType type) } /* --- implementation details --- */ -gboolean -g_type_test_flags (GType type, - guint flags) +static inline gboolean +_g_type_test_flags (GType type, + guint flags) { TypeNode *node; gboolean result = FALSE; @@ -4007,16 +3963,22 @@ g_type_test_flags (GType type, { if ((flags & ~NODE_FLAG_MASK) == 0) { - if (flags & G_TYPE_FLAG_CLASSED) - result |= node->is_classed; + if ((flags & G_TYPE_FLAG_CLASSED) && !node->is_classed) + return FALSE; - if (flags & G_TYPE_FLAG_INSTANTIATABLE) - result |= node->is_instantiatable; + if ((flags & G_TYPE_FLAG_INSTANTIATABLE) && !node->is_instantiatable) + return FALSE; - if (flags & G_TYPE_FLAG_FINAL) - result |= node->is_final; + if ((flags & G_TYPE_FLAG_FINAL) && !node->is_final) + return FALSE; - return result; + if ((flags & G_TYPE_FLAG_ABSTRACT) && !node->is_abstract) + return FALSE; + + if ((flags & G_TYPE_FLAG_DEPRECATED) && !node->is_deprecated) + return FALSE; + + return TRUE; } guint fflags = flags & TYPE_FUNDAMENTAL_FLAG_MASK; @@ -4046,6 +4008,13 @@ g_type_test_flags (GType type, return result; } +gboolean +(g_type_test_flags) (GType type, + guint flags) +{ + return _g_type_test_flags (type, flags); +} + /** * g_type_get_plugin: * @type: #GType to retrieve the plugin for @@ -4421,7 +4390,7 @@ g_type_value_table_peek (GType type) return vtable; if (!node) - g_critical (G_STRLOC ": type id '%" G_GSIZE_FORMAT "' is invalid", type); + g_critical (G_STRLOC ": type id '%" G_GUINTPTR_FORMAT "' is invalid", (guintptr) type); if (!has_refed_data) g_critical ("can't peek value table for type '%s' which is not currently referenced", type_descriptive_name_I (type)); diff --git a/gobject/gtype.h b/gobject/gtype.h index b02121a..a16da45 100644 --- a/gobject/gtype.h +++ b/gobject/gtype.h @@ -421,9 +421,11 @@ G_BEGIN_DECLS * A numerical value which represents the unique identifier of a registered * type. */ -#if GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined (G_CXX_STD_VERSION) +#if GLIB_SIZEOF_VOID_P > GLIB_SIZEOF_SIZE_T +typedef guintptr GType; +#elif GLIB_SIZEOF_SIZE_T != GLIB_SIZEOF_LONG || !defined (G_CXX_STD_VERSION) typedef gsize GType; -#else /* for historic reasons, C++ links against gulong GTypes */ +#else /* for historic reasons, C++ on non-Morello/CHERI systems links against gulong GTypes */ typedef gulong GType; #endif typedef struct _GValue GValue; @@ -2009,8 +2011,8 @@ guint g_type_get_type_registration_serial (void); * GType * gtk_gadget_get_type (void) * { - * static gsize static_g_define_type_id = 0; - * if (g_once_init_enter (&static_g_define_type_id)) + * static GType static_g_define_type_id = 0; + * if (g_once_init_enter_pointer (&static_g_define_type_id)) * { * GType g_define_type_id = * g_type_register_static_simple (GTK_TYPE_WIDGET, @@ -2030,7 +2032,7 @@ guint g_type_get_type_registration_serial (void); * }; * g_type_add_interface_static (g_define_type_id, TYPE_GIZMO, &g_implement_interface_info); * } - * g_once_init_leave (&static_g_define_type_id, g_define_type_id); + * g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); * } * return static_g_define_type_id; * } @@ -2265,6 +2267,16 @@ static void type_name##_class_intern_init (gpointer klass) \ } #endif /* GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38 */ +#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_80 +#define _g_type_once_init_type GType +#define _g_type_once_init_enter g_once_init_enter_pointer +#define _g_type_once_init_leave g_once_init_leave_pointer +#else /* if GLIB_VERSION_MAX_ALLOWED < GLIB_VERSION_2_80 */ +#define _g_type_once_init_type gsize +#define _g_type_once_init_enter g_once_init_enter +#define _g_type_once_init_leave g_once_init_leave +#endif /* GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_80 */ + /* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */ #define _G_DEFINE_TYPE_EXTENDED_BEGIN_PRE(TypeName, type_name, TYPE_PARENT) \ \ @@ -2286,15 +2298,15 @@ type_name##_get_instance_private (TypeName *self) \ GType \ type_name##_get_type (void) \ { \ - static gsize static_g_define_type_id = 0; + static _g_type_once_init_type static_g_define_type_id = 0; /* Prelude goes here */ /* Added for _G_DEFINE_TYPE_EXTENDED_WITH_PRELUDE */ #define _G_DEFINE_TYPE_EXTENDED_BEGIN_REGISTER(TypeName, type_name, TYPE_PARENT, flags) \ - if (g_once_init_enter (&static_g_define_type_id)) \ + if (_g_type_once_init_enter (&static_g_define_type_id)) \ { \ GType g_define_type_id = type_name##_get_type_once (); \ - g_once_init_leave (&static_g_define_type_id, g_define_type_id); \ + _g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \ } \ return static_g_define_type_id; \ } /* closes type_name##_get_type() */ \ @@ -2334,8 +2346,8 @@ static void type_name##_default_init (TypeName##Interface *klass); \ GType \ type_name##_get_type (void) \ { \ - static gsize static_g_define_type_id = 0; \ - if (g_once_init_enter (&static_g_define_type_id)) \ + static _g_type_once_init_type static_g_define_type_id = 0; \ + if (_g_type_once_init_enter (&static_g_define_type_id)) \ { \ GType g_define_type_id = \ g_type_register_static_simple (G_TYPE_INTERFACE, \ @@ -2351,7 +2363,7 @@ type_name##_get_type (void) \ #define _G_DEFINE_INTERFACE_EXTENDED_END() \ /* following custom code */ \ } \ - g_once_init_leave (&static_g_define_type_id, g_define_type_id); \ + _g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \ } \ return static_g_define_type_id; \ } /* closes type_name##_get_type() */ @@ -2460,11 +2472,11 @@ static GType type_name##_get_type_once (void); \ GType \ type_name##_get_type (void) \ { \ - static gsize static_g_define_type_id = 0; \ - if (g_once_init_enter (&static_g_define_type_id)) \ + static _g_type_once_init_type static_g_define_type_id = 0; \ + if (_g_type_once_init_enter (&static_g_define_type_id)) \ { \ GType g_define_type_id = type_name##_get_type_once (); \ - g_once_init_leave (&static_g_define_type_id, g_define_type_id); \ + _g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \ } \ return static_g_define_type_id; \ } \ @@ -2497,11 +2509,11 @@ static GType type_name##_get_type_once (void); \ GType \ type_name##_get_type (void) \ { \ - static gsize static_g_define_type_id = 0; \ - if (g_once_init_enter (&static_g_define_type_id)) \ + static _g_type_once_init_type static_g_define_type_id = 0; \ + if (_g_type_once_init_enter (&static_g_define_type_id)) \ { \ GType g_define_type_id = type_name##_get_type_once (); \ - g_once_init_leave (&static_g_define_type_id, g_define_type_id); \ + _g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \ } \ return static_g_define_type_id; \ } \ @@ -2550,11 +2562,11 @@ static GType type_name##_get_type_once (void); \ GType \ type_name##_get_type (void) \ { \ - static gsize static_g_define_type_id = 0; \ - if (g_once_init_enter (&static_g_define_type_id)) \ + static _g_type_once_init_type static_g_define_type_id = 0; \ + if (_g_type_once_init_enter (&static_g_define_type_id)) \ { \ GType g_define_type_id = type_name##_get_type_once (); \ - g_once_init_leave (&static_g_define_type_id, g_define_type_id); \ + _g_type_once_init_leave (&static_g_define_type_id, g_define_type_id); \ } \ return static_g_define_type_id; \ } \ @@ -2698,6 +2710,27 @@ const gchar * g_type_name_from_class (GTypeClass *g_class); */ #define G_TYPE_FLAG_RESERVED_ID_BIT ((GType) (1 << 0)) +/** + * GPOINTER_TO_TYPE: + * @p: The pointer to convert to a #GType + * + * This macro should be used instead of GPOINTER_TO_SIZE() to ensure + * portability since #GType is not guaranteed to be the same as #gsize. + * + * Since: 2.80 + */ +#define GPOINTER_TO_TYPE(p) ((GType) (guintptr) (p)) GOBJECT_AVAILABLE_MACRO_IN_2_80 +/** + * GTYPE_TO_POINTER: + * @t: The #GType to convert to a pointer + * + * This macro should be used instead of GSIZE_TO_POINTER() to ensure + * portability since #GType is not guaranteed to be the same as #gsize. + * + * Since: 2.80 + */ +#define GTYPE_TO_POINTER(t) ((gpointer) (guintptr) (t)) GOBJECT_AVAILABLE_MACRO_IN_2_80 + G_END_DECLS #endif /* __G_TYPE_H__ */ diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c index ec95110..b7f61c6 100644 --- a/gobject/gtypemodule.c +++ b/gobject/gtypemodule.c @@ -26,41 +26,40 @@ /** - * SECTION:gtypemodule - * @short_description: Type loading modules - * @see_also: #GTypePlugin, #GModule - * @title: GTypeModule + * GTypeModule: + * @name: the name of the module * - * #GTypeModule provides a simple implementation of the #GTypePlugin + * `GTypeModule` provides a simple implementation of the `GTypePlugin` * interface. * - * The model of #GTypeModule is a dynamically loaded module which + * The model of `GTypeModule` is a dynamically loaded module which * implements some number of types and interface implementations. * * When the module is loaded, it registers its types and interfaces - * using g_type_module_register_type() and g_type_module_add_interface(). + * using [method@GObject.TypeModule.register_type] and + * [method@GObject.TypeModule.add_interface]. * As long as any instances of these types and interface implementations * are in use, the module is kept loaded. When the types and interfaces * are gone, the module may be unloaded. If the types and interfaces * become used again, the module will be reloaded. Note that the last * reference cannot be released from within the module code, since that - * would lead to the caller's code being unloaded before g_object_unref() + * would lead to the caller's code being unloaded before `g_object_unref()` * returns to it. * * Keeping track of whether the module should be loaded or not is done by * using a use count - it starts at zero, and whenever it is greater than * zero, the module is loaded. The use count is maintained internally by * the type system, but also can be explicitly controlled by - * g_type_module_use() and g_type_module_unuse(). Typically, when loading - * a module for the first type, g_type_module_use() will be used to load - * it so that it can initialize its types. At some later point, when the - * module no longer needs to be loaded except for the type - * implementations it contains, g_type_module_unuse() is called. + * [method@GObject.TypeModule.use] and [method@GObject.TypeModule.unuse]. + * Typically, when loading a module for the first type, `g_type_module_use()` + * will be used to load it so that it can initialize its types. At some later + * point, when the module no longer needs to be loaded except for the type + * implementations it contains, `g_type_module_unuse()` is called. * - * #GTypeModule does not actually provide any implementation of module + * `GTypeModule` does not actually provide any implementation of module * loading and unloading. To create a particular module type you must - * derive from #GTypeModule and implement the load and unload functions - * in #GTypeModuleClass. + * derive from `GTypeModule` and implement the load and unload functions + * in `GTypeModuleClass`. */ typedef struct _ModuleTypeInfo ModuleTypeInfo; @@ -116,6 +115,10 @@ g_type_module_finalize (GObject *object) g_free (module->name); + /* in case a subclass does not chain-up to parent in dispose() */ + g_assert (module->type_infos == NULL); + g_assert (module->interface_infos == NULL); + G_OBJECT_CLASS (parent_class)->finalize (object); } diff --git a/gobject/gtypemodule.h b/gobject/gtypemodule.h index e386b50..fba714b 100644 --- a/gobject/gtypemodule.h +++ b/gobject/gtypemodule.h @@ -40,13 +40,6 @@ typedef struct _GTypeModuleClass GTypeModuleClass; G_DEFINE_AUTOPTR_CLEANUP_FUNC(GTypeModule, g_object_unref) -/** - * GTypeModule: - * @name: the name of the module - * - * The members of the GTypeModule structure should not - * be accessed directly, except for the @name field. - */ struct _GTypeModule { GObject parent_instance; diff --git a/gobject/gtypeplugin.c b/gobject/gtypeplugin.c index b6f7f32..d9743f5 100644 --- a/gobject/gtypeplugin.c +++ b/gobject/gtypeplugin.c @@ -23,10 +23,7 @@ /** - * SECTION:gtypeplugin - * @short_description: An interface for dynamically loadable types - * @see_also: #GTypeModule and g_type_register_dynamic(). - * @title: GTypePlugin + * GTypePlugin: * * An interface that handles the lifecycle of dynamically loaded types. * @@ -36,45 +33,45 @@ * 1. The type is initially introduced (usually upon loading the module * the first time, or by your main application that knows what modules * introduces what types), like this: - * |[ + * ```c * new_type_id = g_type_register_dynamic (parent_type_id, * "TypeName", * new_type_plugin, * type_flags); - * ]| - * where @new_type_plugin is an implementation of the - * #GTypePlugin interface. + * ``` + * where `new_type_plugin` is an implementation of the + * `GTypePlugin` interface. * * 2. The type's implementation is referenced, e.g. through - * g_type_class_ref() or through g_type_create_instance() (this is - * being called by g_object_new()) or through one of the above done on - * a type derived from @new_type_id. + * [func@GObject.TypeClass.ref] or through [func@GObject.type_create_instance] + * (this is being called by [ctor@GObject.Object.new]) or through one of the above + * done on a type derived from `new_type_id`. * - * 3. This causes the type system to load the type's implementation by - * calling g_type_plugin_use() and g_type_plugin_complete_type_info() - * on @new_type_plugin. - * - * 4. At some point the type's implementation isn't required anymore, - * e.g. after g_type_class_unref() or g_type_free_instance() (called - * when the reference count of an instance drops to zero). + * 3. This causes the type system to load the type's implementation by calling + * [method@GObject.TypePlugin.use] and [method@GObject.TypePlugin.complete_type_info] + * on `new_type_plugin`. + * + * 4. At some point the type's implementation isn't required anymore, e.g. after + * [method@GObject.TypeClass.unref] or [func@GObject.type_free_instance] + * (called when the reference count of an instance drops to zero). * * 5. This causes the type system to throw away the information retrieved - * from g_type_plugin_complete_type_info() and then it calls - * g_type_plugin_unuse() on @new_type_plugin. - * + * from [method@GObject.TypePlugin.complete_type_info] and then it calls + * [method@GObject.TypePlugin.unuse] on `new_type_plugin`. + * * 6. Things may repeat from the second step. * - * So basically, you need to implement a #GTypePlugin type that + * So basically, you need to implement a `GTypePlugin` type that * carries a use_count, once use_count goes from zero to one, you need * to load the implementation to successfully handle the upcoming - * g_type_plugin_complete_type_info() call. Later, maybe after + * [method@GObject.TypePlugin.complete_type_info] call. Later, maybe after * succeeding use/unuse calls, once use_count drops to zero, you can * unload the implementation again. The type system makes sure to call - * g_type_plugin_use() and g_type_plugin_complete_type_info() again - * when the type is needed again. + * [method@GObject.TypePlugin.use] and [method@GObject.TypePlugin.complete_type_info] + * again when the type is needed again. * - * #GTypeModule is an implementation of #GTypePlugin that already - * implements most of this except for the actual module loading and + * [class@GObject.TypeModule] is an implementation of `GTypePlugin` that + * already implements most of this except for the actual module loading and * unloading. It even handles multiple registered types per module. */ diff --git a/gobject/gtypeplugin.h b/gobject/gtypeplugin.h index 3711932..c950dfb 100644 --- a/gobject/gtypeplugin.h +++ b/gobject/gtypeplugin.h @@ -81,12 +81,6 @@ typedef void (*GTypePluginCompleteInterfaceInfo) (GTypePlugin *plugin, GType interface_type, GInterfaceInfo *info); /** - * GTypePlugin: - * - * The GTypePlugin typedef is used as a placeholder - * for objects that implement the GTypePlugin interface. - */ -/** * GTypePluginClass: * @use_plugin: Increases the use count of the plugin. * @unuse_plugin: Decreases the use count of the plugin. diff --git a/gobject/gvalue.c b/gobject/gvalue.c index 10885da..9d974fa 100644 --- a/gobject/gvalue.c +++ b/gobject/gvalue.c @@ -31,122 +31,6 @@ #include "gtype-private.h" -/** - * SECTION:generic_values - * @short_description: A polymorphic type that can hold values of any - * other type - * @see_also: The fundamental types which all support #GValue - * operations and thus can be used as a type initializer for - * g_value_init() are defined by a separate interface. See the - * [standard values API][gobject-Standard-Parameter-and-Value-Types] - * for details - * @title: Generic values - * - * The #GValue structure is basically a variable container that consists - * of a type identifier and a specific value of that type. - * - * The type identifier within a #GValue structure always determines the - * type of the associated value. - * - * To create an undefined #GValue structure, simply create a zero-filled - * #GValue structure. To initialize the #GValue, use the g_value_init() - * function. A #GValue cannot be used until it is initialized. Before - * destruction you must always use g_value_unset() to make sure allocated - * memory is freed. - * - * The basic type operations (such as freeing and copying) are determined - * by the #GTypeValueTable associated with the type ID stored in the #GValue. - * Other #GValue operations (such as converting values between types) are - * provided by this interface. - * - * The code in the example program below demonstrates #GValue's - * features. - * - * |[ - * #include - * - * static void - * int2string (const GValue *src_value, - * GValue *dest_value) - * { - * if (g_value_get_int (src_value) == 42) - * g_value_set_static_string (dest_value, "An important number"); - * else - * g_value_set_static_string (dest_value, "What's that?"); - * } - * - * int - * main (int argc, - * char *argv[]) - * { - * // GValues must be initialized - * GValue a = G_VALUE_INIT; - * GValue b = G_VALUE_INIT; - * const gchar *message; - * - * // The GValue starts empty - * g_assert (!G_VALUE_HOLDS_STRING (&a)); - * - * // Put a string in it - * g_value_init (&a, G_TYPE_STRING); - * g_assert (G_VALUE_HOLDS_STRING (&a)); - * g_value_set_static_string (&a, "Hello, world!"); - * g_printf ("%s\n", g_value_get_string (&a)); - * - * // Reset it to its pristine state - * g_value_unset (&a); - * - * // It can then be reused for another type - * g_value_init (&a, G_TYPE_INT); - * g_value_set_int (&a, 42); - * - * // Attempt to transform it into a GValue of type STRING - * g_value_init (&b, G_TYPE_STRING); - * - * // An INT is transformable to a STRING - * g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING)); - * - * g_value_transform (&a, &b); - * g_printf ("%s\n", g_value_get_string (&b)); - * - * // Attempt to transform it again using a custom transform function - * g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string); - * g_value_transform (&a, &b); - * g_printf ("%s\n", g_value_get_string (&b)); - * return 0; - * } - * ]| - * - * See also [gobject-Standard-Parameter-and-Value-Types] for more information on - * validation of #GValue. - * - * For letting a #GValue own (and memory manage) arbitrary types or pointers, - * they need to become a [boxed type][gboxed]. The example below shows how - * the pointer `mystruct` of type `MyStruct` is used as a [boxed type][gboxed]. - * - * |[ - * typedef struct { ... } MyStruct; - * G_DEFINE_BOXED_TYPE (MyStruct, my_struct, my_struct_copy, my_struct_free) - * - * // These two lines normally go in a public header. By GObject convention, - * // the naming scheme is NAMESPACE_TYPE_NAME: - * #define MY_TYPE_STRUCT (my_struct_get_type ()) - * GType my_struct_get_type (void); - * - * void - * foo () - * { - * GValue *value = g_new0 (GValue, 1); - * g_value_init (value, MY_TYPE_STRUCT); - * g_value_set_boxed (value, mystruct); - * // [... your code ....] - * g_value_unset (value); - * g_free (value); - * } - * ]| - */ - - /* --- typedefs & structures --- */ typedef struct { GType src_type; diff --git a/gobject/gvaluearray.c b/gobject/gvaluearray.c index 07b2ffb..581503b 100644 --- a/gobject/gvaluearray.c +++ b/gobject/gvaluearray.c @@ -30,35 +30,35 @@ /** - * SECTION:value_arrays - * @short_description: A container structure to maintain an array of - * generic values - * @see_also: #GValue, #GParamSpecValueArray, g_param_spec_value_array() - * @title: Value arrays - * - * The prime purpose of a #GValueArray is for it to be used as an - * object property that holds an array of values. A #GValueArray wraps - * an array of #GValue elements in order for it to be used as a boxed - * type through %G_TYPE_VALUE_ARRAY. - * - * #GValueArray is deprecated in favour of #GArray since GLib 2.32. It - * is possible to create a #GArray that behaves like a #GValueArray by - * using the size of #GValue as the element size, and by setting - * g_value_unset() as the clear function using g_array_set_clear_func(), - * for instance, the following code: - * - * |[ + * GValueArray: + * @n_values: number of values contained in the array + * @values: array of values + * + * A `GValueArray` is a container structure to hold an array of generic values. + * + * The prime purpose of a `GValueArray` is for it to be used as an + * object property that holds an array of values. A `GValueArray` wraps + * an array of `GValue` elements in order for it to be used as a boxed + * type through `G_TYPE_VALUE_ARRAY`. + * + * `GValueArray` is deprecated in favour of `GArray` since GLib 2.32. + * It is possible to create a `GArray` that behaves like a `GValueArray` + * by using the size of `GValue` as the element size, and by setting + * [method@GObject.Value.unset] as the clear function using + * [func@GLib.Array.set_clear_func], for instance, the following code: + * + * ```c * GValueArray *array = g_value_array_new (10); - * ]| + * ``` * * can be replaced by: * - * |[ + * ```c * GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (GValue), 10); * g_array_set_clear_func (array, (GDestroyNotify) g_value_unset); - * ]| + * ``` * - * Deprecated: 2.32: Use #GArray instead, if possible for the given use case, + * Deprecated: 2.32: Use `GArray` instead, if possible for the given use case, * as described above. */ diff --git a/gobject/gvaluearray.h b/gobject/gvaluearray.h index 72aa91b..d6052c0 100644 --- a/gobject/gvaluearray.h +++ b/gobject/gvaluearray.h @@ -41,13 +41,6 @@ G_BEGIN_DECLS /* --- typedefs & structs --- */ typedef struct _GValueArray GValueArray; -/** - * GValueArray: - * @n_values: number of values contained in the array - * @values: array of values - * - * A #GValueArray contains an array of #GValue elements. - */ struct _GValueArray { guint n_values; diff --git a/gobject/gvaluecollector.h b/gobject/gvaluecollector.h index 7e7ae02..35608b1 100644 --- a/gobject/gvaluecollector.h +++ b/gobject/gvaluecollector.h @@ -18,17 +18,7 @@ * * gvaluecollector.h: GValue varargs stubs */ -/** - * SECTION:value_collection - * @Short_description: Converting varargs to generic values - * @Title: Varargs Value Collection - * - * The macros in this section provide the varargs parsing support needed - * in variadic GObject functions such as g_object_new() or g_object_set(). - * - * They currently support the collection of integral types, floating point - * types and pointers. - */ + #ifndef __G_VALUE_COLLECTOR_H__ #define __G_VALUE_COLLECTOR_H__ diff --git a/gobject/gvaluetypes.c b/gobject/gvaluetypes.c index f490584..6ed6d9c 100644 --- a/gobject/gvaluetypes.c +++ b/gobject/gvaluetypes.c @@ -1160,6 +1160,41 @@ g_value_dup_string (const GValue *value) } /** + * g_value_steal_string: + * @value: a valid #GValue of type %G_TYPE_STRING + * + * Steal ownership on contents of a %G_TYPE_STRING #GValue. + * As a result of this operation the value's contents will be reset to %NULL. + * + * The purpose of this call is to provide a way to avoid an extra copy + * when some object have been serialized into string through #GValue API. + * + * NOTE: for safety and compatibility purposes, if #GValue contains + * static string, or an interned one, this function will return a copy + * of the string. Otherwise the transfer notation would be ambiguous. + * + * Returns: (nullable) (transfer full): string content of @value; + * Should be freed with g_free() when no longer needed. + * + * Since: 2.80 + */ +gchar* +g_value_steal_string (GValue *value) +{ + gchar *ret; + + g_return_val_if_fail (G_VALUE_HOLDS_STRING (value), NULL); + + ret = value->data[0].v_pointer; + value->data[0].v_pointer = NULL; + + if (value->data[1].v_uint & G_VALUE_NOCOPY_CONTENTS) + return g_strdup (ret); + + return ret; +} + +/** * g_value_set_pointer: * @value: a valid #GValue of %G_TYPE_POINTER * @v_pointer: pointer value to be set @@ -1208,7 +1243,7 @@ g_value_set_gtype (GValue *value, { g_return_if_fail (G_VALUE_HOLDS_GTYPE (value)); - value->data[0].v_pointer = GSIZE_TO_POINTER (v_gtype); + value->data[0].v_pointer = GTYPE_TO_POINTER (v_gtype); } @@ -1227,7 +1262,7 @@ g_value_get_gtype (const GValue *value) { g_return_val_if_fail (G_VALUE_HOLDS_GTYPE (value), 0); - return GPOINTER_TO_SIZE (value->data[0].v_pointer); + return GPOINTER_TO_TYPE (value->data[0].v_pointer); } /** diff --git a/gobject/gvaluetypes.h b/gobject/gvaluetypes.h index 0c8d0f6..afa6595 100644 --- a/gobject/gvaluetypes.h +++ b/gobject/gvaluetypes.h @@ -263,6 +263,8 @@ GOBJECT_AVAILABLE_IN_ALL const gchar * g_value_get_string (const GValue *value); GOBJECT_AVAILABLE_IN_ALL gchar* g_value_dup_string (const GValue *value); +GOBJECT_AVAILABLE_IN_2_80 +gchar* g_value_steal_string (GValue *value); GOBJECT_AVAILABLE_IN_ALL void g_value_set_pointer (GValue *value, gpointer v_pointer); diff --git a/gobject/tests/genmarshal.py b/gobject/tests/genmarshal.py index 1062dfe..e2ecf74 100644 --- a/gobject/tests/genmarshal.py +++ b/gobject/tests/genmarshal.py @@ -88,6 +88,7 @@ class TestGenmarshal(unittest.TestCase): env = os.environ.copy() env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" print("Environment:", env) # We want to ensure consistent line endings... diff --git a/gobject/tests/gobject-query.py b/gobject/tests/gobject-query.py index 618b6ba..aab03be 100644 --- a/gobject/tests/gobject-query.py +++ b/gobject/tests/gobject-query.py @@ -59,6 +59,7 @@ class TestGobjectQuery(unittest.TestCase): env = os.environ.copy() env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" print("Environment:", env) # We want to ensure consistent line endings... diff --git a/gobject/tests/meson.build b/gobject/tests/meson.build index 23f131b..713c1d7 100644 --- a/gobject/tests/meson.build +++ b/gobject/tests/meson.build @@ -83,6 +83,7 @@ gobject_tests = { 'binding' : {}, 'bindinggroup' : {}, 'properties' : {}, + 'properties-introspection' : {}, 'reference' : {}, 'flags' : {}, 'value' : {}, diff --git a/gobject/tests/mkenums.py b/gobject/tests/mkenums.py index 0b40dae..8e92730 100644 --- a/gobject/tests/mkenums.py +++ b/gobject/tests/mkenums.py @@ -100,6 +100,7 @@ class TestMkenums(unittest.TestCase): env = os.environ.copy() env["LC_ALL"] = "C.UTF-8" + env["G_DEBUG"] = "fatal-warnings" print("Environment:", env) # We want to ensure consistent line endings... @@ -784,6 +785,32 @@ comment: {standard_bottom_comment} "7", ) + def test_comma_in_enum_value(self): + """Test use of comma in enum value.""" + h_contents = """ + typedef enum { + ENUM_VALUE_WITH_COMMA = ',', + } TestCommaEnum; + """ + + result = self.runMkenumsWithHeader(h_contents) + self.assertEqual("", result.err) + self.assertSingleEnum( + result, + "TestCommaEnum", + "test_comma_enum", + "TEST_COMMA_ENUM", + "COMMA_ENUM", + "TEST", + "", + "enum", + "Enum", + "ENUM", + "ENUM_VALUE_WITH_COMMA", + "comma", + 44, + ) + class TestRspMkenums(TestMkenums): """Run all tests again in @rspfile mode""" diff --git a/gobject/tests/param.c b/gobject/tests/param.c index 08bc80f..f227e59 100644 --- a/gobject/tests/param.c +++ b/gobject/tests/param.c @@ -1624,6 +1624,23 @@ test_param_spec_custom (void) g_param_spec_unref (pspec); } +static void +test_param_spec_pool (void) +{ + GParamSpecPool *pool = g_param_spec_pool_new (FALSE); + GParamSpec *pspec = g_param_spec_int ("int", NULL, NULL, -1, 100, -1, G_PARAM_READWRITE); + GParamSpec *check = NULL; + + g_param_spec_pool_insert (pool, g_param_spec_ref_sink (pspec), G_TYPE_OBJECT); + check = g_param_spec_pool_lookup (pool, "int", G_TYPE_OBJECT, FALSE); + g_assert_true (check->owner_type == G_TYPE_OBJECT); + + g_param_spec_pool_remove (pool, pspec); + g_assert_null (g_param_spec_pool_lookup (pool, "int", G_TYPE_OBJECT, FALSE)); + + g_param_spec_pool_free (pool); +} + int main (int argc, char *argv[]) { @@ -1680,6 +1697,7 @@ main (int argc, char *argv[]) g_test_add_func ("/paramspec/variant", test_param_spec_variant); g_test_add_func ("/paramspec/variant/cmp", test_param_spec_variant_cmp); g_test_add_func ("/paramspec/custom", test_param_spec_custom); + g_test_add_func ("/paramspec/pool", test_param_spec_pool); return g_test_run (); } diff --git a/gobject/tests/performance/meson.build b/gobject/tests/performance/meson.build index 2984a6c..0147f7c 100644 --- a/gobject/tests/performance/meson.build +++ b/gobject/tests/performance/meson.build @@ -1,5 +1,9 @@ gobject_tests = { - 'performance' : { 'args' : [ '--seconds', '0' ] }, + 'performance' : { + 'args' : [ '--seconds', '0' ], + # FIXME: https://gitlab.gnome.org/GNOME/glib/-/issues/3148 + 'can_fail' : host_system == 'gnu', + }, 'performance-threaded' : { 'args' : [ '--seconds', '0' ] }, } diff --git a/gobject/tests/properties-introspection.c b/gobject/tests/properties-introspection.c new file mode 100644 index 0000000..ac72330 --- /dev/null +++ b/gobject/tests/properties-introspection.c @@ -0,0 +1,114 @@ +/* properties-introspection.c: Test the properties introspection API + * + * SPDX-FileCopyrightText: 2023 Emmanuele Bassi + * SPDX-License-Identifier: LGPL-2.1-or-later + */ + +/* This test is isolated so we can control the initialization of + * GObjectClass, and the global GParamSpecPool + */ + +#include +#include + +G_DECLARE_INTERFACE (MyTestable, my_testable, MY, TESTABLE, GObject) + +struct _MyTestableInterface +{ + GTypeInterface g_iface; +}; + +G_DEFINE_INTERFACE (MyTestable, my_testable, G_TYPE_OBJECT) + +static void +my_testable_default_init (MyTestableInterface *iface) +{ + g_object_interface_install_property (iface, + g_param_spec_int ("check", NULL, NULL, -1, 10, 0, G_PARAM_READWRITE)); +} + +static void +properties_introspection (void) +{ + g_test_summary ("Verify that introspecting properties on an interface initializes the GParamSpecPool."); + + if (g_test_subprocess ()) + { + gpointer klass = g_type_default_interface_ref (my_testable_get_type ()); + g_assert_nonnull (klass); + + GParamSpec *pspec = g_object_interface_find_property (klass, "check"); + g_assert_nonnull (pspec); + + g_type_default_interface_unref (klass); + return; + } + + g_test_trap_subprocess (NULL, 0, G_TEST_SUBPROCESS_DEFAULT); + g_test_trap_assert_passed (); + g_test_trap_assert_stderr (""); +} + +static gpointer +inspect_func (gpointer data) +{ + unsigned int *n_checks = data; /* (atomic) */ + + gpointer klass = NULL; + do + { + klass = g_type_default_interface_ref (my_testable_get_type ()); + } + while (klass == NULL); + + GParamSpec *pspec = NULL; + do + { + pspec = g_object_interface_find_property (klass, "check"); + } + while (pspec == NULL); + + g_type_default_interface_unref (klass); + + g_atomic_int_inc (n_checks); + + return NULL; +} + +#define N_THREADS 10 + +static void +properties_collision (void) +{ + GThread *threads[N_THREADS]; + unsigned int n_checks = 0; /* (atomic) */ + + g_test_summary ("Verify that multiple threads create a single GParamSpecPool."); + + for (unsigned int i = 0; i < N_THREADS; i++) + { + char *t_name = g_strdup_printf ("inspect [%d]", i); + threads[i] = g_thread_new (t_name, inspect_func, &n_checks); + g_assert_nonnull (threads[i]); + g_free (t_name); + } + + while (g_atomic_int_get (&n_checks) != N_THREADS) + g_usleep (50); + + for (unsigned int i = 0; i < N_THREADS; i++) + g_thread_join (threads[i]); +} + +#undef N_THREADS + +int +main (int argc, char *argv[]) +{ + g_test_init (&argc, &argv, NULL); + + g_test_add_func ("/properties/introspection", properties_introspection); + g_test_add_func ("/properties/collision", properties_collision); + + return g_test_run (); +} diff --git a/gobject/tests/signals.c b/gobject/tests/signals.c index 92a2882..834fdd6 100644 --- a/gobject/tests/signals.c +++ b/gobject/tests/signals.c @@ -66,9 +66,9 @@ custom_marshal_VOID__INVOCATIONHINT (GClosure *closure, static GType test_enum_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { static const GEnumValue values[] = { { TEST_ENUM_NEGATIVE, "TEST_ENUM_NEGATIVE", "negative" }, @@ -79,7 +79,7 @@ test_enum_get_type (void) }; GType g_define_type_id = g_enum_register_static (g_intern_static_string ("TestEnum"), values); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; @@ -88,9 +88,9 @@ test_enum_get_type (void) static GType test_unsigned_enum_get_type (void) { - static gsize static_g_define_type_id = 0; + static GType static_g_define_type_id = 0; - if (g_once_init_enter (&static_g_define_type_id)) + if (g_once_init_enter_pointer (&static_g_define_type_id)) { static const GEnumValue values[] = { { TEST_UNSIGNED_ENUM_FOO, "TEST_UNSIGNED_ENUM_FOO", "foo" }, @@ -99,7 +99,7 @@ test_unsigned_enum_get_type (void) }; GType g_define_type_id = g_enum_register_static (g_intern_static_string ("TestUnsignedEnum"), values); - g_once_init_leave (&static_g_define_type_id, g_define_type_id); + g_once_init_leave_pointer (&static_g_define_type_id, g_define_type_id); } return static_g_define_type_id; @@ -2045,6 +2045,44 @@ test_emitv (void) g_array_unref (values); } +typedef struct +{ + GWeakRef wr; + gulong handler; +} TestWeakRefDisconnect; + +static void +weak_ref_disconnect_notify (gpointer data, + GObject *where_object_was) +{ + TestWeakRefDisconnect *state = data; + g_assert_null (g_weak_ref_get (&state->wr)); + state->handler = 0; +} + +static void +test_weak_ref_disconnect (void) +{ + TestWeakRefDisconnect state; + GObject *test; + + test = g_object_new (test_get_type (), NULL); + g_weak_ref_init (&state.wr, test); + state.handler = g_signal_connect_data (test, + "simple", + G_CALLBACK (dont_reach), + &state, + (GClosureNotify) weak_ref_disconnect_notify, + 0); + g_assert_cmpint (state.handler, >, 0); + + g_object_unref (test); + + g_assert_cmpint (state.handler, ==, 0); + g_assert_null (g_weak_ref_get (&state.wr)); + g_weak_ref_clear (&state.wr); +} + /* --- */ int @@ -2083,6 +2121,7 @@ main (int argc, g_test_add_data_func ("/gobject/signals/invalid-name/first-char", "7zip", test_signals_invalid_name); g_test_add_data_func ("/gobject/signals/invalid-name/empty", "", test_signals_invalid_name); g_test_add_func ("/gobject/signals/is-valid-name", test_signal_is_valid_name); + g_test_add_func ("/gobject/signals/weak-ref-disconnect", test_weak_ref_disconnect); return g_test_run (); } diff --git a/gobject/tests/type-flags.c b/gobject/tests/type-flags.c index bb67f8c..a8d13d4 100644 --- a/gobject/tests/type-flags.c +++ b/gobject/tests/type-flags.c @@ -121,7 +121,7 @@ test_type_flags_final (void) * block within the test_final2_get_type() function */ g_test_expect_message ("GLib", G_LOG_LEVEL_CRITICAL, - "*g_once_init_leave: assertion*"); + "*g_once_init_leave_pointer: assertion*"); final2_type = TEST_TYPE_FINAL2; g_assert_true (final2_type == G_TYPE_INVALID); diff --git a/gobject/tests/value.c b/gobject/tests/value.c index 73a5de6..d1a9091 100644 --- a/gobject/tests/value.c +++ b/gobject/tests/value.c @@ -420,7 +420,7 @@ test_value_string (void) const gchar *static2 = "static2"; const gchar *storedstr; const gchar *copystr; - gchar *str1, *str2; + gchar *str1, *str2, *stolen_str; GValue value = G_VALUE_INIT; GValue copy = G_VALUE_INIT; @@ -513,7 +513,12 @@ test_value_string (void) g_assert_true (storedstr != static2); g_assert_cmpstr (storedstr, ==, static2); + /* Now check stealing the ownership of the contents */ + stolen_str = g_value_steal_string (&value); + g_assert_null (g_value_get_string (&value)); g_value_unset (&value); + g_assert_cmpstr (stolen_str, ==, static2); + g_free (stolen_str); /* * Static strings @@ -544,6 +549,14 @@ test_value_string (void) g_assert_true (storedstr != static1); g_assert_cmpstr (storedstr, ==, static2); + /* Check if g_value_steal_string() can handle GValue + * with a static string */ + stolen_str = g_value_steal_string (&value); + g_assert_true (stolen_str != static2); + g_assert_cmpstr (stolen_str, ==, static2); + g_assert_null (g_value_get_string (&value)); + g_free (stolen_str); + g_value_unset (&value); /* @@ -588,6 +601,14 @@ test_value_string (void) g_assert_true (storedstr != static2); g_assert_cmpstr (storedstr, ==, static2); + /* Check if g_value_steal_string() can handle GValue + * with an interned string */ + stolen_str = g_value_steal_string (&value); + g_assert_true (stolen_str != static2); + g_assert_cmpstr (stolen_str, ==, static2); + g_assert_null (g_value_get_string (&value)); + g_free (stolen_str); + g_value_unset (&value); } diff --git a/introspection/meson.build b/introspection/meson.build new file mode 100644 index 0000000..3e99389 --- /dev/null +++ b/introspection/meson.build @@ -0,0 +1,159 @@ + +gi_identifier_prefix = 'G' +gi_symbol_prefix = 'g' + +gi_gen_shared_sources = [ + # Required to compile gdump + gmodule_visibility_h, +] + +gi_gen_env_variables = environment() + +if get_option('b_sanitize') != '' + gi_gen_env_variables.append( + 'ASAN_OPTIONS', 'verify_asan_link_order=0', separator: ',') +endif + +# GLib +glib_gir = gnome.generate_gir(libglib, + sources: [ + gi_gen_shared_sources, + glibconfig_h, + gversionmacros_h, + glib_visibility_h, + glib_headers, + glib_deprecated_headers, + glib_sub_headers, + glib_enumtypes_h, + glib_types_h, + glib_deprecated_sources, + glib_sources, + ], + namespace: 'GLib', + nsversion: '2.0', + identifier_prefix: gi_identifier_prefix, + symbol_prefix: gi_symbol_prefix, + export_packages: 'glib-2.0', + header: 'glib.h', + install: true, + dependencies: [ + libgobject_dep, + ], + env: gi_gen_env_variables, + extra_args: gir_args + [ + '-DGLIB_COMPILATION', + '-DGETTEXT_PACKAGE="dummy"', + '--symbol-prefix=glib', + '--library-path=' + meson.current_build_dir(), + '--library=gobject-2.0', + ], +) + +# GObject +gobject_gir = gnome.generate_gir(libgobject, + sources: [ + gi_gen_shared_sources, + gobject_visibility_h, + gobject_install_headers, + gobject_sources, + ], + namespace: 'GObject', + nsversion: '2.0', + identifier_prefix: gi_identifier_prefix, + symbol_prefix: gi_symbol_prefix, + export_packages: 'gobject-2.0', + header: 'glib-object.h', + includes: [ glib_gir[0] ], + install: true, + env: gi_gen_env_variables, + extra_args: gir_args + [ + '-DGOBJECT_COMPILATION', + '--symbol-prefix=gobject', + ], +) + +# GModule +gmodule_gir = gnome.generate_gir(libgmodule, + sources: [ + gi_gen_shared_sources, + gmoduleconf_h, + gmodule_h, + gmodule_c, + gmodule_deprecated_c, + gmodule_visibility_h, + ], + namespace: 'GModule', + nsversion: '2.0', + identifier_prefix: gi_identifier_prefix, + symbol_prefix: gi_symbol_prefix, + export_packages: 'gmodule-2.0', + header: 'gmodule.h', + includes: [ glib_gir[0] ], + install: true, + dependencies: [ + libglib_dep, + ], + env: gi_gen_env_variables, + extra_args: gir_args + [ + '-DGMODULE_COMPILATION', + '-DGETTEXT_PACKAGE="dummy"', + '--symbol-prefix=gmodule', + ], +) + +# Gio +gio_gir_sources = [ + gi_gen_shared_sources, + gio_visibility_h, + gioenumtypes_h, + gnetworking_h, + gio_headers, + gio_base_sources, + application_sources, + gdbus_sources, + appinfo_sources, + contenttype_sources, + unix_sources, + win32_sources, + settings_sources, +] +gio_gir_packages = [ 'gio-2.0' ] +gio_gir_args = [ + '-DGIO_COMPILATION', + '-DG_SETTINGS_ENABLE_BACKEND', + '--symbol-prefix=gio', +] +if host_system == 'windows' + gio_gir_sources += gio_win32_include_headers + foreach h: gio_win32_include_headers + gio_gir_args += '--c-include=@0@'.format(h) + endforeach + gio_gir_packages += 'gio-win32-2.0' + gio_gir_args += '--pkg=gio-win32-2.0' +else + gio_gir_sources += gio_unix_include_headers + foreach h: gio_unix_include_headers + gio_gir_args += '--c-include=@0@'.format(h) + endforeach + gio_gir_packages += 'gio-unix-2.0' + gio_gir_args += '--pkg=gio-unix-2.0' +endif + +gio_gir = gnome.generate_gir(libgio, + sources: gio_gir_sources, + namespace: 'Gio', + nsversion: '2.0', + identifier_prefix: gi_identifier_prefix, + symbol_prefix: gi_symbol_prefix, + export_packages: gio_gir_packages, + header: 'gio/gio.h', + includes: [ glib_gir[0], gmodule_gir[0], gobject_gir[0] ], + install: true, + dependencies: [ + libglib_dep, + libgobject_dep, + libgmodule_dep, + ], + env: gi_gen_env_variables, + extra_args: gir_args + gio_gir_args, +) diff --git a/meson.build b/meson.build index 47b382b..a868601 100644 --- a/meson.build +++ b/meson.build @@ -1,7 +1,7 @@ project('glib', 'c', - version : '2.78.6', + version : '2.79.0', # NOTE: See the policy in docs/meson-version.md before changing the Meson dependency - meson_version : '>= 0.60.0', + meson_version : '>= 1.2.0', default_options : [ 'buildtype=debugoptimized', 'warning_level=3', @@ -65,6 +65,17 @@ if host_system == 'darwin' endif endif +linux_libc = '' +if host_system == 'linux' + musl_test_code = '''#include + #if defined __GLIBC__ || defined __UCLIBC__ + #error "Not in glibc or uclibc" + #endif''' + if cc.compiles(musl_test_code, name : 'building for musl libc') + linux_libc = 'musl' + endif +endif + glib_version = meson.project_version() glib_api_version = '2.0' version_arr = glib_version.split('.') @@ -87,6 +98,7 @@ glibinc = include_directories('glib') gobjectinc = include_directories('gobject') gmoduleinc = include_directories('gmodule') gioinc = include_directories('gio') +girepoinc = include_directories('girepository') glib_prefix = get_option('prefix') glib_bindir = join_paths(glib_prefix, get_option('bindir')) @@ -213,6 +225,10 @@ if host_system == 'qnx' add_project_arguments('-D_QNX_SOURCE', language: 'c') endif +if host_system == 'windows' + add_project_arguments(['-DUNICODE', '-D_UNICODE'], language: 'c') +endif + # Disable strict aliasing; # see https://bugzilla.gnome.org/show_bug.cgi?id=791622 if cc.has_argument('-fno-strict-aliasing') @@ -359,6 +375,7 @@ headers = [ 'fstab.h', 'grp.h', 'inttypes.h', + 'libproc.h', 'limits.h', 'locale.h', 'mach/mach_time.h', @@ -629,6 +646,7 @@ functions = [ 'free_aligned_sized', 'free_sized', 'fsync', + 'ftruncate64', 'getauxval', 'getc_unlocked', 'getfsstat', @@ -1281,6 +1299,7 @@ if cc.links('''#include endif # Check for nl_langinfo and LC_TIME parts that are needed in gdatetime.c +have_langinfo_time = false if cc.links('''#include int main (int argc, char ** argv) { char *str; @@ -1295,8 +1314,27 @@ if cc.links('''#include str = nl_langinfo (ABDAY_7); return 0; }''', name : 'nl_langinfo (PM_STR)') + have_langinfo_time = true glib_conf.set('HAVE_LANGINFO_TIME', 1) endif + +# Linux glibc supports ERA, but FreeBSD and macOS don’t +if cc.links('''#include + int main (int argc, char **argv) { + char *str; + str = nl_langinfo (ERA); + str = nl_langinfo (ERA_D_T_FMT); + str = nl_langinfo (ERA_D_FMT); + str = nl_langinfo (ERA_T_FMT); + str = nl_langinfo (_NL_TIME_ERA_NUM_ENTRIES); + return 0; + }''', name : 'nl_langinfo (ERA)') + glib_conf.set('HAVE_LANGINFO_ERA', 1) + if not have_langinfo_time + error('nl_langinfo(ERA) is supported but more basic nl_langinfo() functionality like PM_STR is not') + endif +endif + if cc.links('''#include int main (int argc, char ** argv) { char *str; @@ -1313,6 +1351,9 @@ if cc.links('''#include return 0; }''', name : 'nl_langinfo (_NL_CTYPE_OUTDIGITn_MB)') glib_conf.set('HAVE_LANGINFO_OUTDIGIT', 1) + if not have_langinfo_time + error('nl_langinfo(_NL_CTYPE_OUTDIGITn_MB) is supported but more basic nl_langinfo() functionality like PM_STR is not') + endif endif # Check for nl_langinfo and alternative month names @@ -1337,6 +1378,9 @@ if cc.links('''#ifndef _GNU_SOURCE return 0; }''', name : 'nl_langinfo (ALTMON_n)') glib_conf.set('HAVE_LANGINFO_ALTMON', 1) + if not have_langinfo_time + error('nl_langinfo(ALTMON_n) is supported but more basic nl_langinfo() functionality like PM_STR is not') + endif endif # Check for nl_langinfo and abbreviated alternative month names @@ -1361,6 +1405,9 @@ if cc.links('''#ifndef _GNU_SOURCE return 0; }''', name : 'nl_langinfo (_NL_ABALTMON_n)') glib_conf.set('HAVE_LANGINFO_ABALTMON', 1) + if not have_langinfo_time + error('nl_langinfo(_NL_ABALTMON_n) is supported but more basic nl_langinfo() functionality like PM_STR is not') + endif endif # Check for nl_langinfo and _NL_TIME_CODESET @@ -1370,6 +1417,9 @@ if cc.links('''#include return 0; }''', name : 'nl_langinfo and _NL_TIME_CODESET') glib_conf.set('HAVE_LANGINFO_TIME_CODESET', 1) + if not have_langinfo_time + error('nl_langinfo(_NL_TIME_CODESET) is supported but more basic nl_langinfo() functionality like PM_STR is not') + endif endif # Check if C compiler supports the 'signed' keyword @@ -1649,7 +1699,7 @@ if cc.get_id() == 'gcc' or cc.get_id() == 'clang' g_sizet_compatibility += { type_name: size_compatibility and cc.compiles( '''#include - size_t f (size_t *i) { return *i + 1; } + static size_t f (size_t *i) { return *i + 1; } int main (void) { unsigned ''' + type_name + ''' i = 0; f (&i); @@ -2326,12 +2376,12 @@ endif glib_conf.set('HAVE_PROC_SELF_CMDLINE', have_proc_self_cmdline) -python = import('python').find_installation() +python = import('python').find_installation(modules: ['packaging']) # used for '#!/usr/bin/env ' python_name = 'python3' python_version = python.language_version() -python_version_req = '>=3.5' +python_version_req = '>=3.7' if not python_version.version_compare(python_version_req) error('Requires Python @0@, @1@ found.'.format(python_version_req, python_version)) endif @@ -2456,14 +2506,32 @@ if want_systemtap and enable_dtrace enable_systemtap = true endif +# introspection +gir_scanner = find_program('g-ir-scanner', required: get_option('introspection')) +enable_gir = get_option('introspection').allowed() and gir_scanner.found() and meson.can_run_host_binaries() + +if get_option('introspection').enabled() and not meson.can_run_host_binaries() + error('Running binaries on the build host needs to be supported to build with -Dintrospection=enabled') +endif + +gir_args = [ + '--quiet', +] + pkg = import('pkgconfig') windows = import('windows') +gnome = import('gnome') + subdir('tools') subdir('glib') subdir('gobject') subdir('gthread') subdir('gmodule') subdir('gio') +if enable_gir + subdir('introspection') +endif +subdir('girepository') subdir('fuzzing') # xgettext is optional (on Windows for instance) @@ -2493,19 +2561,10 @@ endif configure_file(output : 'config.h', configuration : glib_conf) -if get_option('man') - xsltproc = find_program('xsltproc', required : true) - xsltproc_command = [ - xsltproc, - '--nonet', - '--stringparam', 'man.output.quietly', '1', - '--stringparam', 'funcsynopsis.style', 'ansi', - '--stringparam', 'man.th.extra1.suppress', '1', - '--stringparam', 'man.authors.section.enabled', '0', - '--stringparam', 'man.copyright.section.enabled', '0', - '-o', '@OUTPUT@', - 'http://docbook.sourceforge.net/release/xsl/current/manpages/docbook.xsl', - '@INPUT@', +rst2man = find_program('rst2man', 'rst2man.py', required: get_option('man-pages')) +if rst2man.found() + rst2man_flags = [ + '--syntax-highlight=none', ] man1_dir = join_paths(glib_prefix, get_option('mandir'), 'man1') endif @@ -2531,6 +2590,12 @@ if build_machine.system() != host_system }, section: 'Build environment') endif +if linux_libc != '' + summary({ + 'linux_libc' : linux_libc + }, section: 'Build environment') +endif + summary({ 'prefix' : glib_prefix, 'bindir' : glib_bindir, @@ -2563,11 +2628,11 @@ endif summary({ 'xattr' : xattr_dep.length() > 0, - 'man' : get_option('man'), + 'man-pages' : get_option('man-pages'), 'dtrace' : get_option('dtrace'), 'systemtap' : enable_systemtap, 'sysprof' : libsysprof_capture_dep.found(), - 'gtk_doc' : get_option('gtk_doc'), + 'documentation' : get_option('documentation'), 'bsymbolic_functions' : get_option('bsymbolic_functions'), 'force_posix_threads' : get_option('force_posix_threads'), 'tests' : get_option('tests'), @@ -2579,4 +2644,5 @@ summary({ 'glib_checks' : get_option('glib_checks'), 'libelf' : get_option('libelf'), 'multiarch' : get_option('multiarch'), + 'introspection' : enable_gir, }, section: 'Options') diff --git a/meson_options.txt b/meson_options.txt index 517d575..69a2135 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -40,7 +40,14 @@ option('libmount', option('man', type : 'boolean', value : false, - description : 'generate man pages (requires xsltproc)') + description : 'generate man pages (requires xsltproc)', + deprecated : 'man-pages') + +option('man-pages', + type : 'feature', + value : 'auto', + description : 'generate man pages (requires rst2man)', + deprecated : { 'true': 'enabled', 'false': 'disabled' }) option('dtrace', type : 'boolean', @@ -62,10 +69,16 @@ option('sysprof', value : 'disabled', description : 'include tracing support for sysprof') +option('documentation', + type : 'boolean', + value : false, + description : 'Build API reference and tools documentation') + option('gtk_doc', type : 'boolean', value : false, - description : 'use gtk-doc to build documentation') + description : 'use gtk-doc to build documentation', + deprecated : 'documentation') option('bsymbolic_functions', type : 'boolean', @@ -125,3 +138,12 @@ option('multiarch', type : 'boolean', value : false, description : 'Install some helper executables in per-architecture locations') + +option('gir_dir_prefix', + type: 'string', + description: 'Intermediate prefix for gir installation under ${prefix}') + +option('introspection', + type: 'feature', + value: 'auto', + description: 'Enable generating introspection data (requires gobject-introspection)') diff --git a/po/en_GB.po b/po/en_GB.po index 666bb07..7316cb9 100644 --- a/po/en_GB.po +++ b/po/en_GB.po @@ -5,22 +5,21 @@ # Philip Withnall , 2010. # Zander Brown , 2019-2021. # Bruce Cowan , 2009-2023. -# Andi Chandler , 2024. # msgid "" msgstr "" "Project-Id-Version: glib\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" -"POT-Creation-Date: 2024-01-22 10:44+0000\n" -"PO-Revision-Date: 2024-02-26 13:31+0000\n" -"Last-Translator: Andi Chandler \n" +"POT-Creation-Date: 2023-08-31 11:01+0000\n" +"PO-Revision-Date: 2023-09-06 12:31+0100\n" +"Last-Translator: Bruce Cowan \n" "Language-Team: English - United Kingdom \n" "Language: en_GB\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=2; plural=(n != 1);\n" -"X-Generator: Poedit 3.4.2\n" +"X-Generator: Poedit 3.3.1\n" "X-Project-Style: gnome\n" "X-DL-Team: en_GB\n" "X-DL-Module: glib\n" @@ -46,23 +45,23 @@ msgstr "Failed to find default application for content type ‘%s’" msgid "Failed to find default application for URI Scheme ‘%s’" msgstr "Failed to find default application for URI Scheme ‘%s’" -#: gio/gapplication.c:506 -msgid "GApplication Options:" -msgstr "GApplication Options:" +#: gio/gapplication.c:502 +msgid "GApplication options" +msgstr "GApplication options" -#: gio/gapplication.c:506 +#: gio/gapplication.c:502 msgid "Show GApplication options" msgstr "Show GApplication options" -#: gio/gapplication.c:551 +#: gio/gapplication.c:547 msgid "Enter GApplication service mode (use from D-Bus service files)" msgstr "Enter GApplication service mode (use from D-Bus service files)" -#: gio/gapplication.c:563 +#: gio/gapplication.c:559 msgid "Override the application’s ID" msgstr "Override the application’s ID" -#: gio/gapplication.c:575 +#: gio/gapplication.c:571 msgid "Replace the running instance" msgstr "Replace the running instance" @@ -279,8 +278,8 @@ msgstr "" "\n" #: gio/gbufferedinputstream.c:422 gio/gbufferedinputstream.c:500 -#: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:651 -#: gio/ginputstream.c:1056 gio/goutputstream.c:225 gio/goutputstream.c:1052 +#: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:650 +#: gio/ginputstream.c:1052 gio/goutputstream.c:225 gio/goutputstream.c:1051 #: gio/gpollableinputstream.c:221 gio/gpollableoutputstream.c:293 #, c-format msgid "Too large count value passed to %s" @@ -295,8 +294,8 @@ msgstr "Seek not supported on base stream" msgid "Cannot truncate GBufferedInputStream" msgstr "Cannot truncate GBufferedInputStream" -#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1246 gio/giostream.c:302 -#: gio/goutputstream.c:2208 +#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1241 gio/giostream.c:302 +#: gio/goutputstream.c:2200 msgid "Stream is already closed" msgstr "Stream is already closed" @@ -323,28 +322,28 @@ msgid "Not enough space in destination" msgstr "Not enough space in destination" #: gio/gcharsetconverter.c:344 gio/gdatainputstream.c:850 -#: gio/gdatainputstream.c:1268 glib/gconvert.c:450 glib/gconvert.c:882 +#: gio/gdatainputstream.c:1268 glib/gconvert.c:451 glib/gconvert.c:883 #: glib/giochannel.c:1576 glib/giochannel.c:1618 glib/giochannel.c:2478 -#: glib/gutf8.c:958 glib/gutf8.c:1412 +#: glib/gutf8.c:892 glib/gutf8.c:1346 msgid "Invalid byte sequence in conversion input" msgstr "Invalid byte sequence in conversion input" -#: gio/gcharsetconverter.c:349 glib/gconvert.c:458 glib/gconvert.c:796 +#: gio/gcharsetconverter.c:349 glib/gconvert.c:459 glib/gconvert.c:797 #: glib/giochannel.c:1583 glib/giochannel.c:2493 #, c-format msgid "Error during conversion: %s" msgstr "Error during conversion: %s" -#: gio/gcharsetconverter.c:447 gio/gsocket.c:1164 +#: gio/gcharsetconverter.c:447 gio/gsocket.c:1151 msgid "Cancellable initialization not supported" msgstr "Cancellable initialisation not supported" -#: gio/gcharsetconverter.c:458 glib/gconvert.c:323 glib/giochannel.c:1404 +#: gio/gcharsetconverter.c:458 glib/gconvert.c:324 glib/giochannel.c:1404 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported" msgstr "Conversion from character set “%s” to “%s” is not supported" -#: gio/gcharsetconverter.c:462 glib/gconvert.c:327 +#: gio/gcharsetconverter.c:462 glib/gconvert.c:328 #, c-format msgid "Could not open converter from “%s” to “%s”" msgstr "Could not open converter from “%s” to “%s”" @@ -595,13 +594,13 @@ msgstr "" msgid "Error creating directory “%s”: %s" msgstr "Error creating directory “%s”: %s" -#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1102 gio/gfile.c:1340 -#: gio/gfile.c:1478 gio/gfile.c:1716 gio/gfile.c:1771 gio/gfile.c:1829 -#: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 -#: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 -#: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:8996 gio/gfile.c:9086 -#: gio/gfile.c:9170 gio/win32/gwinhttpfile.c:453 +#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1095 gio/gfile.c:1333 +#: gio/gfile.c:1471 gio/gfile.c:1709 gio/gfile.c:1764 gio/gfile.c:1822 +#: gio/gfile.c:1906 gio/gfile.c:1963 gio/gfile.c:2027 gio/gfile.c:2082 +#: gio/gfile.c:3797 gio/gfile.c:3937 gio/gfile.c:4349 gio/gfile.c:4819 +#: gio/gfile.c:5230 gio/gfile.c:5315 gio/gfile.c:5405 gio/gfile.c:5502 +#: gio/gfile.c:5589 gio/gfile.c:5690 gio/gfile.c:8819 gio/gfile.c:8909 +#: gio/gfile.c:8993 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "Operation not supported" @@ -766,20 +765,24 @@ msgid "type is INVALID" msgstr "type is INVALID" #: gio/gdbusmessage.c:1324 +#| msgid "METHOD_CALL message: PATH or MEMBER header field is missing" msgid "METHOD_CALL message: PATH or MEMBER header field is missing or invalid" msgstr "METHOD_CALL message: PATH or MEMBER header field is missing or invalid" #: gio/gdbusmessage.c:1340 +#| msgid "METHOD_RETURN message: REPLY_SERIAL header field is missing" msgid "METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid" msgstr "METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid" #: gio/gdbusmessage.c:1360 +#| msgid "ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing" msgid "" "ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid" msgstr "" "ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid" #: gio/gdbusmessage.c:1384 +#| msgid "SIGNAL message: PATH, INTERFACE or MEMBER header field is missing" msgid "" "SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid" msgstr "" @@ -1413,83 +1416,78 @@ msgstr "Expected a GEmblem for GEmblemedIcon" #. * trying to find the enclosing (user visible) #. * mount of a file, but none exists. #. -#: gio/gfile.c:1601 +#: gio/gfile.c:1594 msgid "Containing mount does not exist" msgstr "Containing mount does not exist" -#: gio/gfile.c:2648 gio/glocalfile.c:2518 +#: gio/gfile.c:2641 gio/glocalfile.c:2515 msgid "Can’t copy over directory" msgstr "Can’t copy over directory" -#: gio/gfile.c:2708 +#: gio/gfile.c:2701 msgid "Can’t copy directory over directory" msgstr "Can’t copy directory over directory" -#: gio/gfile.c:2716 +#: gio/gfile.c:2709 msgid "Target file exists" msgstr "Target file exists" -#: gio/gfile.c:2735 +#: gio/gfile.c:2728 msgid "Can’t recursively copy directory" msgstr "Can’t recursively copy directory" -#: gio/gfile.c:3044 gio/gfile.c:3092 -#, c-format -msgid "Copy file range not supported" -msgstr "Copy file range not supported" +#: gio/gfile.c:3029 +msgid "Splice not supported" +msgstr "Splice not supported" -#: gio/gfile.c:3050 gio/gfile.c:3161 +#: gio/gfile.c:3033 #, c-format msgid "Error splicing file: %s" msgstr "Error splicing file: %s" -#: gio/gfile.c:3157 -msgid "Splice not supported" -msgstr "Splice not supported" - -#: gio/gfile.c:3321 +#: gio/gfile.c:3195 msgid "Copy (reflink/clone) between mounts is not supported" msgstr "Copy (reflink/clone) between mounts is not supported" -#: gio/gfile.c:3325 +#: gio/gfile.c:3199 msgid "Copy (reflink/clone) is not supported or invalid" msgstr "Copy (reflink/clone) is not supported or invalid" -#: gio/gfile.c:3330 +#: gio/gfile.c:3204 msgid "Copy (reflink/clone) is not supported or didn’t work" msgstr "Copy (reflink/clone) is not supported or didn’t work" -#: gio/gfile.c:3395 +#: gio/gfile.c:3269 msgid "Can’t copy special file" msgstr "Can’t copy special file" -#: gio/gfile.c:4314 +#: gio/gfile.c:4163 msgid "Invalid symlink value given" msgstr "Invalid symlink value given" -#: gio/gfile.c:4324 glib/gfileutils.c:2424 +#: gio/gfile.c:4173 glib/gfileutils.c:2392 msgid "Symbolic links not supported" msgstr "Symbolic links not supported" -#: gio/gfile.c:4611 +#: gio/gfile.c:4460 msgid "Trash not supported" msgstr "Wastebasket not supported" -#: gio/gfile.c:4723 +#: gio/gfile.c:4572 #, c-format msgid "File names cannot contain “%c”" msgstr "File names cannot contain “%c”" -#: gio/gfile.c:7151 gio/gfile.c:7277 +#: gio/gfile.c:7003 gio/gfile.c:7129 #, c-format msgid "Failed to create a temporary directory for template “%s”: %s" msgstr "Failed to create a temporary directory for template “%s”: %s" -#: gio/gfile.c:7595 gio/gvolume.c:366 +#: gio/gfile.c:7418 gio/gvolume.c:366 msgid "volume doesn’t implement mount" msgstr "volume doesn’t implement mount" -#: gio/gfile.c:7709 gio/gfile.c:7786 +#: gio/gfile.c:7532 gio/gfile.c:7609 msgid "No application is registered as handling this file" msgstr "No application is registered as handling this file" @@ -1498,11 +1496,11 @@ msgid "Enumerator is closed" msgstr "Enumerator is closed" #: gio/gfileenumerator.c:221 gio/gfileenumerator.c:280 -#: gio/gfileenumerator.c:425 gio/gfileenumerator.c:525 +#: gio/gfileenumerator.c:424 gio/gfileenumerator.c:523 msgid "File enumerator has outstanding operation" msgstr "File enumerator has outstanding operation" -#: gio/gfileenumerator.c:416 gio/gfileenumerator.c:516 +#: gio/gfileenumerator.c:415 gio/gfileenumerator.c:514 msgid "File enumerator is already closed" msgstr "File enumerator is already closed" @@ -1515,27 +1513,27 @@ msgstr "Can’t handle version %d of GFileIcon encoding" msgid "Malformed input data for GFileIcon" msgstr "Malformed input data for GFileIcon" -#: gio/gfileinputstream.c:151 gio/gfileinputstream.c:397 +#: gio/gfileinputstream.c:151 gio/gfileinputstream.c:396 #: gio/gfileiostream.c:169 gio/gfileoutputstream.c:166 #: gio/gfileoutputstream.c:499 msgid "Stream doesn’t support query_info" msgstr "Stream doesn’t support query_info" -#: gio/gfileinputstream.c:328 gio/gfileiostream.c:382 +#: gio/gfileinputstream.c:327 gio/gfileiostream.c:381 #: gio/gfileoutputstream.c:373 msgid "Seek not supported on stream" msgstr "Seek not supported on stream" -#: gio/gfileinputstream.c:372 +#: gio/gfileinputstream.c:371 msgid "Truncate not allowed on input stream" msgstr "Truncate not allowed on input stream" -#: gio/gfileiostream.c:458 gio/gfileoutputstream.c:449 +#: gio/gfileiostream.c:457 gio/gfileoutputstream.c:449 msgid "Truncate not supported on stream" msgstr "Truncate not supported on stream" -#: gio/ghttpproxy.c:93 gio/gresolver.c:535 gio/gresolver.c:688 -#: glib/gconvert.c:1842 +#: gio/ghttpproxy.c:93 gio/gresolver.c:460 gio/gresolver.c:613 +#: glib/gconvert.c:1829 msgid "Invalid hostname" msgstr "Invalid hostname" @@ -1639,7 +1637,7 @@ msgstr "Input stream doesn’t implement read" #. Translators: This is an error you get if there is #. * already an operation running against this stream when #. * you try to start one -#: gio/ginputstream.c:1256 gio/giostream.c:312 gio/goutputstream.c:2218 +#: gio/ginputstream.c:1251 gio/giostream.c:312 gio/goutputstream.c:2210 msgid "Stream has outstanding operation" msgstr "Stream has outstanding operation" @@ -1748,7 +1746,7 @@ msgstr "Error writing to stdout" #: gio/gio-tool-cat.c:135 gio/gio-tool-info.c:382 gio/gio-tool-list.c:176 #: gio/gio-tool-mkdir.c:50 gio/gio-tool-monitor.c:39 gio/gio-tool-monitor.c:41 #: gio/gio-tool-monitor.c:43 gio/gio-tool-monitor.c:45 -#: gio/gio-tool-monitor.c:206 gio/gio-tool-mount.c:1236 gio/gio-tool-open.c:72 +#: gio/gio-tool-monitor.c:206 gio/gio-tool-mount.c:1210 gio/gio-tool-open.c:72 #: gio/gio-tool-remove.c:50 gio/gio-tool-rename.c:47 gio/gio-tool-set.c:95 #: gio/gio-tool-trash.c:222 gio/gio-tool-tree.c:246 msgid "LOCATION" @@ -1769,7 +1767,7 @@ msgstr "" "like smb://server/resource/file.txt as location." #: gio/gio-tool-cat.c:164 gio/gio-tool-info.c:413 gio/gio-tool-mkdir.c:78 -#: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1287 gio/gio-tool-open.c:98 +#: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1261 gio/gio-tool-open.c:98 #: gio/gio-tool-remove.c:74 gio/gio-tool-trash.c:303 msgid "No locations given" msgstr "No locations given" @@ -1865,18 +1863,11 @@ msgstr "Don’t follow symbolic links" msgid "attributes:\n" msgstr "attributes:\n" -#. Translators: This is a noun and represents and attribute of a file -#: gio/gio-tool-info.c:166 +#: gio/gio-tool-info.c:166 gio/gio-tool-info.c:176 #, c-format msgid "display name: %s\n" msgstr "display name: %s\n" -#. Translators: This is a noun and represents and attribute of a file -#: gio/gio-tool-info.c:176 -#, c-format -msgid "edit name: %s\n" -msgstr "edit name: %s\n" - #: gio/gio-tool-info.c:184 #, c-format msgid "name: %s\n" @@ -2190,15 +2181,15 @@ msgstr "Mount a TCRYPT system volume" msgid "Anonymous access denied" msgstr "Anonymous access denied" -#: gio/gio-tool-mount.c:559 +#: gio/gio-tool-mount.c:533 msgid "No drive for device file" msgstr "No drive for device file" -#: gio/gio-tool-mount.c:1051 +#: gio/gio-tool-mount.c:1025 msgid "No volume for given ID" msgstr "No volume for given ID" -#: gio/gio-tool-mount.c:1240 +#: gio/gio-tool-mount.c:1214 msgid "Mount or unmount the locations." msgstr "Mount or unmount the locations." @@ -3015,12 +3006,12 @@ msgstr "No schema files found: doing nothing." msgid "No schema files found: removed existing output file." msgstr "No schema files found: removed existing output file." -#: gio/glocalfile.c:570 gio/win32/gwinhttpfile.c:436 +#: gio/glocalfile.c:567 gio/win32/gwinhttpfile.c:436 #, c-format msgid "Invalid filename %s" msgstr "Invalid filename %s" -#: gio/glocalfile.c:1012 +#: gio/glocalfile.c:1009 #, c-format msgid "Error getting filesystem info for %s: %s" msgstr "Error getting filesystem info for %s: %s" @@ -3029,124 +3020,124 @@ msgstr "Error getting filesystem info for %s: %s" #. * the enclosing (user visible) mount of a file, but none #. * exists. #. -#: gio/glocalfile.c:1148 +#: gio/glocalfile.c:1145 #, c-format msgid "Containing mount for file %s not found" msgstr "Containing mount for file %s not found" -#: gio/glocalfile.c:1171 +#: gio/glocalfile.c:1168 msgid "Can’t rename root directory" msgstr "Can’t rename root directory" -#: gio/glocalfile.c:1189 gio/glocalfile.c:1212 +#: gio/glocalfile.c:1186 gio/glocalfile.c:1209 #, c-format msgid "Error renaming file %s: %s" msgstr "Error renaming file %s: %s" -#: gio/glocalfile.c:1196 +#: gio/glocalfile.c:1193 msgid "Can’t rename file, filename already exists" msgstr "Can’t rename file, filename already exists" -#: gio/glocalfile.c:1209 gio/glocalfile.c:2412 gio/glocalfile.c:2440 -#: gio/glocalfile.c:2579 gio/glocalfileoutputstream.c:658 +#: gio/glocalfile.c:1206 gio/glocalfile.c:2409 gio/glocalfile.c:2437 +#: gio/glocalfile.c:2576 gio/glocalfileoutputstream.c:658 msgid "Invalid filename" msgstr "Invalid filename" -#: gio/glocalfile.c:1377 gio/glocalfile.c:1388 +#: gio/glocalfile.c:1374 gio/glocalfile.c:1385 #, c-format msgid "Error opening file %s: %s" msgstr "Error opening file %s: %s" -#: gio/glocalfile.c:1513 +#: gio/glocalfile.c:1510 #, c-format msgid "Error removing file %s: %s" msgstr "Error removing file %s: %s" -#: gio/glocalfile.c:2007 gio/glocalfile.c:2018 gio/glocalfile.c:2045 +#: gio/glocalfile.c:2004 gio/glocalfile.c:2015 gio/glocalfile.c:2042 #, c-format msgid "Error trashing file %s: %s" msgstr "Error moving file %s to the wastebasket: %s" -#: gio/glocalfile.c:2065 +#: gio/glocalfile.c:2062 #, c-format msgid "Unable to create trash directory %s: %s" msgstr "Unable to create the wastebasket directory %s: %s" -#: gio/glocalfile.c:2086 +#: gio/glocalfile.c:2083 #, c-format msgid "Unable to find toplevel directory to trash %s" msgstr "Unable to find toplevel directory to move %s to the wastebasket" -#: gio/glocalfile.c:2094 +#: gio/glocalfile.c:2091 #, c-format msgid "Trashing on system internal mounts is not supported" msgstr "Can’t move to wastebasket on system internal mounts" -#: gio/glocalfile.c:2180 gio/glocalfile.c:2208 +#: gio/glocalfile.c:2177 gio/glocalfile.c:2205 #, c-format msgid "Unable to find or create trash directory %s to trash %s" msgstr "Unable to find or create wastebasket directory %s to move %s to" -#: gio/glocalfile.c:2252 +#: gio/glocalfile.c:2249 #, c-format msgid "Unable to create trashing info file for %s: %s" msgstr "Unable to create wastebasket info file for %s: %s" -#: gio/glocalfile.c:2323 +#: gio/glocalfile.c:2320 #, c-format msgid "Unable to trash file %s across filesystem boundaries" msgstr "Unable to move %s to wastebasket across filesystem boundaries" -#: gio/glocalfile.c:2327 gio/glocalfile.c:2383 +#: gio/glocalfile.c:2324 gio/glocalfile.c:2380 #, c-format msgid "Unable to trash file %s: %s" msgstr "Unable to move file %s to the wastebasket: %s" -#: gio/glocalfile.c:2389 +#: gio/glocalfile.c:2386 #, c-format msgid "Unable to trash file %s" msgstr "Unable to move file %s to the wastebasket" -#: gio/glocalfile.c:2415 +#: gio/glocalfile.c:2412 #, c-format msgid "Error creating directory %s: %s" msgstr "Error creating directory %s: %s" -#: gio/glocalfile.c:2444 +#: gio/glocalfile.c:2441 #, c-format msgid "Filesystem does not support symbolic links" msgstr "Filesystem does not support symbolic links" -#: gio/glocalfile.c:2447 +#: gio/glocalfile.c:2444 #, c-format msgid "Error making symbolic link %s: %s" msgstr "Error making symbolic link %s: %s" -#: gio/glocalfile.c:2490 gio/glocalfile.c:2525 gio/glocalfile.c:2582 +#: gio/glocalfile.c:2487 gio/glocalfile.c:2522 gio/glocalfile.c:2579 #, c-format msgid "Error moving file %s: %s" msgstr "Error moving file %s: %s" -#: gio/glocalfile.c:2513 +#: gio/glocalfile.c:2510 msgid "Can’t move directory over directory" msgstr "Can’t move directory over directory" -#: gio/glocalfile.c:2539 gio/glocalfileoutputstream.c:1110 +#: gio/glocalfile.c:2536 gio/glocalfileoutputstream.c:1110 #: gio/glocalfileoutputstream.c:1124 gio/glocalfileoutputstream.c:1139 #: gio/glocalfileoutputstream.c:1156 gio/glocalfileoutputstream.c:1170 msgid "Backup file creation failed" msgstr "Backup file creation failed" -#: gio/glocalfile.c:2558 +#: gio/glocalfile.c:2555 #, c-format msgid "Error removing target file: %s" msgstr "Error removing target file: %s" -#: gio/glocalfile.c:2572 +#: gio/glocalfile.c:2569 msgid "Move between mounts not supported" msgstr "Move between mounts not supported" -#: gio/glocalfile.c:2748 +#: gio/glocalfile.c:2745 #, c-format msgid "Could not determine the disk usage of %s: %s" msgstr "Could not determine the disk usage of %s: %s" @@ -3258,25 +3249,25 @@ msgstr "File “%s” cannot be opened: Windows Error %lu" msgid "Error setting modification or access time for file “%s”: %lu" msgstr "Error setting modification or access time for file “%s”: %lu" -#: gio/glocalfileinfo.c:2970 +#: gio/glocalfileinfo.c:2950 #, c-format msgid "Error setting modification or access time: %s" msgstr "Error setting modification or access time: %s" -#: gio/glocalfileinfo.c:2993 +#: gio/glocalfileinfo.c:2973 msgid "SELinux context must be non-NULL" msgstr "SELinux context must be non-NULL" -#: gio/glocalfileinfo.c:3000 +#: gio/glocalfileinfo.c:2980 msgid "SELinux is not enabled on this system" msgstr "SELinux is not enabled on this system" -#: gio/glocalfileinfo.c:3010 +#: gio/glocalfileinfo.c:2990 #, c-format msgid "Error setting SELinux context: %s" msgstr "Error setting SELinux context: %s" -#: gio/glocalfileinfo.c:3107 +#: gio/glocalfileinfo.c:3087 #, c-format msgid "Setting attribute %s not supported" msgstr "Setting attribute %s not supported" @@ -3477,35 +3468,35 @@ msgstr "NetworkManager version too old" msgid "Output stream doesn’t implement write" msgstr "Output stream doesn’t implement write" -#: gio/goutputstream.c:474 gio/goutputstream.c:1539 +#: gio/goutputstream.c:474 gio/goutputstream.c:1535 #, c-format msgid "Sum of vectors passed to %s too large" msgstr "Sum of vectors passed to %s too large" -#: gio/goutputstream.c:738 gio/goutputstream.c:1769 +#: gio/goutputstream.c:738 gio/goutputstream.c:1763 msgid "Source stream is already closed" msgstr "Source stream is already closed" -#: gio/gproxyaddressenumerator.c:329 gio/gproxyaddressenumerator.c:347 +#: gio/gproxyaddressenumerator.c:324 gio/gproxyaddressenumerator.c:342 msgid "Unspecified proxy lookup failure" msgstr "Unspecified proxy lookup failure" #. Translators: the first placeholder is a domain name, the #. * second is an error message -#: gio/gresolver.c:478 gio/gthreadedresolver.c:317 gio/gthreadedresolver.c:338 -#: gio/gthreadedresolver.c:983 gio/gthreadedresolver.c:1007 -#: gio/gthreadedresolver.c:1032 gio/gthreadedresolver.c:1047 +#: gio/gresolver.c:403 gio/gthreadedresolver.c:152 gio/gthreadedresolver.c:170 +#: gio/gthreadedresolver.c:798 gio/gthreadedresolver.c:822 +#: gio/gthreadedresolver.c:847 gio/gthreadedresolver.c:862 #, c-format msgid "Error resolving “%s”: %s" msgstr "Error resolving “%s”: %s" #. Translators: The placeholder is for a function name. -#: gio/gresolver.c:547 gio/gresolver.c:707 +#: gio/gresolver.c:472 gio/gresolver.c:632 #, c-format msgid "%s not implemented" msgstr "%s not implemented" -#: gio/gresolver.c:1076 gio/gresolver.c:1128 +#: gio/gresolver.c:1001 gio/gresolver.c:1053 msgid "Invalid domain" msgstr "Invalid domain" @@ -3896,8 +3887,7 @@ msgstr "Invalid socket, initialisation failed due to: %s" msgid "Socket is already closed" msgstr "Socket is already closed" -#: gio/gsocket.c:449 gio/gsocket.c:3238 gio/gsocket.c:4469 gio/gsocket.c:4527 -#: gio/gthreadedresolver.c:1445 +#: gio/gsocket.c:449 gio/gsocket.c:3225 gio/gsocket.c:4458 gio/gsocket.c:4516 msgid "Socket I/O timed out" msgstr "Socket I/O timed out" @@ -3906,159 +3896,159 @@ msgstr "Socket I/O timed out" msgid "creating GSocket from fd: %s" msgstr "creating GSocket from fd: %s" -#: gio/gsocket.c:646 gio/gsocket.c:714 gio/gsocket.c:721 +#: gio/gsocket.c:615 gio/gsocket.c:679 gio/gsocket.c:686 #, c-format msgid "Unable to create socket: %s" msgstr "Unable to create socket: %s" -#: gio/gsocket.c:714 +#: gio/gsocket.c:679 msgid "Unknown family was specified" msgstr "Unknown family was specified" -#: gio/gsocket.c:721 +#: gio/gsocket.c:686 msgid "Unknown protocol was specified" msgstr "Unknown protocol was specified" -#: gio/gsocket.c:1190 +#: gio/gsocket.c:1177 #, c-format msgid "Cannot use datagram operations on a non-datagram socket." msgstr "Cannot use datagram operations on a non-datagram socket." -#: gio/gsocket.c:1207 +#: gio/gsocket.c:1194 #, c-format msgid "Cannot use datagram operations on a socket with a timeout set." msgstr "Cannot use datagram operations on a socket with a timeout set." -#: gio/gsocket.c:2014 +#: gio/gsocket.c:2001 #, c-format msgid "could not get local address: %s" msgstr "could not get local address: %s" -#: gio/gsocket.c:2060 +#: gio/gsocket.c:2047 #, c-format msgid "could not get remote address: %s" msgstr "could not get remote address: %s" -#: gio/gsocket.c:2126 +#: gio/gsocket.c:2113 #, c-format msgid "could not listen: %s" msgstr "could not listen: %s" -#: gio/gsocket.c:2230 +#: gio/gsocket.c:2217 #, c-format msgid "Error binding to address %s: %s" msgstr "Error binding to address %s: %s" -#: gio/gsocket.c:2405 gio/gsocket.c:2442 gio/gsocket.c:2552 gio/gsocket.c:2577 -#: gio/gsocket.c:2644 gio/gsocket.c:2702 gio/gsocket.c:2720 +#: gio/gsocket.c:2392 gio/gsocket.c:2429 gio/gsocket.c:2539 gio/gsocket.c:2564 +#: gio/gsocket.c:2631 gio/gsocket.c:2689 gio/gsocket.c:2707 #, c-format msgid "Error joining multicast group: %s" msgstr "Error joining multicast group: %s" -#: gio/gsocket.c:2406 gio/gsocket.c:2443 gio/gsocket.c:2553 gio/gsocket.c:2578 -#: gio/gsocket.c:2645 gio/gsocket.c:2703 gio/gsocket.c:2721 +#: gio/gsocket.c:2393 gio/gsocket.c:2430 gio/gsocket.c:2540 gio/gsocket.c:2565 +#: gio/gsocket.c:2632 gio/gsocket.c:2690 gio/gsocket.c:2708 #, c-format msgid "Error leaving multicast group: %s" msgstr "Error leaving multicast group: %s" -#: gio/gsocket.c:2407 +#: gio/gsocket.c:2394 msgid "No support for source-specific multicast" msgstr "No support for source-specific multicast" -#: gio/gsocket.c:2554 +#: gio/gsocket.c:2541 msgid "Unsupported socket family" msgstr "Unsupported socket family" -#: gio/gsocket.c:2579 +#: gio/gsocket.c:2566 msgid "source-specific not an IPv4 address" msgstr "source-specific not an IPv4 address" -#: gio/gsocket.c:2603 +#: gio/gsocket.c:2590 #, c-format msgid "Interface name too long" msgstr "Interface name too long" -#: gio/gsocket.c:2616 gio/gsocket.c:2670 +#: gio/gsocket.c:2603 gio/gsocket.c:2657 #, c-format msgid "Interface not found: %s" msgstr "Interface not found: %s" -#: gio/gsocket.c:2646 +#: gio/gsocket.c:2633 msgid "No support for IPv4 source-specific multicast" msgstr "No support for IPv4 source-specific multicast" -#: gio/gsocket.c:2704 +#: gio/gsocket.c:2691 msgid "No support for IPv6 source-specific multicast" msgstr "No support for IPv6 source-specific multicast" -#: gio/gsocket.c:2937 +#: gio/gsocket.c:2924 #, c-format msgid "Error accepting connection: %s" msgstr "Error accepting connection: %s" -#: gio/gsocket.c:3063 +#: gio/gsocket.c:3050 msgid "Connection in progress" msgstr "Connection in progress" -#: gio/gsocket.c:3114 +#: gio/gsocket.c:3101 msgid "Unable to get pending error: " msgstr "Unable to get pending error: " -#: gio/gsocket.c:3303 +#: gio/gsocket.c:3290 #, c-format msgid "Error receiving data: %s" msgstr "Error receiving data: %s" -#: gio/gsocket.c:3500 +#: gio/gsocket.c:3487 #, c-format msgid "Error sending data: %s" msgstr "Error sending data: %s" -#: gio/gsocket.c:3687 +#: gio/gsocket.c:3674 #, c-format msgid "Unable to shutdown socket: %s" msgstr "Unable to shutdown socket: %s" -#: gio/gsocket.c:3768 +#: gio/gsocket.c:3755 #, c-format msgid "Error closing socket: %s" msgstr "Error closing socket: %s" -#: gio/gsocket.c:4462 +#: gio/gsocket.c:4451 #, c-format msgid "Waiting for socket condition: %s" msgstr "Waiting for socket condition: %s" -#: gio/gsocket.c:4852 gio/gsocket.c:4868 gio/gsocket.c:4881 +#: gio/gsocket.c:4841 gio/gsocket.c:4857 gio/gsocket.c:4870 #, c-format msgid "Unable to send message: %s" msgstr "Unable to send message: %s" -#: gio/gsocket.c:4853 gio/gsocket.c:4869 gio/gsocket.c:4882 +#: gio/gsocket.c:4842 gio/gsocket.c:4858 gio/gsocket.c:4871 msgid "Message vectors too large" msgstr "Message vectors too large" -#: gio/gsocket.c:4898 gio/gsocket.c:4900 gio/gsocket.c:5047 gio/gsocket.c:5132 -#: gio/gsocket.c:5310 gio/gsocket.c:5350 gio/gsocket.c:5352 +#: gio/gsocket.c:4887 gio/gsocket.c:4889 gio/gsocket.c:5036 gio/gsocket.c:5121 +#: gio/gsocket.c:5299 gio/gsocket.c:5339 gio/gsocket.c:5341 #, c-format msgid "Error sending message: %s" msgstr "Error sending message: %s" -#: gio/gsocket.c:5074 +#: gio/gsocket.c:5063 msgid "GSocketControlMessage not supported on Windows" msgstr "GSocketControlMessage not supported on Windows" -#: gio/gsocket.c:5547 gio/gsocket.c:5623 gio/gsocket.c:5849 +#: gio/gsocket.c:5536 gio/gsocket.c:5612 gio/gsocket.c:5838 #, c-format msgid "Error receiving message: %s" msgstr "Error receiving message: %s" -#: gio/gsocket.c:6134 gio/gsocket.c:6145 gio/gsocket.c:6208 +#: gio/gsocket.c:6123 gio/gsocket.c:6134 gio/gsocket.c:6197 #, c-format msgid "Unable to read socket credentials: %s" msgstr "Unable to read socket credentials: %s" -#: gio/gsocket.c:6217 +#: gio/gsocket.c:6206 msgid "g_socket_get_credentials not implemented for this OS" msgstr "g_socket_get_credentials not implemented for this OS" @@ -4180,12 +4170,12 @@ msgstr "SOCKSv5 proxy does not support provided address type." msgid "Unknown SOCKSv5 proxy error." msgstr "Unknown SOCKSv5 proxy error." -#: gio/gtestdbus.c:614 glib/gspawn-win32.c:433 +#: gio/gtestdbus.c:615 glib/gspawn-win32.c:354 #, c-format msgid "Failed to create pipe for communicating with child process (%s)" msgstr "Failed to create pipe for communicating with child process (%s)" -#: gio/gtestdbus.c:621 +#: gio/gtestdbus.c:622 #, c-format msgid "Pipes are not supported in this platform" msgstr "Pipes are not supported in this platform" @@ -4195,46 +4185,46 @@ msgstr "Pipes are not supported in this platform" msgid "Can’t handle version %d of GThemedIcon encoding" msgstr "Can’t handle version %d of GThemedIcon encoding" -#: gio/gthreadedresolver.c:319 +#: gio/gthreadedresolver.c:154 msgid "No valid addresses were found" msgstr "No valid addresses were found" -#: gio/gthreadedresolver.c:514 +#: gio/gthreadedresolver.c:339 #, c-format msgid "Error reverse-resolving “%s”: %s" msgstr "Error reverse-resolving “%s”: %s" #. Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ -#: gio/gthreadedresolver.c:737 gio/gthreadedresolver.c:759 -#: gio/gthreadedresolver.c:813 gio/gthreadedresolver.c:860 -#: gio/gthreadedresolver.c:889 gio/gthreadedresolver.c:901 +#: gio/gthreadedresolver.c:552 gio/gthreadedresolver.c:574 +#: gio/gthreadedresolver.c:628 gio/gthreadedresolver.c:675 +#: gio/gthreadedresolver.c:704 gio/gthreadedresolver.c:716 #, c-format msgid "Error parsing DNS %s record: malformed DNS packet" msgstr "Error parsing DNS %s record: malformed DNS packet" -#: gio/gthreadedresolver.c:959 gio/gthreadedresolver.c:1096 -#: gio/gthreadedresolver.c:1194 gio/gthreadedresolver.c:1244 +#: gio/gthreadedresolver.c:774 gio/gthreadedresolver.c:911 +#: gio/gthreadedresolver.c:1009 gio/gthreadedresolver.c:1059 #, c-format msgid "No DNS record of the requested type for “%s”" msgstr "No DNS record of the requested type for “%s”" -#: gio/gthreadedresolver.c:964 gio/gthreadedresolver.c:1199 +#: gio/gthreadedresolver.c:779 gio/gthreadedresolver.c:1014 #, c-format msgid "Temporarily unable to resolve “%s”" msgstr "Temporarily unable to resolve “%s”" -#: gio/gthreadedresolver.c:969 gio/gthreadedresolver.c:1204 -#: gio/gthreadedresolver.c:1300 +#: gio/gthreadedresolver.c:784 gio/gthreadedresolver.c:1019 +#: gio/gthreadedresolver.c:1129 #, c-format msgid "Error resolving “%s”" msgstr "Error resolving “%s”" -#: gio/gthreadedresolver.c:983 gio/gthreadedresolver.c:1007 -#: gio/gthreadedresolver.c:1032 gio/gthreadedresolver.c:1047 +#: gio/gthreadedresolver.c:798 gio/gthreadedresolver.c:822 +#: gio/gthreadedresolver.c:847 gio/gthreadedresolver.c:862 msgid "Malformed DNS packet" msgstr "Malformed DNS packet" -#: gio/gthreadedresolver.c:1089 +#: gio/gthreadedresolver.c:904 #, c-format msgid "Failed to parse DNS response for “%s”: " msgstr "Failed to parse DNS response for “%s”: " @@ -4293,14 +4283,14 @@ msgstr "The password entered is incorrect." msgid "Sending FD is not supported" msgstr "Sending FD is not supported" -#: gio/gunixconnection.c:181 gio/gunixconnection.c:602 +#: gio/gunixconnection.c:181 gio/gunixconnection.c:601 #, c-format msgid "Expecting 1 control message, got %d" msgid_plural "Expecting 1 control message, got %d" msgstr[0] "Expecting 1 control message, got %d" msgstr[1] "Expecting 1 control message, got %d" -#: gio/gunixconnection.c:197 gio/gunixconnection.c:614 +#: gio/gunixconnection.c:197 gio/gunixconnection.c:613 msgid "Unexpected type of ancillary data" msgstr "Unexpected type of ancillary data" @@ -4323,28 +4313,28 @@ msgstr "Receiving FD is not supported" msgid "Error sending credentials: " msgstr "Error sending credentials: " -#: gio/gunixconnection.c:542 +#: gio/gunixconnection.c:541 #, c-format msgid "Error checking if SO_PASSCRED is enabled for socket: %s" msgstr "Error checking if SO_PASSCRED is enabled for socket: %s" -#: gio/gunixconnection.c:558 +#: gio/gunixconnection.c:557 #, c-format msgid "Error enabling SO_PASSCRED: %s" msgstr "Error enabling SO_PASSCRED: %s" -#: gio/gunixconnection.c:587 +#: gio/gunixconnection.c:586 msgid "" "Expecting to read a single byte for receiving credentials but read zero bytes" msgstr "" "Expecting to read a single byte for receiving credentials but read zero bytes" -#: gio/gunixconnection.c:628 +#: gio/gunixconnection.c:627 #, c-format msgid "Not expecting control message, but got %d" msgstr "Not expecting control message, but got %d" -#: gio/gunixconnection.c:653 +#: gio/gunixconnection.c:652 #, c-format msgid "Error while disabling SO_PASSCRED: %s" msgstr "Error while disabling SO_PASSCRED: %s" @@ -4360,7 +4350,7 @@ msgstr "Error reading from file descriptor: %s" msgid "Error closing file descriptor: %s" msgstr "Error closing file descriptor: %s" -#: gio/gunixmounts.c:2826 gio/gunixmounts.c:2879 +#: gio/gunixmounts.c:2817 gio/gunixmounts.c:2870 msgid "Filesystem root" msgstr "Filesystem root" @@ -4517,49 +4507,54 @@ msgstr "No application with name “%s” registered a bookmark for “%s”" msgid "Failed to expand exec line “%s” with URI “%s”" msgstr "Failed to expand exec line “%s” with URI “%s”" -#: glib/gconvert.c:469 +#: glib/gconvert.c:470 msgid "Unrepresentable character in conversion input" msgstr "Unrepresentable character in conversion input" -#: glib/gconvert.c:496 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 -#: glib/gutf8.c:1408 +#: glib/gconvert.c:497 glib/gutf8.c:888 glib/gutf8.c:1101 glib/gutf8.c:1238 +#: glib/gutf8.c:1342 msgid "Partial character sequence at end of input" msgstr "Partial character sequence at end of input" -#: glib/gconvert.c:767 +#: glib/gconvert.c:768 #, c-format msgid "Cannot convert fallback “%s” to codeset “%s”" msgstr "Cannot convert fallback “%s” to codeset “%s”" -#: glib/gconvert.c:939 +#: glib/gconvert.c:940 msgid "Embedded NUL byte in conversion input" msgstr "Embedded NUL byte in conversion input" -#: glib/gconvert.c:960 +#: glib/gconvert.c:961 msgid "Embedded NUL byte in conversion output" msgstr "Embedded NUL byte in conversion output" -#: glib/gconvert.c:1698 +#: glib/gconvert.c:1692 #, c-format msgid "The URI “%s” is not an absolute URI using the “file” scheme" msgstr "The URI “%s” is not an absolute URI using the “file” scheme" -#: glib/gconvert.c:1728 +#: glib/gconvert.c:1702 +#, c-format +msgid "The local file URI “%s” may not include a “#”" +msgstr "The local file URI “%s” may not include a “#”" + +#: glib/gconvert.c:1719 #, c-format msgid "The URI “%s” is invalid" msgstr "The URI “%s” is invalid" -#: glib/gconvert.c:1741 +#: glib/gconvert.c:1731 #, c-format msgid "The hostname of the URI “%s” is invalid" msgstr "The hostname of the URI “%s” is invalid" -#: glib/gconvert.c:1758 +#: glib/gconvert.c:1747 #, c-format msgid "The URI “%s” contains invalidly escaped characters" msgstr "The URI “%s” contains invalidly escaped characters" -#: glib/gconvert.c:1832 +#: glib/gconvert.c:1819 #, c-format msgid "The pathname “%s” is not an absolute path" msgstr "The pathname “%s” is not an absolute path" @@ -5004,7 +4999,7 @@ msgstr "File “%s” is too large" msgid "Failed to read from file “%s”: %s" msgstr "Failed to read from file “%s”: %s" -#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1502 +#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1472 #, c-format msgid "Failed to open file “%s”: %s" msgstr "Failed to open file “%s”: %s" @@ -5024,37 +5019,37 @@ msgstr "Failed to open file “%s”: fdopen() failed: %s" msgid "Failed to rename file “%s” to “%s”: g_rename() failed: %s" msgstr "Failed to rename file “%s” to “%s”: g_rename() failed: %s" -#: glib/gfileutils.c:1209 +#: glib/gfileutils.c:1179 #, c-format msgid "Failed to write file “%s”: write() failed: %s" msgstr "Failed to write file “%s”: write() failed: %s" -#: glib/gfileutils.c:1230 +#: glib/gfileutils.c:1200 #, c-format msgid "Failed to write file “%s”: fsync() failed: %s" msgstr "Failed to write file “%s”: fsync() failed: %s" -#: glib/gfileutils.c:1391 glib/gfileutils.c:1808 +#: glib/gfileutils.c:1361 glib/gfileutils.c:1776 #, c-format msgid "Failed to create file “%s”: %s" msgstr "Failed to create file “%s”: %s" -#: glib/gfileutils.c:1436 +#: glib/gfileutils.c:1406 #, c-format msgid "Existing file “%s” could not be removed: g_unlink() failed: %s" msgstr "Existing file “%s” could not be removed: g_unlink() failed: %s" -#: glib/gfileutils.c:1773 +#: glib/gfileutils.c:1741 #, c-format msgid "Template “%s” invalid, should not contain a “%s”" msgstr "Template “%s” invalid, should not contain a “%s”" -#: glib/gfileutils.c:1786 +#: glib/gfileutils.c:1754 #, c-format msgid "Template “%s” doesn’t contain XXXXXX" msgstr "Template “%s” doesn’t contain XXXXXX" -#: glib/gfileutils.c:2380 glib/gfileutils.c:2409 +#: glib/gfileutils.c:2348 glib/gfileutils.c:2377 #, c-format msgid "Failed to read the symbolic link “%s”: %s" msgstr "Failed to read the symbolic link “%s”: %s" @@ -5080,65 +5075,65 @@ msgstr "Channel terminates in a partial character" msgid "Can’t do a raw read in g_io_channel_read_to_end" msgstr "Can’t do a raw read in g_io_channel_read_to_end" -#: glib/gkeyfile.c:802 +#: glib/gkeyfile.c:800 msgid "Valid key file could not be found in search dirs" msgstr "Valid key file could not be found in search dirs" -#: glib/gkeyfile.c:839 +#: glib/gkeyfile.c:837 msgid "Not a regular file" msgstr "Not a regular file" -#: glib/gkeyfile.c:1297 +#: glib/gkeyfile.c:1295 #, c-format msgid "" "Key file contains line “%s” which is not a key-value pair, group, or comment" msgstr "" "Key file contains line “%s” which is not a key-value pair, group, or comment" -#: glib/gkeyfile.c:1354 +#: glib/gkeyfile.c:1352 #, c-format msgid "Invalid group name: %s" msgstr "Invalid group name: %s" -#: glib/gkeyfile.c:1378 +#: glib/gkeyfile.c:1376 msgid "Key file does not start with a group" msgstr "Key file does not start with a group" -#: glib/gkeyfile.c:1402 +#: glib/gkeyfile.c:1400 #, c-format msgid "Invalid key name: %.*s" msgstr "Invalid key name: %.*s" -#: glib/gkeyfile.c:1430 +#: glib/gkeyfile.c:1428 #, c-format msgid "Key file contains unsupported encoding “%s”" msgstr "Key file contains unsupported encoding “%s”" -#: glib/gkeyfile.c:1678 glib/gkeyfile.c:1851 glib/gkeyfile.c:3298 -#: glib/gkeyfile.c:3400 glib/gkeyfile.c:3505 glib/gkeyfile.c:3634 -#: glib/gkeyfile.c:3777 glib/gkeyfile.c:4026 glib/gkeyfile.c:4100 +#: glib/gkeyfile.c:1683 glib/gkeyfile.c:1856 glib/gkeyfile.c:3303 +#: glib/gkeyfile.c:3367 glib/gkeyfile.c:3497 glib/gkeyfile.c:3626 +#: glib/gkeyfile.c:3772 glib/gkeyfile.c:4007 glib/gkeyfile.c:4074 #, c-format msgid "Key file does not have group “%s”" msgstr "Key file does not have group “%s”" -#: glib/gkeyfile.c:1806 +#: glib/gkeyfile.c:1811 #, c-format msgid "Key file does not have key “%s” in group “%s”" msgstr "Key file does not have key “%s” in group “%s”" -#: glib/gkeyfile.c:1968 glib/gkeyfile.c:2084 +#: glib/gkeyfile.c:1973 glib/gkeyfile.c:2089 #, c-format msgid "Key file contains key “%s” with value “%s” which is not UTF-8" msgstr "Key file contains key “%s” with value “%s” which is not UTF-8" -#: glib/gkeyfile.c:1988 glib/gkeyfile.c:2104 glib/gkeyfile.c:2543 +#: glib/gkeyfile.c:1993 glib/gkeyfile.c:2109 glib/gkeyfile.c:2548 #, c-format msgid "" "Key file contains key “%s” which has a value that cannot be interpreted." msgstr "" "Key file contains key “%s” which has a value that cannot be interpreted." -#: glib/gkeyfile.c:2758 glib/gkeyfile.c:3127 +#: glib/gkeyfile.c:2763 glib/gkeyfile.c:3132 #, c-format msgid "" "Key file contains key “%s” in group “%s” which has a value that cannot be " @@ -5147,36 +5142,36 @@ msgstr "" "Key file contains key “%s” in group “%s” which has a value that cannot be " "interpreted." -#: glib/gkeyfile.c:2836 glib/gkeyfile.c:2913 +#: glib/gkeyfile.c:2841 glib/gkeyfile.c:2918 #, c-format msgid "Key “%s” in group “%s” has value “%s” where %s was expected" msgstr "Key “%s” in group “%s” has value “%s” where %s was expected" -#: glib/gkeyfile.c:4357 +#: glib/gkeyfile.c:4330 msgid "Key file contains escape character at end of line" msgstr "Key file contains escape character at end of line" -#: glib/gkeyfile.c:4394 +#: glib/gkeyfile.c:4352 #, c-format msgid "Key file contains invalid escape sequence “%s”" msgstr "Key file contains invalid escape sequence “%s”" -#: glib/gkeyfile.c:4545 +#: glib/gkeyfile.c:4504 #, c-format msgid "Value “%s” cannot be interpreted as a number." msgstr "Value “%s” cannot be interpreted as a number." -#: glib/gkeyfile.c:4559 +#: glib/gkeyfile.c:4518 #, c-format msgid "Integer value “%s” out of range" msgstr "Integer value “%s” out of range" -#: glib/gkeyfile.c:4592 +#: glib/gkeyfile.c:4551 #, c-format msgid "Value “%s” cannot be interpreted as a float number." msgstr "Value “%s” cannot be interpreted as a float number." -#: glib/gkeyfile.c:4631 +#: glib/gkeyfile.c:4590 #, c-format msgid "Value “%s” cannot be interpreted as a boolean." msgstr "Value “%s” cannot be interpreted as a boolean." @@ -5470,180 +5465,184 @@ msgstr "Missing argument for %s" msgid "Unknown option %s" msgstr "Unknown option %s" -#: glib/gregex.c:487 +#: glib/gregex.c:479 msgid "corrupted object" msgstr "corrupted object" -#: glib/gregex.c:489 +#: glib/gregex.c:481 msgid "out of memory" msgstr "out of memory" -#: glib/gregex.c:504 +#: glib/gregex.c:487 +msgid "backtracking limit reached" +msgstr "backtracking limit reached" + +#: glib/gregex.c:498 msgid "internal error" msgstr "internal error" -#: glib/gregex.c:506 +#: glib/gregex.c:500 msgid "the pattern contains items not supported for partial matching" msgstr "the pattern contains items not supported for partial matching" -#: glib/gregex.c:508 +#: glib/gregex.c:502 msgid "back references as conditions are not supported for partial matching" msgstr "back references as conditions are not supported for partial matching" -#: glib/gregex.c:514 +#: glib/gregex.c:508 msgid "recursion limit reached" msgstr "recursion limit reached" -#: glib/gregex.c:516 +#: glib/gregex.c:510 msgid "bad offset" msgstr "bad offset" -#: glib/gregex.c:518 +#: glib/gregex.c:512 msgid "recursion loop" msgstr "recursion loop" #. should not happen in GRegex since we check modes before each match -#: glib/gregex.c:521 +#: glib/gregex.c:515 msgid "matching mode is requested that was not compiled for JIT" msgstr "matching mode is requested that was not compiled for JIT" -#: glib/gregex.c:542 glib/gregex.c:1870 +#: glib/gregex.c:536 glib/gregex.c:1838 msgid "unknown error" msgstr "unknown error" -#: glib/gregex.c:563 +#: glib/gregex.c:557 msgid "\\ at end of pattern" msgstr "\\ at end of pattern" -#: glib/gregex.c:567 +#: glib/gregex.c:561 msgid "\\c at end of pattern" msgstr "\\c at end of pattern" -#: glib/gregex.c:572 +#: glib/gregex.c:566 msgid "unrecognized character following \\" msgstr "unrecognised character following \\" -#: glib/gregex.c:576 +#: glib/gregex.c:570 msgid "numbers out of order in {} quantifier" msgstr "numbers out of order in {} quantifier" -#: glib/gregex.c:580 +#: glib/gregex.c:574 msgid "number too big in {} quantifier" msgstr "number too big in {} quantifier" -#: glib/gregex.c:584 +#: glib/gregex.c:578 msgid "missing terminating ] for character class" msgstr "missing terminating ] for character class" -#: glib/gregex.c:588 +#: glib/gregex.c:582 msgid "invalid escape sequence in character class" msgstr "invalid escape sequence in character class" -#: glib/gregex.c:592 +#: glib/gregex.c:586 msgid "range out of order in character class" msgstr "range out of order in character class" -#: glib/gregex.c:597 +#: glib/gregex.c:591 msgid "nothing to repeat" msgstr "nothing to repeat" -#: glib/gregex.c:601 +#: glib/gregex.c:595 msgid "unrecognized character after (? or (?-" msgstr "unrecognised character after (? or (?-" -#: glib/gregex.c:605 +#: glib/gregex.c:599 msgid "POSIX named classes are supported only within a class" msgstr "POSIX named classes are supported only within a class" -#: glib/gregex.c:609 +#: glib/gregex.c:603 msgid "POSIX collating elements are not supported" msgstr "POSIX collating elements are not supported" -#: glib/gregex.c:615 +#: glib/gregex.c:609 msgid "missing terminating )" msgstr "missing terminating )" -#: glib/gregex.c:619 +#: glib/gregex.c:613 msgid "reference to non-existent subpattern" msgstr "reference to non-existent subpattern" -#: glib/gregex.c:623 +#: glib/gregex.c:617 msgid "missing ) after comment" msgstr "missing ) after comment" -#: glib/gregex.c:627 +#: glib/gregex.c:621 msgid "regular expression is too large" msgstr "regular expression is too large" -#: glib/gregex.c:631 +#: glib/gregex.c:625 msgid "malformed number or name after (?(" msgstr "malformed number or name after (?(" -#: glib/gregex.c:635 +#: glib/gregex.c:629 msgid "lookbehind assertion is not fixed length" msgstr "lookbehind assertion is not fixed length" -#: glib/gregex.c:639 +#: glib/gregex.c:633 msgid "conditional group contains more than two branches" msgstr "conditional group contains more than two branches" -#: glib/gregex.c:643 +#: glib/gregex.c:637 msgid "assertion expected after (?(" msgstr "assertion expected after (?(" -#: glib/gregex.c:647 +#: glib/gregex.c:641 msgid "a numbered reference must not be zero" msgstr "a numbered reference must not be zero" -#: glib/gregex.c:651 +#: glib/gregex.c:645 msgid "unknown POSIX class name" msgstr "unknown POSIX class name" -#: glib/gregex.c:656 +#: glib/gregex.c:650 msgid "character value in \\x{...} sequence is too large" msgstr "character value in \\x{...} sequence is too large" -#: glib/gregex.c:660 +#: glib/gregex.c:654 msgid "\\C not allowed in lookbehind assertion" msgstr "\\C not allowed in lookbehind assertion" -#: glib/gregex.c:664 +#: glib/gregex.c:658 msgid "missing terminator in subpattern name" msgstr "missing terminator in subpattern name" -#: glib/gregex.c:668 +#: glib/gregex.c:662 msgid "two named subpatterns have the same name" msgstr "two named subpatterns have the same name" -#: glib/gregex.c:672 +#: glib/gregex.c:666 msgid "malformed \\P or \\p sequence" msgstr "malformed \\P or \\p sequence" -#: glib/gregex.c:676 +#: glib/gregex.c:670 msgid "unknown property name after \\P or \\p" msgstr "unknown property name after \\P or \\p" -#: glib/gregex.c:680 +#: glib/gregex.c:674 msgid "subpattern name is too long (maximum 32 characters)" msgstr "subpattern name is too long (maximum 32 characters)" -#: glib/gregex.c:684 +#: glib/gregex.c:678 msgid "too many named subpatterns (maximum 10,000)" msgstr "too many named subpatterns (maximum 10,000)" -#: glib/gregex.c:688 +#: glib/gregex.c:682 msgid "octal value is greater than \\377" msgstr "octal value is greater than \\377" -#: glib/gregex.c:692 +#: glib/gregex.c:686 msgid "DEFINE group contains more than one branch" msgstr "DEFINE group contains more than one branch" -#: glib/gregex.c:696 +#: glib/gregex.c:690 msgid "inconsistent NEWLINE options" msgstr "inconsistent NEWLINE options" -#: glib/gregex.c:700 +#: glib/gregex.c:694 msgid "" "\\g is not followed by a braced, angle-bracketed, or quoted name or number, " "or by a plain number" @@ -5651,118 +5650,118 @@ msgstr "" "\\g is not followed by a curly-bracketed, angle-bracketed, or quoted name or " "number, or by a plain number" -#: glib/gregex.c:705 +#: glib/gregex.c:699 msgid "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" msgstr "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" -#: glib/gregex.c:709 +#: glib/gregex.c:703 msgid "(*VERB) not recognized" msgstr "(*VERB) not recognised" -#: glib/gregex.c:713 +#: glib/gregex.c:707 msgid "number is too big" msgstr "number is too big" -#: glib/gregex.c:717 +#: glib/gregex.c:711 msgid "missing subpattern name after (?&" msgstr "missing subpattern name after (?&" -#: glib/gregex.c:721 +#: glib/gregex.c:715 msgid "different names for subpatterns of the same number are not allowed" msgstr "different names for subpatterns of the same number are not allowed" -#: glib/gregex.c:725 +#: glib/gregex.c:719 msgid "(*MARK) must have an argument" msgstr "(*MARK) must have an argument" -#: glib/gregex.c:729 +#: glib/gregex.c:723 msgid "\\c must be followed by an ASCII character" msgstr "\\c must be followed by an ASCII character" -#: glib/gregex.c:733 +#: glib/gregex.c:727 msgid "\\k is not followed by a braced, angle-bracketed, or quoted name" msgstr "" "\\k is not followed by a curly-bracketed, angle-bracketed, or quoted name" -#: glib/gregex.c:737 +#: glib/gregex.c:731 msgid "\\N is not supported in a class" msgstr "\\N is not supported in a class" -#: glib/gregex.c:741 +#: glib/gregex.c:735 msgid "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" msgstr "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" -#: glib/gregex.c:745 glib/gregex.c:881 +#: glib/gregex.c:739 glib/gregex.c:875 msgid "code overflow" msgstr "code overflow" -#: glib/gregex.c:749 +#: glib/gregex.c:743 msgid "unrecognized character after (?P" msgstr "unrecognised character after (?P" -#: glib/gregex.c:753 +#: glib/gregex.c:747 msgid "overran compiling workspace" msgstr "overran compiling workspace" -#: glib/gregex.c:757 +#: glib/gregex.c:751 msgid "previously-checked referenced subpattern not found" msgstr "previously-checked referenced subpattern not found" -#: glib/gregex.c:880 glib/gregex.c:1154 glib/gregex.c:2476 +#: glib/gregex.c:874 glib/gregex.c:1121 glib/gregex.c:2444 #, c-format msgid "Error while matching regular expression %s: %s" msgstr "Error while matching regular expression %s: %s" -#: glib/gregex.c:1754 +#: glib/gregex.c:1721 msgid "PCRE library is compiled without UTF8 support" msgstr "PCRE library is compiled without UTF8 support" -#: glib/gregex.c:1762 +#: glib/gregex.c:1729 msgid "PCRE library is compiled with incompatible options" msgstr "PCRE library is compiled with incompatible options" -#: glib/gregex.c:1879 +#: glib/gregex.c:1847 #, c-format msgid "Error while compiling regular expression ‘%s’ at char %s: %s" msgstr "Error while compiling regular expression ‘%s’ at char %s: %s" -#: glib/gregex.c:2919 +#: glib/gregex.c:2887 msgid "hexadecimal digit or “}” expected" msgstr "hexadecimal digit or “}” expected" -#: glib/gregex.c:2935 +#: glib/gregex.c:2903 msgid "hexadecimal digit expected" msgstr "hexadecimal digit expected" -#: glib/gregex.c:2975 +#: glib/gregex.c:2943 msgid "missing “<” in symbolic reference" msgstr "missing “<” in symbolic reference" -#: glib/gregex.c:2984 +#: glib/gregex.c:2952 msgid "unfinished symbolic reference" msgstr "unfinished symbolic reference" -#: glib/gregex.c:2991 +#: glib/gregex.c:2959 msgid "zero-length symbolic reference" msgstr "zero-length symbolic reference" -#: glib/gregex.c:3002 +#: glib/gregex.c:2970 msgid "digit expected" msgstr "digit expected" -#: glib/gregex.c:3020 +#: glib/gregex.c:2988 msgid "illegal symbolic reference" msgstr "illegal symbolic reference" -#: glib/gregex.c:3083 +#: glib/gregex.c:3051 msgid "stray final “\\”" msgstr "stray final “\\”" -#: glib/gregex.c:3087 +#: glib/gregex.c:3055 msgid "unknown escape sequence" msgstr "unknown escape sequence" -#: glib/gregex.c:3097 +#: glib/gregex.c:3065 #, c-format msgid "Error while parsing replacement text “%s” at char %lu: %s" msgstr "Error while parsing replacement text “%s” at char %lu: %s" @@ -5789,92 +5788,92 @@ msgstr "Text ended before matching quote was found for %c. (The text was “%s msgid "Text was empty (or contained only whitespace)" msgstr "Text was empty (or contained only whitespace)" -#: glib/gspawn.c:320 +#: glib/gspawn.c:319 #, c-format msgid "Failed to read data from child process (%s)" msgstr "Failed to read data from child process (%s)" -#: glib/gspawn.c:473 +#: glib/gspawn.c:471 #, c-format msgid "Unexpected error in reading data from a child process (%s)" msgstr "Unexpected error in reading data from a child process (%s)" -#: glib/gspawn.c:558 +#: glib/gspawn.c:556 #, c-format msgid "Unexpected error in waitpid() (%s)" msgstr "Unexpected error in waitpid() (%s)" -#: glib/gspawn.c:1180 glib/gspawn-win32.c:1575 +#: glib/gspawn.c:1175 glib/gspawn-win32.c:1503 #, c-format msgid "Child process exited with code %ld" msgstr "Child process exited with code %ld" -#: glib/gspawn.c:1188 +#: glib/gspawn.c:1183 #, c-format msgid "Child process killed by signal %ld" msgstr "Child process killed by signal %ld" -#: glib/gspawn.c:1195 +#: glib/gspawn.c:1190 #, c-format msgid "Child process stopped by signal %ld" msgstr "Child process stopped by signal %ld" -#: glib/gspawn.c:1202 +#: glib/gspawn.c:1197 #, c-format msgid "Child process exited abnormally" msgstr "Child process exited abnormally" -#: glib/gspawn.c:2039 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 +#: glib/gspawn.c:2027 glib/gspawn-win32.c:393 glib/gspawn-win32.c:401 #, c-format msgid "Failed to read from child pipe (%s)" msgstr "Failed to read from child pipe (%s)" -#: glib/gspawn.c:2411 +#: glib/gspawn.c:2399 #, c-format msgid "Failed to spawn child process “%s” (%s)" msgstr "Failed to spawn child process “%s” (%s)" -#: glib/gspawn.c:2537 +#: glib/gspawn.c:2525 #, c-format msgid "Failed to fork (%s)" msgstr "Failed to fork (%s)" -#: glib/gspawn.c:2697 glib/gspawn-win32.c:503 +#: glib/gspawn.c:2685 glib/gspawn-win32.c:424 #, c-format msgid "Failed to change to directory “%s” (%s)" msgstr "Failed to change to directory “%s” (%s)" -#: glib/gspawn.c:2707 +#: glib/gspawn.c:2695 #, c-format msgid "Failed to execute child process “%s” (%s)" msgstr "Failed to execute child process “%s” (%s)" -#: glib/gspawn.c:2717 +#: glib/gspawn.c:2705 #, c-format msgid "Failed to open file to remap file descriptor (%s)" msgstr "Failed to open file to remap file descriptor (%s)" -#: glib/gspawn.c:2725 +#: glib/gspawn.c:2713 #, c-format msgid "Failed to duplicate file descriptor for child process (%s)" msgstr "Failed to duplicate file descriptor for child process (%s)" -#: glib/gspawn.c:2734 +#: glib/gspawn.c:2722 #, c-format msgid "Failed to fork child process (%s)" msgstr "Failed to fork child process (%s)" -#: glib/gspawn.c:2742 +#: glib/gspawn.c:2730 #, c-format msgid "Failed to close file descriptor for child process (%s)" msgstr "Failed to close file descriptor for child process (%s)" -#: glib/gspawn.c:2750 +#: glib/gspawn.c:2738 #, c-format msgid "Unknown error executing child process “%s”" msgstr "Unknown error executing child process “%s”" -#: glib/gspawn.c:2774 +#: glib/gspawn.c:2762 #, c-format msgid "Failed to read enough data from child pid pipe (%s)" msgstr "Failed to read enough data from child pid pipe (%s)" @@ -5884,46 +5883,46 @@ msgstr "Failed to read enough data from child pid pipe (%s)" msgid "Invalid source FDs argument" msgstr "Invalid source FDs argument" -#: glib/gspawn-win32.c:416 +#: glib/gspawn-win32.c:337 msgid "Failed to read data from child process" msgstr "Failed to read data from child process" -#: glib/gspawn-win32.c:509 glib/gspawn-win32.c:514 glib/gspawn-win32.c:640 +#: glib/gspawn-win32.c:430 glib/gspawn-win32.c:435 glib/gspawn-win32.c:561 #, c-format msgid "Failed to execute child process (%s)" msgstr "Failed to execute child process (%s)" -#: glib/gspawn-win32.c:519 +#: glib/gspawn-win32.c:440 #, c-format msgid "Failed to dup() in child process (%s)" msgstr "Failed to dup() in child process (%s)" -#: glib/gspawn-win32.c:590 +#: glib/gspawn-win32.c:511 #, c-format msgid "Invalid program name: %s" msgstr "Invalid program name: %s" -#: glib/gspawn-win32.c:600 glib/gspawn-win32.c:940 +#: glib/gspawn-win32.c:521 glib/gspawn-win32.c:868 #, c-format msgid "Invalid string in argument vector at %d: %s" msgstr "Invalid string in argument vector at %d: %s" -#: glib/gspawn-win32.c:611 glib/gspawn-win32.c:956 +#: glib/gspawn-win32.c:532 glib/gspawn-win32.c:884 #, c-format msgid "Invalid string in environment: %s" msgstr "Invalid string in environment: %s" -#: glib/gspawn-win32.c:936 +#: glib/gspawn-win32.c:864 #, c-format msgid "Invalid working directory: %s" msgstr "Invalid working directory: %s" -#: glib/gspawn-win32.c:1001 +#: glib/gspawn-win32.c:929 #, c-format msgid "Failed to execute helper program (%s)" msgstr "Failed to execute helper program (%s)" -#: glib/gspawn-win32.c:1230 +#: glib/gspawn-win32.c:1158 msgid "" "Unexpected error in g_io_channel_win32_poll() reading data from a child " "process" @@ -5950,76 +5949,76 @@ msgstr "Number “%s” is out of bounds [%s, %s]" msgid "“%s” is not an unsigned number" msgstr "“%s” is not an unsigned number" -#: glib/guri.c:318 +#: glib/guri.c:317 #, no-c-format msgid "Invalid %-encoding in URI" msgstr "Invalid %-encoding in URI" -#: glib/guri.c:335 +#: glib/guri.c:334 msgid "Illegal character in URI" msgstr "Illegal character in URI" -#: glib/guri.c:369 +#: glib/guri.c:368 msgid "Non-UTF-8 characters in URI" msgstr "Non-UTF-8 characters in URI" -#: glib/guri.c:549 +#: glib/guri.c:548 #, c-format msgid "Invalid IPv6 address ‘%.*s’ in URI" msgstr "Invalid IPv6 address ‘%.*s’ in URI" -#: glib/guri.c:604 +#: glib/guri.c:603 #, c-format msgid "Illegal encoded IP address ‘%.*s’ in URI" msgstr "Illegal encoded IP address ‘%.*s’ in URI" -#: glib/guri.c:616 +#: glib/guri.c:615 #, c-format msgid "Illegal internationalized hostname ‘%.*s’ in URI" msgstr "Illegal internationalised hostname ‘%.*s’ in URI" -#: glib/guri.c:648 glib/guri.c:660 +#: glib/guri.c:647 glib/guri.c:659 #, c-format msgid "Could not parse port ‘%.*s’ in URI" msgstr "Could not parse port ‘%.*s’ in URI" -#: glib/guri.c:667 +#: glib/guri.c:666 #, c-format msgid "Port ‘%.*s’ in URI is out of range" msgstr "Port ‘%.*s’ in URI is out of range" -#: glib/guri.c:1230 glib/guri.c:1294 +#: glib/guri.c:1226 glib/guri.c:1290 #, c-format msgid "URI ‘%s’ is not an absolute URI" msgstr "URI ‘%s’ is not an absolute URI" -#: glib/guri.c:1236 +#: glib/guri.c:1232 #, c-format msgid "URI ‘%s’ has no host component" msgstr "URI ‘%s’ has no host component" -#: glib/guri.c:1466 +#: glib/guri.c:1462 msgid "URI is not absolute, and no base URI was provided" msgstr "URI is not absolute, and no base URI was provided" -#: glib/guri.c:2252 +#: glib/guri.c:2248 msgid "Missing ‘=’ and parameter value" msgstr "Missing ‘=’ and parameter value" -#: glib/gutf8.c:900 +#: glib/gutf8.c:834 msgid "Failed to allocate memory" msgstr "Failed to allocate memory" -#: glib/gutf8.c:1033 +#: glib/gutf8.c:967 msgid "Character out of range for UTF-8" msgstr "Character out of range for UTF-8" -#: glib/gutf8.c:1135 glib/gutf8.c:1144 glib/gutf8.c:1274 glib/gutf8.c:1283 -#: glib/gutf8.c:1422 glib/gutf8.c:1519 +#: glib/gutf8.c:1069 glib/gutf8.c:1078 glib/gutf8.c:1208 glib/gutf8.c:1217 +#: glib/gutf8.c:1356 glib/gutf8.c:1453 msgid "Invalid sequence in conversion input" msgstr "Invalid sequence in conversion input" -#: glib/gutf8.c:1433 glib/gutf8.c:1530 +#: glib/gutf8.c:1367 glib/gutf8.c:1464 msgid "Character out of range for UTF-16" msgstr "Character out of range for UTF-16" @@ -6246,15 +6245,9 @@ msgstr "%.1f PB" msgid "%.1f EB" msgstr "%.1f EB" -#~ msgid "GApplication options" -#~ msgstr "GApplication options" - #, c-format -#~ msgid "The local file URI “%s” may not include a “#”" -#~ msgstr "The local file URI “%s” may not include a “#”" - -#~ msgid "backtracking limit reached" -#~ msgstr "backtracking limit reached" +#~ msgid "edit name: %s\n" +#~ msgstr "edit name: %s\n" #~ msgid "internal error or corrupted object" #~ msgstr "internal error or corrupted object" diff --git a/po/ka.po b/po/ka.po index 5617adc..b050f94 100644 --- a/po/ka.po +++ b/po/ka.po @@ -6,9 +6,9 @@ msgid "" msgstr "" "Project-Id-Version: glib\n" -"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues/new\n" -"POT-Creation-Date: 2024-03-19 07:49+0000\n" -"PO-Revision-Date: 2024-03-25 05:52+0100\n" +"Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" +"POT-Creation-Date: 2023-09-06 04:18+0000\n" +"PO-Revision-Date: 2023-09-08 14:07+0200\n" "Last-Translator: Ekaterine Papava \n" "Language-Team: Georgian <(nothing)>\n" "Language: ka\n" @@ -610,8 +610,8 @@ msgstr "საქაღალდის (\"%s\") შექმნის შეც #: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 #: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 #: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:8996 gio/gfile.c:9086 -#: gio/gfile.c:9170 gio/win32/gwinhttpfile.c:453 +#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:9000 gio/gfile.c:9090 +#: gio/gfile.c:9174 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "ოპერაცია მხარდაუჭერელია" @@ -1478,15 +1478,15 @@ msgstr "შეერთება მხარდაჭერილი არა #: gio/gfile.c:3321 msgid "Copy (reflink/clone) between mounts is not supported" -msgstr "მიმაგრების წერტილებს შორის კოპირება (reflink/clone) მხარდაჭერილი არაა" +msgstr "" #: gio/gfile.c:3325 msgid "Copy (reflink/clone) is not supported or invalid" -msgstr "კოპირება (reflink/clone) მხარდაუჭერელი ან არასწორია" +msgstr "" #: gio/gfile.c:3330 msgid "Copy (reflink/clone) is not supported or didn’t work" -msgstr "კოპირება (reflink/clone) მხარდაუჭერელია ან არ იმუშავა" +msgstr "" #: gio/gfile.c:3395 msgid "Can’t copy special file" @@ -1496,7 +1496,7 @@ msgstr "სპეციალური ფაილის კოპირებ msgid "Invalid symlink value given" msgstr "სიმბმბულის მითითებული მნიშვნელობა არასწორია" -#: gio/gfile.c:4324 glib/gfileutils.c:2424 +#: gio/gfile.c:4324 glib/gfileutils.c:2392 msgid "Symbolic links not supported" msgstr "სიმბოლური ბმების გამოყენება არაა რეალიზებული" @@ -1509,16 +1509,16 @@ msgstr "ნაგავი მხარდაუჭერელია" msgid "File names cannot contain “%c”" msgstr "ფაილის სახელი არ შეიძლება, \"%c\"-ს შეიცავდეს" -#: gio/gfile.c:7151 gio/gfile.c:7277 +#: gio/gfile.c:7155 gio/gfile.c:7281 #, c-format msgid "Failed to create a temporary directory for template “%s”: %s" msgstr "შაბლონისთვის \"%s\" დროებითი საქაღალდის შექმნის შეცდომა: %s" -#: gio/gfile.c:7595 gio/gvolume.c:366 +#: gio/gfile.c:7599 gio/gvolume.c:366 msgid "volume doesn’t implement mount" msgstr "ტომს მიმაგრების მხარდაჭერა არ გააჩნია" -#: gio/gfile.c:7709 gio/gfile.c:7786 +#: gio/gfile.c:7713 gio/gfile.c:7790 msgid "No application is registered as handling this file" msgstr "ამ ფაილის გასახსნელი პროგრამა დარეგისტრირებული არაა" @@ -1670,7 +1670,7 @@ msgstr "შეყვანის ნაკადს წაკითხვის #. * you try to start one #: gio/ginputstream.c:1256 gio/giostream.c:312 gio/goutputstream.c:2218 msgid "Stream has outstanding operation" -msgstr "ნაკადი გადაუდებელ ოპერაციას ასრულებს" +msgstr "" #: gio/gio-tool.c:162 msgid "Copy with file" @@ -1698,7 +1698,7 @@ msgstr "ბრძანებები:" #: gio/gio-tool.c:231 msgid "Concatenate files to standard output" -msgstr "სტანდარტულ შეტანაზე არსებული ფაილების შეერთება" +msgstr "" #: gio/gio-tool.c:232 msgid "Copy one or more files" @@ -1785,7 +1785,7 @@ msgstr "მდებარეობა" #: gio/gio-tool-cat.c:140 msgid "Concatenate files and print to standard output." -msgstr "ფაილების შეერთება და სტანდარტულ გამოტანაზე ჩვენება." +msgstr "" #: gio/gio-tool-cat.c:142 msgid "" @@ -1793,9 +1793,6 @@ msgid "" "locations instead of local files: for example, you can use something\n" "like smb://server/resource/file.txt as location." msgstr "" -"gio cat ჩვეულებრივი cat ბრძანებასავით მუშაობს, მაგრამ\n" -"ლოკალური ფაილების მაგიერ GIO მდებარეობებს იყენებს: მაგალითად,\n" -"შეგიძლიათ, მდებარეობად smb://server/resource/file.txt გამოიყენოთ." #: gio/gio-tool-cat.c:164 gio/gio-tool-info.c:413 gio/gio-tool-mkdir.c:78 #: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1287 gio/gio-tool-open.c:98 @@ -1848,7 +1845,7 @@ msgstr "დანიშნულება" #: gio/gio-tool-copy.c:107 msgid "Copy one or more files from SOURCE to DESTINATION." -msgstr "ერთი ან მეტი ფაილის კოპირება მითითებული წყაროდან მითითებულ სამიზნეში." +msgstr "" #: gio/gio-tool-copy.c:109 msgid "" @@ -1856,9 +1853,6 @@ msgid "" "locations instead of local files: for example, you can use something\n" "like smb://server/resource/file.txt as location." msgstr "" -"gio copy ჩვეულებრივი cp ბრძანების მსგავსია, მაგრამ ლოკალური ფაილების\n" -"მაგიერ GIO-ის მდებარეობებს იყენებს: მაგალითად, შეგიძლიათ გამოიყენოთ\n" -"smb://server/resource/file.txt." #: gio/gio-tool-copy.c:151 #, c-format @@ -1959,12 +1953,6 @@ msgid "" "be specified with their GIO name, e.g. standard::icon, or just by\n" "namespace, e.g. unix, or by “*”, which matches all attributes" msgstr "" -"gio info ჩვეულებრივი ls ბრძანების მსგავსია, მაგრამ ლოკალური ფაილების მაგიერ\n" -"GIO მდებარეობებს იყენებს. მაგალითად, მდებარეობად შეგიძლიათ გამოიყენოთ\n" -"smb://server/resource/file.txt. ფაილის ატრიბუტები მათი GIO სახელებთან ერთად " -"შეგიძლიათ, გამოიყენოთ\n" -"მაგ: standard::icon ან, უბრალოდ, სახელების სივრცით. მაგ: unix ან \"*\", " -"რომელიც ყველა ატრიბუტს ნიშნავს" #. Translators: commandline placeholder #: gio/gio-tool-launch.c:56 @@ -1976,8 +1964,6 @@ msgid "" "Launch an application from a desktop file, passing optional filename " "arguments to it." msgstr "" -"აპლიკაციის გაშვება სამუშაო მაგიდის ფაილიდან, არასავალდებულო ფაილის სახელის " -"გადაცემით." #: gio/gio-tool-launch.c:79 msgid "No desktop file given" @@ -1995,7 +1981,7 @@ msgstr "%s-ის ჩატვირთვის შეცდომა: %s" #: gio/gio-tool-launch.c:109 #, c-format msgid "Unable to load application information for ‘%s‘" -msgstr "ვერ ჩავტვირთე აპლიკაციის ინფორმაცია '%s'-სთვის" +msgstr "" #: gio/gio-tool-launch.c:121 #, c-format @@ -2029,10 +2015,6 @@ msgid "" "like smb://server/resource/file.txt as location. File attributes can\n" "be specified with their GIO name, e.g. standard::icon" msgstr "" -"gio list ჩვეულებრივი ls ბრძანების მსგავსია, მაგრამ ლოკალური ფაილების\n" -"ნაცვლად GIO მდებარეობებს იყენებს. შეგიძლიათ გამოიყენოთ, მაგ:\n" -"smb://server/resource/file.txt. ფაილის ატრიბუტები მათი GIO სახელით\n" -"შეგიძლიათ, მიუთითოთ. მაგ: standard::icon" #. Translators: commandline placeholder #: gio/gio-tool-mime.c:73 @@ -2053,14 +2035,10 @@ msgid "" "for the mimetype. If a handler is given, it is set as the default\n" "handler for the mimetype." msgstr "" -"თუ დამმუშავებელი მითითებული არაა, ნაჩვენები იქნება რეგისტრირებული და " -"რეკომენდებული აპლიკაციების\n" -"სია ამ mime ტიპისთვის. თუ დამმუშავებელი მითითებულია, ის ამ mime ტიპისთვის\n" -"ნაგულისხმევ დამმუშავებლად იქნება დაყენებული." #: gio/gio-tool-mime.c:102 msgid "Must specify a single mimetype, and maybe a handler" -msgstr "უნდა მიუთითოთ ერთი MIME ტიპი ან, შეიძლება, დამმუშავებელი" +msgstr "" #: gio/gio-tool-mime.c:118 #, c-format @@ -2097,7 +2075,6 @@ msgstr "შეცდომა ინფორმაციის ჩატვი #, c-format msgid "Failed to set “%s” as the default handler for “%s”: %s\n" msgstr "" -"შეცდომა \"%s\"-ის ნაგულიხმევ დამმუშავებლად დაყენებისას \"%s\"-სთვის: %s\n" #: gio/gio-tool-mkdir.c:33 msgid "Create parent directories" @@ -2113,31 +2090,26 @@ msgid "" "locations instead of local files: for example, you can use something\n" "like smb://server/resource/mydir as location." msgstr "" -"gio mkidr ჩვეულებრივი mkdir ბრძანების მსგავსია, მაგრამ ლოკალური\n" -"ფაილები მაგიერ GIO მდებარეობებს იყენებს. მაგ; შეგიძლიათ გამოიყენოთ\n" -"smb://server/resource/mydir." #: gio/gio-tool-monitor.c:39 msgid "Monitor a directory (default: depends on type)" -msgstr "საქაღალდის მონიტორინგი (ნაგულისხმევი: დამოკიდებულია ტიპზე)" +msgstr "" #: gio/gio-tool-monitor.c:41 msgid "Monitor a file (default: depends on type)" -msgstr "ფაილის მონიტორინგი (ნაგულისხმევი: დამოკიდებულია ტიპზე)" +msgstr "" #: gio/gio-tool-monitor.c:43 msgid "Monitor a file directly (notices changes made via hardlinks)" -msgstr "ფაილის პირდაპირი თვალთვალი (ამჩნევს მყარი ბმულების ცვლილებებს)" +msgstr "" #: gio/gio-tool-monitor.c:45 msgid "Monitors a file directly, but doesn’t report changes" -msgstr "ფაილის პირდაპირი მონიტორინგი ცვლილებების გადმოცემის გარეშე" +msgstr "" #: gio/gio-tool-monitor.c:47 msgid "Report moves and renames as simple deleted/created events" msgstr "" -"გადატანების და სახელის გადარქმევის ოპერაციების ერთ წაშლა/შექმნის მოვლენებად " -"გამოტანა" #: gio/gio-tool-monitor.c:49 msgid "Watch for mount events" @@ -2185,7 +2157,7 @@ msgstr "სქემა" #: gio/gio-tool-mount.c:71 msgid "Ignore outstanding file operations when unmounting or ejecting" -msgstr "დაუსრულებელი ფაილის ოპერაციების გამოტოვება მოხსნისას ან გამოღებისას" +msgstr "" #: gio/gio-tool-mount.c:72 msgid "Use an anonymous user when authenticating" @@ -2206,7 +2178,7 @@ msgstr "დამატებითი ინფორმაციის ჩვ #: gio/gio-tool-mount.c:77 msgid "The numeric PIM when unlocking a VeraCrypt volume" -msgstr "რიცხვითი PIM დაშიფრული VeraCrypt ტომის გახსნისას" +msgstr "" #: gio/gio-tool-mount.c:77 msgid "PIM" @@ -2238,11 +2210,11 @@ msgstr "მდებარეობების მიმაგრება ა #: gio/gio-tool-move.c:44 msgid "Don’t use copy and delete fallback" -msgstr "მარქაფი არ გამოიყენება და წაიშლება" +msgstr "" #: gio/gio-tool-move.c:101 msgid "Move one or more files from SOURCE to DEST." -msgstr "ერთი ან მეტი ფაილის გადატანა მითითებული წყაროდან მითითებულ სამიზნეში." +msgstr "" #: gio/gio-tool-move.c:103 msgid "" @@ -2250,9 +2222,6 @@ msgid "" "locations instead of local files: for example, you can use something\n" "like smb://server/resource/file.txt as location" msgstr "" -"gio move ჩვეულებრივი mv ბრძანების მსგავსია, მაგრამ ლოკალური ფაილების\n" -"მაგიერ GIO-ის მდებარეობებს იყენებს: მაგალითად, შეგიძლიათ გამოიყენოთ\n" -"smb://server/resource/file.txt" #: gio/gio-tool-move.c:145 #, c-format @@ -2264,12 +2233,10 @@ msgid "" "Open files with the default application that\n" "is registered to handle files of this type." msgstr "" -"ფაილების გახსნა ნაგულისხმევი აპლიკაციით,\n" -"რომელიც დარეგისტრირებულია, ამ ტიპის ფაილები გახსნას." #: gio/gio-tool-remove.c:33 gio/gio-tool-trash.c:35 msgid "Ignore nonexistent files, never prompt" -msgstr "არარსებული ფაილების გამოტოვება. არასდროს მკითხო" +msgstr "" #: gio/gio-tool-remove.c:54 msgid "Delete the given files." @@ -2310,7 +2277,7 @@ msgstr "შექმნისას მიმდინარე მომხმ #: gio/gio-tool-save.c:55 msgid "When replacing, replace as if the destination did not exist" -msgstr "ჩანაცვლებისას, ჩაანაცვლე, თითქოს სამიზნე ფაილი არც არსებობდა" +msgstr "" #. Translators: The "etag" is a token allowing to verify whether a file has been modified #: gio/gio-tool-save.c:57 @@ -2339,7 +2306,7 @@ msgstr "" #: gio/gio-tool-save.c:165 msgid "Read from standard input and save to DEST." -msgstr "წაკითხვა სტანდარტული შეყვანიდან და მითითებულ სამიზნეზე ჩაწერა." +msgstr "" #: gio/gio-tool-save.c:185 msgid "No destination given" @@ -2367,7 +2334,7 @@ msgstr "მნიშვნელობა" #: gio/gio-tool-set.c:99 msgid "Set a file attribute of LOCATION." -msgstr "მითითებული მდებარეობის ფაილის ატრიბუტის დაყენება." +msgstr "" #: gio/gio-tool-set.c:119 msgid "Location not specified" @@ -2392,15 +2359,13 @@ msgstr "ნაგვის ყუთის გასუფთავება" #: gio/gio-tool-trash.c:37 msgid "List files in the trash with their original locations" -msgstr "ნაგვის ყუთში არსებული ფაილების სია მათი საწყისი მდებარეობებით" +msgstr "" #: gio/gio-tool-trash.c:38 msgid "" "Restore a file from trash to its original location (possibly recreating the " "directory)" msgstr "" -"ფაილის აღდგენა ნაგვის ყუთიდან საწყის მდებარეობაზე (შეიძლება, საქაღალდეები " -"თავიდან შეიქმნას)" #: gio/gio-tool-trash.c:108 msgid "Unable to find original path" @@ -2416,20 +2381,17 @@ msgstr "შეუძლებელია ფაილების გადა #: gio/gio-tool-trash.c:227 msgid "Move/Restore files or directories to the trash." -msgstr "ფაილების ან საქაღალდეების ნაგვის ყუთში გადატანა/აღდგენა." +msgstr "" #: gio/gio-tool-trash.c:229 msgid "" "Note: for --restore switch, if the original location of the trashed file \n" "already exists, it will not be overwritten unless --force is set." msgstr "" -"შენიშვნა: პარამეტრისთვის --restore, თუ ნაგვის ყუთში არსებული ფაილის საწყისი " -"მდებარეობა უკვე არსებობს,\n" -"მას თავზე არ გადავაწერთ, თუ არ მიუთითებთ პარამეტრს --force." #: gio/gio-tool-trash.c:260 msgid "Location given doesn't start with trash:///" -msgstr "მითითებული მდებარეობა არ იწყება სტრიქონით trash:///" +msgstr "" #: gio/gio-tool-tree.c:35 msgid "Follow symbolic links, mounts and shortcuts" @@ -2478,8 +2440,6 @@ msgstr "დამუშავების უცნობი პარამე #, c-format msgid "%s preprocessing requested, but %s is not set, and %s is not in PATH" msgstr "" -"%s წინასწარი დამუშავება მოთხოვნილია, მაგრამ %s დაყენებული არაა და %s გარემოს " -"ცვლად PATH-ში არაა" #: gio/glib-compile-resources.c:459 #, c-format @@ -2509,8 +2469,6 @@ msgid "" "The directories to load files referenced in FILE from (default: current " "directory)" msgstr "" -"საქაღალდეები, საიდანაც ფაილში მითითებული ფაილები ჩაიტვირთება (ნაგულისხმევი: " -"მიმდინარე საქაღალდე)" #: gio/glib-compile-resources.c:823 gio/glib-compile-schemas.c:2173 #: gio/glib-compile-schemas.c:2203 @@ -2521,8 +2479,6 @@ msgstr "DIRECTORY" msgid "" "Generate output in the format selected for by the target filename extension" msgstr "" -"გამოტანის გენერაცია ფორმატში, რომელიც სამიზნე ფაილის სახელის გაფართოების " -"მიხედვითაა არჩეული" #: gio/glib-compile-resources.c:825 msgid "Generate source header" @@ -2531,8 +2487,6 @@ msgstr "წყაროს თავსართის გენერაცი #: gio/glib-compile-resources.c:826 msgid "Generate source code used to link in the resource file into your code" msgstr "" -"კოდის ფაილის შექმნა, რომელიც რესურსის ფაილის თქვენ კოდთან მისაბმელად " -"გამოიყენება" #: gio/glib-compile-resources.c:827 msgid "Generate dependency list" @@ -2544,7 +2498,7 @@ msgstr "დასაგენერირებელი დამოკიდ #: gio/glib-compile-resources.c:829 msgid "Include phony targets in the generated dependency file" -msgstr "ფიქტიური სამიზნეების ჩასმა შექმნილ დამოკიდებულების ფაილში" +msgstr "" #: gio/glib-compile-resources.c:830 msgid "Don’t automatically create and register resource" @@ -2575,9 +2529,6 @@ msgid "" "Resource specification files have the extension .gresource.xml,\n" "and the resource file have the extension called .gresource." msgstr "" -"რესურსის აღწერის კომპილაცია რესურსის ფაილში.\n" -"რესურსის სპეციფიკაციის ფაილებს .gresource.xml გაფართოება აქვთ,\n" -"რესურსის ფაილებს კი .gresource." #: gio/glib-compile-resources.c:893 msgid "You should give exactly one file name\n" @@ -2586,7 +2537,7 @@ msgstr "უნდა მიაწოდოთ ზუსტად ერთი #: gio/glib-compile-schemas.c:95 #, c-format msgid "nick must be a minimum of 2 characters" -msgstr "ფსევდონიმი, მიმიმუმ, 2 სიმბოლოს უნდა შეიცავდეს" +msgstr "" #: gio/glib-compile-schemas.c:106 #, c-format @@ -2616,22 +2567,22 @@ msgstr "<%s> სულ ცოტა ერთ -ს უნდა შეი #: gio/glib-compile-schemas.c:317 #, c-format msgid "<%s> is not contained in the specified range" -msgstr "<%s> მითითებული შუალედიდან არაა" +msgstr "" #: gio/glib-compile-schemas.c:329 #, c-format msgid "<%s> is not a valid member of the specified enumerated type" -msgstr "<%s> მითითებული ჩამონათვალის ტიპის სწორი წევრი არაა" +msgstr "" #: gio/glib-compile-schemas.c:335 #, c-format msgid "<%s> contains string not in the specified flags type" -msgstr "<%s> შეიცავს სტრიქონს, რომელიც მითითებული ალმის ტიპში არაა" +msgstr "" #: gio/glib-compile-schemas.c:341 #, c-format msgid "<%s> contains a string not in " -msgstr "<%s> შეიცავს სტრიქონს, რომელიც -ში არაა" +msgstr "" #: gio/glib-compile-schemas.c:375 msgid " already specified for this key" @@ -2640,12 +2591,12 @@ msgstr " ამ გასაღებისთვის უკვე მ #: gio/glib-compile-schemas.c:393 #, c-format msgid " not allowed for keys of type “%s”" -msgstr " დაუშვებელია გასაღებებისთვის ტიპით “%s”" +msgstr "" #: gio/glib-compile-schemas.c:410 #, c-format msgid " specified minimum is greater than maximum" -msgstr " მაქსიმალური მნიშვნელობა მინიმალურზე მეტი უნდა იყოს" +msgstr "" #: gio/glib-compile-schemas.c:435 #, c-format @@ -2658,18 +2609,17 @@ msgstr "l10n მოთხოვნილია, მაგრამ gettext-ი #: gio/glib-compile-schemas.c:455 msgid "translation context given for value without l10n enabled" -msgstr "მითითებულია თარგმანის კონტექსტი l10n-ის ჩართვის გარეშე" +msgstr "" #: gio/glib-compile-schemas.c:477 #, c-format msgid "Failed to parse value of type “%s”: " -msgstr "ჩავარდა დამუშავება მნიშვნელობისა ტიპით “%s”: " +msgstr "" #: gio/glib-compile-schemas.c:494 msgid "" " cannot be specified for keys tagged as having an enumerated type" msgstr "" -" მითითებული ვერ იქნება გასაღებებისთვის, რომლებიც ჩამონათვლის ტიპისაა" #: gio/glib-compile-schemas.c:503 msgid " already specified for this key" @@ -2678,7 +2628,7 @@ msgstr " ამ გასაღებისთვის უკვე #: gio/glib-compile-schemas.c:515 #, c-format msgid " not allowed for keys of type “%s”" -msgstr " დაუშვებელია გასაღებებისთვის ტიპით “%s”" +msgstr "" #: gio/glib-compile-schemas.c:531 #, c-format @@ -2688,7 +2638,7 @@ msgstr " უკვე გადაცემულია" #: gio/glib-compile-schemas.c:546 #, c-format msgid " must contain at least one " -msgstr " უნდა შეიცავდეს სულ ცოტა ერთ " +msgstr "" #: gio/glib-compile-schemas.c:560 msgid " already specified for this key" @@ -2699,21 +2649,18 @@ msgid "" " can only be specified for keys with enumerated or flags types or " "after " msgstr "" -" შეიძლება, მხოლოდ, ჩამონათვლის ან ალმების ტიპის გასაღებებისთვის, ან " -"შემდეგ შეიძლება მითითებული იყოს " #: gio/glib-compile-schemas.c:583 #, c-format msgid "" " given when “%s” is already a member of the enumerated " "type" -msgstr " მოცემულია, როცა “%s” უკვე ჩამონათვლის ტიპის წევრია" +msgstr "" #: gio/glib-compile-schemas.c:589 #, c-format msgid " given when was already given" msgstr "" -"მითითებულია , როცა უკვე მითითებულია" #: gio/glib-compile-schemas.c:597 #, c-format @@ -2723,17 +2670,17 @@ msgstr " უკვე მითითებულია" #: gio/glib-compile-schemas.c:607 #, c-format msgid "alias target “%s” is not in enumerated type" -msgstr "ფსევდონიმის სამიზნე “%s” ჩამონათვლის ტიპი არაა" +msgstr "" #: gio/glib-compile-schemas.c:608 #, c-format msgid "alias target “%s” is not in " -msgstr "ფსევდონიმის სამიზნე “%s” სიაში არაა" +msgstr "" #: gio/glib-compile-schemas.c:623 #, c-format msgid " must contain at least one " -msgstr " სულ ცოტა ერთ -ს უნდა შეიცავდეს" +msgstr "" #: gio/glib-compile-schemas.c:797 msgid "Empty names are not permitted" @@ -2743,7 +2690,6 @@ msgstr "ცარელი სახელები დაუშვებელ #, c-format msgid "Invalid name “%s”: names must begin with a lowercase letter" msgstr "" -"არასწორი სახელი \"%s\": სახელები ქვედა რეგისტრის სიმბოლოებით უნდა იწყებოდეს" #: gio/glib-compile-schemas.c:819 #, c-format @@ -2751,23 +2697,21 @@ msgid "" "Invalid name “%s”: invalid character “%c”; only lowercase letters, numbers " "and hyphen (“-”) are permitted" msgstr "" -"არასწორი სახელი \"%s\": არასწორი სიმბოლო \"%c\": დაშვებულია, მხოლოდ პატარა " -"ასოები, ციფრები და ტირე (\"-\")" #: gio/glib-compile-schemas.c:828 #, c-format msgid "Invalid name “%s”: two successive hyphens (“--”) are not permitted" -msgstr "არასწორი სახელი “%s”: ორი ტირე ზედიზედ (“--”) დაშვებული არაა" +msgstr "" #: gio/glib-compile-schemas.c:837 #, c-format msgid "Invalid name “%s”: the last character may not be a hyphen (“-”)" -msgstr "არასწორი სახელი “%s”: ბოლო სიმბოლო ტირე (“-”) ვერ იქნება" +msgstr "" #: gio/glib-compile-schemas.c:845 #, c-format msgid "Invalid name “%s”: maximum length is 1024" -msgstr "არასწორი სახელი \"%s\": მაქსიმალური სიგრძეა 1024" +msgstr "" #: gio/glib-compile-schemas.c:917 #, c-format @@ -2776,7 +2720,7 @@ msgstr " უკვე მითითებულია" #: gio/glib-compile-schemas.c:943 msgid "Cannot add keys to a “list-of” schema" -msgstr "ვერ დავამატე გასაღებების სქემას \"list-of\"" +msgstr "" #: gio/glib-compile-schemas.c:954 #, c-format @@ -2789,8 +2733,6 @@ msgid "" " shadows in ; use " "to modify value" msgstr "" -" ჩრდილავს -ში. მნიშვნელობის " -"შესაცვლელად გამოიყენეთ " #: gio/glib-compile-schemas.c:983 #, c-format @@ -2798,8 +2740,6 @@ msgid "" "Exactly one of “type”, “enum” or “flags” must be specified as an attribute " "to " msgstr "" -"აუცილებელია ერთ-ერთის, “type”, “enum” ან “flags” მითითება ატრიბუტად " -"გასაღებისთვის " #: gio/glib-compile-schemas.c:1002 #, c-format @@ -2813,12 +2753,12 @@ msgstr "არასწორი GVariant ტიპის სტრიქონ #: gio/glib-compile-schemas.c:1047 msgid " given but schema isn’t extending anything" -msgstr " მითითებულია, მაგრამ სქემა არაფერს აფართოებს" +msgstr "" #: gio/glib-compile-schemas.c:1060 #, c-format msgid "No to override" -msgstr "გადასაფარი -ის გარეშე" +msgstr "" #: gio/glib-compile-schemas.c:1068 #, c-format @@ -2863,18 +2803,16 @@ msgid "" " extends but “%s” " "does not extend “%s”" msgstr "" -" აფართოებს -ს, " -"მაგრამ “%s” არ აფართოებს “%s”-ს" #: gio/glib-compile-schemas.c:1224 #, c-format msgid "A path, if given, must begin and end with a slash" -msgstr "ბილიკი, თუ მითითებულია, უნდა იწყებოდეს და მთავრდებოდეს დახრილი ხაზით" +msgstr "" #: gio/glib-compile-schemas.c:1231 #, c-format msgid "The path of a list must end with “:/”" -msgstr "სიის ბილიკი ':/'-ით უნდა მთავრდებოდეს" +msgstr "" #: gio/glib-compile-schemas.c:1240 #, c-format @@ -2882,8 +2820,6 @@ msgid "" "Warning: Schema “%s” has path “%s”. Paths starting with “/apps/”, “/" "desktop/” or “/system/” are deprecated." msgstr "" -"გაფრთხილება: სქემას “%s” აქვს ბილიკი “%s”. ბილიკები, რომლებიც იწყება “/" -"apps/”, “/desktop/” ან “/system/” მოძველებულია." #: gio/glib-compile-schemas.c:1270 #, c-format @@ -2893,16 +2829,16 @@ msgstr "<%s id='%s'> უკვე მითითებულია" #: gio/glib-compile-schemas.c:1420 gio/glib-compile-schemas.c:1436 #, c-format msgid "Only one <%s> element allowed inside <%s>" -msgstr "დაშვებულია, მხოლოდ, ერთი <%s> ელემენტი <%s>-ის შიგნით" +msgstr "" #: gio/glib-compile-schemas.c:1518 #, c-format msgid "Element <%s> not allowed at the top level" -msgstr "ელემენტი <%s> დაუშვებელია უმაღლეს დონეზე" +msgstr "" #: gio/glib-compile-schemas.c:1536 msgid "Element is required in " -msgstr "ელემენტი აუცილებელია გასაღებში " +msgstr "" #: gio/glib-compile-schemas.c:1626 #, c-format @@ -2912,7 +2848,7 @@ msgstr "<%s>-ის შიგნით შეუძლებელია, ტე #: gio/glib-compile-schemas.c:1694 #, c-format msgid "Warning: undefined reference to " -msgstr "გაფრთხილება: აღუწერელი მიმართვა სქემაზე " +msgstr "" #. Translators: Do not translate "--strict". #: gio/glib-compile-schemas.c:1833 gio/glib-compile-schemas.c:1912 @@ -2933,8 +2869,6 @@ msgid "" "No such key “%s” in schema “%s” as specified in override file “%s”; ignoring " "override for this key." msgstr "" -"არ არსებობს გასაღები \"%s\" სქემაში \"%s\", როგორც ეს მითითებულია გადაფარვის " -"ფაილში \"%s\". გადაფარვა ამ გასაღებისთვის გამოტოვებული იქნება." #: gio/glib-compile-schemas.c:1971 #, c-format @@ -2942,8 +2876,6 @@ msgid "" "No such key “%s” in schema “%s” as specified in override file “%s” and --" "strict was specified; exiting." msgstr "" -"არ არსებობს გასაღები \"%s\" სქემაში \"%s\", როგორც ეს მითითებულია გადაფარვის " -"ფაილში \"%s\" და მითითებულია პარამეტრი --strict. გასვლა." #: gio/glib-compile-schemas.c:1993 #, c-format @@ -2951,9 +2883,6 @@ msgid "" "Cannot provide per-desktop overrides for localized key “%s” in schema " "“%s” (override file “%s”); ignoring override for this key." msgstr "" -"შეუძლებელია თითოეული სამუშაო მაგიდის ფაილის გადაფარვების წარმოდგენა " -"ლოკალიზებული პარამეტრისთვის \"%s\" სქემაში \"%s\" (გადაფარვის ფაილი \"%s\"). " -"ამ პარამეტრისთვის გადაფარვა გამოტოვებული იქნება." #: gio/glib-compile-schemas.c:2002 #, c-format @@ -2961,9 +2890,6 @@ msgid "" "Cannot provide per-desktop overrides for localized key “%s” in schema " "“%s” (override file “%s”) and --strict was specified; exiting." msgstr "" -"შეუძლებელია თითოეული სამუშაო მაგიდის ფაილის გადაფარვების წარმოდგენა " -"ლოკალიზებული პარამეტრისთვის \"%s\" სქემაში \"%s\" (გადაფარვის ფაილი \"%s\") " -"და მითითებულია პარამეტრი --strict. გასვლა." #: gio/glib-compile-schemas.c:2026 #, c-format @@ -2971,9 +2897,6 @@ msgid "" "Error parsing key “%s” in schema “%s” as specified in override file “%s”: " "%s. Ignoring override for this key." msgstr "" -"დამუშავების შეცდომა პარამეტრისთვის \"%s\" სქემაში \"%s\", როგორც ეს " -"მითითებულია გადაფარვის ფაილში \"%s\": %s. ამ პარამეტრისთვის გადაფარვა " -"გამოტოვებული იქნება." #: gio/glib-compile-schemas.c:2038 #, c-format @@ -2981,9 +2904,6 @@ msgid "" "Error parsing key “%s” in schema “%s” as specified in override file “%s”: " "%s. --strict was specified; exiting." msgstr "" -"დამუშავების შეცდომა პარამეტრისთვის \"%s\" სქემაში \"%s\", როგორც ეს " -"მითითებულია გადაფარვის ფაილში \"%s\": %s. ასევე მითითებულია პარამეტრი --" -"strict. გასვლა." #: gio/glib-compile-schemas.c:2065 #, c-format @@ -2991,9 +2911,6 @@ msgid "" "Override for key “%s” in schema “%s” in override file “%s” is outside the " "range given in the schema; ignoring override for this key." msgstr "" -"გადაფარვა პარამეტრისთვის \"%s\" სქემაში \"%s\" გადაფარვის ფაილში \"%s\" " -"სქემაში მითითებულ შუალედს გარეთაა. ამ პარამეტრის გადაფარვა გამოტოვებული " -"იქნება." #: gio/glib-compile-schemas.c:2075 #, c-format @@ -3001,8 +2918,6 @@ msgid "" "Override for key “%s” in schema “%s” in override file “%s” is outside the " "range given in the schema and --strict was specified; exiting." msgstr "" -"გადაფარვა პარამეტრისთვის \"%s\" სქემაში \"%s\" გადაფარვის ფაილში \"%s\" " -"სქემაში მითითებულ შუალედს გარეთაა და მითითებულია პარამეტრი --strict. გასვლა." #: gio/glib-compile-schemas.c:2101 #, c-format @@ -3010,9 +2925,6 @@ msgid "" "Override for key “%s” in schema “%s” in override file “%s” is not in the " "list of valid choices; ignoring override for this key." msgstr "" -"გადაფარვა პარამეტრისთვის \"%s\" სქემაში \"%s\" გადაფარვის ფაილში \"%s\" " -"სქემაში სწორი არჩევნების სიაში არაა. ამ პარამეტრის გადაფარვა გამოტოვებული " -"იქნება." #: gio/glib-compile-schemas.c:2111 #, c-format @@ -3020,9 +2932,6 @@ msgid "" "Override for key “%s” in schema “%s” in override file “%s” is not in the " "list of valid choices and --strict was specified; exiting." msgstr "" -"გადაფარვა პარამეტრისთვის \"%s\" სქემაში \"%s\" გადაფარვის ფაილში \"%s\" " -"სქემაში სწორი არჩევნების სიაში არაა და მითითებულია პარამეტრი --strict. " -"გასვლა." #: gio/glib-compile-schemas.c:2173 msgid "Where to store the gschemas.compiled file" @@ -3046,9 +2955,6 @@ msgid "" "Schema files are required to have the extension .gschema.xml,\n" "and the cache file is called gschemas.compiled." msgstr "" -"ყველა GSettings-ის სქემა ფაილის კომპილაცია სქემის კეშში.\n" -"სქემის ფაილებს, აუცილებლად, უნდა ჰქონდეთ გაფართოება .gschema.xml\n" -"და კეშის ფაილს ჰქვია gschemas.compiled." #: gio/glib-compile-schemas.c:2238 msgid "You should give exactly one directory name" @@ -3275,22 +3181,22 @@ msgstr "სიმბმულის დაყენების შეცდო #: gio/glocalfileinfo.c:2599 #, c-format msgid "Extra nanoseconds %d for UNIX timestamp %lld are negative" -msgstr "დამატებითი ნანოწამები %d UNIX დროის შტამპისთვის %lld უარყოფითებია" +msgstr "" #: gio/glocalfileinfo.c:2608 #, c-format msgid "Extra nanoseconds %d for UNIX timestamp %lld reach 1 second" -msgstr "დამატებითი ნანოწამები %d UNIX დროის შტამპისთვის %lld 1 წამს აღწევს" +msgstr "" #: gio/glocalfileinfo.c:2618 #, c-format msgid "UNIX timestamp %lld does not fit into 64 bits" -msgstr "UNIX დროის შტამპი %lld 64 ბიტში არ ეტევა" +msgstr "" #: gio/glocalfileinfo.c:2629 #, c-format msgid "UNIX timestamp %lld is outside of the range supported by Windows" -msgstr "UNIX დროის შტამპი %lld Windows-ის მიერ მხარდაჭერილი შუალედის გარეთაა" +msgstr "" #: gio/glocalfileinfo.c:2761 #, c-format @@ -3300,32 +3206,32 @@ msgstr "ფაილის სახელის \"%s\" UTF-16-ში გად #: gio/glocalfileinfo.c:2780 #, c-format msgid "File “%s” cannot be opened: Windows Error %lu" -msgstr "ფაილის \"%s\" გახსნა შეუძლებელია: Windows-ის შეცდომა %lu" +msgstr "" #: gio/glocalfileinfo.c:2793 #, c-format msgid "Error setting modification or access time for file “%s”: %lu" msgstr "%s-ისთვის შეცვლის ან წვდომის დროის დაყენების შეცდომა: %lu" -#: gio/glocalfileinfo.c:2970 +#: gio/glocalfileinfo.c:2950 #, c-format msgid "Error setting modification or access time: %s" msgstr "ცვლილების ან წვდომის დროის დაყენების შეცდომა: %s" -#: gio/glocalfileinfo.c:2993 +#: gio/glocalfileinfo.c:2973 msgid "SELinux context must be non-NULL" msgstr "SELinux-ის კონტექსტი ნულოვანი არ უნდა იყოს" -#: gio/glocalfileinfo.c:3000 +#: gio/glocalfileinfo.c:2980 msgid "SELinux is not enabled on this system" msgstr "ამ სისტემაზე SELnux ჩართული არაა" -#: gio/glocalfileinfo.c:3010 +#: gio/glocalfileinfo.c:2990 #, c-format msgid "Error setting SELinux context: %s" msgstr "SELinux-ის კონტექსტის დაყენების შეცდომა: %s" -#: gio/glocalfileinfo.c:3107 +#: gio/glocalfileinfo.c:3087 #, c-format msgid "Setting attribute %s not supported" msgstr "ატრიბუტის (%s) დაყენება მხარდაუჭერელია" @@ -3425,15 +3331,14 @@ msgid "" "Amount of memory required to process the write is larger than available " "address space" msgstr "" -"მეხსიერება, რომელიც პროცესს ჩასაწერად სჭირდება, ხელმისაწვდომ სივრცეზე დიდია" #: gio/gmemoryoutputstream.c:774 msgid "Requested seek before the beginning of the stream" -msgstr "მოთხოვნილია გადახვევა ნაკადის დასაწყისამდე" +msgstr "" #: gio/gmemoryoutputstream.c:789 msgid "Requested seek beyond the end of the stream" -msgstr "მოთხოვნილა გადახვევა ნაკადის ბოლოს შემდეგ" +msgstr "" #. Translators: This is an error #. * message for mount objects that @@ -3593,7 +3498,7 @@ msgstr "შეყვანის ნაკადს გადახვევი #: gio/gresource-tool.c:502 msgid "List sections containing resources in an elf FILE" -msgstr "რესურსების შემცველი სექციების სია მითითებულ elf ფაილში" +msgstr "" #: gio/gresource-tool.c:508 msgid "" @@ -3601,9 +3506,6 @@ msgid "" "If SECTION is given, only list resources in this section\n" "If PATH is given, only list matching resources" msgstr "" -"რესურსების სია\n" -"თუ მითითებულია სექცია, ჩამოთვლილი იქნება მხოლოდ ამ სექციის რესურსები\n" -"თუ მითითებულია ბილიკი, ჩამოთვლილი იქნება მხოლოდ შესაბამისი რესურსები" #: gio/gresource-tool.c:511 gio/gresource-tool.c:521 msgid "FILE [PATH]" @@ -3620,11 +3522,6 @@ msgid "" "If PATH is given, only list matching resources\n" "Details include the section, size and compression" msgstr "" -"რესურსების ჩამოთვლა დეტალებით\n" -"თუ მითითებულია სექცია, ჩამოთვლილი იქნება, მხოლოდ, ამ სექციაში არსებული " -"რესურსები\n" -"თუ მითითებულია ბილიკი, ჩამოთვლილი იქნება, მხოლოდ, შესაბამისი რესურსები\n" -"დეტალები შეიცავს სექციას, ზომას და შეკუმშვას" #: gio/gresource-tool.c:527 msgid "Extract a resource file to stdout" @@ -3649,18 +3546,6 @@ msgid "" "Use “gresource help COMMAND” to get detailed help.\n" "\n" msgstr "" -"გამოყენება:\n" -" gresource [--section სექცია] ბრძანება [არგუმენტები…]\n" -"\n" -"ბრძანებები:\n" -" help ამ ინფორმაციის ჩვენება\n" -" sections რესურსის სექციების ჩვენება\n" -" list რესურსების სია\n" -" details რესურსების სია დეტალების ჩათვლით\n" -" extract რესურსის გამოღება\n" -"\n" -"მეტი ინფორმაციისთვის გამოიყენეთ ბრძანება “gresource help ბრძანება”.\n" -"\n" #: gio/gresource-tool.c:556 #, c-format @@ -3679,23 +3564,21 @@ msgstr "" #: gio/gresource-tool.c:563 msgid " SECTION An (optional) elf section name\n" -msgstr " სექცია (არასავალდებულო) elf სექციის სახელი\n" +msgstr "" #: gio/gresource-tool.c:567 gio/gsettings-tool.c:720 msgid " COMMAND The (optional) command to explain\n" -msgstr " ბრძანება (არასავალდებულო) ასახსნელი ბრძანება\n" +msgstr "" #: gio/gresource-tool.c:573 msgid " FILE An elf file (a binary or a shared library)\n" -msgstr " ფაილი elf ფაილი (გამშვები ან გაზიარებული ბიბლიოთეკა)\n" +msgstr "" #: gio/gresource-tool.c:576 msgid "" " FILE An elf file (a binary or a shared library)\n" " or a compiled resource file\n" msgstr "" -" ფაილი elf ფაილი (გამშვები ან გაზიარებული ბიბლიოთეკა)\n" -" ან აგებული რესურსის ფაილი\n" #: gio/gresource-tool.c:580 msgid "[PATH]" @@ -3704,7 +3587,6 @@ msgstr "[ბილიკი]" #: gio/gresource-tool.c:582 msgid " PATH An (optional) resource path (may be partial)\n" msgstr "" -" ბილიკი (არასავალდებულო) რესურსის ბილიკი (შეიძლება იყოს ნაწილობრივი)\n" #: gio/gresource-tool.c:583 msgid "PATH" @@ -3722,12 +3604,12 @@ msgstr "სქემა \"%s\" არ არსებობს\n" #: gio/gsettings-tool.c:57 #, c-format msgid "Schema “%s” is not relocatable (path must not be specified)\n" -msgstr "სქემა \"%s\" გადატანადი არაა (ბილიკი მითითებული არ უნდა იყოს)\n" +msgstr "" #: gio/gsettings-tool.c:78 #, c-format msgid "Schema “%s” is relocatable (path must be specified)\n" -msgstr "სქემა \"%s\" გადატანადია (ბილიკი მითითებული არ უნდა იყოს)\n" +msgstr "" #: gio/gsettings-tool.c:92 msgid "Empty path given.\n" @@ -3778,8 +3660,6 @@ msgid "" "List keys and values, recursively\n" "If no SCHEMA is given, list all keys\n" msgstr "" -"გასაღებების და მნიშვნელობების რეკურსიული ჩამონათვალი\n" -"თუ სქემა მითითებული არაა, გამოჩნდება ყველა გასაღები\n" #: gio/gsettings-tool.c:624 msgid "[SCHEMA[:PATH]]" @@ -3796,7 +3676,7 @@ msgstr "სქემა[:ბილიკი] გასაღები" #: gio/gsettings-tool.c:635 msgid "Query the range of valid values for KEY" -msgstr "მითითებული გასაღებისთვის სწორი მნიშვნელობის შუალედების გამოთხოვა" +msgstr "" #: gio/gsettings-tool.c:641 msgid "Query the description for KEY" @@ -3828,10 +3708,6 @@ msgid "" "If no KEY is specified, monitor all keys in SCHEMA.\n" "Use ^C to stop monitoring.\n" msgstr "" -"მითითებული გასაღების თვალყური ცვლილებებზე.\n" -"თუ გასაღები მითითებული არაა, თვალყური მიდევნებული იქნება სქემაში არსებულ " -"ყველა გასაღებზე.\n" -"გასაჩერებლად გამოიყენეთ ^C.\n" #: gio/gsettings-tool.c:674 msgid "SCHEMA[:PATH] [KEY]" @@ -3862,30 +3738,6 @@ msgid "" "Use “gsettings help COMMAND” to get detailed help.\n" "\n" msgstr "" -"გამოყენება:\n" -" gsettings --version\n" -" gsettings [--schemadir SCHEMADIR] COMMAND [ARGS…]\n" -"\n" -"ბრძანებები:\n" -" help ამ ინფორმაციის ჩვენება\n" -" list-schemas დაყენებული სქემების სია\n" -" list-relocatable-schemas გადატანადი სქემების ჩამოთვლა\n" -" list-keys სქემაში პარამეტრების ჩამოთვლა\n" -" list-children სქემის შვილების ჩამოთვლა\n" -" list-recursively პარამეტრიების და მნიშვნელობების ჩამოთვლა, " -"რეკურსიულად\n" -" range პარამეტრის შუალედის გამოთხოვა\n" -" describe პარამეტრის აღწერის გამოთხოვა\n" -" get პარამეტრის მნიშვნელობის მიღება\n" -" set პარამეტრის მნიშვნელობის დაყენება\n" -" reset პარამეტრის მნიშვნელობის ჩამოყრა\n" -" reset-recursively მითითებულ სქემაში ყველა მნიშვნელობის ჩამოყრა\n" -" writable შემოწმება, არის თუ არა პარამეტრი ჩაწერადი\n" -" monitor ცვლილებების თვალყურის დევნება\n" -"\n" -"დეტალური დახმარების მისაღებად გამოიყენეთ ბრძანება “gsettings help " -"ბრძანება”.\n" -"\n" #: gio/gsettings-tool.c:710 #, c-format @@ -3896,35 +3748,28 @@ msgid "" "%s\n" "\n" msgstr "" -"გამოყენება:\n" -" gsettings [--schemadir SCHEMADIR] %s %s\n" -"\n" -"%s\n" -"\n" #: gio/gsettings-tool.c:716 msgid " SCHEMADIR A directory to search for additional schemas\n" -msgstr " SCHEMADIR საქაღალდე დამატებითი სქემების მოსაძებნად\n" +msgstr "" #: gio/gsettings-tool.c:724 msgid "" " SCHEMA The name of the schema\n" " PATH The path, for relocatable schemas\n" msgstr "" -" SCHEMA სქემის სახელი\n" -" PATH ბილიკი გადატანადი სქემებისთვის\n" #: gio/gsettings-tool.c:729 msgid " KEY The (optional) key within the schema\n" -msgstr " KEY (არასავალდებულო) გასაღები სქემაში\n" +msgstr "" #: gio/gsettings-tool.c:733 msgid " KEY The key within the schema\n" -msgstr " გასაღები გასაღები სქემაშ\n" +msgstr "" #: gio/gsettings-tool.c:737 msgid " VALUE The value to set\n" -msgstr " მნისვნელობა დასაყენებელი მნიშვნელობა\n" +msgstr "" #: gio/gsettings-tool.c:792 #, c-format @@ -3958,7 +3803,7 @@ msgid "Socket is already closed" msgstr "სოკეტი უკვე დახურულია" #: gio/gsocket.c:449 gio/gsocket.c:3238 gio/gsocket.c:4469 gio/gsocket.c:4527 -#: gio/gthreadedresolver.c:1445 +#: gio/gthreadedresolver.c:1438 msgid "Socket I/O timed out" msgstr "სოკეტის I/O ვადა გავიდა" @@ -3983,14 +3828,12 @@ msgstr "მითითებული პროტოკოლი უცნო #: gio/gsocket.c:1190 #, c-format msgid "Cannot use datagram operations on a non-datagram socket." -msgstr "დატაგრამის ოპერაციებს არა-დატაგრამის სოკეტზე ვერ გამოიყენებთ." +msgstr "" #: gio/gsocket.c:1207 #, c-format msgid "Cannot use datagram operations on a socket with a timeout set." msgstr "" -"დატაგრამის ოპერაციებს სოკეტზე, რომელსაც მოლოდინის დრო დაყენებული აქვს, ვერ " -"გამოიყენებთ." #: gio/gsocket.c:2014 #, c-format @@ -4048,11 +3891,11 @@ msgstr "ინტერფეისი ვერ ვიპოვე: %s" #: gio/gsocket.c:2646 msgid "No support for IPv4 source-specific multicast" -msgstr "IPv4 წყაროზე-დამოკიდებული multicast-ის მხარდაჭერის გარეშე" +msgstr "" #: gio/gsocket.c:2704 msgid "No support for IPv6 source-specific multicast" -msgstr "IPv6 წყაროზე-დამოკიდებული multicast-ის მხარდაჭერის გარეშე" +msgstr "" #: gio/gsocket.c:2937 #, c-format @@ -4109,7 +3952,7 @@ msgstr "შეტყობინების გაგზავნის შე #: gio/gsocket.c:5074 msgid "GSocketControlMessage not supported on Windows" -msgstr "ფუნქცია GSocketControlMessage Windows-ზე მხარდაჭერილი არაა" +msgstr "" #: gio/gsocket.c:5547 gio/gsocket.c:5623 gio/gsocket.c:5849 #, c-format @@ -4123,7 +3966,7 @@ msgstr "სოკეტის მომხმარებლის/პარო #: gio/gsocket.c:6217 msgid "g_socket_get_credentials not implemented for this OS" -msgstr "g_socket_get_credentials ამ OS-სთვის განხორციელებული არაა" +msgstr "" #: gio/gsocketclient.c:193 #, c-format @@ -4159,58 +4002,55 @@ msgstr "დამატებული სოკეტი დახურულ #: gio/gsocks4aproxy.c:120 #, c-format msgid "SOCKSv4 does not support IPv6 address “%s”" -msgstr "SOCKSv4-ს არ აქვს მხარდაჭერა IPv6 მისამართისთვის “%s”" +msgstr "" #: gio/gsocks4aproxy.c:138 msgid "Username is too long for SOCKSv4 protocol" -msgstr "SOCKSv4 პროტოკოლისთვის მომხმარებლის სახელი ძალიან გრძელია" +msgstr "" #: gio/gsocks4aproxy.c:155 #, c-format msgid "Hostname “%s” is too long for SOCKSv4 protocol" -msgstr "SOCKSv4 პროტოკოლისთვის ჰოსტის სახელი '%s' მეტისმეტად გრძელია" +msgstr "" #: gio/gsocks4aproxy.c:181 msgid "The server is not a SOCKSv4 proxy server." -msgstr "სერვერი SOCKSv4 პროქსი სერვერი არაა." +msgstr "" #: gio/gsocks4aproxy.c:188 msgid "Connection through SOCKSv4 server was rejected" -msgstr "შეერთება SOCKSv4 სერვერის გავლით უარყოფილია" +msgstr "" #: gio/gsocks5proxy.c:155 gio/gsocks5proxy.c:340 gio/gsocks5proxy.c:350 msgid "The server is not a SOCKSv5 proxy server." -msgstr "სერვერი SOCKSv5 პროქსი სერვერი არაა." +msgstr "" #: gio/gsocks5proxy.c:169 gio/gsocks5proxy.c:186 msgid "The SOCKSv5 proxy requires authentication." -msgstr "SOCKSv5 პროქსის ავთენტიკაციას მოითხოვს." +msgstr "" #: gio/gsocks5proxy.c:193 msgid "" "The SOCKSv5 proxy requires an authentication method that is not supported by " "GLib." msgstr "" -"SOCKSv5 პროქსი მოითხოვს ავთენტიკაციის მეთოდს, რომელიც GLib-ის მიერ " -"მხარდაჭერილი არაა." #: gio/gsocks5proxy.c:222 msgid "Username or password is too long for SOCKSv5 protocol." -msgstr "SOCKSv5 პროტოკოლისთვის მომხმარებლის სახელი ან პაროლი ძალიან გრძელია." +msgstr "" #: gio/gsocks5proxy.c:252 msgid "SOCKSv5 authentication failed due to wrong username or password." msgstr "" -"SOCKSv5 ავთენტიკაცია ჩავარდა, რადგან მომხმარებლის სახელი ან პაროლი არასწორია." #: gio/gsocks5proxy.c:302 #, c-format msgid "Hostname “%s” is too long for SOCKSv5 protocol" -msgstr "SOCKSv5 პროტოკოლისთვის ჰოსტის სახელი '%s' მეტისმეტად გრძელია" +msgstr "" #: gio/gsocks5proxy.c:364 msgid "The SOCKSv5 proxy server uses unknown address type." -msgstr "SOCKSv5 პროქსი სერვერი უცნობი მისამართის ტიპს იყენებს." +msgstr "" #: gio/gsocks5proxy.c:371 msgid "Internal SOCKSv5 proxy server error." @@ -4218,27 +4058,27 @@ msgstr "შიდა SOCKSv5 პროქსის შეცდომა." #: gio/gsocks5proxy.c:377 msgid "SOCKSv5 connection not allowed by ruleset." -msgstr "SOCKSv5 მიერთება დაუშვებელია წესების მიერ." +msgstr "" #: gio/gsocks5proxy.c:384 msgid "Host unreachable through SOCKSv5 server." -msgstr "SOCKSv5 სერვერის გავლით ჰოსტი მიუწვდომელია." +msgstr "" #: gio/gsocks5proxy.c:390 msgid "Network unreachable through SOCKSv5 proxy." -msgstr "SOCKSv5 სერვერის გავლით ქსელი ხელმიუწვდომელია." +msgstr "" #: gio/gsocks5proxy.c:396 msgid "Connection refused through SOCKSv5 proxy." -msgstr "SOCKSv5 პროქსის გავლით მიერთება უარყოფილია." +msgstr "" #: gio/gsocks5proxy.c:402 msgid "SOCKSv5 proxy does not support “connect” command." -msgstr "SOCKSv5 პროქსის ბრძანება \"connect\"-ის მხარდაჭერა არ გააჩნია." +msgstr "" #: gio/gsocks5proxy.c:408 msgid "SOCKSv5 proxy does not support provided address type." -msgstr "SOCKSv5 პროქსის მითითებული მისამართის ტიპის მხარდაჭერა არ გააჩნია." +msgstr "" #: gio/gsocks5proxy.c:414 msgid "Unknown SOCKSv5 proxy error." @@ -4266,7 +4106,7 @@ msgstr "სწორი მისამართები ვერ ვიპო #: gio/gthreadedresolver.c:514 #, c-format msgid "Error reverse-resolving “%s”: %s" -msgstr "\"%s\"-ის უკუამოხსნის შეცდომა: %s" +msgstr "" #. Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ #: gio/gthreadedresolver.c:737 gio/gthreadedresolver.c:759 @@ -4274,18 +4114,18 @@ msgstr "\"%s\"-ის უკუამოხსნის შეცდომა: % #: gio/gthreadedresolver.c:889 gio/gthreadedresolver.c:901 #, c-format msgid "Error parsing DNS %s record: malformed DNS packet" -msgstr "DNS %s ჩანაწერის დამუშავება ჩავარდა: DNS პაკეტი შეცდომებს შეიცავს" +msgstr "" #: gio/gthreadedresolver.c:959 gio/gthreadedresolver.c:1096 #: gio/gthreadedresolver.c:1194 gio/gthreadedresolver.c:1244 #, c-format msgid "No DNS record of the requested type for “%s”" -msgstr "მოთხოვნილი ტიპის DNS ჩანაწერის გარეშე \"%s\"-სთვის" +msgstr "" #: gio/gthreadedresolver.c:964 gio/gthreadedresolver.c:1199 #, c-format msgid "Temporarily unable to resolve “%s”" -msgstr "დროებით \"%s\" ვერ ამოვხსენი" +msgstr "" #: gio/gthreadedresolver.c:969 gio/gthreadedresolver.c:1204 #: gio/gthreadedresolver.c:1300 @@ -4301,41 +4141,41 @@ msgstr "არასწორი DNS პაკეტი" #: gio/gthreadedresolver.c:1089 #, c-format msgid "Failed to parse DNS response for “%s”: " -msgstr "\"%s\"-სთვის DNS პასუხის დამუშავება ჩავარდა: " +msgstr "" #: gio/gtlscertificate.c:480 msgid "No PEM-encoded private key found" -msgstr "PEM-ით კოდირებული პირადი გასაღები ვერ ვიპოვე" +msgstr "" #: gio/gtlscertificate.c:490 msgid "Cannot decrypt PEM-encoded private key" -msgstr "PEM-ით დაშიფრული პირადი გასაღების გაშიფვრა შეუძლებელია" +msgstr "" #: gio/gtlscertificate.c:501 msgid "Could not parse PEM-encoded private key" -msgstr "PEM-ით დაშიფრული პირადი გასაღების გაშიფვრის შეცდომა" +msgstr "" #: gio/gtlscertificate.c:528 msgid "No PEM-encoded certificate found" -msgstr "PEM-ით დაშიფრული სერტიფიკატი ვერ ვიპოვე" +msgstr "" #: gio/gtlscertificate.c:537 msgid "Could not parse PEM-encoded certificate" -msgstr "PEM-ით დაშიფრული სერტიფიკატის გაშიფვრის შეცდომა" +msgstr "" #: gio/gtlscertificate.c:800 msgid "The current TLS backend does not support PKCS #12" -msgstr "მიმდინარე TLS უკანაბოლოს PKCS #12-ის მხარდაჭერა არ გააჩნია" +msgstr "" #: gio/gtlscertificate.c:1017 msgid "This GTlsBackend does not support creating PKCS #11 certificates" -msgstr "GTlsBackend-ს PKCS #11 სერტიფიკატების შექმნის მხარდაჭერა არ გააჩნია" +msgstr "" #: gio/gtlspassword.c:113 msgid "" "This is the last chance to enter the password correctly before your access " "is locked out." -msgstr "ბოლო შანსი, შეიყვანოთ სწორი პაროლი, სანამ წვდომა დაგებლოკებათ." +msgstr "" #. Translators: This is not the 'This is the last chance' string. It is #. * displayed when more than one attempt is allowed. @@ -4344,8 +4184,6 @@ msgid "" "Several passwords entered have been incorrect, and your access will be " "locked out after further failures." msgstr "" -"რამდენიმე პაროლი, რომელიც შეიყვანეთ, არასწორი აღმოჩნდა. თუ ეს განმეორდება, " -"წვდომა დაგებლოკებათ." #: gio/gtlspassword.c:119 msgid "The password entered is incorrect." @@ -4359,11 +4197,11 @@ msgstr "FD-ის გაგზავნა მხარდაუჭერელ #, c-format msgid "Expecting 1 control message, got %d" msgid_plural "Expecting 1 control message, got %d" -msgstr[0] "მოველოდი 1 საკონტროლო შეტყობინებას. მივიღე %d" +msgstr[0] "" #: gio/gunixconnection.c:197 gio/gunixconnection.c:614 msgid "Unexpected type of ancillary data" -msgstr "დამატებითი მონაცემების მოულოდნელი ტიპი" +msgstr "" #: gio/gunixconnection.c:216 #, c-format @@ -4386,29 +4224,27 @@ msgstr "შეცდომა ავტორიზაციის დეტა #: gio/gunixconnection.c:542 #, c-format msgid "Error checking if SO_PASSCRED is enabled for socket: %s" -msgstr "შემოწმების შეცდომა, ჩართულია თუ არა SO_PASSCRED სოკეტისთვის: %s" +msgstr "" #: gio/gunixconnection.c:558 #, c-format msgid "Error enabling SO_PASSCRED: %s" -msgstr "შეცდომა SO_PASSCRED-ის ჩართვისას: %s" +msgstr "" #: gio/gunixconnection.c:587 msgid "" "Expecting to read a single byte for receiving credentials but read zero bytes" msgstr "" -"მოველოდი ერთი ბაიტის წაკითხვას შესვლის დეტალების მისაღებად, მაგრამ წავიკითხე " -"ნული ბაიტი" #: gio/gunixconnection.c:628 #, c-format msgid "Not expecting control message, but got %d" -msgstr "არ მოველოდი საკონტროლო შეტყობინებას. მივიღე %d" +msgstr "" #: gio/gunixconnection.c:653 #, c-format msgid "Error while disabling SO_PASSCRED: %s" -msgstr "შეცდომა SO_PASSCRED-ის გამორთვისას: %s" +msgstr "" #: gio/gunixinputstream.c:359 gio/gunixinputstream.c:380 #, c-format @@ -4434,7 +4270,7 @@ msgstr "შეცდომა ფაილის დესკრიპტორ #: gio/gunixsocketaddress.c:253 msgid "Abstract UNIX domain socket addresses not supported on this system" -msgstr "აბსტრაქტული UNIX სოკეტის მისამართები ამ სისტემაზე მხარდაჭერილი არაა" +msgstr "" #: gio/gvolume.c:440 msgid "volume doesn’t implement eject" @@ -4445,7 +4281,7 @@ msgstr "ტომს გამოღების ფუნქცია არ #. * don't implement any of eject or eject_with_operation. #: gio/gvolume.c:517 msgid "volume doesn’t implement eject or eject_with_operation" -msgstr "ტომს eject ან eject_with_operaton ბრძანებების მხარდაჭერა არ გააჩნია" +msgstr "" #: gio/gwin32inputstream.c:187 #, c-format @@ -4485,7 +4321,7 @@ msgstr "მოსასმენი მისამართი" #: gio/tests/gdbus-daemon.c:19 msgid "Ignored, for compat with GTestDbus" -msgstr "გამოტოვებულია. GTestDbus-სთან თავსებადობისთვის" +msgstr "" #: gio/tests/gdbus-daemon.c:20 msgid "Print address" @@ -4529,7 +4365,7 @@ msgstr "უცნობი ჭდე '%s' - '%s'-ში" #: glib/gbookmarkfile.c:1717 #, c-format msgid "Invalid date/time ‘%s’ in bookmark file" -msgstr "არასწორი დრო/თარიღი ‘%s’ სანიშნეს ფაილში" +msgstr "" #: glib/gbookmarkfile.c:1956 msgid "No valid bookmark file found in data dirs" @@ -4576,11 +4412,11 @@ msgstr "პროგრამას სახელით \"%s\" სანიშ #: glib/gbookmarkfile.c:3863 #, c-format msgid "Failed to expand exec line “%s” with URI “%s”" -msgstr "ვერ დავასრულე შესრულების ხაზი \"%s\" URI-ით \"%s\"" +msgstr "" #: glib/gconvert.c:469 msgid "Unrepresentable character in conversion input" -msgstr "გადაყვანის შეტანაზე აღმოჩენილია არაჩვენებადი სიმბოლო" +msgstr "" #: glib/gconvert.c:496 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 #: glib/gutf8.c:1408 @@ -5042,7 +4878,7 @@ msgstr "PM" #: glib/gdir.c:158 #, c-format msgid "Error opening directory “%s”: %s" -msgstr "ვერ გავხსენი საქაღალდე \"%s\": %s" +msgstr "" #: glib/gfileutils.c:753 glib/gfileutils.c:845 #, c-format @@ -5065,7 +4901,7 @@ msgstr "%s: ფაილი ძალიან დიდია" msgid "Failed to read from file “%s”: %s" msgstr "ფაილიდან \"%s\" წაკითხვის შეცდომა: %s" -#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1502 +#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1472 #, c-format msgid "Failed to open file “%s”: %s" msgstr "ფაილის (%s) გახსნა შეუძლებელია: %s" @@ -5085,37 +4921,37 @@ msgstr "ფაილის \"%s\" გახსნის შეცდომა: f msgid "Failed to rename file “%s” to “%s”: g_rename() failed: %s" msgstr "ვერ მოხერხდა '%s' ფაილის გადარქმევა - '%s': g_rename() ვერ შედგა: %s" -#: glib/gfileutils.c:1209 +#: glib/gfileutils.c:1179 #, c-format msgid "Failed to write file “%s”: write() failed: %s" msgstr "ვერ ვწერ '%s' ფაილს: fwrite() ვერ შედგა: %s" -#: glib/gfileutils.c:1230 +#: glib/gfileutils.c:1200 #, c-format msgid "Failed to write file “%s”: fsync() failed: %s" msgstr "ვერ ვწერ '%s' ფაილს: fsync() ვერ შედგა: %s" -#: glib/gfileutils.c:1391 glib/gfileutils.c:1808 +#: glib/gfileutils.c:1361 glib/gfileutils.c:1776 #, c-format msgid "Failed to create file “%s”: %s" msgstr "ვერ ვქმნი '%s' ფაილს: %s" -#: glib/gfileutils.c:1436 +#: glib/gfileutils.c:1406 #, c-format msgid "Existing file “%s” could not be removed: g_unlink() failed: %s" msgstr "არსებული '%s' ფაილი ვერ ამოიშლება: g_unlink() ვერ შედგა: %s" -#: glib/gfileutils.c:1773 +#: glib/gfileutils.c:1741 #, c-format msgid "Template “%s” invalid, should not contain a “%s”" msgstr "შაბლონი '%s' მცდარია და '%s'-ს არ უნდა შეიცავდეს" -#: glib/gfileutils.c:1786 +#: glib/gfileutils.c:1754 #, c-format msgid "Template “%s” doesn’t contain XXXXXX" msgstr "შაბლონი '%s' არ შეიცავს XXXXXX" -#: glib/gfileutils.c:2380 glib/gfileutils.c:2409 +#: glib/gfileutils.c:2348 glib/gfileutils.c:2377 #, c-format msgid "Failed to read the symbolic link “%s”: %s" msgstr "სიმბოლური ბმის \"%s\" წაკითხვის შეცდომა: %s" @@ -5211,33 +5047,33 @@ msgstr "" #: glib/gkeyfile.c:2836 glib/gkeyfile.c:2913 #, c-format msgid "Key “%s” in group “%s” has value “%s” where %s was expected" -msgstr "გასაღებს “%s” ჯგუფში “%s” აქვს მნიშვნელობა “%s” სადაც მოველოდი %s" +msgstr "" -#: glib/gkeyfile.c:4357 +#: glib/gkeyfile.c:4356 msgid "Key file contains escape character at end of line" msgstr "გასაღების ფაილი სტრიქონის ბოლოს escape სიმბოლოს შეიცავს" -#: glib/gkeyfile.c:4394 +#: glib/gkeyfile.c:4378 #, c-format msgid "Key file contains invalid escape sequence “%s”" msgstr "გასაღების ფაილი მცდარ escape მიმდევრობას '%s' შეიცავს" -#: glib/gkeyfile.c:4545 +#: glib/gkeyfile.c:4530 #, c-format msgid "Value “%s” cannot be interpreted as a number." msgstr "მნიშვნელობა '%s' ვერ აღიქმება, როგორც რიცხვი." -#: glib/gkeyfile.c:4559 +#: glib/gkeyfile.c:4544 #, c-format msgid "Integer value “%s” out of range" msgstr "მთელი მნიშვნელობა '%s' დიაპაზონს გარეთაა" -#: glib/gkeyfile.c:4592 +#: glib/gkeyfile.c:4577 #, c-format msgid "Value “%s” cannot be interpreted as a float number." msgstr "მნიშვნელობა '%s' ვერ აღიქმება, როგორც წილადი." -#: glib/gkeyfile.c:4631 +#: glib/gkeyfile.c:4616 #, c-format msgid "Value “%s” cannot be interpreted as a boolean." msgstr "მნიშვნელობა '%s' ვერ აღიქმება, როგორც ლოგიკური ოპერატორი." @@ -5245,7 +5081,7 @@ msgstr "მნიშვნელობა '%s' ვერ აღიქმებ #: glib/gmappedfile.c:135 #, c-format msgid "Failed to get attributes of file “%s%s%s%s”: fstat() failed: %s" -msgstr "ჩავარდა ატრიბუტების მიღება ფაილისთვის “%s%s%s%s”: fstat() failed: %s" +msgstr "" #: glib/gmappedfile.c:201 #, c-format @@ -5260,7 +5096,7 @@ msgstr "ვერ მოხერხდა '%s' ფაილის გახს #: glib/gmarkup.c:398 glib/gmarkup.c:440 #, c-format msgid "Error on line %d char %d: " -msgstr "შეცდომა ხაზზე %d სიმბოლო %d: " +msgstr "" #: glib/gmarkup.c:462 glib/gmarkup.c:545 #, c-format @@ -5297,13 +5133,11 @@ msgid "" "ampersand character without intending to start an entity — escape ampersand " "as &" msgstr "" -"სიმბოლოს მიმართვა წერტილმძიმით არ სრულდება. როგორც ჩანს, გამოიყენეთ " -"ამპერსანდის სიმბოლო სახელის დაწყების გარეშე. ჩაანაცვლეთ ის სტრიქონით — &" #: glib/gmarkup.c:728 #, c-format msgid "Character reference “%-.*s” does not encode a permitted character" -msgstr "კოდი “%-.*s” დაშვებულ სიმბოლოს არ შეიცავს" +msgstr "" #: glib/gmarkup.c:766 msgid "" @@ -5349,7 +5183,7 @@ msgstr "" #: glib/gmarkup.c:1346 #, c-format msgid "Too many attributes in element “%s”" -msgstr "მეტისმეტად ბევრი ატრიბუტი ელემენტში \"%s\"" +msgstr "" #: glib/gmarkup.c:1366 #, c-format @@ -5530,302 +5364,297 @@ msgstr "არ არსებული არგუმენტი - %s-თვ msgid "Unknown option %s" msgstr "უცნობი პარამეტრი %s" -#: glib/gregex.c:487 +#: glib/gregex.c:480 msgid "corrupted object" msgstr "დაზიანებული ობიექტი" -#: glib/gregex.c:489 +#: glib/gregex.c:482 msgid "out of memory" msgstr "არასაკმარისი მეხსიერება" -#: glib/gregex.c:504 +#: glib/gregex.c:497 msgid "internal error" msgstr "შიდა შეცდომა" -#: glib/gregex.c:506 +#: glib/gregex.c:499 msgid "the pattern contains items not supported for partial matching" msgstr "თარგი შეიცავს ნაწილობრივი დამთხვევისთვის მხარდაუჭერელ ელემეტებს" -#: glib/gregex.c:508 +#: glib/gregex.c:501 msgid "back references as conditions are not supported for partial matching" msgstr "უკუ მიმართვა პირობების სახით მხარდაუჭერელია ნაწილობრივი დამთხვევისთვის" -#: glib/gregex.c:514 +#: glib/gregex.c:507 msgid "recursion limit reached" msgstr "რეკურსიის ლიმიტი მიღწეულია" -#: glib/gregex.c:516 +#: glib/gregex.c:509 msgid "bad offset" msgstr "არასწორი წანაცვლება" -#: glib/gregex.c:518 +#: glib/gregex.c:511 msgid "recursion loop" msgstr "რეკურსიის მარყუჟი" #. should not happen in GRegex since we check modes before each match -#: glib/gregex.c:521 +#: glib/gregex.c:514 msgid "matching mode is requested that was not compiled for JIT" -msgstr "მოთხოვნილია დამთხვევის რეჟიმი, რომელიც JIT-სთვის დაკომპილებული არაა" +msgstr "" -#: glib/gregex.c:542 glib/gregex.c:1870 +#: glib/gregex.c:535 glib/gregex.c:1851 msgid "unknown error" msgstr "უცნობი შეცდომა" -#: glib/gregex.c:563 +#: glib/gregex.c:556 msgid "\\ at end of pattern" msgstr "\\ ნიმუშის ბოლოში" -#: glib/gregex.c:567 +#: glib/gregex.c:560 msgid "\\c at end of pattern" msgstr "\\c ნიმუშის ბოლოში" -#: glib/gregex.c:572 +#: glib/gregex.c:565 msgid "unrecognized character following \\" -msgstr "უცნობი სიმბოლო \\-ის შემდეგ" +msgstr "" -#: glib/gregex.c:576 +#: glib/gregex.c:569 msgid "numbers out of order in {} quantifier" msgstr "მთვლელში რიცხვები დაულაგებელია {}" -#: glib/gregex.c:580 +#: glib/gregex.c:573 msgid "number too big in {} quantifier" msgstr "მთვლელში {} რიცხვები ძალიან დიდია" -#: glib/gregex.c:584 +#: glib/gregex.c:577 msgid "missing terminating ] for character class" msgstr "სიმბოლოების კლასს დამაბოლოებელი ] აკლია" -#: glib/gregex.c:588 +#: glib/gregex.c:581 msgid "invalid escape sequence in character class" msgstr "სიმბოლოების კლასის არასწორი დამაბოლოებელი თანამიმდევრობა" -#: glib/gregex.c:592 +#: glib/gregex.c:585 msgid "range out of order in character class" msgstr "სიმბოლოების კლასის დიაპაზონი მიმდევრობის გარეთაა" -#: glib/gregex.c:597 +#: glib/gregex.c:590 msgid "nothing to repeat" msgstr "გასამეორებელი არაფერია" -#: glib/gregex.c:601 +#: glib/gregex.c:594 msgid "unrecognized character after (? or (?-" msgstr "უცნობი სიმბლოები (? ან (?- ის შემდეგ" -#: glib/gregex.c:605 +#: glib/gregex.c:598 msgid "POSIX named classes are supported only within a class" msgstr "POSIX-ის დასახელებული კლასები მხოლოდ კლასის შიგნითაა ხელმისაწვდომი" -#: glib/gregex.c:609 +#: glib/gregex.c:602 msgid "POSIX collating elements are not supported" msgstr "POSIX-ის გადაფარვადი ელემენტები მხარდაუჭერელია" -#: glib/gregex.c:615 +#: glib/gregex.c:608 msgid "missing terminating )" -msgstr "აკლია დამხურავი )" +msgstr "" -#: glib/gregex.c:619 +#: glib/gregex.c:612 msgid "reference to non-existent subpattern" msgstr "ბმა არარსებულ ქვეშაბლონთან" -#: glib/gregex.c:623 +#: glib/gregex.c:616 msgid "missing ) after comment" msgstr "კომენტარის შემდეგ ) აკლია" -#: glib/gregex.c:627 +#: glib/gregex.c:620 msgid "regular expression is too large" msgstr "რეგულარული გამოსახულება ძალიან გრძელია" -#: glib/gregex.c:631 +#: glib/gregex.c:624 msgid "malformed number or name after (?(" msgstr "(?(-ის შემდეგ არასწორი რიცხვი ან სახელია" -#: glib/gregex.c:635 +#: glib/gregex.c:628 msgid "lookbehind assertion is not fixed length" msgstr "lookbehind assertion is not fixed length" -#: glib/gregex.c:639 +#: glib/gregex.c:632 msgid "conditional group contains more than two branches" msgstr "პირობითი ჯგუფი ორ ბრენჩზე მეტს შეიცავს" -#: glib/gregex.c:643 +#: glib/gregex.c:636 msgid "assertion expected after (?(" msgstr "assertion expected after (?(" -#: glib/gregex.c:647 +#: glib/gregex.c:640 msgid "a numbered reference must not be zero" -msgstr "რიცხვითი მიმართვა ნუილის ტოლი ვერ იქნება" +msgstr "" -#: glib/gregex.c:651 +#: glib/gregex.c:644 msgid "unknown POSIX class name" msgstr "posix-ის უცნობი კლასის სახელი" -#: glib/gregex.c:656 +#: glib/gregex.c:649 msgid "character value in \\x{...} sequence is too large" msgstr "character value in \\x{...} sequence is too large" -#: glib/gregex.c:660 +#: glib/gregex.c:653 msgid "\\C not allowed in lookbehind assertion" msgstr "\\C not allowed in lookbehind assertion" -#: glib/gregex.c:664 +#: glib/gregex.c:657 msgid "missing terminator in subpattern name" -msgstr "ქვეშაბლონის სახელს დამაბოლოებელი აკლია" +msgstr "" -#: glib/gregex.c:668 +#: glib/gregex.c:661 msgid "two named subpatterns have the same name" msgstr "ორ სხვადასხვა ქვეშაბლონს ერთი და იგივე სახელი აქვთ" -#: glib/gregex.c:672 +#: glib/gregex.c:665 msgid "malformed \\P or \\p sequence" msgstr "არასწორი \\P ან \\p მიმდევრობა" -#: glib/gregex.c:676 +#: glib/gregex.c:669 msgid "unknown property name after \\P or \\p" msgstr "უცნობი თვისების სახელი \\P-ის ან \\p-ის შემდეგ" -#: glib/gregex.c:680 +#: glib/gregex.c:673 msgid "subpattern name is too long (maximum 32 characters)" msgstr "ქვეშაბლონის სახელი ძალიან გრძელია (მაქს 32 სიმბოლო)" -#: glib/gregex.c:684 +#: glib/gregex.c:677 msgid "too many named subpatterns (maximum 10,000)" -msgstr "მეტისმეტად ბევრი სახელიანი ქვეშაბლონი (მაქს 10000)" +msgstr "" -#: glib/gregex.c:688 +#: glib/gregex.c:681 msgid "octal value is greater than \\377" -msgstr "რვაობითი მნიშვნელობა მეტია, ვიდრე \\377" +msgstr "" -#: glib/gregex.c:692 +#: glib/gregex.c:685 msgid "DEFINE group contains more than one branch" -msgstr "ჯგუფი DEFINE ერთზე მეტ ჯგუფს შეიცავს" +msgstr "" -#: glib/gregex.c:696 +#: glib/gregex.c:689 msgid "inconsistent NEWLINE options" -msgstr "არამდგრადი ახალი ხაზის პარამეტრები" +msgstr "" -#: glib/gregex.c:700 +#: glib/gregex.c:693 msgid "" "\\g is not followed by a braced, angle-bracketed, or quoted name or number, " "or by a plain number" msgstr "" -"\\g-ს არ მოსდევს ფრჩხილი, ერთი ბრჭყალი, ორმაგი ბრჭყალი ან რიცხვი ან უბრალოდ " -"რიცხვი" -#: glib/gregex.c:705 +#: glib/gregex.c:698 msgid "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" msgstr "" -"ბრძანებებისთვის (*ACCEPT), (*FAIL), ან (*COMMIT) არგუმენტი დაშვებული არაა" -#: glib/gregex.c:709 +#: glib/gregex.c:702 msgid "(*VERB) not recognized" msgstr "(*VERB) უცნობია" -#: glib/gregex.c:713 +#: glib/gregex.c:706 msgid "number is too big" msgstr "რიცხვი ძალიან დიდია" -#: glib/gregex.c:717 +#: glib/gregex.c:710 msgid "missing subpattern name after (?&" -msgstr "აკლია ქვეშაბლონის სახელი (?& -ის შემდეგ" +msgstr "" -#: glib/gregex.c:721 +#: glib/gregex.c:714 msgid "different names for subpatterns of the same number are not allowed" -msgstr "იგივე ნომრის მქონე ქვენიმუშებისთვის სხვადასხვა სახელები დაშვებული არაა" +msgstr "" -#: glib/gregex.c:725 +#: glib/gregex.c:718 msgid "(*MARK) must have an argument" -msgstr "(*MARK) არგუმენტის ქონა აუცილებელია" +msgstr "" -#: glib/gregex.c:729 +#: glib/gregex.c:722 msgid "\\c must be followed by an ASCII character" -msgstr "\\c-ს ASCII სიმბოლო უნდა მოჰყვებოდეს" +msgstr "" -#: glib/gregex.c:733 +#: glib/gregex.c:726 msgid "\\k is not followed by a braced, angle-bracketed, or quoted name" msgstr "" -"\\k-ის შემდეგი ტექსტი არაა ჩასმული არც ფრჩხილებში, არც ბრჭყალებში, არც ორმაგ " -"ბრჭყალებში" -#: glib/gregex.c:737 +#: glib/gregex.c:730 msgid "\\N is not supported in a class" msgstr "კლასში \\N მხარდაუჭერელია" -#: glib/gregex.c:741 +#: glib/gregex.c:734 msgid "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" msgstr "სახელი ძალიან გრძელია (*MARK), (*PRUNE), (*SKIP) ან (*THEN)" -#: glib/gregex.c:745 glib/gregex.c:881 +#: glib/gregex.c:738 glib/gregex.c:874 msgid "code overflow" msgstr "კოდის გადავსება" -#: glib/gregex.c:749 +#: glib/gregex.c:742 msgid "unrecognized character after (?P" msgstr "უცნობი სიმბოლო (?P-ის შემდეგ" -#: glib/gregex.c:753 +#: glib/gregex.c:746 msgid "overran compiling workspace" msgstr "კომპილაციის სამუშაო სივრცის გადავსება" -#: glib/gregex.c:757 +#: glib/gregex.c:750 msgid "previously-checked referenced subpattern not found" -msgstr "ადრე შემოწმებული მიმართული ქვენიმუში ვერ ვიპოვე" +msgstr "" -#: glib/gregex.c:880 glib/gregex.c:1154 glib/gregex.c:2476 +#: glib/gregex.c:873 glib/gregex.c:1135 glib/gregex.c:2457 #, c-format msgid "Error while matching regular expression %s: %s" msgstr "დაიშვა შეცდომა სტანდარტული გამოსახულების %s დამთხვევის ძიების დროს: %s" -#: glib/gregex.c:1754 +#: glib/gregex.c:1735 msgid "PCRE library is compiled without UTF8 support" msgstr "ბიბლიოთეკა PCRE-ს არ გააჩნია UTF8-ის მხარდაჭერა" -#: glib/gregex.c:1762 +#: glib/gregex.c:1743 msgid "PCRE library is compiled with incompatible options" msgstr "PCRE ბიბლიოთეკა კომპილირებულია შეუთავსებელი პარამეტრებით" -#: glib/gregex.c:1879 +#: glib/gregex.c:1860 #, c-format msgid "Error while compiling regular expression ‘%s’ at char %s: %s" msgstr "" "შეცდომა რეგულარული გამოსახულება %s-ის კომპილირებისას, სიმბოლოსთან %s: %s" -#: glib/gregex.c:2919 +#: glib/gregex.c:2900 msgid "hexadecimal digit or “}” expected" msgstr "მოსალოდნელია თექვსმეტობითი რიცხვი, ან '}'" -#: glib/gregex.c:2935 +#: glib/gregex.c:2916 msgid "hexadecimal digit expected" msgstr "მოსალოდნელია თექვსმეტობითი სიმბოლო" -#: glib/gregex.c:2975 +#: glib/gregex.c:2956 msgid "missing “<” in symbolic reference" msgstr "არ მოიძებნა '<', სიმბოლურ მითითებაში" -#: glib/gregex.c:2984 +#: glib/gregex.c:2965 msgid "unfinished symbolic reference" msgstr "დაუსრულებელი სიმბოლური მითითება" -#: glib/gregex.c:2991 +#: glib/gregex.c:2972 msgid "zero-length symbolic reference" msgstr "ნულოვანი სიგრძის სიმბოლური მითითება" -#: glib/gregex.c:3002 +#: glib/gregex.c:2983 msgid "digit expected" msgstr "მოველოდი ციფრს" -#: glib/gregex.c:3020 +#: glib/gregex.c:3001 msgid "illegal symbolic reference" msgstr "მიუღებელი სიმბოლური მითითება" -#: glib/gregex.c:3083 +#: glib/gregex.c:3064 msgid "stray final “\\”" msgstr "დაბოლოვება '\\'" -#: glib/gregex.c:3087 +#: glib/gregex.c:3068 msgid "unknown escape sequence" msgstr "უცნობი escape სეკვენცია" -#: glib/gregex.c:3097 +#: glib/gregex.c:3078 #, c-format msgid "Error while parsing replacement text “%s” at char %lu: %s" msgstr "" @@ -5871,74 +5700,74 @@ msgstr "მოულოდნელი შეცდომა ფუნქცი #: glib/gspawn.c:1180 glib/gspawn-win32.c:1575 #, c-format msgid "Child process exited with code %ld" -msgstr "შვილეული პროცესი დასრულდა სტატუსით %ld" +msgstr "" #: glib/gspawn.c:1188 #, c-format msgid "Child process killed by signal %ld" -msgstr "შვილი პროცესი მოკვდა სიგნალის მიერ: %ld" +msgstr "" #: glib/gspawn.c:1195 #, c-format msgid "Child process stopped by signal %ld" -msgstr "შვილი პროცესი შეწყდა სიგნალის მიერ: %ld" +msgstr "" #: glib/gspawn.c:1202 #, c-format msgid "Child process exited abnormally" -msgstr "შვილი პროცესი არანორმალურად დასრულდა" +msgstr "" -#: glib/gspawn.c:2039 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 +#: glib/gspawn.c:2032 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 #, c-format msgid "Failed to read from child pipe (%s)" msgstr "მონაცემთა წაკითხვა ქვეპროცესის არხიდან ვერ მოხერხდა (%s)" -#: glib/gspawn.c:2411 +#: glib/gspawn.c:2404 #, c-format msgid "Failed to spawn child process “%s” (%s)" msgstr "ქვეპროცესის (%s) განტოტვის შეცდომა (%s)" -#: glib/gspawn.c:2537 +#: glib/gspawn.c:2530 #, c-format msgid "Failed to fork (%s)" msgstr "განტოტების შეცდომა (%s)" -#: glib/gspawn.c:2697 glib/gspawn-win32.c:503 +#: glib/gspawn.c:2690 glib/gspawn-win32.c:503 #, c-format msgid "Failed to change to directory “%s” (%s)" msgstr "საქაღალდის ცვლილების შეცდომა \"%s\" (%s)" -#: glib/gspawn.c:2707 +#: glib/gspawn.c:2700 #, c-format msgid "Failed to execute child process “%s” (%s)" msgstr "შვილობილი პროცესის %s გაშვების შეცდომა %s" -#: glib/gspawn.c:2717 +#: glib/gspawn.c:2710 #, c-format msgid "Failed to open file to remap file descriptor (%s)" msgstr "დესკრიპტორისთვის ფაილის გადამაგრების შეცდომა (%s)" -#: glib/gspawn.c:2725 +#: glib/gspawn.c:2718 #, c-format msgid "Failed to duplicate file descriptor for child process (%s)" msgstr "შვილეული პროცესისთვის (%s) ფაილის დესკრიპტორის დუბლირების შეცდომა" -#: glib/gspawn.c:2734 +#: glib/gspawn.c:2727 #, c-format msgid "Failed to fork child process (%s)" msgstr "დამხმარე პროცესის გაშვების შეცდომა (%s)" -#: glib/gspawn.c:2742 +#: glib/gspawn.c:2735 #, c-format msgid "Failed to close file descriptor for child process (%s)" msgstr "შვილეული პროცესის (%s) ფაილის დესკრიპტორის დახურვის შეცდომა" -#: glib/gspawn.c:2750 +#: glib/gspawn.c:2743 #, c-format msgid "Unknown error executing child process “%s”" msgstr "შეცდომა შვილეული პროცესის (%s) შესრულებისას" -#: glib/gspawn.c:2774 +#: glib/gspawn.c:2767 #, c-format msgid "Failed to read enough data from child pid pipe (%s)" msgstr "ქვეპროცესის არხიდან საკმარის მონაცემთა წაკითხვა ვერ მოხერხდა (%s)" diff --git a/po/pt_BR.po b/po/pt_BR.po index 533ed7a..b159cc3 100644 --- a/po/pt_BR.po +++ b/po/pt_BR.po @@ -23,16 +23,16 @@ msgid "" msgstr "" "Project-Id-Version: glib\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" -"POT-Creation-Date: 2023-10-07 15:03+0000\n" -"PO-Revision-Date: 2024-03-08 08:52-0300\n" -"Last-Translator: Leônidas Araújo \n" +"POT-Creation-Date: 2023-08-31 11:01+0000\n" +"PO-Revision-Date: 2023-09-17 22:27-0300\n" +"Last-Translator: Rafael Fontenelle \n" "Language-Team: Brazilian Portuguese \n" "Language: pt_BR\n" "MIME-Version: 1.0\n" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" -"Plural-Forms: nplurals=2; plural=(n > 1);\n" -"X-Generator: Poedit 3.3.1\n" +"Plural-Forms: nplurals=2; plural=(n > 1)\n" +"X-Generator: Gtranslator 45.alpha0\n" "X-Project-Style: gnome\n" "X-DL-Team: pt_BR\n" "X-DL-Module: glib\n" @@ -60,25 +60,25 @@ msgstr "Falha ao encontrar o aplicativo padrão para o tipo de conteúdo '%s'" msgid "Failed to find default application for URI Scheme ‘%s’" msgstr "Falha ao encontrar o aplicativo padrão para o Esquema de URI “%s”" -#: gio/gapplication.c:506 -msgid "GApplication Options:" -msgstr "Opções do GApplication:" +#: gio/gapplication.c:502 +msgid "GApplication options" +msgstr "Opções do GApplication" -#: gio/gapplication.c:506 +#: gio/gapplication.c:502 msgid "Show GApplication options" msgstr "Mostra as opções do GApplication" -#: gio/gapplication.c:551 +#: gio/gapplication.c:547 msgid "Enter GApplication service mode (use from D-Bus service files)" msgstr "" "Digite o modo de serviço do GApplication (usar dos arquivos de serviços do D-" "Bus)" -#: gio/gapplication.c:563 +#: gio/gapplication.c:559 msgid "Override the application’s ID" msgstr "Substitui ID do aplicativo" -#: gio/gapplication.c:575 +#: gio/gapplication.c:571 msgid "Replace the running instance" msgstr "Substitui a instância em execução" @@ -300,8 +300,8 @@ msgstr "" "\n" #: gio/gbufferedinputstream.c:422 gio/gbufferedinputstream.c:500 -#: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:651 -#: gio/ginputstream.c:1056 gio/goutputstream.c:225 gio/goutputstream.c:1052 +#: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:650 +#: gio/ginputstream.c:1052 gio/goutputstream.c:225 gio/goutputstream.c:1051 #: gio/gpollableinputstream.c:221 gio/gpollableoutputstream.c:293 #, c-format msgid "Too large count value passed to %s" @@ -316,8 +316,8 @@ msgstr "Não há suporte à busca no fluxo base" msgid "Cannot truncate GBufferedInputStream" msgstr "Não é possível truncar GBufferedInputStream" -#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1246 gio/giostream.c:302 -#: gio/goutputstream.c:2208 +#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1241 gio/giostream.c:302 +#: gio/goutputstream.c:2200 msgid "Stream is already closed" msgstr "O fluxo já está fechado" @@ -344,28 +344,28 @@ msgid "Not enough space in destination" msgstr "Espaço insuficiente no destino" #: gio/gcharsetconverter.c:344 gio/gdatainputstream.c:850 -#: gio/gdatainputstream.c:1268 glib/gconvert.c:450 glib/gconvert.c:882 +#: gio/gdatainputstream.c:1268 glib/gconvert.c:451 glib/gconvert.c:883 #: glib/giochannel.c:1576 glib/giochannel.c:1618 glib/giochannel.c:2478 -#: glib/gutf8.c:958 glib/gutf8.c:1412 +#: glib/gutf8.c:892 glib/gutf8.c:1346 msgid "Invalid byte sequence in conversion input" msgstr "Sequência de bytes inválida na entrada de conversão" -#: gio/gcharsetconverter.c:349 glib/gconvert.c:458 glib/gconvert.c:796 +#: gio/gcharsetconverter.c:349 glib/gconvert.c:459 glib/gconvert.c:797 #: glib/giochannel.c:1583 glib/giochannel.c:2493 #, c-format msgid "Error during conversion: %s" msgstr "Erro durante a conversão: %s" -#: gio/gcharsetconverter.c:447 gio/gsocket.c:1164 +#: gio/gcharsetconverter.c:447 gio/gsocket.c:1151 msgid "Cancellable initialization not supported" msgstr "Sem suporte a inicialização cancelável" -#: gio/gcharsetconverter.c:458 glib/gconvert.c:323 glib/giochannel.c:1404 +#: gio/gcharsetconverter.c:458 glib/gconvert.c:324 glib/giochannel.c:1404 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported" msgstr "Não há suporte à conversão do conjunto de caracteres “%s” para “%s”" -#: gio/gcharsetconverter.c:462 glib/gconvert.c:327 +#: gio/gcharsetconverter.c:462 glib/gconvert.c:328 #, c-format msgid "Could not open converter from “%s” to “%s”" msgstr "Não foi possível abrir conversor de “%s” para “%s”" @@ -631,13 +631,13 @@ msgstr "" msgid "Error creating directory “%s”: %s" msgstr "Erro ao criar o diretório “%s”: %s" -#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1102 gio/gfile.c:1340 -#: gio/gfile.c:1478 gio/gfile.c:1716 gio/gfile.c:1771 gio/gfile.c:1829 -#: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 -#: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 -#: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:9000 gio/gfile.c:9090 -#: gio/gfile.c:9174 gio/win32/gwinhttpfile.c:453 +#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1095 gio/gfile.c:1333 +#: gio/gfile.c:1471 gio/gfile.c:1709 gio/gfile.c:1764 gio/gfile.c:1822 +#: gio/gfile.c:1906 gio/gfile.c:1963 gio/gfile.c:2027 gio/gfile.c:2082 +#: gio/gfile.c:3797 gio/gfile.c:3937 gio/gfile.c:4349 gio/gfile.c:4819 +#: gio/gfile.c:5230 gio/gfile.c:5315 gio/gfile.c:5405 gio/gfile.c:5502 +#: gio/gfile.c:5589 gio/gfile.c:5690 gio/gfile.c:8819 gio/gfile.c:8909 +#: gio/gfile.c:8993 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "Operação sem suporte" @@ -1486,83 +1486,78 @@ msgstr "Esperado um GEmblem para o GEmblemedIcon" #. * trying to find the enclosing (user visible) #. * mount of a file, but none exists. #. -#: gio/gfile.c:1601 +#: gio/gfile.c:1594 msgid "Containing mount does not exist" msgstr "Ponto de montagem contido não existe" -#: gio/gfile.c:2648 gio/glocalfile.c:2518 +#: gio/gfile.c:2641 gio/glocalfile.c:2515 msgid "Can’t copy over directory" msgstr "Não é possível copiar sobre diretório" -#: gio/gfile.c:2708 +#: gio/gfile.c:2701 msgid "Can’t copy directory over directory" msgstr "Não é possível copiar diretório sobre diretório" -#: gio/gfile.c:2716 +#: gio/gfile.c:2709 msgid "Target file exists" msgstr "Arquivo alvo existe" -#: gio/gfile.c:2735 +#: gio/gfile.c:2728 msgid "Can’t recursively copy directory" msgstr "Não é possível copiar o diretório recursivamente" -#: gio/gfile.c:3044 gio/gfile.c:3092 -#, c-format -msgid "Copy file range not supported" -msgstr "Intervalo de cópia de arquivo não suportado" +#: gio/gfile.c:3029 +msgid "Splice not supported" +msgstr "Não há suporte a união de arquivos" -#: gio/gfile.c:3050 gio/gfile.c:3161 +#: gio/gfile.c:3033 #, c-format msgid "Error splicing file: %s" msgstr "Erro ao unir o arquivo: %s" -#: gio/gfile.c:3157 -msgid "Splice not supported" -msgstr "Não há suporte a união de arquivos" - -#: gio/gfile.c:3321 +#: gio/gfile.c:3195 msgid "Copy (reflink/clone) between mounts is not supported" msgstr "Não há suporte a copiar (reflink/clone) entre montagens" -#: gio/gfile.c:3325 +#: gio/gfile.c:3199 msgid "Copy (reflink/clone) is not supported or invalid" msgstr "Não há suporte a copiar (reflink/clone) ou é inválido" -#: gio/gfile.c:3330 +#: gio/gfile.c:3204 msgid "Copy (reflink/clone) is not supported or didn’t work" msgstr "Não há suporte a copiar (reflink/clone) ou não funcionou" -#: gio/gfile.c:3395 +#: gio/gfile.c:3269 msgid "Can’t copy special file" msgstr "Não é possível copiar o arquivo especial" -#: gio/gfile.c:4314 +#: gio/gfile.c:4163 msgid "Invalid symlink value given" msgstr "Fornecido valor inválido de link simbólico" -#: gio/gfile.c:4324 glib/gfileutils.c:2392 +#: gio/gfile.c:4173 glib/gfileutils.c:2392 msgid "Symbolic links not supported" msgstr "Não há suporte a links simbólicos" -#: gio/gfile.c:4611 +#: gio/gfile.c:4460 msgid "Trash not supported" msgstr "Não há suporte para lixeira" -#: gio/gfile.c:4723 +#: gio/gfile.c:4572 #, c-format msgid "File names cannot contain “%c”" msgstr "Nomes de arquivo não podem conter “%c”" -#: gio/gfile.c:7155 gio/gfile.c:7281 +#: gio/gfile.c:7003 gio/gfile.c:7129 #, c-format msgid "Failed to create a temporary directory for template “%s”: %s" msgstr "Falha ao criar um diretório temporário para o modelo “%s”: %s" -#: gio/gfile.c:7599 gio/gvolume.c:366 +#: gio/gfile.c:7418 gio/gvolume.c:366 msgid "volume doesn’t implement mount" msgstr "volume não implementa montagem" -#: gio/gfile.c:7713 gio/gfile.c:7790 +#: gio/gfile.c:7532 gio/gfile.c:7609 msgid "No application is registered as handling this file" msgstr "Nenhum aplicativo está registrado como manipulador deste arquivo" @@ -1571,11 +1566,11 @@ msgid "Enumerator is closed" msgstr "O enumerador está fechado" #: gio/gfileenumerator.c:221 gio/gfileenumerator.c:280 -#: gio/gfileenumerator.c:425 gio/gfileenumerator.c:525 +#: gio/gfileenumerator.c:424 gio/gfileenumerator.c:523 msgid "File enumerator has outstanding operation" msgstr "O enumerador do arquivo tem operação pendente" -#: gio/gfileenumerator.c:416 gio/gfileenumerator.c:516 +#: gio/gfileenumerator.c:415 gio/gfileenumerator.c:514 msgid "File enumerator is already closed" msgstr "O enumerador do arquivo já está fechado" @@ -1588,27 +1583,27 @@ msgstr "Não é possível lidar com a versão %d da codificação GFileIcon" msgid "Malformed input data for GFileIcon" msgstr "Dados de entrada malformados para o GFileIcon" -#: gio/gfileinputstream.c:151 gio/gfileinputstream.c:397 +#: gio/gfileinputstream.c:151 gio/gfileinputstream.c:396 #: gio/gfileiostream.c:169 gio/gfileoutputstream.c:166 #: gio/gfileoutputstream.c:499 msgid "Stream doesn’t support query_info" msgstr "Fluxo não tem suporte para query_info" -#: gio/gfileinputstream.c:328 gio/gfileiostream.c:382 +#: gio/gfileinputstream.c:327 gio/gfileiostream.c:381 #: gio/gfileoutputstream.c:373 msgid "Seek not supported on stream" msgstr "Não há suporte à busca no fluxo" -#: gio/gfileinputstream.c:372 +#: gio/gfileinputstream.c:371 msgid "Truncate not allowed on input stream" msgstr "Não é permitido truncar fluxo de entrada" -#: gio/gfileiostream.c:458 gio/gfileoutputstream.c:449 +#: gio/gfileiostream.c:457 gio/gfileoutputstream.c:449 msgid "Truncate not supported on stream" msgstr "Não há suporte para truncar fluxo" -#: gio/ghttpproxy.c:93 gio/gresolver.c:535 gio/gresolver.c:688 -#: glib/gconvert.c:1842 +#: gio/ghttpproxy.c:93 gio/gresolver.c:460 gio/gresolver.c:613 +#: glib/gconvert.c:1829 msgid "Invalid hostname" msgstr "Nome de máquina inválido" @@ -1712,7 +1707,7 @@ msgstr "Fluxo de entrada não implementa leitura" #. Translators: This is an error you get if there is #. * already an operation running against this stream when #. * you try to start one -#: gio/ginputstream.c:1256 gio/giostream.c:312 gio/goutputstream.c:2218 +#: gio/ginputstream.c:1251 gio/giostream.c:312 gio/goutputstream.c:2210 msgid "Stream has outstanding operation" msgstr "O fluxo tem operação pendente" @@ -1821,7 +1816,7 @@ msgstr "Erro ao gravar para a saída padrão" #: gio/gio-tool-cat.c:135 gio/gio-tool-info.c:382 gio/gio-tool-list.c:176 #: gio/gio-tool-mkdir.c:50 gio/gio-tool-monitor.c:39 gio/gio-tool-monitor.c:41 #: gio/gio-tool-monitor.c:43 gio/gio-tool-monitor.c:45 -#: gio/gio-tool-monitor.c:206 gio/gio-tool-mount.c:1236 gio/gio-tool-open.c:72 +#: gio/gio-tool-monitor.c:206 gio/gio-tool-mount.c:1210 gio/gio-tool-open.c:72 #: gio/gio-tool-remove.c:50 gio/gio-tool-rename.c:47 gio/gio-tool-set.c:95 #: gio/gio-tool-trash.c:222 gio/gio-tool-tree.c:246 msgid "LOCATION" @@ -1842,7 +1837,7 @@ msgstr "" "usar alguma coisa como smb://servidor/recurso/arquivo.txt como local." #: gio/gio-tool-cat.c:164 gio/gio-tool-info.c:413 gio/gio-tool-mkdir.c:78 -#: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1287 gio/gio-tool-open.c:98 +#: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1261 gio/gio-tool-open.c:98 #: gio/gio-tool-remove.c:74 gio/gio-tool-trash.c:303 msgid "No locations given" msgstr "Nenhum local fornecido" @@ -1938,18 +1933,11 @@ msgstr "Não segue links simbólicos" msgid "attributes:\n" msgstr "atributos:\n" -#. Translators: This is a noun and represents and attribute of a file -#: gio/gio-tool-info.c:166 +#: gio/gio-tool-info.c:166 gio/gio-tool-info.c:176 #, c-format msgid "display name: %s\n" msgstr "nome de exibição: %s\n" -#. Translators: This is a noun and represents and attribute of a file -#: gio/gio-tool-info.c:176 -#, c-format -msgid "edit name: %s\n" -msgstr "nome para edição: %s\n" - #: gio/gio-tool-info.c:184 #, c-format msgid "name: %s\n" @@ -2267,15 +2255,15 @@ msgstr "Mota um volume TCRYPT de sistema" msgid "Anonymous access denied" msgstr "Acesso anônimo negado" -#: gio/gio-tool-mount.c:559 +#: gio/gio-tool-mount.c:533 msgid "No drive for device file" msgstr "Nenhuma unidade para o arquivo de dispositivo" -#: gio/gio-tool-mount.c:1051 +#: gio/gio-tool-mount.c:1025 msgid "No volume for given ID" msgstr "Nenhum volume para o ID dado" -#: gio/gio-tool-mount.c:1240 +#: gio/gio-tool-mount.c:1214 msgid "Mount or unmount the locations." msgstr "Monta ou desmontar os locais." @@ -3096,12 +3084,12 @@ msgid "No schema files found: removed existing output file." msgstr "" "Nenhum arquivo de schema encontrado: arquivo de saída existente removido." -#: gio/glocalfile.c:570 gio/win32/gwinhttpfile.c:436 +#: gio/glocalfile.c:567 gio/win32/gwinhttpfile.c:436 #, c-format msgid "Invalid filename %s" msgstr "Nome de arquivo inválido: %s" -#: gio/glocalfile.c:1012 +#: gio/glocalfile.c:1009 #, c-format msgid "Error getting filesystem info for %s: %s" msgstr "Erro ao obter informações do sistema de arquivos para %s: %s" @@ -3110,127 +3098,127 @@ msgstr "Erro ao obter informações do sistema de arquivos para %s: %s" #. * the enclosing (user visible) mount of a file, but none #. * exists. #. -#: gio/glocalfile.c:1148 +#: gio/glocalfile.c:1145 #, c-format msgid "Containing mount for file %s not found" msgstr "Ponto de montagem contido para arquivo %s não existe" -#: gio/glocalfile.c:1171 +#: gio/glocalfile.c:1168 msgid "Can’t rename root directory" msgstr "Não é possível renomear o diretório root" -#: gio/glocalfile.c:1189 gio/glocalfile.c:1212 +#: gio/glocalfile.c:1186 gio/glocalfile.c:1209 #, c-format msgid "Error renaming file %s: %s" msgstr "Erro ao renomear arquivo %s: %s" -#: gio/glocalfile.c:1196 +#: gio/glocalfile.c:1193 msgid "Can’t rename file, filename already exists" msgstr "Não é possível renomear o arquivo, o nome do arquivo já existe" -#: gio/glocalfile.c:1209 gio/glocalfile.c:2412 gio/glocalfile.c:2440 -#: gio/glocalfile.c:2579 gio/glocalfileoutputstream.c:658 +#: gio/glocalfile.c:1206 gio/glocalfile.c:2409 gio/glocalfile.c:2437 +#: gio/glocalfile.c:2576 gio/glocalfileoutputstream.c:658 msgid "Invalid filename" msgstr "Nome de arquivo inválido" -#: gio/glocalfile.c:1377 gio/glocalfile.c:1388 +#: gio/glocalfile.c:1374 gio/glocalfile.c:1385 #, c-format msgid "Error opening file %s: %s" msgstr "Erro ao abrir arquivo %s: %s" -#: gio/glocalfile.c:1513 +#: gio/glocalfile.c:1510 #, c-format msgid "Error removing file %s: %s" msgstr "Erro ao remover arquivo %s: %s" -#: gio/glocalfile.c:2007 gio/glocalfile.c:2018 gio/glocalfile.c:2045 +#: gio/glocalfile.c:2004 gio/glocalfile.c:2015 gio/glocalfile.c:2042 #, c-format msgid "Error trashing file %s: %s" msgstr "Erro ao mover para a lixeira o arquivo %s: %s" -#: gio/glocalfile.c:2065 +#: gio/glocalfile.c:2062 #, c-format msgid "Unable to create trash directory %s: %s" msgstr "Não é possível criar o diretório da lixeira %s: %s" -#: gio/glocalfile.c:2086 +#: gio/glocalfile.c:2083 #, c-format msgid "Unable to find toplevel directory to trash %s" msgstr "Não é possível localizar diretório de nível superior para a lixeira %s" -#: gio/glocalfile.c:2094 +#: gio/glocalfile.c:2091 #, c-format msgid "Trashing on system internal mounts is not supported" msgstr "Não há suporte a mover para lixeira em montagens internas do sistema" -#: gio/glocalfile.c:2180 gio/glocalfile.c:2208 +#: gio/glocalfile.c:2177 gio/glocalfile.c:2205 #, c-format msgid "Unable to find or create trash directory %s to trash %s" msgstr "" "Não é possível localizar ou criar o diretório da lixeira %s para a lixeira %s" -#: gio/glocalfile.c:2252 +#: gio/glocalfile.c:2249 #, c-format msgid "Unable to create trashing info file for %s: %s" msgstr "Não é possível criar o arquivo de informações da lixeira para %s: %s" -#: gio/glocalfile.c:2323 +#: gio/glocalfile.c:2320 #, c-format msgid "Unable to trash file %s across filesystem boundaries" msgstr "" "Não é possível mover para a lixeira o arquivo %s entre os limites de sistema " "de arquivos" -#: gio/glocalfile.c:2327 gio/glocalfile.c:2383 +#: gio/glocalfile.c:2324 gio/glocalfile.c:2380 #, c-format msgid "Unable to trash file %s: %s" msgstr "Não é possível mover para a lixeira o arquivo %s: %s" -#: gio/glocalfile.c:2389 +#: gio/glocalfile.c:2386 #, c-format msgid "Unable to trash file %s" msgstr "Não é possível mover para a lixeira o arquivo %s" -#: gio/glocalfile.c:2415 +#: gio/glocalfile.c:2412 #, c-format msgid "Error creating directory %s: %s" msgstr "Erro ao criar o diretório %s: %s" -#: gio/glocalfile.c:2444 +#: gio/glocalfile.c:2441 #, c-format msgid "Filesystem does not support symbolic links" msgstr "O sistema de arquivos não tem suporte a links simbólicos" -#: gio/glocalfile.c:2447 +#: gio/glocalfile.c:2444 #, c-format msgid "Error making symbolic link %s: %s" msgstr "Erro ao criar link simbólico %s: %s" -#: gio/glocalfile.c:2490 gio/glocalfile.c:2525 gio/glocalfile.c:2582 +#: gio/glocalfile.c:2487 gio/glocalfile.c:2522 gio/glocalfile.c:2579 #, c-format msgid "Error moving file %s: %s" msgstr "Erro ao mover arquivo %s: %s" -#: gio/glocalfile.c:2513 +#: gio/glocalfile.c:2510 msgid "Can’t move directory over directory" msgstr "Não é possível mover diretório sobre diretório" -#: gio/glocalfile.c:2539 gio/glocalfileoutputstream.c:1110 +#: gio/glocalfile.c:2536 gio/glocalfileoutputstream.c:1110 #: gio/glocalfileoutputstream.c:1124 gio/glocalfileoutputstream.c:1139 #: gio/glocalfileoutputstream.c:1156 gio/glocalfileoutputstream.c:1170 msgid "Backup file creation failed" msgstr "Falha ao criar arquivo de backup" -#: gio/glocalfile.c:2558 +#: gio/glocalfile.c:2555 #, c-format msgid "Error removing target file: %s" msgstr "Erro ao remover arquivo alvo: %s" -#: gio/glocalfile.c:2572 +#: gio/glocalfile.c:2569 msgid "Move between mounts not supported" msgstr "Não há suporte a mover entre montagens" -#: gio/glocalfile.c:2748 +#: gio/glocalfile.c:2745 #, c-format msgid "Could not determine the disk usage of %s: %s" msgstr "Não foi possível determinar a utilização de disco de %s: %s" @@ -3568,35 +3556,35 @@ msgstr "A versão do NetworkManager é muito antiga" msgid "Output stream doesn’t implement write" msgstr "Fluxo de saída não implementa escrita" -#: gio/goutputstream.c:474 gio/goutputstream.c:1539 +#: gio/goutputstream.c:474 gio/goutputstream.c:1535 #, c-format msgid "Sum of vectors passed to %s too large" msgstr "A soma dos vetores passada para %s é grande demais" -#: gio/goutputstream.c:738 gio/goutputstream.c:1769 +#: gio/goutputstream.c:738 gio/goutputstream.c:1763 msgid "Source stream is already closed" msgstr "A fonte do fluxo já está fechada" -#: gio/gproxyaddressenumerator.c:329 gio/gproxyaddressenumerator.c:347 +#: gio/gproxyaddressenumerator.c:324 gio/gproxyaddressenumerator.c:342 msgid "Unspecified proxy lookup failure" msgstr "Falha não especificada na pesquisa de proxy" #. Translators: the first placeholder is a domain name, the #. * second is an error message -#: gio/gresolver.c:478 gio/gthreadedresolver.c:317 gio/gthreadedresolver.c:338 -#: gio/gthreadedresolver.c:983 gio/gthreadedresolver.c:1007 -#: gio/gthreadedresolver.c:1032 gio/gthreadedresolver.c:1047 +#: gio/gresolver.c:403 gio/gthreadedresolver.c:152 gio/gthreadedresolver.c:170 +#: gio/gthreadedresolver.c:798 gio/gthreadedresolver.c:822 +#: gio/gthreadedresolver.c:847 gio/gthreadedresolver.c:862 #, c-format msgid "Error resolving “%s”: %s" msgstr "Erro ao resolver “%s”: %s" #. Translators: The placeholder is for a function name. -#: gio/gresolver.c:547 gio/gresolver.c:707 +#: gio/gresolver.c:472 gio/gresolver.c:632 #, c-format msgid "%s not implemented" msgstr "%s não implementado" -#: gio/gresolver.c:1076 gio/gresolver.c:1128 +#: gio/gresolver.c:1001 gio/gresolver.c:1053 msgid "Invalid domain" msgstr "Domínio inválido" @@ -3988,8 +3976,7 @@ msgstr "Soquete inválido, inicialização falhou devido a: %s" msgid "Socket is already closed" msgstr "O soquete já está fechado" -#: gio/gsocket.c:449 gio/gsocket.c:3238 gio/gsocket.c:4469 gio/gsocket.c:4527 -#: gio/gthreadedresolver.c:1445 +#: gio/gsocket.c:449 gio/gsocket.c:3225 gio/gsocket.c:4458 gio/gsocket.c:4516 msgid "Socket I/O timed out" msgstr "Tempo de E/S do soquete foi esgotado" @@ -3998,162 +3985,162 @@ msgstr "Tempo de E/S do soquete foi esgotado" msgid "creating GSocket from fd: %s" msgstr "criando GSocket a partir do fd: %s" -#: gio/gsocket.c:646 gio/gsocket.c:714 gio/gsocket.c:721 +#: gio/gsocket.c:615 gio/gsocket.c:679 gio/gsocket.c:686 #, c-format msgid "Unable to create socket: %s" msgstr "Não é possível criar soquete: %s" -#: gio/gsocket.c:714 +#: gio/gsocket.c:679 msgid "Unknown family was specified" msgstr "Foi especificada uma família desconhecida" -#: gio/gsocket.c:721 +#: gio/gsocket.c:686 msgid "Unknown protocol was specified" msgstr "Foi especificado um protocolo desconhecido" -#: gio/gsocket.c:1190 +#: gio/gsocket.c:1177 #, c-format msgid "Cannot use datagram operations on a non-datagram socket." msgstr "" "Não foi possível usar operações de datagrama em um soquete não-datagrama." -#: gio/gsocket.c:1207 +#: gio/gsocket.c:1194 #, c-format msgid "Cannot use datagram operations on a socket with a timeout set." msgstr "" "Não foi possível usar operações de datagrama em um soquete com um tempo " "limite definido." -#: gio/gsocket.c:2014 +#: gio/gsocket.c:2001 #, c-format msgid "could not get local address: %s" msgstr "não foi possível obter endereço local: %s" -#: gio/gsocket.c:2060 +#: gio/gsocket.c:2047 #, c-format msgid "could not get remote address: %s" msgstr "não foi possível obter endereço remoto: %s" -#: gio/gsocket.c:2126 +#: gio/gsocket.c:2113 #, c-format msgid "could not listen: %s" msgstr "não foi possível escutar: %s" -#: gio/gsocket.c:2230 +#: gio/gsocket.c:2217 #, c-format msgid "Error binding to address %s: %s" msgstr "Erro ao vincular ao endereço %s: %s" -#: gio/gsocket.c:2405 gio/gsocket.c:2442 gio/gsocket.c:2552 gio/gsocket.c:2577 -#: gio/gsocket.c:2644 gio/gsocket.c:2702 gio/gsocket.c:2720 +#: gio/gsocket.c:2392 gio/gsocket.c:2429 gio/gsocket.c:2539 gio/gsocket.c:2564 +#: gio/gsocket.c:2631 gio/gsocket.c:2689 gio/gsocket.c:2707 #, c-format msgid "Error joining multicast group: %s" msgstr "Erro ao entrar no grupo multicast: %s" -#: gio/gsocket.c:2406 gio/gsocket.c:2443 gio/gsocket.c:2553 gio/gsocket.c:2578 -#: gio/gsocket.c:2645 gio/gsocket.c:2703 gio/gsocket.c:2721 +#: gio/gsocket.c:2393 gio/gsocket.c:2430 gio/gsocket.c:2540 gio/gsocket.c:2565 +#: gio/gsocket.c:2632 gio/gsocket.c:2690 gio/gsocket.c:2708 #, c-format msgid "Error leaving multicast group: %s" msgstr "Erro ao sair do grupo multicast: %s" -#: gio/gsocket.c:2407 +#: gio/gsocket.c:2394 msgid "No support for source-specific multicast" msgstr "Não há suporte para multicast específico da origem" -#: gio/gsocket.c:2554 +#: gio/gsocket.c:2541 msgid "Unsupported socket family" msgstr "Família de soquete sem suporte" -#: gio/gsocket.c:2579 +#: gio/gsocket.c:2566 msgid "source-specific not an IPv4 address" msgstr "a origem específica não é um endereço IPv4" -#: gio/gsocket.c:2603 +#: gio/gsocket.c:2590 #, c-format msgid "Interface name too long" msgstr "Nome de interface grande demais" -#: gio/gsocket.c:2616 gio/gsocket.c:2670 +#: gio/gsocket.c:2603 gio/gsocket.c:2657 #, c-format msgid "Interface not found: %s" msgstr "Interface não localizada: %s" -#: gio/gsocket.c:2646 +#: gio/gsocket.c:2633 msgid "No support for IPv4 source-specific multicast" msgstr "Não há suporte para multicast específico da origem IPv4" -#: gio/gsocket.c:2704 +#: gio/gsocket.c:2691 msgid "No support for IPv6 source-specific multicast" msgstr "Não há suporte para multicast específico da origem IPv6" -#: gio/gsocket.c:2937 +#: gio/gsocket.c:2924 #, c-format msgid "Error accepting connection: %s" msgstr "Erro ao aceitar a conexão: %s" -#: gio/gsocket.c:3063 +#: gio/gsocket.c:3050 msgid "Connection in progress" msgstr "Conexão em progresso" -#: gio/gsocket.c:3114 +#: gio/gsocket.c:3101 msgid "Unable to get pending error: " msgstr "Não é possível obter erro pendente: " -#: gio/gsocket.c:3303 +#: gio/gsocket.c:3290 #, c-format msgid "Error receiving data: %s" msgstr "Erro ao receber dados: %s" -#: gio/gsocket.c:3500 +#: gio/gsocket.c:3487 #, c-format msgid "Error sending data: %s" msgstr "Erro ao enviar dados: %s" -#: gio/gsocket.c:3687 +#: gio/gsocket.c:3674 #, c-format msgid "Unable to shutdown socket: %s" msgstr "Não é possível encerrar soquete: %s" -#: gio/gsocket.c:3768 +#: gio/gsocket.c:3755 #, c-format msgid "Error closing socket: %s" msgstr "Erro ao fechar soquete: %s" -#: gio/gsocket.c:4462 +#: gio/gsocket.c:4451 #, c-format msgid "Waiting for socket condition: %s" msgstr "Aguardando pela condição do soquete: %s" -#: gio/gsocket.c:4852 gio/gsocket.c:4868 gio/gsocket.c:4881 +#: gio/gsocket.c:4841 gio/gsocket.c:4857 gio/gsocket.c:4870 #, c-format msgid "Unable to send message: %s" msgstr "Não foi possível enviar mensagem: %s" -#: gio/gsocket.c:4853 gio/gsocket.c:4869 gio/gsocket.c:4882 +#: gio/gsocket.c:4842 gio/gsocket.c:4858 gio/gsocket.c:4871 msgid "Message vectors too large" msgstr "Vetores da mensagem muito grandes" -#: gio/gsocket.c:4898 gio/gsocket.c:4900 gio/gsocket.c:5047 gio/gsocket.c:5132 -#: gio/gsocket.c:5310 gio/gsocket.c:5350 gio/gsocket.c:5352 +#: gio/gsocket.c:4887 gio/gsocket.c:4889 gio/gsocket.c:5036 gio/gsocket.c:5121 +#: gio/gsocket.c:5299 gio/gsocket.c:5339 gio/gsocket.c:5341 #, c-format msgid "Error sending message: %s" msgstr "Erro ao enviar mensagem: %s" -#: gio/gsocket.c:5074 +#: gio/gsocket.c:5063 msgid "GSocketControlMessage not supported on Windows" msgstr "Não há suporte a GSocketControlMessage no Windows" -#: gio/gsocket.c:5547 gio/gsocket.c:5623 gio/gsocket.c:5849 +#: gio/gsocket.c:5536 gio/gsocket.c:5612 gio/gsocket.c:5838 #, c-format msgid "Error receiving message: %s" msgstr "Erro ao receber mensagem: %s" -#: gio/gsocket.c:6134 gio/gsocket.c:6145 gio/gsocket.c:6208 +#: gio/gsocket.c:6123 gio/gsocket.c:6134 gio/gsocket.c:6197 #, c-format msgid "Unable to read socket credentials: %s" msgstr "Não é possível ler as credenciais do soquete: %s" -#: gio/gsocket.c:6217 +#: gio/gsocket.c:6206 msgid "g_socket_get_credentials not implemented for this OS" msgstr "g_socket_get_credentials não está implementado para este SO" @@ -4275,12 +4262,12 @@ msgstr "Proxy SOCKSv5 sem suporte ao tipo de endereço fornecido." msgid "Unknown SOCKSv5 proxy error." msgstr "Erro de proxy SOCKSv5 desconhecido." -#: gio/gtestdbus.c:614 glib/gspawn-win32.c:433 +#: gio/gtestdbus.c:615 glib/gspawn-win32.c:354 #, c-format msgid "Failed to create pipe for communicating with child process (%s)" msgstr "Falha ao criar canal para comunicar com processo filho (%s)" -#: gio/gtestdbus.c:621 +#: gio/gtestdbus.c:622 #, c-format msgid "Pipes are not supported in this platform" msgstr "Não há suporte a canais nesta plataforma" @@ -4290,46 +4277,46 @@ msgstr "Não há suporte a canais nesta plataforma" msgid "Can’t handle version %d of GThemedIcon encoding" msgstr "Não é possível lidar com a versão %d da codificação GThemedIcon" -#: gio/gthreadedresolver.c:319 +#: gio/gthreadedresolver.c:154 msgid "No valid addresses were found" msgstr "Nenhum endereço válido foi localizado" -#: gio/gthreadedresolver.c:514 +#: gio/gthreadedresolver.c:339 #, c-format msgid "Error reverse-resolving “%s”: %s" msgstr "Erro ao resolver reversalmente “%s”: %s" #. Translators: the placeholder is a DNS record type, such as ‘MX’ or ‘SRV’ -#: gio/gthreadedresolver.c:737 gio/gthreadedresolver.c:759 -#: gio/gthreadedresolver.c:813 gio/gthreadedresolver.c:860 -#: gio/gthreadedresolver.c:889 gio/gthreadedresolver.c:901 +#: gio/gthreadedresolver.c:552 gio/gthreadedresolver.c:574 +#: gio/gthreadedresolver.c:628 gio/gthreadedresolver.c:675 +#: gio/gthreadedresolver.c:704 gio/gthreadedresolver.c:716 #, c-format msgid "Error parsing DNS %s record: malformed DNS packet" msgstr "Erro ao analisar registro %s do DNS: pacote DNS mal formado" -#: gio/gthreadedresolver.c:959 gio/gthreadedresolver.c:1096 -#: gio/gthreadedresolver.c:1194 gio/gthreadedresolver.c:1244 +#: gio/gthreadedresolver.c:774 gio/gthreadedresolver.c:911 +#: gio/gthreadedresolver.c:1009 gio/gthreadedresolver.c:1059 #, c-format msgid "No DNS record of the requested type for “%s”" msgstr "Nenhum registro DNS do tipo de requisição para “%s”" -#: gio/gthreadedresolver.c:964 gio/gthreadedresolver.c:1199 +#: gio/gthreadedresolver.c:779 gio/gthreadedresolver.c:1014 #, c-format msgid "Temporarily unable to resolve “%s”" msgstr "Temporariamente sem condições de resolver “%s”" -#: gio/gthreadedresolver.c:969 gio/gthreadedresolver.c:1204 -#: gio/gthreadedresolver.c:1300 +#: gio/gthreadedresolver.c:784 gio/gthreadedresolver.c:1019 +#: gio/gthreadedresolver.c:1129 #, c-format msgid "Error resolving “%s”" msgstr "Erro ao resolver “%s”" -#: gio/gthreadedresolver.c:983 gio/gthreadedresolver.c:1007 -#: gio/gthreadedresolver.c:1032 gio/gthreadedresolver.c:1047 +#: gio/gthreadedresolver.c:798 gio/gthreadedresolver.c:822 +#: gio/gthreadedresolver.c:847 gio/gthreadedresolver.c:862 msgid "Malformed DNS packet" msgstr "Pacote DNS mal formado" -#: gio/gthreadedresolver.c:1089 +#: gio/gthreadedresolver.c:904 #, c-format msgid "Failed to parse DNS response for “%s”: " msgstr "Falha ao analisar resposta DNS para “%s”: " @@ -4389,14 +4376,14 @@ msgstr "A senha digitada está incorreta." msgid "Sending FD is not supported" msgstr "Não há suporte ao envio de FD" -#: gio/gunixconnection.c:181 gio/gunixconnection.c:602 +#: gio/gunixconnection.c:181 gio/gunixconnection.c:601 #, c-format msgid "Expecting 1 control message, got %d" msgid_plural "Expecting 1 control message, got %d" msgstr[0] "Esperando 1 mensagem de controle, obtive %d" msgstr[1] "Esperando 1 mensagem de controle, obtive %d" -#: gio/gunixconnection.c:197 gio/gunixconnection.c:614 +#: gio/gunixconnection.c:197 gio/gunixconnection.c:613 msgid "Unexpected type of ancillary data" msgstr "Tipo de dado auxiliar não esperado" @@ -4419,29 +4406,29 @@ msgstr "Não há suporte ao recebimento de FD" msgid "Error sending credentials: " msgstr "Erro ao enviar credenciais: " -#: gio/gunixconnection.c:542 +#: gio/gunixconnection.c:541 #, c-format msgid "Error checking if SO_PASSCRED is enabled for socket: %s" msgstr "Erro ao verificar se SO_PASSCRED está habilitado pelo soquete: %s" -#: gio/gunixconnection.c:558 +#: gio/gunixconnection.c:557 #, c-format msgid "Error enabling SO_PASSCRED: %s" msgstr "Erro ao habilitar SO_PASSCRED: %s" -#: gio/gunixconnection.c:587 +#: gio/gunixconnection.c:586 msgid "" "Expecting to read a single byte for receiving credentials but read zero bytes" msgstr "" "Era esperado ler apenas um byte para receber credenciais, mas foi lido zero " "byte" -#: gio/gunixconnection.c:628 +#: gio/gunixconnection.c:627 #, c-format msgid "Not expecting control message, but got %d" msgstr "Não esperava mensagem de controle, mas recebeu %d" -#: gio/gunixconnection.c:653 +#: gio/gunixconnection.c:652 #, c-format msgid "Error while disabling SO_PASSCRED: %s" msgstr "Erro ao desabilitar SO_PASSCRED: %s" @@ -4457,7 +4444,7 @@ msgstr "Erro ao ler do descritor de arquivo: %s" msgid "Error closing file descriptor: %s" msgstr "Erro ao fechar o descritor de arquivo: %s" -#: gio/gunixmounts.c:2826 gio/gunixmounts.c:2879 +#: gio/gunixmounts.c:2817 gio/gunixmounts.c:2870 msgid "Filesystem root" msgstr "Sistema de arquivos root" @@ -4617,50 +4604,55 @@ msgstr "Nenhum aplicativo chamado “%s” registrou um marcador para “%s”" msgid "Failed to expand exec line “%s” with URI “%s”" msgstr "Falha em expandir linha de execução “%s” com URI “%s”" -#: glib/gconvert.c:469 +#: glib/gconvert.c:470 msgid "Unrepresentable character in conversion input" msgstr "Caractere não representável na conversão da entrada" -#: glib/gconvert.c:496 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 -#: glib/gutf8.c:1408 +#: glib/gconvert.c:497 glib/gutf8.c:888 glib/gutf8.c:1101 glib/gutf8.c:1238 +#: glib/gutf8.c:1342 msgid "Partial character sequence at end of input" msgstr "Sequência de caracteres parcial no final da entrada" -#: glib/gconvert.c:767 +#: glib/gconvert.c:768 #, c-format msgid "Cannot convert fallback “%s” to codeset “%s”" msgstr "" "Não é possível converter a sequência “%s” para conjunto caracteres “%s”" -#: glib/gconvert.c:939 +#: glib/gconvert.c:940 msgid "Embedded NUL byte in conversion input" msgstr "Byte NULO embutido na entrada de conversão" -#: glib/gconvert.c:960 +#: glib/gconvert.c:961 msgid "Embedded NUL byte in conversion output" msgstr "Byte NULO embutido na saída de conversão" -#: glib/gconvert.c:1698 +#: glib/gconvert.c:1692 #, c-format msgid "The URI “%s” is not an absolute URI using the “file” scheme" msgstr "O URI “%s” não é um URI absoluto que utilize o esquema “file”" -#: glib/gconvert.c:1728 +#: glib/gconvert.c:1702 +#, c-format +msgid "The local file URI “%s” may not include a “#”" +msgstr "O URI de arquivo local “%s” não pode incluir um “#”" + +#: glib/gconvert.c:1719 #, c-format msgid "The URI “%s” is invalid" msgstr "O URI “%s” é inválido" -#: glib/gconvert.c:1741 +#: glib/gconvert.c:1731 #, c-format msgid "The hostname of the URI “%s” is invalid" msgstr "O nome de máquina do URI “%s” é inválido" -#: glib/gconvert.c:1758 +#: glib/gconvert.c:1747 #, c-format msgid "The URI “%s” contains invalidly escaped characters" msgstr "O URI “%s” contém caracteres com escape inválido" -#: glib/gconvert.c:1832 +#: glib/gconvert.c:1819 #, c-format msgid "The pathname “%s” is not an absolute path" msgstr "O nome de caminho “%s” não é um caminho absoluto" @@ -5182,16 +5174,16 @@ msgstr "Canal termina em um caractere parcial" msgid "Can’t do a raw read in g_io_channel_read_to_end" msgstr "Não é possível fazer uma leitura em bruto de g_io_channel_read_to_end" -#: glib/gkeyfile.c:802 +#: glib/gkeyfile.c:800 msgid "Valid key file could not be found in search dirs" msgstr "" "Não foi possível localizar arquivo de chave válido nos diretórios pesquisados" -#: glib/gkeyfile.c:839 +#: glib/gkeyfile.c:837 msgid "Not a regular file" msgstr "Não é um arquivo comum" -#: glib/gkeyfile.c:1297 +#: glib/gkeyfile.c:1295 #, c-format msgid "" "Key file contains line “%s” which is not a key-value pair, group, or comment" @@ -5199,50 +5191,50 @@ msgstr "" "Arquivo de chave contém a linha “%s” que não é um par chave-valor, grupo ou " "comentário" -#: glib/gkeyfile.c:1354 +#: glib/gkeyfile.c:1352 #, c-format msgid "Invalid group name: %s" msgstr "Nome de grupo inválido: %s" -#: glib/gkeyfile.c:1378 +#: glib/gkeyfile.c:1376 msgid "Key file does not start with a group" msgstr "Arquivo de chave não começa com um grupo" -#: glib/gkeyfile.c:1402 +#: glib/gkeyfile.c:1400 #, c-format msgid "Invalid key name: %.*s" msgstr "Nome de chave inválido: %.*s" -#: glib/gkeyfile.c:1430 +#: glib/gkeyfile.c:1428 #, c-format msgid "Key file contains unsupported encoding “%s”" msgstr "Arquivo de chave contém codificação “%s” sem suporte" -#: glib/gkeyfile.c:1678 glib/gkeyfile.c:1851 glib/gkeyfile.c:3298 -#: glib/gkeyfile.c:3400 glib/gkeyfile.c:3505 glib/gkeyfile.c:3634 -#: glib/gkeyfile.c:3777 glib/gkeyfile.c:4026 glib/gkeyfile.c:4100 +#: glib/gkeyfile.c:1683 glib/gkeyfile.c:1856 glib/gkeyfile.c:3303 +#: glib/gkeyfile.c:3367 glib/gkeyfile.c:3497 glib/gkeyfile.c:3626 +#: glib/gkeyfile.c:3772 glib/gkeyfile.c:4007 glib/gkeyfile.c:4074 #, c-format msgid "Key file does not have group “%s”" msgstr "Arquivo de chave não tem grupo “%s”" -#: glib/gkeyfile.c:1806 +#: glib/gkeyfile.c:1811 #, c-format msgid "Key file does not have key “%s” in group “%s”" msgstr "Arquivo de chave não tem chave “%s” no grupo “%s”" -#: glib/gkeyfile.c:1968 glib/gkeyfile.c:2084 +#: glib/gkeyfile.c:1973 glib/gkeyfile.c:2089 #, c-format msgid "Key file contains key “%s” with value “%s” which is not UTF-8" msgstr "Arquivo de chave contém chave “%s” com valor “%s” que não é UTF-8" -#: glib/gkeyfile.c:1988 glib/gkeyfile.c:2104 glib/gkeyfile.c:2543 +#: glib/gkeyfile.c:1993 glib/gkeyfile.c:2109 glib/gkeyfile.c:2548 #, c-format msgid "" "Key file contains key “%s” which has a value that cannot be interpreted." msgstr "" "Arquivo de chave contém chave “%s” cujo valor não pode ser interpretado." -#: glib/gkeyfile.c:2758 glib/gkeyfile.c:3127 +#: glib/gkeyfile.c:2763 glib/gkeyfile.c:3132 #, c-format msgid "" "Key file contains key “%s” in group “%s” which has a value that cannot be " @@ -5251,36 +5243,36 @@ msgstr "" "Arquivo de chave contém chave “%s” no grupo “%s” que tem um valor que não " "pode ser interpretado." -#: glib/gkeyfile.c:2836 glib/gkeyfile.c:2913 +#: glib/gkeyfile.c:2841 glib/gkeyfile.c:2918 #, c-format msgid "Key “%s” in group “%s” has value “%s” where %s was expected" msgstr "Chave “%s” no grupo “%s” tem o valor “%s” onde %s era esperado" -#: glib/gkeyfile.c:4357 +#: glib/gkeyfile.c:4330 msgid "Key file contains escape character at end of line" msgstr "Arquivo de chave contém caractere de escape no fim da linha" -#: glib/gkeyfile.c:4394 +#: glib/gkeyfile.c:4352 #, c-format msgid "Key file contains invalid escape sequence “%s”" msgstr "Arquivo de chave contém sequência de escape “%s” inválida" -#: glib/gkeyfile.c:4545 +#: glib/gkeyfile.c:4504 #, c-format msgid "Value “%s” cannot be interpreted as a number." msgstr "O valor “%s” não pode ser interpretado como um número." -#: glib/gkeyfile.c:4559 +#: glib/gkeyfile.c:4518 #, c-format msgid "Integer value “%s” out of range" msgstr "Valor inteiro “%s” fora dos limites" -#: glib/gkeyfile.c:4592 +#: glib/gkeyfile.c:4551 #, c-format msgid "Value “%s” cannot be interpreted as a float number." msgstr "O valor “%s” não pode ser interpretado como ponto flutuante." -#: glib/gkeyfile.c:4631 +#: glib/gkeyfile.c:4590 #, c-format msgid "Value “%s” cannot be interpreted as a boolean." msgstr "O valor “%s” não pode ser interpretado como um booleano." @@ -5583,183 +5575,187 @@ msgstr "Falta argumento para %s" msgid "Unknown option %s" msgstr "Opção %s desconhecida" -#: glib/gregex.c:480 +#: glib/gregex.c:479 msgid "corrupted object" msgstr "objeto corrompido" -#: glib/gregex.c:482 +#: glib/gregex.c:481 msgid "out of memory" msgstr "memória insuficiente" -#: glib/gregex.c:497 +#: glib/gregex.c:487 +msgid "backtracking limit reached" +msgstr "limite de backtracking alcançado" + +#: glib/gregex.c:498 msgid "internal error" msgstr "erro interno" -#: glib/gregex.c:499 +#: glib/gregex.c:500 msgid "the pattern contains items not supported for partial matching" msgstr "o padrão contém itens sem suporte para correspondência parcial" -#: glib/gregex.c:501 +#: glib/gregex.c:502 msgid "back references as conditions are not supported for partial matching" msgstr "" "não há suporte à referência retroativa como condição para correspondência " "parcial" -#: glib/gregex.c:507 +#: glib/gregex.c:508 msgid "recursion limit reached" msgstr "limite de recursão alcançado" -#: glib/gregex.c:509 +#: glib/gregex.c:510 msgid "bad offset" msgstr "deslocamento ruim" -#: glib/gregex.c:511 +#: glib/gregex.c:512 msgid "recursion loop" msgstr "recursão infinita" #. should not happen in GRegex since we check modes before each match -#: glib/gregex.c:514 +#: glib/gregex.c:515 msgid "matching mode is requested that was not compiled for JIT" msgstr "é solicitado o modo de correspondência que não foi compilado para JIT" -#: glib/gregex.c:535 glib/gregex.c:1851 +#: glib/gregex.c:536 glib/gregex.c:1838 msgid "unknown error" msgstr "erro desconhecido" -#: glib/gregex.c:556 +#: glib/gregex.c:557 msgid "\\ at end of pattern" msgstr "\\ no fim do padrão" -#: glib/gregex.c:560 +#: glib/gregex.c:561 msgid "\\c at end of pattern" msgstr "\\c no fim do padrão" -#: glib/gregex.c:565 +#: glib/gregex.c:566 msgid "unrecognized character following \\" msgstr "caractere não reconhecido seguindo \\" -#: glib/gregex.c:569 +#: glib/gregex.c:570 msgid "numbers out of order in {} quantifier" msgstr "números fora de ordem no quantificador {}" -#: glib/gregex.c:573 +#: glib/gregex.c:574 msgid "number too big in {} quantifier" msgstr "número grande demais no quantificador {}" -#: glib/gregex.c:577 +#: glib/gregex.c:578 msgid "missing terminating ] for character class" msgstr "terminação ] em falta para classe de caracteres" -#: glib/gregex.c:581 +#: glib/gregex.c:582 msgid "invalid escape sequence in character class" msgstr "sequência de escape inválida na classe de caracteres" -#: glib/gregex.c:585 +#: glib/gregex.c:586 msgid "range out of order in character class" msgstr "intervalo fora de ordem na classe de caracteres" -#: glib/gregex.c:590 +#: glib/gregex.c:591 msgid "nothing to repeat" msgstr "nada a repetir" -#: glib/gregex.c:594 +#: glib/gregex.c:595 msgid "unrecognized character after (? or (?-" msgstr "caractere não reconhecido após (? ou (?-" -#: glib/gregex.c:598 +#: glib/gregex.c:599 msgid "POSIX named classes are supported only within a class" msgstr "Classes nomeadas POSIX têm suporte apenas dentro de uma classe" -#: glib/gregex.c:602 +#: glib/gregex.c:603 msgid "POSIX collating elements are not supported" msgstr "Elementos de arranjo POSIX sem suporte" -#: glib/gregex.c:608 +#: glib/gregex.c:609 msgid "missing terminating )" msgstr "faltando terminação )" -#: glib/gregex.c:612 +#: glib/gregex.c:613 msgid "reference to non-existent subpattern" msgstr "referência a subpadrão não existente" -#: glib/gregex.c:616 +#: glib/gregex.c:617 msgid "missing ) after comment" msgstr "faltando ) após o comentário" -#: glib/gregex.c:620 +#: glib/gregex.c:621 msgid "regular expression is too large" msgstr "expressão regular é grande demais" -#: glib/gregex.c:624 +#: glib/gregex.c:625 msgid "malformed number or name after (?(" msgstr "número mal formado ou nome após (?(" -#: glib/gregex.c:628 +#: glib/gregex.c:629 msgid "lookbehind assertion is not fixed length" msgstr "declaração de verificação anterior não é de largura fixa" -#: glib/gregex.c:632 +#: glib/gregex.c:633 msgid "conditional group contains more than two branches" msgstr "grupo condicional contém mais que duas ramificações" -#: glib/gregex.c:636 +#: glib/gregex.c:637 msgid "assertion expected after (?(" msgstr "esperava-se declaração após (?(" -#: glib/gregex.c:640 +#: glib/gregex.c:641 msgid "a numbered reference must not be zero" msgstr "uma referência numerada não pode ser zero" -#: glib/gregex.c:644 +#: glib/gregex.c:645 msgid "unknown POSIX class name" msgstr "nome de classe POSIX desconhecido" -#: glib/gregex.c:649 +#: glib/gregex.c:650 msgid "character value in \\x{...} sequence is too large" msgstr "valor de caractere na sequência \\x{...} é grande demais" -#: glib/gregex.c:653 +#: glib/gregex.c:654 msgid "\\C not allowed in lookbehind assertion" msgstr "\\C não permitido na declaração de verificação anterior" -#: glib/gregex.c:657 +#: glib/gregex.c:658 msgid "missing terminator in subpattern name" msgstr "terminação em falta no nome do subpadrão" -#: glib/gregex.c:661 +#: glib/gregex.c:662 msgid "two named subpatterns have the same name" msgstr "dois subpadrões nomeados têm o mesmo nome" -#: glib/gregex.c:665 +#: glib/gregex.c:666 msgid "malformed \\P or \\p sequence" msgstr "sequência \\P ou \\p mal formada" -#: glib/gregex.c:669 +#: glib/gregex.c:670 msgid "unknown property name after \\P or \\p" msgstr "nome de propriedade desconhecido após \\P ou \\p" -#: glib/gregex.c:673 +#: glib/gregex.c:674 msgid "subpattern name is too long (maximum 32 characters)" msgstr "nome de subpadrão é grande demais (máximo 32 caracteres)" -#: glib/gregex.c:677 +#: glib/gregex.c:678 msgid "too many named subpatterns (maximum 10,000)" msgstr "excesso de subpadrões nomeados (máximo 10.000)" -#: glib/gregex.c:681 +#: glib/gregex.c:682 msgid "octal value is greater than \\377" msgstr "valor octal é maior que \\377" -#: glib/gregex.c:685 +#: glib/gregex.c:686 msgid "DEFINE group contains more than one branch" msgstr "O grupo DEFINE contém mais que uma ramificação" -#: glib/gregex.c:689 +#: glib/gregex.c:690 msgid "inconsistent NEWLINE options" msgstr "opções do NEWLINE inconsistentes" # obs.: "angle-brackets" não existe no Brasil, mas existe brackets, que é '<' e '>' -#: glib/gregex.c:693 +#: glib/gregex.c:694 msgid "" "\\g is not followed by a braced, angle-bracketed, or quoted name or number, " "or by a plain number" @@ -5767,120 +5763,120 @@ msgstr "" "\\g não é seguido por um número ou nome entre aspas, chaves ou sinais de " "menor que ou maior que um número diferente de zero opcionalmente entre chaves" -#: glib/gregex.c:698 +#: glib/gregex.c:699 msgid "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" msgstr "um argumento não é permitido para (*ACCEPT), (*FAIL) ou (*COMMIT)" -#: glib/gregex.c:702 +#: glib/gregex.c:703 msgid "(*VERB) not recognized" msgstr "(*VERB) não reconhecido" -#: glib/gregex.c:706 +#: glib/gregex.c:707 msgid "number is too big" msgstr "número é muito grande" -#: glib/gregex.c:710 +#: glib/gregex.c:711 msgid "missing subpattern name after (?&" msgstr "faltando o nome do subpadrão após (?&" -#: glib/gregex.c:714 +#: glib/gregex.c:715 msgid "different names for subpatterns of the same number are not allowed" msgstr "não é permitido dois subpadrões nomeados com o mesmo nome" -#: glib/gregex.c:718 +#: glib/gregex.c:719 msgid "(*MARK) must have an argument" msgstr "(*MARK) deve possuir um argumento" -#: glib/gregex.c:722 +#: glib/gregex.c:723 msgid "\\c must be followed by an ASCII character" msgstr "\\c pode ser seguido por um caractere ASCII" # obs.: "angle-brackets" não existe no Brasil, mas existe brackets, que é '<' e '>' -#: glib/gregex.c:726 +#: glib/gregex.c:727 msgid "\\k is not followed by a braced, angle-bracketed, or quoted name" msgstr "" "\\k não é seguido por um nome entre aspas, chaves ou sinais de menor que ou " "maior que" -#: glib/gregex.c:730 +#: glib/gregex.c:731 msgid "\\N is not supported in a class" msgstr "\\N não é suportado em uma classe" -#: glib/gregex.c:734 +#: glib/gregex.c:735 msgid "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" msgstr "nome é muito cumprido em (*MARK), (*PRUNE), (*SKIP) ou (*THEN)" -#: glib/gregex.c:738 glib/gregex.c:874 +#: glib/gregex.c:739 glib/gregex.c:875 msgid "code overflow" msgstr "estouro de código" -#: glib/gregex.c:742 +#: glib/gregex.c:743 msgid "unrecognized character after (?P" msgstr "caractere não reconhecido após (?P" -#: glib/gregex.c:746 +#: glib/gregex.c:747 msgid "overran compiling workspace" msgstr "espaço de trabalho de compilação invadido" -#: glib/gregex.c:750 +#: glib/gregex.c:751 msgid "previously-checked referenced subpattern not found" msgstr "subpadrão de referência verificado anteriormente não localizado" -#: glib/gregex.c:873 glib/gregex.c:1135 glib/gregex.c:2457 +#: glib/gregex.c:874 glib/gregex.c:1121 glib/gregex.c:2444 #, c-format msgid "Error while matching regular expression %s: %s" msgstr "Erro ao coincidir expressão regular %s: %s" -#: glib/gregex.c:1735 +#: glib/gregex.c:1721 msgid "PCRE library is compiled without UTF8 support" msgstr "Biblioteca PCRE compilada sem suporte a UTF-8" -#: glib/gregex.c:1743 +#: glib/gregex.c:1729 msgid "PCRE library is compiled with incompatible options" msgstr "Biblioteca PCRE compilada com opções incompatíveis" -#: glib/gregex.c:1860 +#: glib/gregex.c:1847 #, c-format msgid "Error while compiling regular expression ‘%s’ at char %s: %s" msgstr "Erro ao compilar a expressão regular “%s” no caractere %s: %s" -#: glib/gregex.c:2900 +#: glib/gregex.c:2887 msgid "hexadecimal digit or “}” expected" msgstr "esperava-se dígito hexadecimal ou “}”" -#: glib/gregex.c:2916 +#: glib/gregex.c:2903 msgid "hexadecimal digit expected" msgstr "esperava-se dígito hexadecimal" -#: glib/gregex.c:2956 +#: glib/gregex.c:2943 msgid "missing “<” in symbolic reference" msgstr "“<” em falta na referência simbólica" -#: glib/gregex.c:2965 +#: glib/gregex.c:2952 msgid "unfinished symbolic reference" msgstr "referência simbólica inacabada" -#: glib/gregex.c:2972 +#: glib/gregex.c:2959 msgid "zero-length symbolic reference" msgstr "referência simbólica de comprimento zero" -#: glib/gregex.c:2983 +#: glib/gregex.c:2970 msgid "digit expected" msgstr "esperava-se dígito" -#: glib/gregex.c:3001 +#: glib/gregex.c:2988 msgid "illegal symbolic reference" msgstr "referência simbólica ilegal" -#: glib/gregex.c:3064 +#: glib/gregex.c:3051 msgid "stray final “\\”" msgstr "“\\” final errado" -#: glib/gregex.c:3068 +#: glib/gregex.c:3055 msgid "unknown escape sequence" msgstr "sequência de escape desconhecida" -#: glib/gregex.c:3078 +#: glib/gregex.c:3065 #, c-format msgid "Error while parsing replacement text “%s” at char %lu: %s" msgstr "Erro ao analisar texto de substituição “%s” no caractere %lu: %s" @@ -5909,92 +5905,92 @@ msgstr "" msgid "Text was empty (or contained only whitespace)" msgstr "Texto estava vazio (ou apenas continha espaços)" -#: glib/gspawn.c:320 +#: glib/gspawn.c:319 #, c-format msgid "Failed to read data from child process (%s)" msgstr "Falha ao ler dados de processo filho (%s)" -#: glib/gspawn.c:473 +#: glib/gspawn.c:471 #, c-format msgid "Unexpected error in reading data from a child process (%s)" msgstr "Erro inesperado na leitura de dados de um processo filho (%s)" -#: glib/gspawn.c:558 +#: glib/gspawn.c:556 #, c-format msgid "Unexpected error in waitpid() (%s)" msgstr "Erro inesperado em waitpid() (%s)" -#: glib/gspawn.c:1180 glib/gspawn-win32.c:1575 +#: glib/gspawn.c:1175 glib/gspawn-win32.c:1503 #, c-format msgid "Child process exited with code %ld" msgstr "Processo filho concluiu com código %ld" -#: glib/gspawn.c:1188 +#: glib/gspawn.c:1183 #, c-format msgid "Child process killed by signal %ld" msgstr "Processo filho foi terminado pelo sinal %ld" -#: glib/gspawn.c:1195 +#: glib/gspawn.c:1190 #, c-format msgid "Child process stopped by signal %ld" msgstr "Processo filho foi parado pelo sinal %ld" -#: glib/gspawn.c:1202 +#: glib/gspawn.c:1197 #, c-format msgid "Child process exited abnormally" msgstr "Processo filho concluiu anormalmente" -#: glib/gspawn.c:2039 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 +#: glib/gspawn.c:2027 glib/gspawn-win32.c:393 glib/gspawn-win32.c:401 #, c-format msgid "Failed to read from child pipe (%s)" msgstr "Falha ao ler de canal filho (%s)" -#: glib/gspawn.c:2411 +#: glib/gspawn.c:2399 #, c-format msgid "Failed to spawn child process “%s” (%s)" msgstr "Falha ao criar processo filho “%s” (%s)" -#: glib/gspawn.c:2537 +#: glib/gspawn.c:2525 #, c-format msgid "Failed to fork (%s)" msgstr "Falha no fork (%s)" -#: glib/gspawn.c:2697 glib/gspawn-win32.c:503 +#: glib/gspawn.c:2685 glib/gspawn-win32.c:424 #, c-format msgid "Failed to change to directory “%s” (%s)" msgstr "Falha ao ir para diretório “%s” (%s)" -#: glib/gspawn.c:2707 +#: glib/gspawn.c:2695 #, c-format msgid "Failed to execute child process “%s” (%s)" msgstr "Falha ao executar processo filho “%s” (%s)" -#: glib/gspawn.c:2717 +#: glib/gspawn.c:2705 #, c-format msgid "Failed to open file to remap file descriptor (%s)" msgstr "Falha ao abrir o arquivo para remapear o descritor de arquivo (%s)" -#: glib/gspawn.c:2725 +#: glib/gspawn.c:2713 #, c-format msgid "Failed to duplicate file descriptor for child process (%s)" msgstr "Falha ao duplicar o descritor de arquivo para o processo filho (%s)" -#: glib/gspawn.c:2734 +#: glib/gspawn.c:2722 #, c-format msgid "Failed to fork child process (%s)" msgstr "Falha no fork de processo filho (%s)" -#: glib/gspawn.c:2742 +#: glib/gspawn.c:2730 #, c-format msgid "Failed to close file descriptor for child process (%s)" msgstr "Falha ao fechar o descritor de arquivo para o processo filho (%s)" -#: glib/gspawn.c:2750 +#: glib/gspawn.c:2738 #, c-format msgid "Unknown error executing child process “%s”" msgstr "Erro desconhecido ao executar processo filho “%s”" -#: glib/gspawn.c:2774 +#: glib/gspawn.c:2762 #, c-format msgid "Failed to read enough data from child pid pipe (%s)" msgstr "Falha ao ler dados suficientes de canal pid do filho (%s)" @@ -6004,46 +6000,46 @@ msgstr "Falha ao ler dados suficientes de canal pid do filho (%s)" msgid "Invalid source FDs argument" msgstr "Argumento de FDs de origem inválido" -#: glib/gspawn-win32.c:416 +#: glib/gspawn-win32.c:337 msgid "Failed to read data from child process" msgstr "Falha ao ler dados de processo filho" -#: glib/gspawn-win32.c:509 glib/gspawn-win32.c:514 glib/gspawn-win32.c:640 +#: glib/gspawn-win32.c:430 glib/gspawn-win32.c:435 glib/gspawn-win32.c:561 #, c-format msgid "Failed to execute child process (%s)" msgstr "Falha ao executar processo filho (%s)" -#: glib/gspawn-win32.c:519 +#: glib/gspawn-win32.c:440 #, c-format msgid "Failed to dup() in child process (%s)" msgstr "Falha em dup() no processo filho (%s)" -#: glib/gspawn-win32.c:590 +#: glib/gspawn-win32.c:511 #, c-format msgid "Invalid program name: %s" msgstr "Nome de programa inválido: %s" -#: glib/gspawn-win32.c:600 glib/gspawn-win32.c:940 +#: glib/gspawn-win32.c:521 glib/gspawn-win32.c:868 #, c-format msgid "Invalid string in argument vector at %d: %s" msgstr "String inválida no vetor de argumentos em %d: %s" -#: glib/gspawn-win32.c:611 glib/gspawn-win32.c:956 +#: glib/gspawn-win32.c:532 glib/gspawn-win32.c:884 #, c-format msgid "Invalid string in environment: %s" msgstr "String inválida no ambiente: %s" -#: glib/gspawn-win32.c:936 +#: glib/gspawn-win32.c:864 #, c-format msgid "Invalid working directory: %s" msgstr "Diretório de trabalho inválido: %s" -#: glib/gspawn-win32.c:1001 +#: glib/gspawn-win32.c:929 #, c-format msgid "Failed to execute helper program (%s)" msgstr "Falha ao executar programa auxiliar (%s)" -#: glib/gspawn-win32.c:1230 +#: glib/gspawn-win32.c:1158 msgid "" "Unexpected error in g_io_channel_win32_poll() reading data from a child " "process" @@ -6070,76 +6066,76 @@ msgstr "O número “%s” está fora dos limites [%s, %s]" msgid "“%s” is not an unsigned number" msgstr "“%s” não é um número não assinado" -#: glib/guri.c:318 +#: glib/guri.c:317 #, no-c-format msgid "Invalid %-encoding in URI" msgstr "%-encoding inválida na URI" -#: glib/guri.c:335 +#: glib/guri.c:334 msgid "Illegal character in URI" msgstr "Caractere ilegal na URI" -#: glib/guri.c:369 +#: glib/guri.c:368 msgid "Non-UTF-8 characters in URI" msgstr "Caracteres não UTF-8 na URI" -#: glib/guri.c:549 +#: glib/guri.c:548 #, c-format msgid "Invalid IPv6 address ‘%.*s’ in URI" msgstr "Endereço IPv6 “%.*s” inválido na URI" -#: glib/guri.c:604 +#: glib/guri.c:603 #, c-format msgid "Illegal encoded IP address ‘%.*s’ in URI" msgstr "Endereço IP “%.*s” codificado ilegal na URI" -#: glib/guri.c:616 +#: glib/guri.c:615 #, c-format msgid "Illegal internationalized hostname ‘%.*s’ in URI" msgstr "Nome de máquina internacionalizado ilegal “%.*s” na URI" -#: glib/guri.c:648 glib/guri.c:660 +#: glib/guri.c:647 glib/guri.c:659 #, c-format msgid "Could not parse port ‘%.*s’ in URI" msgstr "Não foi possível analisar a porta “%.*s” na URI" -#: glib/guri.c:667 +#: glib/guri.c:666 #, c-format msgid "Port ‘%.*s’ in URI is out of range" msgstr "A porta “%.*s” na URI está fora dos limites" -#: glib/guri.c:1230 glib/guri.c:1294 +#: glib/guri.c:1226 glib/guri.c:1290 #, c-format msgid "URI ‘%s’ is not an absolute URI" msgstr "A URI “%s” não é uma URI absoluta" -#: glib/guri.c:1236 +#: glib/guri.c:1232 #, c-format msgid "URI ‘%s’ has no host component" msgstr "A URI “%s” possui nenhum componente de host" -#: glib/guri.c:1466 +#: glib/guri.c:1462 msgid "URI is not absolute, and no base URI was provided" msgstr "A URI não é absoluta, e nenhuma URI base foi fornecida" -#: glib/guri.c:2252 +#: glib/guri.c:2248 msgid "Missing ‘=’ and parameter value" msgstr "Faltando “=” e valor de parâmetro" -#: glib/gutf8.c:900 +#: glib/gutf8.c:834 msgid "Failed to allocate memory" msgstr "Falha ao alocar memória" -#: glib/gutf8.c:1033 +#: glib/gutf8.c:967 msgid "Character out of range for UTF-8" msgstr "Caractere fora do limite para UTF-8" -#: glib/gutf8.c:1135 glib/gutf8.c:1144 glib/gutf8.c:1274 glib/gutf8.c:1283 -#: glib/gutf8.c:1422 glib/gutf8.c:1519 +#: glib/gutf8.c:1069 glib/gutf8.c:1078 glib/gutf8.c:1208 glib/gutf8.c:1217 +#: glib/gutf8.c:1356 glib/gutf8.c:1453 msgid "Invalid sequence in conversion input" msgstr "Sequência inválida na conversão da entrada" -#: glib/gutf8.c:1433 glib/gutf8.c:1530 +#: glib/gutf8.c:1367 glib/gutf8.c:1464 msgid "Character out of range for UTF-16" msgstr "Caractere fora do limite para UTF-16" @@ -6366,15 +6362,9 @@ msgstr "%.1f PB" msgid "%.1f EB" msgstr "%.1f EB" -#~ msgid "GApplication options" -#~ msgstr "Opções do GApplication" - #, c-format -#~ msgid "The local file URI “%s” may not include a “#”" -#~ msgstr "O URI de arquivo local “%s” não pode incluir um “#”" - -#~ msgid "backtracking limit reached" -#~ msgstr "limite de backtracking alcançado" +#~ msgid "edit name: %s\n" +#~ msgstr "nome para edição: %s\n" #~ msgid "internal error or corrupted object" #~ msgstr "erro interno ou objeto corrompido" diff --git a/po/ro.po b/po/ro.po index 36165bc..0ca8941 100644 --- a/po/ro.po +++ b/po/ro.po @@ -10,8 +10,8 @@ msgid "" msgstr "" "Project-Id-Version: glib\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" -"POT-Creation-Date: 2023-10-18 18:26+0000\n" -"PO-Revision-Date: 2023-10-18 20:27+0200\n" +"POT-Creation-Date: 2023-10-04 22:23+0000\n" +"PO-Revision-Date: 2023-10-09 15:17+0300\n" "Last-Translator: Florentina Mușat \n" "Language-Team: Gnome Romanian Translation Team 0 && n%100 < " "20)) ? 1 : 2);\n" -"X-Generator: Poedit 3.3.2\n" +"X-Generator: Poedit 3.4\n" "X-Project-Style: gnome\n" "X-Poedit-SourceCharset: UTF-8\n" @@ -306,7 +306,7 @@ msgstr "Flux deja închis" msgid "Truncate not supported on base stream" msgstr "Trunchierea fluxului de bază nu este suportată" -#: gio/gcancellable.c:326 gio/gdbusconnection.c:1867 gio/gdbusprivate.c:1434 +#: gio/gcancellable.c:326 gio/gdbusconnection.c:1867 gio/gdbusprivate.c:1432 #: gio/gsimpleasyncresult.c:873 gio/gsimpleasyncresult.c:899 #, c-format msgid "Operation was cancelled" @@ -612,8 +612,8 @@ msgstr "Eroare la crearea directorului „%s”: %s" #: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 #: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 #: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:8996 gio/gfile.c:9086 -#: gio/gfile.c:9170 gio/win32/gwinhttpfile.c:453 +#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:9000 gio/gfile.c:9090 +#: gio/gfile.c:9174 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "Operațiune neimplementată" @@ -1000,23 +1000,23 @@ msgstr "Eroare la întoarcere cu corpul de tipul „%s”" msgid "Error return with empty body" msgstr "Rezultat de eroare cu corp vid" -#: gio/gdbusprivate.c:2201 +#: gio/gdbusprivate.c:2199 #, c-format msgid "(Type any character to close this window)\n" msgstr "(Tastați orice caracter pentru a închide această fereastră)\n" -#: gio/gdbusprivate.c:2387 +#: gio/gdbusprivate.c:2385 #, c-format msgid "Session dbus not running, and autolaunch failed" msgstr "Sesiunea dbus nu rulează, și lansarea automată a eșuat" -#: gio/gdbusprivate.c:2410 +#: gio/gdbusprivate.c:2408 #, c-format msgid "Unable to get Hardware profile: %s" msgstr "Nu se poate obține profilul hardware: %s" #. Translators: Both placeholders are file paths -#: gio/gdbusprivate.c:2461 +#: gio/gdbusprivate.c:2459 #, c-format msgid "Unable to load %s or %s: " msgstr "Nu s-a putut încărca %s sau %s: " @@ -1361,45 +1361,45 @@ msgstr "Eroare: %s nu este un nume de magistrală popular valid.\n" msgid "Not authorized to change debug settings" msgstr "Neautorizat pentru a modifica configurările de depanare" -#: gio/gdesktopappinfo.c:2242 gio/gdesktopappinfo.c:5226 +#: gio/gdesktopappinfo.c:2243 gio/gdesktopappinfo.c:5227 msgid "Unnamed" msgstr "Nedenumit" -#: gio/gdesktopappinfo.c:2652 +#: gio/gdesktopappinfo.c:2653 msgid "Desktop file didn’t specify Exec field" msgstr "Fișierul desktop nu a specificat un câmp Exec" -#: gio/gdesktopappinfo.c:2942 +#: gio/gdesktopappinfo.c:2943 msgid "Unable to find terminal required for application" msgstr "Nu s-a găsit un terminal pentru pornirea aplicației" -#: gio/gdesktopappinfo.c:3002 +#: gio/gdesktopappinfo.c:3003 #, c-format msgid "Program ‘%s’ not found in $PATH" msgstr "Programul „%s” nu a fost găsit în $PATH" -#: gio/gdesktopappinfo.c:3738 +#: gio/gdesktopappinfo.c:3739 #, c-format msgid "Can’t create user application configuration folder %s: %s" msgstr "" "Nu se poate crea dosarul de configurare pentru aplicațiile utilizatorului " "%s: %s" -#: gio/gdesktopappinfo.c:3742 +#: gio/gdesktopappinfo.c:3743 #, c-format msgid "Can’t create user MIME configuration folder %s: %s" msgstr "Nu se poate crea dosarul de configurare MIME al utilizatorului %s: %s" -#: gio/gdesktopappinfo.c:3984 gio/gdesktopappinfo.c:4008 +#: gio/gdesktopappinfo.c:3985 gio/gdesktopappinfo.c:4009 msgid "Application information lacks an identifier" msgstr "Informațiile despre aplicație nu au un indentificator" -#: gio/gdesktopappinfo.c:4244 +#: gio/gdesktopappinfo.c:4245 #, c-format msgid "Can’t create user desktop file %s" msgstr "Nu se poate crea fișierul desktop al utilizatorului %s" -#: gio/gdesktopappinfo.c:4380 +#: gio/gdesktopappinfo.c:4381 #, c-format msgid "Custom definition for %s" msgstr "Definiție personalizată pentru %s" @@ -1540,16 +1540,16 @@ msgstr "Nu există o implementare pentru coșul de gunoi" msgid "File names cannot contain “%c”" msgstr "Numele de fișiere nu pot conține „%c”" -#: gio/gfile.c:7151 gio/gfile.c:7277 +#: gio/gfile.c:7155 gio/gfile.c:7281 #, c-format msgid "Failed to create a temporary directory for template “%s”: %s" msgstr "Nu s-a putut crea un director temporar pentru șablonul „%s”: %s" -#: gio/gfile.c:7595 gio/gvolume.c:366 +#: gio/gfile.c:7599 gio/gvolume.c:366 msgid "volume doesn’t implement mount" msgstr "volumul nu implementează montarea" -#: gio/gfile.c:7709 gio/gfile.c:7786 +#: gio/gfile.c:7713 gio/gfile.c:7790 msgid "No application is registered as handling this file" msgstr "Nu există o aplicație înregistrată pentru deschiderea acestui fișier" @@ -4293,13 +4293,13 @@ msgstr "Proxy-ul SOCKSv5 nu acceptă tipul de adresă furnizat." msgid "Unknown SOCKSv5 proxy error." msgstr "Eroare necunoscută a proxy-ului SOCKSv5." -#: gio/gtestdbus.c:614 glib/gspawn-win32.c:433 +#: gio/gtestdbus.c:611 glib/gspawn-win32.c:433 #, c-format msgid "Failed to create pipe for communicating with child process (%s)" msgstr "" "Nu s-a putut crea conectorul „pipe” pentru comunicarea cu procesul copil (%s)" -#: gio/gtestdbus.c:621 +#: gio/gtestdbus.c:618 #, c-format msgid "Pipes are not supported in this platform" msgstr "Conductele nu sunt suportate pe această platformă" @@ -6400,11 +6400,6 @@ msgstr "%.1f PB" msgid "%.1f EB" msgstr "%.1f EB" -#, fuzzy -#~| msgid "Use default permissions for the destination" -#~ msgid "Use default file modification timestamps for the destination" -#~ msgstr "Utilizează permisiunile implicite pentru destinație" - #~ msgid "backtracking limit reached" #~ msgstr "s-a atins limita de backtracking" diff --git a/po/ru.po b/po/ru.po index 1dc4d39..65514b7 100644 --- a/po/ru.po +++ b/po/ru.po @@ -16,8 +16,8 @@ msgid "" msgstr "" "Project-Id-Version: ru\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" -"POT-Creation-Date: 2023-08-31 14:09+0000\n" -"PO-Revision-Date: 2023-08-31 18:12+0300\n" +"POT-Creation-Date: 2023-11-23 12:42+0000\n" +"PO-Revision-Date: 2023-11-25 14:32+0300\n" "Last-Translator: Artur So \n" "Language-Team: Русский \n" "Language: ru\n" @@ -26,7 +26,7 @@ msgstr "" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=3; plural=(n%10==1 && n%100!=11 ? 0 : n%10>=2 && " "n%10<=4 && (n%100<10 || n%100>=20) ? 1 : 2);\n" -"X-Generator: Poedit 3.3.2\n" +"X-Generator: Poedit 3.4.1\n" #: gio/gappinfo.c:339 msgid "Setting default applications not supported yet" @@ -48,29 +48,29 @@ msgstr "Не удалось найти приложение по умолчан msgid "Failed to find default application for URI Scheme ‘%s’" msgstr "Не удалось найти приложение по умолчанию для схемы URI '%s'" -#: gio/gapplication.c:506 +#: gio/gapplication.c:503 msgid "GApplication Options:" msgstr "Параметры GApplication:" -#: gio/gapplication.c:506 +#: gio/gapplication.c:503 msgid "Show GApplication options" msgstr "Показать параметры GApplication" -#: gio/gapplication.c:551 +#: gio/gapplication.c:548 msgid "Enter GApplication service mode (use from D-Bus service files)" msgstr "" "Запустить GApplication в режиме сервиса (использовать из сервисных файлов D-" "Bus)" -#: gio/gapplication.c:563 +#: gio/gapplication.c:560 msgid "Override the application’s ID" msgstr "Переопределить идентификатор приложения" -#: gio/gapplication.c:575 +#: gio/gapplication.c:572 msgid "Replace the running instance" msgstr "Заменить запущенный экземпляр" -#: gio/gapplication-tool.c:47 gio/gapplication-tool.c:48 gio/gio-tool.c:229 +#: gio/gapplication-tool.c:47 gio/gapplication-tool.c:48 gio/gio-tool.c:230 #: gio/gresource-tool.c:496 gio/gsettings-tool.c:586 msgid "Print help" msgstr "Напечатать справку" @@ -79,7 +79,7 @@ msgstr "Напечатать справку" msgid "[COMMAND]" msgstr "[КОМАНДА]" -#: gio/gapplication-tool.c:51 gio/gio-tool.c:230 +#: gio/gapplication-tool.c:51 gio/gio-tool.c:231 msgid "Print version" msgstr "Вывести номер верии" @@ -134,7 +134,7 @@ msgid "APPID" msgstr "ID_ПРИЛОЖЕНИЯ" #: gio/gapplication-tool.c:74 gio/gapplication-tool.c:137 gio/gdbus-tool.c:108 -#: gio/gio-tool.c:226 +#: gio/gio-tool.c:259 msgid "COMMAND" msgstr "КОМАНДА" @@ -193,7 +193,7 @@ msgstr "Использование:\n" msgid "Arguments:\n" msgstr "Аргументы:\n" -#: gio/gapplication-tool.c:137 gio/gio-tool.c:226 +#: gio/gapplication-tool.c:137 gio/gio-tool.c:259 msgid "[ARGS…]" msgstr "[АРГУМЕНТЫ…]" @@ -286,78 +286,78 @@ msgstr "" "нераспознанная команда %s\n" "\n" -#: gio/gbufferedinputstream.c:422 gio/gbufferedinputstream.c:500 +#: gio/gbufferedinputstream.c:418 gio/gbufferedinputstream.c:496 #: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:651 -#: gio/ginputstream.c:1056 gio/goutputstream.c:225 gio/goutputstream.c:1052 -#: gio/gpollableinputstream.c:221 gio/gpollableoutputstream.c:293 +#: gio/ginputstream.c:1056 gio/goutputstream.c:227 gio/goutputstream.c:1052 +#: gio/gpollableinputstream.c:217 gio/gpollableoutputstream.c:289 #, c-format msgid "Too large count value passed to %s" msgstr "Слишком большое значение количества передано в %s" -#: gio/gbufferedinputstream.c:893 gio/gbufferedoutputstream.c:577 -#: gio/gdataoutputstream.c:564 +#: gio/gbufferedinputstream.c:889 gio/gbufferedoutputstream.c:573 +#: gio/gdataoutputstream.c:559 msgid "Seek not supported on base stream" msgstr "Переход в базовом потоке не поддерживается" -#: gio/gbufferedinputstream.c:940 +#: gio/gbufferedinputstream.c:936 msgid "Cannot truncate GBufferedInputStream" msgstr "Нельзя усечь GBufferedInputStream" -#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1246 gio/giostream.c:302 +#: gio/gbufferedinputstream.c:981 gio/ginputstream.c:1246 gio/giostream.c:301 #: gio/goutputstream.c:2208 msgid "Stream is already closed" msgstr "Поток уже закрыт" -#: gio/gbufferedoutputstream.c:614 gio/gdataoutputstream.c:594 +#: gio/gbufferedoutputstream.c:610 gio/gdataoutputstream.c:589 msgid "Truncate not supported on base stream" msgstr "Усечение не поддерживается в базовом потоке" -#: gio/gcancellable.c:326 gio/gdbusconnection.c:1867 gio/gdbusprivate.c:1434 -#: gio/gsimpleasyncresult.c:873 gio/gsimpleasyncresult.c:899 +#: gio/gcancellable.c:326 gio/gdbusconnection.c:1862 gio/gdbusprivate.c:1432 +#: gio/gsimpleasyncresult.c:871 gio/gsimpleasyncresult.c:897 #, c-format msgid "Operation was cancelled" msgstr "Действие было отменено" -#: gio/gcharsetconverter.c:262 +#: gio/gcharsetconverter.c:255 msgid "Invalid object, not initialized" msgstr "Недопустимый объект, не инициализировано" -#: gio/gcharsetconverter.c:283 gio/gcharsetconverter.c:311 +#: gio/gcharsetconverter.c:276 gio/gcharsetconverter.c:304 msgid "Incomplete multibyte sequence in input" msgstr "Неполная многобайтовая последовательность во входных данных" -#: gio/gcharsetconverter.c:317 gio/gcharsetconverter.c:326 +#: gio/gcharsetconverter.c:310 gio/gcharsetconverter.c:319 msgid "Not enough space in destination" msgstr "Недостаточно места в целевом расположении" -#: gio/gcharsetconverter.c:344 gio/gdatainputstream.c:850 -#: gio/gdatainputstream.c:1268 glib/gconvert.c:450 glib/gconvert.c:882 -#: glib/giochannel.c:1576 glib/giochannel.c:1618 glib/giochannel.c:2478 +#: gio/gcharsetconverter.c:337 gio/gdatainputstream.c:846 +#: gio/gdatainputstream.c:1264 glib/gconvert.c:351 glib/gconvert.c:783 +#: glib/giochannel.c:1565 glib/giochannel.c:1607 glib/giochannel.c:2467 #: glib/gutf8.c:958 glib/gutf8.c:1412 msgid "Invalid byte sequence in conversion input" msgstr "Недопустимая последовательность байтов во входных преобразуемых данных" -#: gio/gcharsetconverter.c:349 glib/gconvert.c:458 glib/gconvert.c:796 -#: glib/giochannel.c:1583 glib/giochannel.c:2493 +#: gio/gcharsetconverter.c:342 glib/gconvert.c:359 glib/gconvert.c:697 +#: glib/giochannel.c:1572 glib/giochannel.c:2482 #, c-format msgid "Error during conversion: %s" msgstr "Произошла ошибка при преобразовании: %s" -#: gio/gcharsetconverter.c:447 gio/gsocket.c:1164 +#: gio/gcharsetconverter.c:440 gio/gsocket.c:1162 msgid "Cancellable initialization not supported" msgstr "Прерываемая инициализация не поддерживается" -#: gio/gcharsetconverter.c:458 glib/gconvert.c:323 glib/giochannel.c:1404 +#: gio/gcharsetconverter.c:451 glib/gconvert.c:224 glib/giochannel.c:1393 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported" msgstr "Преобразование из набора символов «%s» в «%s» не поддерживается" -#: gio/gcharsetconverter.c:462 glib/gconvert.c:327 +#: gio/gcharsetconverter.c:455 glib/gconvert.c:228 #, c-format msgid "Could not open converter from “%s” to “%s”" msgstr "Не удалось открыть преобразователь из «%s» в «%s»" -#: gio/gcontenttype.c:472 +#: gio/gcontenttype.c:470 #, c-format msgid "%s type" msgstr "Тип %s" @@ -371,41 +371,41 @@ msgstr "Неизвестный тип" msgid "%s filetype" msgstr "Тип файлов %s" -#: gio/gcredentials.c:337 +#: gio/gcredentials.c:327 msgid "GCredentials contains invalid data" msgstr "Объект GCredentials содержит некорректные данные" -#: gio/gcredentials.c:397 gio/gcredentials.c:688 +#: gio/gcredentials.c:387 gio/gcredentials.c:678 msgid "GCredentials is not implemented on this OS" msgstr "Тип GCredentials не реализован для этой ОС" -#: gio/gcredentials.c:552 gio/gcredentials.c:570 +#: gio/gcredentials.c:542 gio/gcredentials.c:560 msgid "There is no GCredentials support for your platform" msgstr "Поддержка GCredentials для вашей платформы отсутствует" -#: gio/gcredentials.c:628 +#: gio/gcredentials.c:618 msgid "GCredentials does not contain a process ID on this OS" msgstr "Тип GCredentials не содержит идентификатора процесса для этой ОС" -#: gio/gcredentials.c:682 +#: gio/gcredentials.c:672 msgid "Credentials spoofing is not possible on this OS" msgstr "Спуфинг учётных данных невозможен в этой ОС" -#: gio/gdatainputstream.c:306 +#: gio/gdatainputstream.c:302 msgid "Unexpected early end-of-stream" msgstr "Неожиданный ранний конец потока" -#: gio/gdbusaddress.c:168 gio/gdbusaddress.c:240 gio/gdbusaddress.c:327 +#: gio/gdbusaddress.c:165 gio/gdbusaddress.c:237 gio/gdbusaddress.c:324 #, c-format msgid "Unsupported key “%s” in address entry “%s”" msgstr "Неподдерживаемый ключ «%s» в элементе адреса «%s»" -#: gio/gdbusaddress.c:181 +#: gio/gdbusaddress.c:178 #, c-format msgid "Meaningless key/value pair combination in address entry “%s”" msgstr "Бессмысленная комбинация ключ/значение в элементе адреса «%s»" -#: gio/gdbusaddress.c:190 +#: gio/gdbusaddress.c:187 #, c-format msgid "" "Address “%s” is invalid (need exactly one of path, dir, tmpdir, or abstract " @@ -414,28 +414,28 @@ msgstr "" "Неправильный адрес «%s» (требуется путь, временный каталог или один из " "абстрактных ключей)" -#: gio/gdbusaddress.c:255 gio/gdbusaddress.c:266 gio/gdbusaddress.c:281 -#: gio/gdbusaddress.c:342 gio/gdbusaddress.c:353 +#: gio/gdbusaddress.c:252 gio/gdbusaddress.c:263 gio/gdbusaddress.c:278 +#: gio/gdbusaddress.c:339 gio/gdbusaddress.c:350 #, c-format msgid "Error in address “%s” — the “%s” attribute is malformed" msgstr "Ошибка в адресе «%s» — неправильный формат атрибута «%s»" -#: gio/gdbusaddress.c:423 gio/gdbusaddress.c:682 +#: gio/gdbusaddress.c:420 gio/gdbusaddress.c:679 #, c-format msgid "Unknown or unsupported transport “%s” for address “%s”" msgstr "Неизвестный или неподдерживаемый транспорт «%s» для адреса «%s»" -#: gio/gdbusaddress.c:467 +#: gio/gdbusaddress.c:464 #, c-format msgid "Address element “%s” does not contain a colon (:)" msgstr "В элементе адреса «%s» отсутствует двоеточие (:)" -#: gio/gdbusaddress.c:476 +#: gio/gdbusaddress.c:473 #, c-format msgid "Transport name in address element “%s” must not be empty" msgstr "Название протокола в элементе адреса “%s” не должен быть пустым" -#: gio/gdbusaddress.c:497 +#: gio/gdbusaddress.c:494 #, c-format msgid "" "Key/Value pair %d, “%s”, in address element “%s” does not contain an equal " @@ -444,7 +444,7 @@ msgstr "" "Пара ключ/значение %d, «%s», в элементе адреса «%s» не содержит знака " "равенства" -#: gio/gdbusaddress.c:508 +#: gio/gdbusaddress.c:505 #, c-format msgid "" "Key/Value pair %d, “%s”, in address element “%s” must not have an empty key" @@ -452,7 +452,7 @@ msgstr "" "Пара ключ/значение %d, «%s», в элементе адреса «%s» не должна иметь пустого " "ключа" -#: gio/gdbusaddress.c:522 +#: gio/gdbusaddress.c:519 #, c-format msgid "" "Error unescaping key or value in Key/Value pair %d, “%s”, in address element " @@ -461,7 +461,7 @@ msgstr "" "Ошибка снятия экранирования ключа или значения в паре ключ/значение %d, " "«%s», в элементе адреса «%s»" -#: gio/gdbusaddress.c:590 +#: gio/gdbusaddress.c:587 #, c-format msgid "" "Error in address “%s” — the unix transport requires exactly one of the keys " @@ -470,82 +470,82 @@ msgstr "" "Ошибка в адресе «%s» — для транспорта unix требуется только один " "установленный ключ «path» или «abstract»" -#: gio/gdbusaddress.c:625 +#: gio/gdbusaddress.c:622 #, c-format msgid "Error in address “%s” — the host attribute is missing or malformed" msgstr "" "Ошибка в адресе «%s» — атрибут узла отсутствует или имеет неправильный формат" -#: gio/gdbusaddress.c:639 +#: gio/gdbusaddress.c:636 #, c-format msgid "Error in address “%s” — the port attribute is missing or malformed" msgstr "" "Ошибка в адресе «%s» — атрибут порта отсутствует или имеет неправильный " "формат" -#: gio/gdbusaddress.c:653 +#: gio/gdbusaddress.c:650 #, c-format msgid "Error in address “%s” — the noncefile attribute is missing or malformed" msgstr "" "Ошибка в адресе «%s» — атрибут noncefile отсутствует или имеет неправильный " "формат" -#: gio/gdbusaddress.c:674 +#: gio/gdbusaddress.c:671 msgid "Error auto-launching: " msgstr "Ошибка автоматического запуска: " -#: gio/gdbusaddress.c:727 +#: gio/gdbusaddress.c:724 #, c-format msgid "Error opening nonce file “%s”: %s" msgstr "Произошла ошибка при открытии nonce-файла «%s»: %s" -#: gio/gdbusaddress.c:746 +#: gio/gdbusaddress.c:743 #, c-format msgid "Error reading from nonce file “%s”: %s" msgstr "Произошла ошибка при чтении nonce-файла «%s»: %s" -#: gio/gdbusaddress.c:755 +#: gio/gdbusaddress.c:752 #, c-format msgid "Error reading from nonce file “%s”, expected 16 bytes, got %d" msgstr "" "Произошла ошибка при чтении nonce-файла «%s», ожидалось 16 байт, получено %d" -#: gio/gdbusaddress.c:773 +#: gio/gdbusaddress.c:770 #, c-format msgid "Error writing contents of nonce file “%s” to stream:" msgstr "Произошла ошибка записи содержимого nonce-файла «%s» в поток:" -#: gio/gdbusaddress.c:988 +#: gio/gdbusaddress.c:985 msgid "The given address is empty" msgstr "Указанный адрес пуст" -#: gio/gdbusaddress.c:1101 +#: gio/gdbusaddress.c:1098 #, c-format msgid "Cannot spawn a message bus when AT_SECURE is set" msgstr "" "Невозможно создать шину сообщений, когда установлено значение AT_SECURE" -#: gio/gdbusaddress.c:1108 +#: gio/gdbusaddress.c:1105 msgid "Cannot spawn a message bus without a machine-id: " msgstr "Невозможно породить процесс шины сообщений без идентификатора машины: " -#: gio/gdbusaddress.c:1115 +#: gio/gdbusaddress.c:1112 #, c-format msgid "Cannot autolaunch D-Bus without X11 $DISPLAY" msgstr "Невозможно автоматически запустить D-Bus без X11 $DISPLAY" -#: gio/gdbusaddress.c:1157 +#: gio/gdbusaddress.c:1154 #, c-format msgid "Error spawning command line “%s”: " msgstr "Произошла ошибка при создании процесса командной строки «%s»: " -#: gio/gdbusaddress.c:1226 +#: gio/gdbusaddress.c:1223 #, c-format msgid "Cannot determine session bus address (not implemented for this OS)" msgstr "" "Не удалось определить адрес сеансовой шины (не реализовано для этой ОС)" -#: gio/gdbusaddress.c:1380 gio/gdbusconnection.c:7339 +#: gio/gdbusaddress.c:1377 gio/gdbusconnection.c:7334 #, c-format msgid "" "Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable " @@ -554,7 +554,7 @@ msgstr "" "Не удалось определить адрес шины из значения переменной окружения " "DBUS_STARTER_BUS_TYPE — неизвестное значение «%s»" -#: gio/gdbusaddress.c:1389 gio/gdbusconnection.c:7348 +#: gio/gdbusaddress.c:1386 gio/gdbusconnection.c:7343 msgid "" "Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment " "variable is not set" @@ -562,7 +562,7 @@ msgstr "" "Не удалось определить адрес шины, т. к. значение переменной окружения " "DBUS_STARTER_BUS_TYPE не установлено" -#: gio/gdbusaddress.c:1399 +#: gio/gdbusaddress.c:1396 #, c-format msgid "Unknown bus type %d" msgstr "Неизвестный тип шины %d" @@ -611,13 +611,13 @@ msgstr "Ошибочные права на каталог «%s». Ожидало msgid "Error creating directory “%s”: %s" msgstr "Произошла ошибка при создании каталога «%s»: %s" -#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1102 gio/gfile.c:1340 -#: gio/gfile.c:1478 gio/gfile.c:1716 gio/gfile.c:1771 gio/gfile.c:1829 -#: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 -#: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 -#: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:9000 gio/gfile.c:9090 -#: gio/gfile.c:9174 gio/win32/gwinhttpfile.c:453 +#: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1105 gio/gfile.c:1343 +#: gio/gfile.c:1481 gio/gfile.c:1718 gio/gfile.c:1773 gio/gfile.c:1831 +#: gio/gfile.c:1915 gio/gfile.c:1972 gio/gfile.c:2036 gio/gfile.c:2091 +#: gio/gfile.c:3955 gio/gfile.c:4094 gio/gfile.c:4501 gio/gfile.c:4966 +#: gio/gfile.c:5378 gio/gfile.c:5463 gio/gfile.c:5553 gio/gfile.c:5650 +#: gio/gfile.c:5737 gio/gfile.c:5836 gio/gfile.c:8990 gio/gfile.c:9080 +#: gio/gfile.c:9164 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "Действие не поддерживается" @@ -682,133 +682,133 @@ msgstr "Произошла ошибка при открытии связки к msgid "(Additionally, releasing the lock for “%s” also failed: %s) " msgstr "(Также, не удалось освободить блокировку для «%s»: %s) " -#: gio/gdbusconnection.c:590 gio/gdbusconnection.c:2415 +#: gio/gdbusconnection.c:585 gio/gdbusconnection.c:2410 msgid "The connection is closed" msgstr "Соединение закрыто" -#: gio/gdbusconnection.c:1899 +#: gio/gdbusconnection.c:1894 msgid "Timeout was reached" msgstr "Время ожидания истекло" -#: gio/gdbusconnection.c:2538 +#: gio/gdbusconnection.c:2533 msgid "" "Unsupported flags encountered when constructing a client-side connection" msgstr "При создании клиентского соединения обнаружены неподдерживаемые флаги" -#: gio/gdbusconnection.c:4277 gio/gdbusconnection.c:4631 +#: gio/gdbusconnection.c:4272 gio/gdbusconnection.c:4626 #, c-format msgid "" "No such interface “org.freedesktop.DBus.Properties” on object at path %s" msgstr "" "Интерфейс «org.freedesktop.DBus.Properties» для пути %s объекта не найден" -#: gio/gdbusconnection.c:4422 +#: gio/gdbusconnection.c:4417 #, c-format msgid "No such property “%s”" msgstr "Свойство «%s» отсутствует" -#: gio/gdbusconnection.c:4434 +#: gio/gdbusconnection.c:4429 #, c-format msgid "Property “%s” is not readable" msgstr "Свойство «%s» недоступно для чтения" -#: gio/gdbusconnection.c:4445 +#: gio/gdbusconnection.c:4440 #, c-format msgid "Property “%s” is not writable" msgstr "Свойство «%s» недоступно для записи" -#: gio/gdbusconnection.c:4465 +#: gio/gdbusconnection.c:4460 #, c-format msgid "Error setting property “%s”: Expected type “%s” but got “%s”" msgstr "Ошибка установки свойства «%s»: ожидался тип «%s», но получен «%s»" -#: gio/gdbusconnection.c:4570 gio/gdbusconnection.c:4785 -#: gio/gdbusconnection.c:6762 +#: gio/gdbusconnection.c:4565 gio/gdbusconnection.c:4780 +#: gio/gdbusconnection.c:6757 #, c-format msgid "No such interface “%s”" msgstr "Интерфейс «%s» отсутствует" -#: gio/gdbusconnection.c:5001 gio/gdbusconnection.c:7279 +#: gio/gdbusconnection.c:4996 gio/gdbusconnection.c:7274 #, c-format msgid "No such interface “%s” on object at path %s" msgstr "Интерфейс «%s» для пути %s объекта не найден" -#: gio/gdbusconnection.c:5102 +#: gio/gdbusconnection.c:5097 #, c-format msgid "No such method “%s”" msgstr "Ключ «%s» отсутствует" -#: gio/gdbusconnection.c:5133 +#: gio/gdbusconnection.c:5128 #, c-format msgid "Type of message, “%s”, does not match expected type “%s”" msgstr "Тип сообщения «%s» не совпадает с ожидаемым типом «%s»" -#: gio/gdbusconnection.c:5336 +#: gio/gdbusconnection.c:5331 #, c-format msgid "An object is already exported for the interface %s at %s" msgstr "Объект интерфейса %s уже экспортирован как %s" -#: gio/gdbusconnection.c:5563 +#: gio/gdbusconnection.c:5558 #, c-format msgid "Unable to retrieve property %s.%s" msgstr "Невозможно получить свойство %s.%s" -#: gio/gdbusconnection.c:5619 +#: gio/gdbusconnection.c:5614 #, c-format msgid "Unable to set property %s.%s" msgstr "Невозможно установить свойство %s.%s" -#: gio/gdbusconnection.c:5798 +#: gio/gdbusconnection.c:5793 #, c-format msgid "Method “%s” returned type “%s”, but expected “%s”" msgstr "Метод «%s» вернул тип «%s», но ожидалось «%s»" -#: gio/gdbusconnection.c:6874 +#: gio/gdbusconnection.c:6869 #, c-format msgid "Method “%s” on interface “%s” with signature “%s” does not exist" msgstr "Метод «%s» интерфейса «%s» с сигнатурой «%s» не существует" -#: gio/gdbusconnection.c:6995 +#: gio/gdbusconnection.c:6990 #, c-format msgid "A subtree is already exported for %s" msgstr "Поддерево уже экспортировано для %s" -#: gio/gdbusconnection.c:7287 +#: gio/gdbusconnection.c:7282 #, c-format msgid "Object does not exist at path “%s”" msgstr "Объект по пути «%s» не существует" -#: gio/gdbusmessage.c:1306 +#: gio/gdbusmessage.c:1296 msgid "type is INVALID" msgstr "тип является НЕДОПУСТИМЫМ" -#: gio/gdbusmessage.c:1324 +#: gio/gdbusmessage.c:1314 msgid "METHOD_CALL message: PATH or MEMBER header field is missing or invalid" msgstr "" "Сообщение METHOD_CALL: отсутствует или недопустимо поле заголовка PATH или " "MEMBER" -#: gio/gdbusmessage.c:1340 +#: gio/gdbusmessage.c:1330 msgid "METHOD_RETURN message: REPLY_SERIAL header field is missing or invalid" msgstr "" "Сообщение METHOD_RETURN: отсутствует или недопустимо поле заголовка " "REPLY_SERIAL" -#: gio/gdbusmessage.c:1360 +#: gio/gdbusmessage.c:1350 msgid "" "ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing or invalid" msgstr "" "Сообщение ERROR: отсутствует или недопустимо поле заголовка REPLY_SERIAL или " "ERROR_NAME" -#: gio/gdbusmessage.c:1384 +#: gio/gdbusmessage.c:1374 msgid "" "SIGNAL message: PATH, INTERFACE or MEMBER header field is missing or invalid" msgstr "" "Сообщение SIGNAL: отсутствует или недопустимо поле заголовка PATH, INTERFACE " "или MEMBER" -#: gio/gdbusmessage.c:1392 +#: gio/gdbusmessage.c:1382 msgid "" "SIGNAL message: The PATH header field is using the reserved value /org/" "freedesktop/DBus/Local" @@ -816,7 +816,7 @@ msgstr "" "Сообщение SIGNAL: поле заголовка PATH использует зарезервированное значение /" "org/freedesktop/DBus/Local" -#: gio/gdbusmessage.c:1400 +#: gio/gdbusmessage.c:1390 msgid "" "SIGNAL message: The INTERFACE header field is using the reserved value org." "freedesktop.DBus.Local" @@ -824,7 +824,7 @@ msgstr "" "Сообщение SIGNAL: поле заголовка INTERFACE использует зарезервированное " "значение org.freedesktop.DBus.Local" -#: gio/gdbusmessage.c:1449 gio/gdbusmessage.c:1509 +#: gio/gdbusmessage.c:1439 gio/gdbusmessage.c:1499 #, c-format msgid "Wanted to read %lu byte but only got %lu" msgid_plural "Wanted to read %lu bytes but only got %lu" @@ -832,12 +832,12 @@ msgstr[0] "Требовалось прочитать %lu байт, но проч msgstr[1] "Требовалось прочитать %lu байта, но прочитано только %lu" msgstr[2] "Требовалось прочитать %lu байт, но прочитано только %lu" -#: gio/gdbusmessage.c:1463 +#: gio/gdbusmessage.c:1453 #, c-format msgid "Expected NUL byte after the string “%s” but found byte %d" msgstr "Ожидался байт NUL после строки «%s», но найден байт %d" -#: gio/gdbusmessage.c:1482 +#: gio/gdbusmessage.c:1472 #, c-format msgid "" "Expected valid UTF-8 string but found invalid bytes at byte offset %d " @@ -847,21 +847,21 @@ msgstr "" "(смещение %d, длина строки %d). Корректная строка UTF-8 вплоть до тех байт: " "«%s»" -#: gio/gdbusmessage.c:1546 gio/gdbusmessage.c:1822 gio/gdbusmessage.c:2033 +#: gio/gdbusmessage.c:1536 gio/gdbusmessage.c:1812 gio/gdbusmessage.c:2023 msgid "Value nested too deeply" msgstr "Слишком глубокая иерархия" -#: gio/gdbusmessage.c:1714 +#: gio/gdbusmessage.c:1704 #, c-format msgid "Parsed value “%s” is not a valid D-Bus object path" msgstr "Разобранное значение «%s» не является допустимым путём объекта D-Bus" -#: gio/gdbusmessage.c:1738 +#: gio/gdbusmessage.c:1728 #, c-format msgid "Parsed value “%s” is not a valid D-Bus signature" msgstr "Разобранное значение «%s» не является допустимой подписью D-Bus" -#: gio/gdbusmessage.c:1789 +#: gio/gdbusmessage.c:1779 #, c-format msgid "" "Encountered array of length %u byte. Maximum length is 2<<26 bytes (64 MiB)." @@ -877,7 +877,7 @@ msgstr[2] "" "Обнаружен массив длинной %u байт. Максимальная длина равна 2<<26 байт (64 " "МиБ)." -#: gio/gdbusmessage.c:1809 +#: gio/gdbusmessage.c:1799 #, c-format msgid "" "Encountered array of type “a%c”, expected to have a length a multiple of %u " @@ -886,24 +886,24 @@ msgstr "" "Получен массив типа «a%c», который должен иметь размер кратный %u (байт), но " "массив имеет длину %u (байт)" -#: gio/gdbusmessage.c:1963 gio/gdbusmessage.c:2682 +#: gio/gdbusmessage.c:1953 gio/gdbusmessage.c:2672 msgid "Empty structures (tuples) are not allowed in D-Bus" msgstr "Пустые структуры (записи) не допускаются в D-Bus" -#: gio/gdbusmessage.c:2017 +#: gio/gdbusmessage.c:2007 #, c-format msgid "Parsed value “%s” for variant is not a valid D-Bus signature" msgstr "" "Разобранное значение «%s» для варианта не является допустимой подписью D-Bus" -#: gio/gdbusmessage.c:2058 +#: gio/gdbusmessage.c:2048 #, c-format msgid "" "Error deserializing GVariant with type string “%s” from the D-Bus wire format" msgstr "" "Ошибка десериализации GVariant с типом строки «%s» из формата D-Bus wire" -#: gio/gdbusmessage.c:2243 +#: gio/gdbusmessage.c:2233 #, c-format msgid "" "Invalid endianness value. Expected 0x6c (“l”) or 0x42 (“B”) but found value " @@ -912,27 +912,27 @@ msgstr "" "Неправильный порядок байтов в значении. Ожидался 0x6c ('l') или 0x42 ('B'), " "но найдено значение 0x%02x" -#: gio/gdbusmessage.c:2262 +#: gio/gdbusmessage.c:2252 #, c-format msgid "Invalid major protocol version. Expected 1 but found %d" msgstr "Неправильный старший номер версии протокола. Ожидался 1, но найден %d" -#: gio/gdbusmessage.c:2320 gio/gdbusmessage.c:2918 +#: gio/gdbusmessage.c:2310 gio/gdbusmessage.c:2908 msgid "Signature header found but is not of type signature" msgstr "Заголовок подписи найден, но его тип отличается от подписи" -#: gio/gdbusmessage.c:2332 +#: gio/gdbusmessage.c:2322 #, c-format msgid "Signature header with signature “%s” found but message body is empty" msgstr "Найден заголовок подписи с подписью «%s», но тело сообщения пусто" -#: gio/gdbusmessage.c:2347 +#: gio/gdbusmessage.c:2337 #, c-format msgid "Parsed value “%s” is not a valid D-Bus signature (for body)" msgstr "" "Разобранное значение «%s» не является допустимой подписью D-Bus (для тела)" -#: gio/gdbusmessage.c:2379 +#: gio/gdbusmessage.c:2369 #, c-format msgid "No signature header in message but the message body is %u byte" msgid_plural "No signature header in message but the message body is %u bytes" @@ -944,17 +944,17 @@ msgstr[1] "" msgstr[2] "" "Отсутствует заголовок подписи в сообщении, но тело сообщения занимает %u байт" -#: gio/gdbusmessage.c:2389 +#: gio/gdbusmessage.c:2379 msgid "Cannot deserialize message: " msgstr "Не удалось выполнить извлечение сообщения: " -#: gio/gdbusmessage.c:2735 +#: gio/gdbusmessage.c:2725 #, c-format msgid "" "Error serializing GVariant with type string “%s” to the D-Bus wire format" msgstr "Ошибка сериализации GVariant с типом строки «%s» в формат D-Bus wire" -#: gio/gdbusmessage.c:2872 +#: gio/gdbusmessage.c:2862 #, c-format msgid "" "Number of file descriptors in message (%d) differs from header field (%d)" @@ -962,16 +962,16 @@ msgstr "" "Количество дескрипторов файлов в сообщении (%d) отличается от указанного в " "заголовке (%d)" -#: gio/gdbusmessage.c:2880 +#: gio/gdbusmessage.c:2870 msgid "Cannot serialize message: " msgstr "Не удалось сериализовать сообщение: " -#: gio/gdbusmessage.c:2933 +#: gio/gdbusmessage.c:2923 #, c-format msgid "Message body has signature “%s” but there is no signature header" msgstr "Тело сообщения имеет подпись «%s», но нет заголовка подписи" -#: gio/gdbusmessage.c:2943 +#: gio/gdbusmessage.c:2933 #, c-format msgid "" "Message body has type signature “%s” but signature in the header field is " @@ -980,53 +980,53 @@ msgstr "" "Тело сообщения имеет тип подписи «%s», но значение подписи в поле заголовка " "равно «%s»" -#: gio/gdbusmessage.c:2959 +#: gio/gdbusmessage.c:2949 #, c-format msgid "Message body is empty but signature in the header field is “(%s)”" msgstr "" "Тело сообщения пусто, но значение подписи в поле заголовка равно «(%s)»" -#: gio/gdbusmessage.c:3514 +#: gio/gdbusmessage.c:3504 #, c-format msgid "Error return with body of type “%s”" msgstr "Возвращена ошибка с телом типа «%s»" -#: gio/gdbusmessage.c:3522 +#: gio/gdbusmessage.c:3512 msgid "Error return with empty body" msgstr "Возвращена ошибка с пустым телом" -#: gio/gdbusprivate.c:2201 +#: gio/gdbusprivate.c:2199 #, c-format msgid "(Type any character to close this window)\n" msgstr "(Чтобы закрыть это окно, введите любой символ)\n" -#: gio/gdbusprivate.c:2387 +#: gio/gdbusprivate.c:2385 #, c-format msgid "Session dbus not running, and autolaunch failed" msgstr "Сеанс dbus не запущен, и автозапуск не выполнился" -#: gio/gdbusprivate.c:2410 +#: gio/gdbusprivate.c:2408 #, c-format msgid "Unable to get Hardware profile: %s" msgstr "Не удалось получить профиль аппаратуры: %s" #. Translators: Both placeholders are file paths -#: gio/gdbusprivate.c:2461 +#: gio/gdbusprivate.c:2464 #, c-format msgid "Unable to load %s or %s: " msgstr "Не удалось загрузить %s или %s: " -#: gio/gdbusproxy.c:1568 +#: gio/gdbusproxy.c:1570 #, c-format msgid "Error calling StartServiceByName for %s: " msgstr "Ошибка вызова StartServiceByName для %s: " -#: gio/gdbusproxy.c:1591 +#: gio/gdbusproxy.c:1593 #, c-format msgid "Unexpected reply %d from StartServiceByName(\"%s\") method" msgstr "Неожиданный ответ %d из метода StartServiceByName(«%s»)" -#: gio/gdbusproxy.c:2702 gio/gdbusproxy.c:2837 +#: gio/gdbusproxy.c:2704 gio/gdbusproxy.c:2839 #, c-format msgid "" "Cannot invoke method; proxy is for the well-known name %s without an owner, " @@ -1035,25 +1035,25 @@ msgstr "" "Не удалось вызвать метод; у прокси с хорошо известным именем %s нет " "владельца и прокси создать с флагом G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START" -#: gio/gdbusserver.c:758 +#: gio/gdbusserver.c:751 msgid "Abstract namespace not supported" msgstr "Абстрактное пространство имён не поддерживается" -#: gio/gdbusserver.c:850 +#: gio/gdbusserver.c:843 msgid "Cannot specify nonce file when creating a server" msgstr "Не удалось задать nonce-файл при создании сервера" -#: gio/gdbusserver.c:932 +#: gio/gdbusserver.c:925 #, c-format msgid "Error writing nonce file at “%s”: %s" msgstr "Произошла ошибка при записи в nonce-файл у «%s»: %s" -#: gio/gdbusserver.c:1107 +#: gio/gdbusserver.c:1100 #, c-format msgid "The string “%s” is not a valid D-Bus GUID" msgstr "Строка «%s» не является допустимым D-Bus GUID" -#: gio/gdbusserver.c:1145 +#: gio/gdbusserver.c:1138 #, c-format msgid "Cannot listen on unsupported transport “%s”" msgstr "Невозможно прослушивать неподдерживаемый транспорт «%s»" @@ -1345,71 +1345,71 @@ msgstr "Ошибка: %s не является допустимым извест msgid "Not authorized to change debug settings" msgstr "Не вправе изменять настройки отладки" -#: gio/gdesktopappinfo.c:2242 gio/gdesktopappinfo.c:5226 +#: gio/gdesktopappinfo.c:2235 gio/gdesktopappinfo.c:5219 msgid "Unnamed" msgstr "Без имени" -#: gio/gdesktopappinfo.c:2652 +#: gio/gdesktopappinfo.c:2645 msgid "Desktop file didn’t specify Exec field" msgstr "В desktop-файле не указано поле Exec" -#: gio/gdesktopappinfo.c:2942 +#: gio/gdesktopappinfo.c:2935 msgid "Unable to find terminal required for application" msgstr "Не удалось найти терминал, требуемый для приложения" -#: gio/gdesktopappinfo.c:3002 +#: gio/gdesktopappinfo.c:2995 #, c-format msgid "Program ‘%s’ not found in $PATH" msgstr "Программа '%s' не найдена в $PATH" -#: gio/gdesktopappinfo.c:3738 +#: gio/gdesktopappinfo.c:3731 #, c-format msgid "Can’t create user application configuration folder %s: %s" msgstr "Не удалось создать пользовательскую папку настроек приложения %s: %s" -#: gio/gdesktopappinfo.c:3742 +#: gio/gdesktopappinfo.c:3735 #, c-format msgid "Can’t create user MIME configuration folder %s: %s" msgstr "Не удалось создать пользовательскую папку настроек MIME %s: %s" -#: gio/gdesktopappinfo.c:3984 gio/gdesktopappinfo.c:4008 +#: gio/gdesktopappinfo.c:3977 gio/gdesktopappinfo.c:4001 msgid "Application information lacks an identifier" msgstr "В информации о приложении отсутствует идентификатор" -#: gio/gdesktopappinfo.c:4244 +#: gio/gdesktopappinfo.c:4237 #, c-format msgid "Can’t create user desktop file %s" msgstr "Не удалось создать пользовательский desktop-файл %s" -#: gio/gdesktopappinfo.c:4380 +#: gio/gdesktopappinfo.c:4373 #, c-format msgid "Custom definition for %s" msgstr "Особое определение для %s" -#: gio/gdrive.c:419 +#: gio/gdrive.c:417 msgid "drive doesn’t implement eject" msgstr "привод не поддерживает извлечение" #. Translators: This is an error #. * message for drive objects that #. * don't implement any of eject or eject_with_operation. -#: gio/gdrive.c:497 +#: gio/gdrive.c:495 msgid "drive doesn’t implement eject or eject_with_operation" msgstr "привод не поддерживает извлечение или извлечение_с_операцией" -#: gio/gdrive.c:573 +#: gio/gdrive.c:571 msgid "drive doesn’t implement polling for media" msgstr "привод не поддерживает опрос носителя" -#: gio/gdrive.c:780 +#: gio/gdrive.c:778 msgid "drive doesn’t implement start" msgstr "привод не поддерживает запуск" -#: gio/gdrive.c:882 +#: gio/gdrive.c:880 msgid "drive doesn’t implement stop" msgstr "привод не поддерживает остановку" -#: gio/gdtlsconnection.c:1188 gio/gtlsconnection.c:957 +#: gio/gdtlsconnection.c:1178 gio/gtlsconnection.c:947 msgid "TLS backend does not implement TLS binding retrieval" msgstr "Библиотека TLS не реализует запрос на TLS binding" @@ -1422,27 +1422,27 @@ msgstr "Поддержка TLS недоступна" msgid "DTLS support is not available" msgstr "Поддержка DTLS недоступна" -#: gio/gemblem.c:325 +#: gio/gemblem.c:322 #, c-format msgid "Can’t handle version %d of GEmblem encoding" msgstr "Не удалось обработать версию %d текстового представления GEmblem" -#: gio/gemblem.c:335 +#: gio/gemblem.c:332 #, c-format msgid "Malformed number of tokens (%d) in GEmblem encoding" msgstr "Некорректное число лексем (%d) текстового представления GEmblem" -#: gio/gemblemedicon.c:364 +#: gio/gemblemedicon.c:361 #, c-format msgid "Can’t handle version %d of GEmblemedIcon encoding" msgstr "Не удалось обработать версию %d текстового представления GEmblemedIcon" -#: gio/gemblemedicon.c:374 +#: gio/gemblemedicon.c:371 #, c-format msgid "Malformed number of tokens (%d) in GEmblemedIcon encoding" msgstr "Некорректное число лексем (%d) текстового представления GEmblemedIcon" -#: gio/gemblemedicon.c:397 +#: gio/gemblemedicon.c:394 msgid "Expected a GEmblem for GEmblemedIcon" msgstr "Для GEmblemedIcon ожидается GEmblem" @@ -1450,130 +1450,130 @@ msgstr "Для GEmblemedIcon ожидается GEmblem" #. * trying to find the enclosing (user visible) #. * mount of a file, but none exists. #. -#: gio/gfile.c:1601 +#: gio/gfile.c:1604 msgid "Containing mount does not exist" msgstr "Содержащая точка монтирования не существует" -#: gio/gfile.c:2648 gio/glocalfile.c:2518 +#: gio/gfile.c:2650 gio/glocalfile.c:2518 msgid "Can’t copy over directory" msgstr "Нельзя скопировать поверх каталога" -#: gio/gfile.c:2708 +#: gio/gfile.c:2710 msgid "Can’t copy directory over directory" msgstr "Нельзя скопировать каталог поверх каталога" -#: gio/gfile.c:2716 +#: gio/gfile.c:2718 msgid "Target file exists" msgstr "Целевой файл существует" -#: gio/gfile.c:2735 +#: gio/gfile.c:2737 msgid "Can’t recursively copy directory" msgstr "Не удалось рекурсивно скопировать каталог" -#: gio/gfile.c:3044 gio/gfile.c:3092 +#: gio/gfile.c:3050 gio/gfile.c:3098 #, c-format msgid "Copy file range not supported" msgstr "Диапазон копируемых файлов не поддерживается" -#: gio/gfile.c:3050 gio/gfile.c:3161 +#: gio/gfile.c:3056 gio/gfile.c:3167 #, c-format msgid "Error splicing file: %s" msgstr "Произошла ошибка при соединении файла: %s" -#: gio/gfile.c:3157 +#: gio/gfile.c:3163 msgid "Splice not supported" msgstr "Соединение не поддерживается" -#: gio/gfile.c:3321 +#: gio/gfile.c:3327 msgid "Copy (reflink/clone) between mounts is not supported" msgstr "" "Копирование (reflink/clone) между точками монтирования не поддерживается" -#: gio/gfile.c:3325 +#: gio/gfile.c:3331 msgid "Copy (reflink/clone) is not supported or invalid" msgstr "Копирование (reflink/clone) не поддерживается или некорректно" -#: gio/gfile.c:3330 +#: gio/gfile.c:3336 msgid "Copy (reflink/clone) is not supported or didn’t work" msgstr "Копирование (reflink/clone) не поддерживается или не работает" -#: gio/gfile.c:3395 +#: gio/gfile.c:3401 msgid "Can’t copy special file" msgstr "Нельзя скопировать специальный файл" -#: gio/gfile.c:4314 +#: gio/gfile.c:4318 msgid "Invalid symlink value given" msgstr "Дано неверное значение символьной ссылки" -#: gio/gfile.c:4324 glib/gfileutils.c:2392 +#: gio/gfile.c:4328 glib/gfileutils.c:2436 msgid "Symbolic links not supported" msgstr "Символьные ссылки не поддерживаются" -#: gio/gfile.c:4611 +#: gio/gfile.c:4609 msgid "Trash not supported" msgstr "Корзина не поддерживается" -#: gio/gfile.c:4723 +#: gio/gfile.c:4719 #, c-format msgid "File names cannot contain “%c”" msgstr "Имена файлов не могут содержать «%c»" -#: gio/gfile.c:7155 gio/gfile.c:7281 +#: gio/gfile.c:7145 gio/gfile.c:7271 #, c-format msgid "Failed to create a temporary directory for template “%s”: %s" msgstr "Не удалось создать временный каталог для шаблона \"%s\": %s" -#: gio/gfile.c:7599 gio/gvolume.c:366 +#: gio/gfile.c:7589 gio/gvolume.c:362 msgid "volume doesn’t implement mount" msgstr "том не поддерживает присоединение" -#: gio/gfile.c:7713 gio/gfile.c:7790 +#: gio/gfile.c:7703 gio/gfile.c:7780 msgid "No application is registered as handling this file" msgstr "Нет зарегистрированного приложения для обработки данного файла" -#: gio/gfileenumerator.c:214 +#: gio/gfileenumerator.c:212 msgid "Enumerator is closed" msgstr "Перечислитель закрыт" -#: gio/gfileenumerator.c:221 gio/gfileenumerator.c:280 -#: gio/gfileenumerator.c:425 gio/gfileenumerator.c:525 +#: gio/gfileenumerator.c:219 gio/gfileenumerator.c:278 +#: gio/gfileenumerator.c:423 gio/gfileenumerator.c:523 msgid "File enumerator has outstanding operation" msgstr "Перечислитель файлов имеет незавершённое действие" -#: gio/gfileenumerator.c:416 gio/gfileenumerator.c:516 +#: gio/gfileenumerator.c:414 gio/gfileenumerator.c:514 msgid "File enumerator is already closed" msgstr "Перечислитель файлов уже закрыт" -#: gio/gfileicon.c:252 +#: gio/gfileicon.c:250 #, c-format msgid "Can’t handle version %d of GFileIcon encoding" msgstr "Не удалось обработать версию %d текстового представления GFileIcon" -#: gio/gfileicon.c:262 +#: gio/gfileicon.c:260 msgid "Malformed input data for GFileIcon" msgstr "Некорректные входные данные для GFileIcon" -#: gio/gfileinputstream.c:151 gio/gfileinputstream.c:397 -#: gio/gfileiostream.c:169 gio/gfileoutputstream.c:166 -#: gio/gfileoutputstream.c:499 +#: gio/gfileinputstream.c:148 gio/gfileinputstream.c:394 +#: gio/gfileiostream.c:166 gio/gfileoutputstream.c:163 +#: gio/gfileoutputstream.c:497 msgid "Stream doesn’t support query_info" msgstr "Поток не поддерживает query_info" -#: gio/gfileinputstream.c:328 gio/gfileiostream.c:382 -#: gio/gfileoutputstream.c:373 +#: gio/gfileinputstream.c:325 gio/gfileiostream.c:380 +#: gio/gfileoutputstream.c:371 msgid "Seek not supported on stream" msgstr "Переход по потоку не поддерживается" -#: gio/gfileinputstream.c:372 +#: gio/gfileinputstream.c:369 msgid "Truncate not allowed on input stream" msgstr "Усечение на входном потоке не разрешено" -#: gio/gfileiostream.c:458 gio/gfileoutputstream.c:449 +#: gio/gfileiostream.c:456 gio/gfileoutputstream.c:447 msgid "Truncate not supported on stream" msgstr "Усечение не поддерживается на потоке" -#: gio/ghttpproxy.c:93 gio/gresolver.c:535 gio/gresolver.c:688 -#: glib/gconvert.c:1842 +#: gio/ghttpproxy.c:93 gio/gresolver.c:531 gio/gresolver.c:684 +#: glib/gconvert.c:1743 msgid "Invalid hostname" msgstr "Недопустимое имя узла" @@ -1606,64 +1606,64 @@ msgstr "Ответ HTTP с прокси слишком большой" msgid "HTTP proxy server closed connection unexpectedly." msgstr "Cервер прокси HTTP неожиданно закрыл соединение." -#: gio/gicon.c:299 +#: gio/gicon.c:297 #, c-format msgid "Wrong number of tokens (%d)" msgstr "Неверное число лексем (%d)" -#: gio/gicon.c:319 +#: gio/gicon.c:317 #, c-format msgid "No type for class name %s" msgstr "Нет типа для класса с именем %s" -#: gio/gicon.c:329 +#: gio/gicon.c:327 #, c-format msgid "Type %s does not implement the GIcon interface" msgstr "Тип %s не реализует интерфейс GIcon" -#: gio/gicon.c:340 +#: gio/gicon.c:338 #, c-format msgid "Type %s is not classed" msgstr "Тип %s не является классифицируемым" -#: gio/gicon.c:354 +#: gio/gicon.c:352 #, c-format msgid "Malformed version number: %s" msgstr "Некорректный номер версии: %s" -#: gio/gicon.c:368 +#: gio/gicon.c:366 #, c-format msgid "Type %s does not implement from_tokens() on the GIcon interface" msgstr "Тип %s не реализует from_tokens() интерфейса GIcon" -#: gio/gicon.c:470 +#: gio/gicon.c:468 msgid "Can’t handle the supplied version of the icon encoding" msgstr "Не удалось обработать данную версию текстового представления значка" -#: gio/ginetaddressmask.c:184 +#: gio/ginetaddressmask.c:175 msgid "No address specified" msgstr "Адрес не указан" -#: gio/ginetaddressmask.c:192 +#: gio/ginetaddressmask.c:183 #, c-format msgid "Length %u is too long for address" msgstr "Значение длины %u слишком велико для адреса" -#: gio/ginetaddressmask.c:225 +#: gio/ginetaddressmask.c:216 msgid "Address has bits set beyond prefix length" msgstr "В адресе установлены биты вне пределов длины префикса" -#: gio/ginetaddressmask.c:302 +#: gio/ginetaddressmask.c:293 #, c-format msgid "Could not parse “%s” as IP address mask" msgstr "Невозможно считать «%s» маской IP-адреса" -#: gio/ginetsocketaddress.c:205 gio/ginetsocketaddress.c:222 -#: gio/gnativesocketaddress.c:111 gio/gunixsocketaddress.c:230 +#: gio/ginetsocketaddress.c:199 gio/ginetsocketaddress.c:216 +#: gio/gnativesocketaddress.c:107 gio/gunixsocketaddress.c:222 msgid "Not enough space for socket address" msgstr "Недостаточно места для адреса сокета" -#: gio/ginetsocketaddress.c:237 +#: gio/ginetsocketaddress.c:231 msgid "Unsupported socket address" msgstr "Неподдерживаемый адрес сокета" @@ -1677,7 +1677,7 @@ msgstr "Входной поток не поддерживает чтение" #. Translators: This is an error you get if there is #. * already an operation running against this stream when #. * you try to start one -#: gio/ginputstream.c:1256 gio/giostream.c:312 gio/goutputstream.c:2218 +#: gio/ginputstream.c:1256 gio/giostream.c:311 gio/goutputstream.c:2218 msgid "Stream has outstanding operation" msgstr "Поток имеет незавершённое действие" @@ -1693,7 +1693,7 @@ msgstr "Сохранять с файлом при перемещении" msgid "“version” takes no arguments" msgstr "«version» не принимает аргументов" -#: gio/gio-tool.c:209 gio/gio-tool.c:225 glib/goption.c:871 +#: gio/gio-tool.c:209 gio/gio-tool.c:258 glib/goption.c:712 msgid "Usage:" msgstr "Использование:" @@ -1701,79 +1701,79 @@ msgstr "Использование:" msgid "Print version information and exit." msgstr "Вывести информацию о версии и выйти." -#: gio/gio-tool.c:228 -msgid "Commands:" -msgstr "Команды:" - -#: gio/gio-tool.c:231 +#: gio/gio-tool.c:232 msgid "Concatenate files to standard output" msgstr "Объединить файлы и вывести в стандартный вывод" -#: gio/gio-tool.c:232 +#: gio/gio-tool.c:233 msgid "Copy one or more files" msgstr "Копировать один или несколько файлов" -#: gio/gio-tool.c:233 +#: gio/gio-tool.c:234 msgid "Show information about locations" msgstr "Показать информацию о расположениях" -#: gio/gio-tool.c:234 +#: gio/gio-tool.c:235 msgid "Launch an application from a desktop file" msgstr "Запустить приложение из desktop-файла" -#: gio/gio-tool.c:235 +#: gio/gio-tool.c:236 msgid "List the contents of locations" msgstr "Показать содержимое расположений" -#: gio/gio-tool.c:236 +#: gio/gio-tool.c:237 msgid "Get or set the handler for a mimetype" msgstr "Получить или установить обработчик для типа MIME" -#: gio/gio-tool.c:237 +#: gio/gio-tool.c:238 msgid "Create directories" msgstr "Создать каталоги" -#: gio/gio-tool.c:238 +#: gio/gio-tool.c:239 msgid "Monitor files and directories for changes" msgstr "Отслеживать изменение файлов и каталогов" -#: gio/gio-tool.c:239 +#: gio/gio-tool.c:240 msgid "Mount or unmount the locations" msgstr "Монтирование или размонтирование расположений" -#: gio/gio-tool.c:240 +#: gio/gio-tool.c:241 msgid "Move one or more files" msgstr "Переместить один или несколько файлов" -#: gio/gio-tool.c:241 +#: gio/gio-tool.c:242 msgid "Open files with the default application" msgstr "Открыть файлы приложением по умолчанию" -#: gio/gio-tool.c:242 +#: gio/gio-tool.c:243 msgid "Rename a file" msgstr "Переименовать файл" -#: gio/gio-tool.c:243 +#: gio/gio-tool.c:244 msgid "Delete one or more files" msgstr "Удалить один или несколько файлов" -#: gio/gio-tool.c:244 +#: gio/gio-tool.c:245 msgid "Read from standard input and save" msgstr "Прочитать со стандартного входа и сохранить" -#: gio/gio-tool.c:245 +#: gio/gio-tool.c:246 msgid "Set a file attribute" msgstr "Установить атрибут файла" -#: gio/gio-tool.c:246 +#: gio/gio-tool.c:247 msgid "Move files or directories to the trash" msgstr "Переместить файлы или каталоги в корзину" -#: gio/gio-tool.c:247 +#: gio/gio-tool.c:248 msgid "Lists the contents of locations in a tree" msgstr "Показать содержимое расположений в виде дерева" -#: gio/gio-tool.c:249 +#: gio/gio-tool.c:261 +msgid "Commands:" +msgstr "Команды:" + +#: gio/gio-tool.c:275 #, c-format msgid "Use %s to get detailed help.\n" msgstr "Используйте команду %s для получения подробной справки.\n" @@ -1783,7 +1783,7 @@ msgid "Error writing to stdout" msgstr "Ошибка при записи в stdout" #. Translators: commandline placeholder -#: gio/gio-tool-cat.c:135 gio/gio-tool-info.c:382 gio/gio-tool-list.c:176 +#: gio/gio-tool-cat.c:135 gio/gio-tool-info.c:383 gio/gio-tool-list.c:176 #: gio/gio-tool-mkdir.c:50 gio/gio-tool-monitor.c:39 gio/gio-tool-monitor.c:41 #: gio/gio-tool-monitor.c:43 gio/gio-tool-monitor.c:45 #: gio/gio-tool-monitor.c:206 gio/gio-tool-mount.c:1236 gio/gio-tool-open.c:72 @@ -1806,61 +1806,67 @@ msgstr "" "расположения вместо локальных файлов: например, вы можете использовать что-" "то вроде smb://server/resource/file.txt в качестве расположения." -#: gio/gio-tool-cat.c:164 gio/gio-tool-info.c:413 gio/gio-tool-mkdir.c:78 +#: gio/gio-tool-cat.c:164 gio/gio-tool-info.c:414 gio/gio-tool-mkdir.c:78 #: gio/gio-tool-monitor.c:231 gio/gio-tool-mount.c:1287 gio/gio-tool-open.c:98 #: gio/gio-tool-remove.c:74 gio/gio-tool-trash.c:303 msgid "No locations given" msgstr "Не указаны адреса" -#: gio/gio-tool-copy.c:45 gio/gio-tool-move.c:40 +#: gio/gio-tool-copy.c:46 gio/gio-tool-move.c:40 msgid "No target directory" msgstr "Не указан целевой каталог" -#: gio/gio-tool-copy.c:46 gio/gio-tool-move.c:41 +#: gio/gio-tool-copy.c:47 gio/gio-tool-move.c:41 msgid "Show progress" msgstr "Показать ход выполнения" -#: gio/gio-tool-copy.c:47 gio/gio-tool-move.c:42 +#: gio/gio-tool-copy.c:48 gio/gio-tool-move.c:42 msgid "Prompt before overwrite" msgstr "Спрашивать перед перезаписью" -#: gio/gio-tool-copy.c:48 +#: gio/gio-tool-copy.c:49 msgid "Preserve all attributes" msgstr "Сохранять все атрибуты" -#: gio/gio-tool-copy.c:49 gio/gio-tool-move.c:43 gio/gio-tool-save.c:51 +#: gio/gio-tool-copy.c:50 gio/gio-tool-move.c:43 gio/gio-tool-save.c:51 msgid "Backup existing destination files" msgstr "Создать резервную копию существующих файлов назначения" -#: gio/gio-tool-copy.c:50 +#: gio/gio-tool-copy.c:51 msgid "Never follow symbolic links" msgstr "Никогда не переходить по символическим ссылкам" -#: gio/gio-tool-copy.c:51 +#: gio/gio-tool-copy.c:52 msgid "Use default permissions for the destination" msgstr "Использовать разрешения по умолчанию" -#: gio/gio-tool-copy.c:76 gio/gio-tool-move.c:69 +#: gio/gio-tool-copy.c:53 +msgid "Use default file modification timestamps for the destination" +msgstr "" +"Использовать временные метки модификации файлов по умолчанию для места " +"назначения" + +#: gio/gio-tool-copy.c:78 gio/gio-tool-move.c:69 #, c-format msgid "Transferred %s out of %s (%s/s)" msgstr "Передано %s из %s (%s/с)" #. Translators: commandline placeholder -#: gio/gio-tool-copy.c:102 gio/gio-tool-move.c:96 +#: gio/gio-tool-copy.c:104 gio/gio-tool-move.c:96 msgid "SOURCE" msgstr "ИСТОЧНИК" #. Translators: commandline placeholder -#: gio/gio-tool-copy.c:102 gio/gio-tool-move.c:96 gio/gio-tool-save.c:162 +#: gio/gio-tool-copy.c:104 gio/gio-tool-move.c:96 gio/gio-tool-save.c:162 msgid "DESTINATION" msgstr "ПРИЁМНИК" -#: gio/gio-tool-copy.c:107 +#: gio/gio-tool-copy.c:109 msgid "Copy one or more files from SOURCE to DESTINATION." msgstr "" "Копировать один или несколько файлов из ИСТОЧНИКА в каталог НАЗНАЧЕНИЯ." -#: gio/gio-tool-copy.c:109 +#: gio/gio-tool-copy.c:111 msgid "" "gio copy is similar to the traditional cp utility, but using GIO\n" "locations instead of local files: for example, you can use something\n" @@ -1870,12 +1876,12 @@ msgstr "" "GIO-расположения вместо локальных файлов: например, вы можете использовать\n" "что-то вроде smb://server/resource/file.txt в качестве расположения." -#: gio/gio-tool-copy.c:151 +#: gio/gio-tool-copy.c:153 #, c-format msgid "Destination %s is not a directory" msgstr "Цель «%s» не является каталогом" -#: gio/gio-tool-copy.c:198 gio/gio-tool-move.c:188 +#: gio/gio-tool-copy.c:202 gio/gio-tool-move.c:188 #, c-format msgid "%s: overwrite “%s”? " msgstr "%s: перезаписать «%s»? " @@ -1916,52 +1922,52 @@ msgstr "отображаемое имя: %s\n" msgid "edit name: %s\n" msgstr "редактируемое имя: %s\n" -#: gio/gio-tool-info.c:184 +#: gio/gio-tool-info.c:185 #, c-format msgid "name: %s\n" msgstr "имя: %s\n" -#: gio/gio-tool-info.c:191 +#: gio/gio-tool-info.c:192 #, c-format msgid "type: %s\n" msgstr "тип: %s\n" -#: gio/gio-tool-info.c:197 +#: gio/gio-tool-info.c:198 msgid "size: " msgstr "размер: " -#: gio/gio-tool-info.c:203 +#: gio/gio-tool-info.c:204 msgid "hidden\n" msgstr "скрытый\n" -#: gio/gio-tool-info.c:206 +#: gio/gio-tool-info.c:207 #, c-format msgid "uri: %s\n" msgstr "uri: %s\n" -#: gio/gio-tool-info.c:213 +#: gio/gio-tool-info.c:214 #, c-format msgid "local path: %s\n" msgstr "локальный путь: %s\n" -#: gio/gio-tool-info.c:247 +#: gio/gio-tool-info.c:248 #, c-format msgid "unix mount: %s%s %s %s %s\n" msgstr "подключения unix: %s%s %s %s %s\n" -#: gio/gio-tool-info.c:328 +#: gio/gio-tool-info.c:329 msgid "Settable attributes:\n" msgstr "Устанавливаемые атрибуты:\n" -#: gio/gio-tool-info.c:352 +#: gio/gio-tool-info.c:353 msgid "Writable attribute namespaces:\n" msgstr "Пространства имён записываемых атрибутов:\n" -#: gio/gio-tool-info.c:387 +#: gio/gio-tool-info.c:388 msgid "Show information about locations." msgstr "Показать информацию о расположениях." -#: gio/gio-tool-info.c:389 +#: gio/gio-tool-info.c:390 msgid "" "gio info is similar to the traditional ls utility, but using GIO\n" "locations instead of local files: for example, you can use something\n" @@ -3320,25 +3326,25 @@ msgstr "" "Произошла ошибка при установке времени модификации или доступа файла «%s»: " "%lu" -#: gio/glocalfileinfo.c:2950 +#: gio/glocalfileinfo.c:2970 #, c-format msgid "Error setting modification or access time: %s" msgstr "Произошла ошибка при установке времени модификации или доступа: %s" -#: gio/glocalfileinfo.c:2973 +#: gio/glocalfileinfo.c:2993 msgid "SELinux context must be non-NULL" msgstr "Контекст SELinux не должен быть равен NULL" -#: gio/glocalfileinfo.c:2980 +#: gio/glocalfileinfo.c:3000 msgid "SELinux is not enabled on this system" msgstr "В этой системе не включён SELinux" -#: gio/glocalfileinfo.c:2990 +#: gio/glocalfileinfo.c:3010 #, c-format msgid "Error setting SELinux context: %s" msgstr "Произошла ошибка при установке контекста SELinux: %s" -#: gio/glocalfileinfo.c:3087 +#: gio/glocalfileinfo.c:3107 #, c-format msgid "Setting attribute %s not supported" msgstr "Установка атрибута %s не поддерживается" @@ -3391,7 +3397,7 @@ msgid "Error truncating file: %s" msgstr "Произошла ошибка при усечении файла: %s" #: gio/glocalfileoutputstream.c:664 gio/glocalfileoutputstream.c:909 -#: gio/glocalfileoutputstream.c:1223 gio/gsubprocess.c:231 +#: gio/glocalfileoutputstream.c:1223 gio/gsubprocess.c:227 #, c-format msgid "Error opening file “%s”: %s" msgstr "Произошла ошибка при открытии файла «%s»: %s" @@ -3413,27 +3419,27 @@ msgstr "Файл был изменён извне" msgid "Error removing old file: %s" msgstr "Произошла ошибка при удалении старого файла: %s" -#: gio/gmemoryinputstream.c:476 gio/gmemoryoutputstream.c:764 +#: gio/gmemoryinputstream.c:473 gio/gmemoryoutputstream.c:761 msgid "Invalid GSeekType supplied" msgstr "Передан недопустимый GSeekType" -#: gio/gmemoryinputstream.c:486 +#: gio/gmemoryinputstream.c:483 msgid "Invalid seek request" msgstr "Недопустимый запрос на переход" -#: gio/gmemoryinputstream.c:510 +#: gio/gmemoryinputstream.c:507 msgid "Cannot truncate GMemoryInputStream" msgstr "Нельзя усечь GMemoryInputStream" -#: gio/gmemoryoutputstream.c:570 +#: gio/gmemoryoutputstream.c:567 msgid "Memory output stream not resizable" msgstr "Невозможно изменить размер выходного потока в память" -#: gio/gmemoryoutputstream.c:586 +#: gio/gmemoryoutputstream.c:583 msgid "Failed to resize memory output stream" msgstr "Не удалось изменить размер выходного потока в память" -#: gio/gmemoryoutputstream.c:665 +#: gio/gmemoryoutputstream.c:662 msgid "" "Amount of memory required to process the write is larger than available " "address space" @@ -3441,32 +3447,32 @@ msgstr "" "Количество памяти, требуемое процессом записи, больше чем доступное адресное " "пространство" -#: gio/gmemoryoutputstream.c:774 +#: gio/gmemoryoutputstream.c:771 msgid "Requested seek before the beginning of the stream" msgstr "Выполнять перемещение в начало потока" -#: gio/gmemoryoutputstream.c:789 +#: gio/gmemoryoutputstream.c:786 msgid "Requested seek beyond the end of the stream" msgstr "Выполнять перемещение в конец потока" #. Translators: This is an error #. * message for mount objects that #. * don't implement unmount. -#: gio/gmount.c:401 +#: gio/gmount.c:400 msgid "mount doesn’t implement “unmount”" msgstr "точка монтирования не поддерживает «отсоединение»" #. Translators: This is an error #. * message for mount objects that #. * don't implement eject. -#: gio/gmount.c:477 +#: gio/gmount.c:476 msgid "mount doesn’t implement “eject”" msgstr "точка монтирования не поддерживает «извлечение»" #. Translators: This is an error #. * message for mount objects that #. * don't implement any of unmount or unmount_with_operation. -#: gio/gmount.c:555 +#: gio/gmount.c:554 msgid "mount doesn’t implement “unmount” or “unmount_with_operation”" msgstr "" "точка монтирования не поддерживает «отсоединение» или " @@ -3475,7 +3481,7 @@ msgstr "" #. Translators: This is an error #. * message for mount objects that #. * don't implement any of eject or eject_with_operation. -#: gio/gmount.c:640 +#: gio/gmount.c:639 msgid "mount doesn’t implement “eject” or “eject_with_operation”" msgstr "" "точка монтирования не поддерживает «извлечение» или «извлечение_с_операцией»" @@ -3483,14 +3489,14 @@ msgstr "" #. Translators: This is an error #. * message for mount objects that #. * don't implement remount. -#: gio/gmount.c:728 +#: gio/gmount.c:727 msgid "mount doesn’t implement “remount”" msgstr "точка монтирования не поддерживает «переподсоединение»" #. Translators: This is an error #. * message for mount objects that #. * don't implement content type guessing. -#: gio/gmount.c:810 +#: gio/gmount.c:809 msgid "mount doesn’t implement content type guessing" msgstr "" "точка монтирования не поддерживает возможность определения типа содержимого" @@ -3498,13 +3504,13 @@ msgstr "" #. Translators: This is an error #. * message for mount objects that #. * don't implement content type guessing. -#: gio/gmount.c:897 +#: gio/gmount.c:896 msgid "mount doesn’t implement synchronous content type guessing" msgstr "" "точка монтирования не поддерживает возможность синхронного определения типа " "содержимого" -#: gio/gnetworkaddress.c:417 +#: gio/gnetworkaddress.c:408 #, c-format msgid "Hostname “%s” contains “[” but not “]”" msgstr "Имя узла «%s» содержит «[», но не «]»" @@ -3541,7 +3547,7 @@ msgstr "NetworkManager не запущен" msgid "NetworkManager version too old" msgstr "Версия NetworkManager слишком старая" -#: gio/goutputstream.c:234 gio/goutputstream.c:777 +#: gio/goutputstream.c:236 gio/goutputstream.c:777 msgid "Output stream doesn’t implement write" msgstr "Выходной поток не поддерживает запись" @@ -3554,13 +3560,13 @@ msgstr "Сумма массивов, переданных в «%s» слишко msgid "Source stream is already closed" msgstr "Исходный поток уже закрыт" -#: gio/gproxyaddressenumerator.c:329 gio/gproxyaddressenumerator.c:347 +#: gio/gproxyaddressenumerator.c:328 gio/gproxyaddressenumerator.c:346 msgid "Unspecified proxy lookup failure" msgstr "Неуказанный сбой поиска прокси-сервера" #. Translators: the first placeholder is a domain name, the #. * second is an error message -#: gio/gresolver.c:478 gio/gthreadedresolver.c:317 gio/gthreadedresolver.c:338 +#: gio/gresolver.c:474 gio/gthreadedresolver.c:317 gio/gthreadedresolver.c:338 #: gio/gthreadedresolver.c:983 gio/gthreadedresolver.c:1007 #: gio/gthreadedresolver.c:1032 gio/gthreadedresolver.c:1047 #, c-format @@ -3568,24 +3574,24 @@ msgid "Error resolving “%s”: %s" msgstr "Ошибка разрешения «%s»: %s" #. Translators: The placeholder is for a function name. -#: gio/gresolver.c:547 gio/gresolver.c:707 +#: gio/gresolver.c:543 gio/gresolver.c:703 #, c-format msgid "%s not implemented" msgstr "«%s» не реализовано" -#: gio/gresolver.c:1076 gio/gresolver.c:1128 +#: gio/gresolver.c:1072 gio/gresolver.c:1124 msgid "Invalid domain" msgstr "Недопустимый домен" -#: gio/gresource.c:683 gio/gresource.c:945 gio/gresource.c:985 -#: gio/gresource.c:1109 gio/gresource.c:1181 gio/gresource.c:1255 -#: gio/gresource.c:1336 gio/gresourcefile.c:482 gio/gresourcefile.c:606 +#: gio/gresource.c:704 gio/gresource.c:966 gio/gresource.c:1006 +#: gio/gresource.c:1130 gio/gresource.c:1202 gio/gresource.c:1276 +#: gio/gresource.c:1357 gio/gresourcefile.c:482 gio/gresourcefile.c:606 #: gio/gresourcefile.c:757 #, c-format msgid "The resource at “%s” does not exist" msgstr "Ресурс из «%s» не существует" -#: gio/gresource.c:850 +#: gio/gresource.c:871 #, c-format msgid "The resource at “%s” failed to decompress" msgstr "Не удалось распаковать ресурс из «%s»" @@ -3953,216 +3959,216 @@ msgstr "Указано пустое имя схемы\n" msgid "No such key “%s”\n" msgstr "Ключ «%s» отсутствует\n" -#: gio/gsocket.c:419 +#: gio/gsocket.c:417 msgid "Invalid socket, not initialized" msgstr "Недопустимый сокет, не инициализировано" -#: gio/gsocket.c:426 +#: gio/gsocket.c:424 #, c-format msgid "Invalid socket, initialization failed due to: %s" msgstr "Недопустимый сокет, инициализация не удалась по причине: %s" -#: gio/gsocket.c:434 +#: gio/gsocket.c:432 msgid "Socket is already closed" msgstr "Сокет уже закрыт" -#: gio/gsocket.c:449 gio/gsocket.c:3238 gio/gsocket.c:4469 gio/gsocket.c:4527 -#: gio/gthreadedresolver.c:1438 +#: gio/gsocket.c:447 gio/gsocket.c:3236 gio/gsocket.c:4467 gio/gsocket.c:4525 +#: gio/gthreadedresolver.c:1452 msgid "Socket I/O timed out" msgstr "Превышено время ожидания ввода-вывода сокета" -#: gio/gsocket.c:586 +#: gio/gsocket.c:584 #, c-format msgid "creating GSocket from fd: %s" msgstr "создаётся GSocket из fd: %s" -#: gio/gsocket.c:646 gio/gsocket.c:714 gio/gsocket.c:721 +#: gio/gsocket.c:644 gio/gsocket.c:712 gio/gsocket.c:719 #, c-format msgid "Unable to create socket: %s" msgstr "Не удалось создать сокет: %s" -#: gio/gsocket.c:714 +#: gio/gsocket.c:712 msgid "Unknown family was specified" msgstr "Указано неизвестное семейство" -#: gio/gsocket.c:721 +#: gio/gsocket.c:719 msgid "Unknown protocol was specified" msgstr "Указан неизвестный протокол" -#: gio/gsocket.c:1190 +#: gio/gsocket.c:1188 #, c-format msgid "Cannot use datagram operations on a non-datagram socket." msgstr "" "Невозможно использовать дейтаграммные операции на не-дейтаграммном сокете." -#: gio/gsocket.c:1207 +#: gio/gsocket.c:1205 #, c-format msgid "Cannot use datagram operations on a socket with a timeout set." msgstr "" "Невозможно использовать дейтаграммные операции на сокете с установленным " "тайм-аутом." -#: gio/gsocket.c:2014 +#: gio/gsocket.c:2012 #, c-format msgid "could not get local address: %s" msgstr "не удалось получить локальный адрес: %s" -#: gio/gsocket.c:2060 +#: gio/gsocket.c:2058 #, c-format msgid "could not get remote address: %s" msgstr "не удалось получить удаленный адрес: %s" -#: gio/gsocket.c:2126 +#: gio/gsocket.c:2124 #, c-format msgid "could not listen: %s" msgstr "не удалось слушать: %s" -#: gio/gsocket.c:2230 +#: gio/gsocket.c:2228 #, c-format msgid "Error binding to address %s: %s" msgstr "Произошла ошибка при связывании к адресу %s: %s" -#: gio/gsocket.c:2405 gio/gsocket.c:2442 gio/gsocket.c:2552 gio/gsocket.c:2577 -#: gio/gsocket.c:2644 gio/gsocket.c:2702 gio/gsocket.c:2720 +#: gio/gsocket.c:2403 gio/gsocket.c:2440 gio/gsocket.c:2550 gio/gsocket.c:2575 +#: gio/gsocket.c:2642 gio/gsocket.c:2700 gio/gsocket.c:2718 #, c-format msgid "Error joining multicast group: %s" msgstr "Ошибка при вступлении в мультикастовую группу: %s" -#: gio/gsocket.c:2406 gio/gsocket.c:2443 gio/gsocket.c:2553 gio/gsocket.c:2578 -#: gio/gsocket.c:2645 gio/gsocket.c:2703 gio/gsocket.c:2721 +#: gio/gsocket.c:2404 gio/gsocket.c:2441 gio/gsocket.c:2551 gio/gsocket.c:2576 +#: gio/gsocket.c:2643 gio/gsocket.c:2701 gio/gsocket.c:2719 #, c-format msgid "Error leaving multicast group: %s" msgstr "Ошибка при выходе из мультикастовой группы: %s" -#: gio/gsocket.c:2407 +#: gio/gsocket.c:2405 msgid "No support for source-specific multicast" msgstr "Отсутствует поддержка мультикаста по источнику" -#: gio/gsocket.c:2554 +#: gio/gsocket.c:2552 msgid "Unsupported socket family" msgstr "Неподдерживаемое семейство сокетов" -#: gio/gsocket.c:2579 +#: gio/gsocket.c:2577 msgid "source-specific not an IPv4 address" msgstr "специфичный источник, не адрес IP4" -#: gio/gsocket.c:2603 +#: gio/gsocket.c:2601 #, c-format msgid "Interface name too long" msgstr "Имя интерфейса слишком длинное" -#: gio/gsocket.c:2616 gio/gsocket.c:2670 +#: gio/gsocket.c:2614 gio/gsocket.c:2668 #, c-format msgid "Interface not found: %s" msgstr "Интерфейс не найден: %s" -#: gio/gsocket.c:2646 +#: gio/gsocket.c:2644 msgid "No support for IPv4 source-specific multicast" msgstr "Отсутствует поддержка IPv4 мультикаста по источнику" -#: gio/gsocket.c:2704 +#: gio/gsocket.c:2702 msgid "No support for IPv6 source-specific multicast" msgstr "Отсутствует поддержка IPv6 мультикаста по источнику" -#: gio/gsocket.c:2937 +#: gio/gsocket.c:2935 #, c-format msgid "Error accepting connection: %s" msgstr "Ошибка приёма подключения: %s" -#: gio/gsocket.c:3063 +#: gio/gsocket.c:3061 msgid "Connection in progress" msgstr "Выполняется соединение" -#: gio/gsocket.c:3114 +#: gio/gsocket.c:3112 msgid "Unable to get pending error: " msgstr "Не удалось получить ошибку ожидания: " -#: gio/gsocket.c:3303 +#: gio/gsocket.c:3301 #, c-format msgid "Error receiving data: %s" msgstr "Ошибка при получении данных: %s" -#: gio/gsocket.c:3500 +#: gio/gsocket.c:3498 #, c-format msgid "Error sending data: %s" msgstr "Ошибка при отправлении данных: %s" -#: gio/gsocket.c:3687 +#: gio/gsocket.c:3685 #, c-format msgid "Unable to shutdown socket: %s" msgstr "Не удалось выключить сокет: %s" -#: gio/gsocket.c:3768 +#: gio/gsocket.c:3766 #, c-format msgid "Error closing socket: %s" msgstr "Произошла ошибка при закрытии сокета: %s" -#: gio/gsocket.c:4462 +#: gio/gsocket.c:4460 #, c-format msgid "Waiting for socket condition: %s" msgstr "Ожидание состояния сокета: %s" -#: gio/gsocket.c:4852 gio/gsocket.c:4868 gio/gsocket.c:4881 +#: gio/gsocket.c:4850 gio/gsocket.c:4866 gio/gsocket.c:4879 #, c-format msgid "Unable to send message: %s" msgstr "Не удалось отправить сообщение: %s" -#: gio/gsocket.c:4853 gio/gsocket.c:4869 gio/gsocket.c:4882 +#: gio/gsocket.c:4851 gio/gsocket.c:4867 gio/gsocket.c:4880 msgid "Message vectors too large" msgstr "Слишком большие массивы сообщения" -#: gio/gsocket.c:4898 gio/gsocket.c:4900 gio/gsocket.c:5047 gio/gsocket.c:5132 -#: gio/gsocket.c:5310 gio/gsocket.c:5350 gio/gsocket.c:5352 +#: gio/gsocket.c:4896 gio/gsocket.c:4898 gio/gsocket.c:5045 gio/gsocket.c:5130 +#: gio/gsocket.c:5308 gio/gsocket.c:5348 gio/gsocket.c:5350 #, c-format msgid "Error sending message: %s" msgstr "Произошла ошибка при отправлении сообщения: %s" -#: gio/gsocket.c:5074 +#: gio/gsocket.c:5072 msgid "GSocketControlMessage not supported on Windows" msgstr "GSocketControlMessage не поддерживается в Windows" -#: gio/gsocket.c:5547 gio/gsocket.c:5623 gio/gsocket.c:5849 +#: gio/gsocket.c:5545 gio/gsocket.c:5621 gio/gsocket.c:5847 #, c-format msgid "Error receiving message: %s" msgstr "Произошла ошибка при получении сообщения: %s" -#: gio/gsocket.c:6134 gio/gsocket.c:6145 gio/gsocket.c:6208 +#: gio/gsocket.c:6132 gio/gsocket.c:6143 gio/gsocket.c:6206 #, c-format msgid "Unable to read socket credentials: %s" msgstr "Не удалось прочитать полномочия сокета: %s" -#: gio/gsocket.c:6217 +#: gio/gsocket.c:6215 msgid "g_socket_get_credentials not implemented for this OS" msgstr "g_socket_get_credentials не реализован для данной ОС" -#: gio/gsocketclient.c:193 +#: gio/gsocketclient.c:190 #, c-format msgid "Could not connect to proxy server %s: " msgstr "Не удалось подключиться к прокси-серверу %s: " -#: gio/gsocketclient.c:207 +#: gio/gsocketclient.c:204 #, c-format msgid "Could not connect to %s: " msgstr "Не удалось подключиться к %s: " -#: gio/gsocketclient.c:209 +#: gio/gsocketclient.c:206 msgid "Could not connect: " msgstr "Не удалось подключиться к: " -#: gio/gsocketclient.c:1204 gio/gsocketclient.c:1807 +#: gio/gsocketclient.c:1201 gio/gsocketclient.c:1804 msgid "Proxying over a non-TCP connection is not supported." msgstr "Проксирование через не-TCP соединение не поддерживается." -#: gio/gsocketclient.c:1236 gio/gsocketclient.c:1836 +#: gio/gsocketclient.c:1233 gio/gsocketclient.c:1833 #, c-format msgid "Proxy protocol “%s” is not supported." msgstr "Протокол прокси «%s» не поддерживается." -#: gio/gsocketlistener.c:232 +#: gio/gsocketlistener.c:229 msgid "Listener is already closed" msgstr "Слушатель уже закрыт" -#: gio/gsocketlistener.c:278 +#: gio/gsocketlistener.c:275 msgid "Added socket is closed" msgstr "Добавленный сокет закрыт" @@ -4255,17 +4261,17 @@ msgstr "Прокси SOCKSv5 не поддерживает предложенн msgid "Unknown SOCKSv5 proxy error." msgstr "Неизвестная ошибка прокси SOCKSv5." -#: gio/gtestdbus.c:614 glib/gspawn-win32.c:433 +#: gio/gtestdbus.c:610 glib/gspawn-win32.c:433 #, c-format msgid "Failed to create pipe for communicating with child process (%s)" msgstr "Не удалось создать канал для сообщения с процессом-потомком (%s)" -#: gio/gtestdbus.c:621 +#: gio/gtestdbus.c:617 #, c-format msgid "Pipes are not supported in this platform" msgstr "Каналы не поддерживаются на этой платформе" -#: gio/gthemedicon.c:597 +#: gio/gthemedicon.c:596 #, c-format msgid "Can’t handle version %d of GThemedIcon encoding" msgstr "Не удалось обработать версию %d текстового представления GThemedIcon" @@ -4314,35 +4320,35 @@ msgstr "Некорректный DNS-пакет" msgid "Failed to parse DNS response for “%s”: " msgstr "Не удалось разобрать ответ DNS для \"%s\": " -#: gio/gtlscertificate.c:480 +#: gio/gtlscertificate.c:468 msgid "No PEM-encoded private key found" msgstr "Не найден секретный ключ в формате PEM" -#: gio/gtlscertificate.c:490 +#: gio/gtlscertificate.c:478 msgid "Cannot decrypt PEM-encoded private key" msgstr "Не удалось расшифровать секретный ключ в формате PEM" -#: gio/gtlscertificate.c:501 +#: gio/gtlscertificate.c:489 msgid "Could not parse PEM-encoded private key" msgstr "Не удалось разобрать секретный ключ в формате PEM" -#: gio/gtlscertificate.c:528 +#: gio/gtlscertificate.c:516 msgid "No PEM-encoded certificate found" msgstr "Не найден сертификат в формате PEM" -#: gio/gtlscertificate.c:537 +#: gio/gtlscertificate.c:525 msgid "Could not parse PEM-encoded certificate" msgstr "Не удалось разобрать сертификат в формате PEM" -#: gio/gtlscertificate.c:800 +#: gio/gtlscertificate.c:788 msgid "The current TLS backend does not support PKCS #12" msgstr "Текущий бэкенд TLS не поддерживает PKCS #12" -#: gio/gtlscertificate.c:1017 +#: gio/gtlscertificate.c:1005 msgid "This GTlsBackend does not support creating PKCS #11 certificates" msgstr "Сервис GTlsBackend не поддерживает создание сертификатов PKCS #11" -#: gio/gtlspassword.c:113 +#: gio/gtlspassword.c:104 msgid "" "This is the last chance to enter the password correctly before your access " "is locked out." @@ -4352,7 +4358,7 @@ msgstr "" #. Translators: This is not the 'This is the last chance' string. It is #. * displayed when more than one attempt is allowed. -#: gio/gtlspassword.c:117 +#: gio/gtlspassword.c:108 msgid "" "Several passwords entered have been incorrect, and your access will be " "locked out after further failures." @@ -4360,15 +4366,15 @@ msgstr "" "Пароль был несколько раз введён неправильно, после следующих отказов ваш " "доступ будет заблокирован." -#: gio/gtlspassword.c:119 +#: gio/gtlspassword.c:110 msgid "The password entered is incorrect." msgstr "Введённый пароль неверен." -#: gio/gunixconnection.c:127 +#: gio/gunixconnection.c:116 msgid "Sending FD is not supported" msgstr "Отправка дескриптора файла не поддерживается" -#: gio/gunixconnection.c:181 gio/gunixconnection.c:602 +#: gio/gunixconnection.c:170 gio/gunixconnection.c:591 #, c-format msgid "Expecting 1 control message, got %d" msgid_plural "Expecting 1 control message, got %d" @@ -4376,11 +4382,11 @@ msgstr[0] "Ожидается 1 контрольное сообщение, по msgstr[1] "Ожидается 1 контрольное сообщение, получено %d" msgstr[2] "Ожидается 1 контрольное сообщение, получено %d" -#: gio/gunixconnection.c:197 gio/gunixconnection.c:614 +#: gio/gunixconnection.c:186 gio/gunixconnection.c:603 msgid "Unexpected type of ancillary data" msgstr "Неожиданный тип вспомогательных данных" -#: gio/gunixconnection.c:216 +#: gio/gunixconnection.c:205 #, c-format msgid "Expecting one fd, but got %d\n" msgid_plural "Expecting one fd, but got %d\n" @@ -4388,112 +4394,112 @@ msgstr[0] "Ожидается один файловый дескриптор н msgstr[1] "Ожидается один файловый дескриптор но получено %d\n" msgstr[2] "Ожидается один файловый дескриптор но получено %d\n" -#: gio/gunixconnection.c:235 +#: gio/gunixconnection.c:224 msgid "Received invalid fd" msgstr "Получен недопустимый файловый дескриптор" -#: gio/gunixconnection.c:242 +#: gio/gunixconnection.c:231 msgid "Receiving FD is not supported" msgstr "Получение дескриптора файла не поддерживается" -#: gio/gunixconnection.c:384 +#: gio/gunixconnection.c:373 msgid "Error sending credentials: " msgstr "Произошла ошибка при отправлении мандата: " -#: gio/gunixconnection.c:542 +#: gio/gunixconnection.c:531 #, c-format msgid "Error checking if SO_PASSCRED is enabled for socket: %s" msgstr "Произошла ошибка при проверке включения SO_PASSCRED для сокета: %s" -#: gio/gunixconnection.c:558 +#: gio/gunixconnection.c:547 #, c-format msgid "Error enabling SO_PASSCRED: %s" msgstr "Произошла ошибка при включении SO_PASSCRED: %s" -#: gio/gunixconnection.c:587 +#: gio/gunixconnection.c:576 msgid "" "Expecting to read a single byte for receiving credentials but read zero bytes" msgstr "" "Ожидалось прочитать один байт идентификационной информации (credentials), но " "не прочитано ни одного байта" -#: gio/gunixconnection.c:628 +#: gio/gunixconnection.c:617 #, c-format msgid "Not expecting control message, but got %d" msgstr "Контрольное сообщение не ожидалось, но получено %d" -#: gio/gunixconnection.c:653 +#: gio/gunixconnection.c:642 #, c-format msgid "Error while disabling SO_PASSCRED: %s" msgstr "Произошла ошибка при отключении SO_PASSCRED: %s" -#: gio/gunixinputstream.c:359 gio/gunixinputstream.c:380 +#: gio/gunixinputstream.c:356 gio/gunixinputstream.c:377 #, c-format msgid "Error reading from file descriptor: %s" msgstr "Ошибка при чтении из файлового дескриптора: %s" -#: gio/gunixinputstream.c:413 gio/gunixoutputstream.c:522 -#: gio/gwin32inputstream.c:219 gio/gwin32outputstream.c:206 +#: gio/gunixinputstream.c:410 gio/gunixoutputstream.c:519 +#: gio/gwin32inputstream.c:216 gio/gwin32outputstream.c:203 #, c-format msgid "Error closing file descriptor: %s" msgstr "Ошибка при закрытии файлового дескриптора: %s" -#: gio/gunixmounts.c:2826 gio/gunixmounts.c:2879 +#: gio/gunixmounts.c:2814 gio/gunixmounts.c:2867 msgid "Filesystem root" msgstr "Корень файловой системы" -#: gio/gunixoutputstream.c:359 gio/gunixoutputstream.c:379 -#: gio/gunixoutputstream.c:466 gio/gunixoutputstream.c:486 -#: gio/gunixoutputstream.c:632 +#: gio/gunixoutputstream.c:356 gio/gunixoutputstream.c:376 +#: gio/gunixoutputstream.c:463 gio/gunixoutputstream.c:483 +#: gio/gunixoutputstream.c:629 #, c-format msgid "Error writing to file descriptor: %s" msgstr "Ошибка при записи в файловый дескриптор: %s" -#: gio/gunixsocketaddress.c:253 +#: gio/gunixsocketaddress.c:245 msgid "Abstract UNIX domain socket addresses not supported on this system" msgstr "" "Абстрактные адреса доменных сокетов UNIX не поддерживаются на этой системе" -#: gio/gvolume.c:440 +#: gio/gvolume.c:436 msgid "volume doesn’t implement eject" msgstr "том не поддерживает извлечение" #. Translators: This is an error #. * message for volume objects that #. * don't implement any of eject or eject_with_operation. -#: gio/gvolume.c:517 +#: gio/gvolume.c:513 msgid "volume doesn’t implement eject or eject_with_operation" msgstr "том не поддерживает извлечение или извлечение_с_операцией" -#: gio/gwin32inputstream.c:187 +#: gio/gwin32inputstream.c:184 #, c-format msgid "Error reading from handle: %s" msgstr "Произошла ошибка при чтении из дескриптора: %s" -#: gio/gwin32inputstream.c:234 gio/gwin32outputstream.c:221 +#: gio/gwin32inputstream.c:231 gio/gwin32outputstream.c:218 #, c-format msgid "Error closing handle: %s" msgstr "Произошла ошибка при закрытии дескриптора: %s" -#: gio/gwin32outputstream.c:174 +#: gio/gwin32outputstream.c:171 #, c-format msgid "Error writing to handle: %s" msgstr "Произошла ошибка при записи в дескриптор: %s" -#: gio/gzlibcompressor.c:396 gio/gzlibdecompressor.c:349 +#: gio/gzlibcompressor.c:389 gio/gzlibdecompressor.c:342 msgid "Not enough memory" msgstr "Недостаточно памяти" -#: gio/gzlibcompressor.c:403 gio/gzlibdecompressor.c:356 +#: gio/gzlibcompressor.c:396 gio/gzlibdecompressor.c:349 #, c-format msgid "Internal error: %s" msgstr "Внутренняя ошибка: %s" -#: gio/gzlibcompressor.c:416 gio/gzlibdecompressor.c:370 +#: gio/gzlibcompressor.c:409 gio/gzlibdecompressor.c:363 msgid "Need more input" msgstr "Требуется больше входных данных" -#: gio/gzlibdecompressor.c:342 +#: gio/gzlibdecompressor.c:335 msgid "Invalid compressed data" msgstr "Неправильные сжатые данные" @@ -4521,151 +4527,151 @@ msgstr "Запуск службы dbus" msgid "Wrong args\n" msgstr "Неверные параметры\n" -#: glib/gbookmarkfile.c:861 +#: glib/gbookmarkfile.c:816 #, c-format msgid "Unexpected attribute “%s” for element “%s”" msgstr "Неожиданный атрибут «%s» для элемента «%s»" -#: glib/gbookmarkfile.c:872 glib/gbookmarkfile.c:952 glib/gbookmarkfile.c:962 -#: glib/gbookmarkfile.c:1075 +#: glib/gbookmarkfile.c:827 glib/gbookmarkfile.c:907 glib/gbookmarkfile.c:917 +#: glib/gbookmarkfile.c:1030 #, c-format msgid "Attribute “%s” of element “%s” not found" msgstr "Не найден атрибут «%s» элемента «%s»" -#: glib/gbookmarkfile.c:1284 glib/gbookmarkfile.c:1349 -#: glib/gbookmarkfile.c:1413 glib/gbookmarkfile.c:1423 +#: glib/gbookmarkfile.c:1239 glib/gbookmarkfile.c:1304 +#: glib/gbookmarkfile.c:1368 glib/gbookmarkfile.c:1378 #, c-format msgid "Unexpected tag “%s”, tag “%s” expected" msgstr "Неожиданный тэг «%s», ожидался тэг «%s»" -#: glib/gbookmarkfile.c:1309 glib/gbookmarkfile.c:1323 -#: glib/gbookmarkfile.c:1391 glib/gbookmarkfile.c:1437 +#: glib/gbookmarkfile.c:1264 glib/gbookmarkfile.c:1278 +#: glib/gbookmarkfile.c:1346 glib/gbookmarkfile.c:1392 #, c-format msgid "Unexpected tag “%s” inside “%s”" msgstr "Неожиданный тэг «%s» внутри «%s»" -#: glib/gbookmarkfile.c:1717 +#: glib/gbookmarkfile.c:1672 #, c-format msgid "Invalid date/time ‘%s’ in bookmark file" msgstr "Неверная дата и время ‘%s’ в файле закладок" -#: glib/gbookmarkfile.c:1956 +#: glib/gbookmarkfile.c:1911 msgid "No valid bookmark file found in data dirs" msgstr "Не удалось найти допустимый файл закладок в каталогах поиска" -#: glib/gbookmarkfile.c:2157 +#: glib/gbookmarkfile.c:2112 #, c-format msgid "A bookmark for URI “%s” already exists" msgstr "Закладка для ресурса URI «%s» уже существует" -#: glib/gbookmarkfile.c:2206 glib/gbookmarkfile.c:2364 -#: glib/gbookmarkfile.c:2449 glib/gbookmarkfile.c:2529 -#: glib/gbookmarkfile.c:2614 glib/gbookmarkfile.c:2748 -#: glib/gbookmarkfile.c:2881 glib/gbookmarkfile.c:3016 -#: glib/gbookmarkfile.c:3058 glib/gbookmarkfile.c:3155 -#: glib/gbookmarkfile.c:3276 glib/gbookmarkfile.c:3470 -#: glib/gbookmarkfile.c:3611 glib/gbookmarkfile.c:3830 -#: glib/gbookmarkfile.c:3919 glib/gbookmarkfile.c:4008 -#: glib/gbookmarkfile.c:4127 +#: glib/gbookmarkfile.c:2161 glib/gbookmarkfile.c:2319 +#: glib/gbookmarkfile.c:2404 glib/gbookmarkfile.c:2484 +#: glib/gbookmarkfile.c:2569 glib/gbookmarkfile.c:2703 +#: glib/gbookmarkfile.c:2836 glib/gbookmarkfile.c:2971 +#: glib/gbookmarkfile.c:3013 glib/gbookmarkfile.c:3110 +#: glib/gbookmarkfile.c:3231 glib/gbookmarkfile.c:3425 +#: glib/gbookmarkfile.c:3566 glib/gbookmarkfile.c:3785 +#: glib/gbookmarkfile.c:3874 glib/gbookmarkfile.c:3963 +#: glib/gbookmarkfile.c:4082 #, c-format msgid "No bookmark found for URI “%s”" msgstr "Для ресурса URI «%s» закладок не найдено" -#: glib/gbookmarkfile.c:2538 +#: glib/gbookmarkfile.c:2493 #, c-format msgid "No MIME type defined in the bookmark for URI “%s”" msgstr "В закладке на ресурс «%s» не определён тип MIME" -#: glib/gbookmarkfile.c:2623 +#: glib/gbookmarkfile.c:2578 #, c-format msgid "No private flag has been defined in bookmark for URI “%s”" msgstr "Отметка о приватности данных в закладке для URI «%s» не определена" -#: glib/gbookmarkfile.c:3164 +#: glib/gbookmarkfile.c:3119 #, c-format msgid "No groups set in bookmark for URI “%s”" msgstr "В закладке для URI «%s» не определена группа" -#: glib/gbookmarkfile.c:3632 glib/gbookmarkfile.c:3840 +#: glib/gbookmarkfile.c:3587 glib/gbookmarkfile.c:3795 #, c-format msgid "No application with name “%s” registered a bookmark for “%s”" msgstr "Нет приложения с именем «%s», создавшего закладку для «%s»" -#: glib/gbookmarkfile.c:3863 +#: glib/gbookmarkfile.c:3818 #, c-format msgid "Failed to expand exec line “%s” with URI “%s”" msgstr "Не удалось дополнить строку выполнения «%s» с помощью URI «%s»" -#: glib/gconvert.c:469 +#: glib/gconvert.c:370 msgid "Unrepresentable character in conversion input" msgstr "Во входной строке для преобразования обнаружен неотображаемый символ" -#: glib/gconvert.c:496 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 +#: glib/gconvert.c:397 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 #: glib/gutf8.c:1408 msgid "Partial character sequence at end of input" msgstr "" "Неполная символьная последовательность содержится в конце входных данных" -#: glib/gconvert.c:767 +#: glib/gconvert.c:668 #, c-format msgid "Cannot convert fallback “%s” to codeset “%s”" msgstr "Невозможно корректно преобразовать символ «%s» в символ из набора «%s»" -#: glib/gconvert.c:939 +#: glib/gconvert.c:840 msgid "Embedded NUL byte in conversion input" msgstr "Байт со значением NUL во входных преобразуемых данных" -#: glib/gconvert.c:960 +#: glib/gconvert.c:861 msgid "Embedded NUL byte in conversion output" msgstr "Байт со значением NUL в выходных преобразованных данных" -#: glib/gconvert.c:1698 +#: glib/gconvert.c:1599 #, c-format msgid "The URI “%s” is not an absolute URI using the “file” scheme" msgstr "" "URI «%s» не является абсолютным идентификатором при использовании схемы " "«file»" -#: glib/gconvert.c:1728 +#: glib/gconvert.c:1629 #, c-format msgid "The URI “%s” is invalid" msgstr "Недопустимый URI «%s»" -#: glib/gconvert.c:1741 +#: glib/gconvert.c:1642 #, c-format msgid "The hostname of the URI “%s” is invalid" msgstr "Недопустимое имя узла в URI «%s»" -#: glib/gconvert.c:1758 +#: glib/gconvert.c:1659 #, c-format msgid "The URI “%s” contains invalidly escaped characters" msgstr "URI «%s» содержит недопустимо экранированные символы" -#: glib/gconvert.c:1832 +#: glib/gconvert.c:1733 #, c-format msgid "The pathname “%s” is not an absolute path" msgstr "Путь «%s» не является абсолютным" #. Translators: this is the preferred format for expressing the date and the time -#: glib/gdatetime.c:228 +#: glib/gdatetime.c:196 msgctxt "GDateTime" msgid "%a %b %e %H:%M:%S %Y" msgstr "%a, %-d %b %Y, %H∶%M∶%S" #. Translators: this is the preferred format for expressing the date -#: glib/gdatetime.c:231 +#: glib/gdatetime.c:199 msgctxt "GDateTime" msgid "%m/%d/%y" msgstr "%d.%m.%y" #. Translators: this is the preferred format for expressing the time -#: glib/gdatetime.c:234 +#: glib/gdatetime.c:202 msgctxt "GDateTime" msgid "%H:%M:%S" msgstr "%H:%M:%S" #. Translators: this is the preferred format for expressing 12 hour time -#: glib/gdatetime.c:237 +#: glib/gdatetime.c:205 msgctxt "GDateTime" msgid "%I:%M:%S %p" msgstr "%-I∶%M∶%S %p" @@ -4686,62 +4692,62 @@ msgstr "%-I∶%M∶%S %p" #. * non-European) there is no difference between the standalone and #. * complete date form. #. -#: glib/gdatetime.c:276 +#: glib/gdatetime.c:244 msgctxt "full month name" msgid "January" msgstr "Январь" -#: glib/gdatetime.c:278 +#: glib/gdatetime.c:246 msgctxt "full month name" msgid "February" msgstr "Февраль" -#: glib/gdatetime.c:280 +#: glib/gdatetime.c:248 msgctxt "full month name" msgid "March" msgstr "Март" -#: glib/gdatetime.c:282 +#: glib/gdatetime.c:250 msgctxt "full month name" msgid "April" msgstr "Апрель" -#: glib/gdatetime.c:284 +#: glib/gdatetime.c:252 msgctxt "full month name" msgid "May" msgstr "Май" -#: glib/gdatetime.c:286 +#: glib/gdatetime.c:254 msgctxt "full month name" msgid "June" msgstr "Июнь" -#: glib/gdatetime.c:288 +#: glib/gdatetime.c:256 msgctxt "full month name" msgid "July" msgstr "Июль" -#: glib/gdatetime.c:290 +#: glib/gdatetime.c:258 msgctxt "full month name" msgid "August" msgstr "Август" -#: glib/gdatetime.c:292 +#: glib/gdatetime.c:260 msgctxt "full month name" msgid "September" msgstr "Сентябрь" -#: glib/gdatetime.c:294 +#: glib/gdatetime.c:262 msgctxt "full month name" msgid "October" msgstr "Октябрь" -#: glib/gdatetime.c:296 +#: glib/gdatetime.c:264 msgctxt "full month name" msgid "November" msgstr "Ноябрь" -#: glib/gdatetime.c:298 +#: glib/gdatetime.c:266 msgctxt "full month name" msgid "December" msgstr "Декабрь" @@ -4763,132 +4769,132 @@ msgstr "Декабрь" #. * other platform. Here are abbreviated month names in a form #. * appropriate when they are used standalone. #. -#: glib/gdatetime.c:330 +#: glib/gdatetime.c:298 msgctxt "abbreviated month name" msgid "Jan" msgstr "Янв" -#: glib/gdatetime.c:332 +#: glib/gdatetime.c:300 msgctxt "abbreviated month name" msgid "Feb" msgstr "Фев" -#: glib/gdatetime.c:334 +#: glib/gdatetime.c:302 msgctxt "abbreviated month name" msgid "Mar" msgstr "Мар" -#: glib/gdatetime.c:336 +#: glib/gdatetime.c:304 msgctxt "abbreviated month name" msgid "Apr" msgstr "Апр" -#: glib/gdatetime.c:338 +#: glib/gdatetime.c:306 msgctxt "abbreviated month name" msgid "May" msgstr "Май" -#: glib/gdatetime.c:340 +#: glib/gdatetime.c:308 msgctxt "abbreviated month name" msgid "Jun" msgstr "Июн" -#: glib/gdatetime.c:342 +#: glib/gdatetime.c:310 msgctxt "abbreviated month name" msgid "Jul" msgstr "Июл" -#: glib/gdatetime.c:344 +#: glib/gdatetime.c:312 msgctxt "abbreviated month name" msgid "Aug" msgstr "Авг" -#: glib/gdatetime.c:346 +#: glib/gdatetime.c:314 msgctxt "abbreviated month name" msgid "Sep" msgstr "Сен" -#: glib/gdatetime.c:348 +#: glib/gdatetime.c:316 msgctxt "abbreviated month name" msgid "Oct" msgstr "Окт" -#: glib/gdatetime.c:350 +#: glib/gdatetime.c:318 msgctxt "abbreviated month name" msgid "Nov" msgstr "Ноя" -#: glib/gdatetime.c:352 +#: glib/gdatetime.c:320 msgctxt "abbreviated month name" msgid "Dec" msgstr "Дек" -#: glib/gdatetime.c:367 +#: glib/gdatetime.c:335 msgctxt "full weekday name" msgid "Monday" msgstr "Понедельник" -#: glib/gdatetime.c:369 +#: glib/gdatetime.c:337 msgctxt "full weekday name" msgid "Tuesday" msgstr "Вторник" -#: glib/gdatetime.c:371 +#: glib/gdatetime.c:339 msgctxt "full weekday name" msgid "Wednesday" msgstr "Среда" -#: glib/gdatetime.c:373 +#: glib/gdatetime.c:341 msgctxt "full weekday name" msgid "Thursday" msgstr "Четверг" -#: glib/gdatetime.c:375 +#: glib/gdatetime.c:343 msgctxt "full weekday name" msgid "Friday" msgstr "Пятница" -#: glib/gdatetime.c:377 +#: glib/gdatetime.c:345 msgctxt "full weekday name" msgid "Saturday" msgstr "Суббота" -#: glib/gdatetime.c:379 +#: glib/gdatetime.c:347 msgctxt "full weekday name" msgid "Sunday" msgstr "Воскресенье" -#: glib/gdatetime.c:394 +#: glib/gdatetime.c:362 msgctxt "abbreviated weekday name" msgid "Mon" msgstr "Пн" -#: glib/gdatetime.c:396 +#: glib/gdatetime.c:364 msgctxt "abbreviated weekday name" msgid "Tue" msgstr "Вт" -#: glib/gdatetime.c:398 +#: glib/gdatetime.c:366 msgctxt "abbreviated weekday name" msgid "Wed" msgstr "Ср" -#: glib/gdatetime.c:400 +#: glib/gdatetime.c:368 msgctxt "abbreviated weekday name" msgid "Thu" msgstr "Чт" -#: glib/gdatetime.c:402 +#: glib/gdatetime.c:370 msgctxt "abbreviated weekday name" msgid "Fri" msgstr "Пт" -#: glib/gdatetime.c:404 +#: glib/gdatetime.c:372 msgctxt "abbreviated weekday name" msgid "Sat" msgstr "Сб" -#: glib/gdatetime.c:406 +#: glib/gdatetime.c:374 msgctxt "abbreviated weekday name" msgid "Sun" msgstr "Вс" @@ -4910,62 +4916,62 @@ msgstr "Вс" #. * (western European, non-European) there is no difference between the #. * standalone and complete date form. #. -#: glib/gdatetime.c:470 +#: glib/gdatetime.c:438 msgctxt "full month name with day" msgid "January" msgstr "Января" -#: glib/gdatetime.c:472 +#: glib/gdatetime.c:440 msgctxt "full month name with day" msgid "February" msgstr "Февраля" -#: glib/gdatetime.c:474 +#: glib/gdatetime.c:442 msgctxt "full month name with day" msgid "March" msgstr "Марта" -#: glib/gdatetime.c:476 +#: glib/gdatetime.c:444 msgctxt "full month name with day" msgid "April" msgstr "Апреля" -#: glib/gdatetime.c:478 +#: glib/gdatetime.c:446 msgctxt "full month name with day" msgid "May" msgstr "Мая" -#: glib/gdatetime.c:480 +#: glib/gdatetime.c:448 msgctxt "full month name with day" msgid "June" msgstr "Июня" -#: glib/gdatetime.c:482 +#: glib/gdatetime.c:450 msgctxt "full month name with day" msgid "July" msgstr "Июля" -#: glib/gdatetime.c:484 +#: glib/gdatetime.c:452 msgctxt "full month name with day" msgid "August" msgstr "Августа" -#: glib/gdatetime.c:486 +#: glib/gdatetime.c:454 msgctxt "full month name with day" msgid "September" msgstr "Сентября" -#: glib/gdatetime.c:488 +#: glib/gdatetime.c:456 msgctxt "full month name with day" msgid "October" msgstr "Октября" -#: glib/gdatetime.c:490 +#: glib/gdatetime.c:458 msgctxt "full month name with day" msgid "November" msgstr "Ноября" -#: glib/gdatetime.c:492 +#: glib/gdatetime.c:460 msgctxt "full month name with day" msgid "December" msgstr "Декабря" @@ -4987,74 +4993,74 @@ msgstr "Декабря" #. * month names almost ready to copy and paste here. In other systems #. * due to a bug the result is incorrect in some languages. #. -#: glib/gdatetime.c:557 +#: glib/gdatetime.c:525 msgctxt "abbreviated month name with day" msgid "Jan" msgstr "Янв" -#: glib/gdatetime.c:559 +#: glib/gdatetime.c:527 msgctxt "abbreviated month name with day" msgid "Feb" msgstr "Фев" -#: glib/gdatetime.c:561 +#: glib/gdatetime.c:529 msgctxt "abbreviated month name with day" msgid "Mar" msgstr "Мар" -#: glib/gdatetime.c:563 +#: glib/gdatetime.c:531 msgctxt "abbreviated month name with day" msgid "Apr" msgstr "Апр" -#: glib/gdatetime.c:565 +#: glib/gdatetime.c:533 msgctxt "abbreviated month name with day" msgid "May" msgstr "Мая" -#: glib/gdatetime.c:567 +#: glib/gdatetime.c:535 msgctxt "abbreviated month name with day" msgid "Jun" msgstr "Июн" -#: glib/gdatetime.c:569 +#: glib/gdatetime.c:537 msgctxt "abbreviated month name with day" msgid "Jul" msgstr "Июл" -#: glib/gdatetime.c:571 +#: glib/gdatetime.c:539 msgctxt "abbreviated month name with day" msgid "Aug" msgstr "Авг" -#: glib/gdatetime.c:573 +#: glib/gdatetime.c:541 msgctxt "abbreviated month name with day" msgid "Sep" msgstr "Сен" -#: glib/gdatetime.c:575 +#: glib/gdatetime.c:543 msgctxt "abbreviated month name with day" msgid "Oct" msgstr "Окт" -#: glib/gdatetime.c:577 +#: glib/gdatetime.c:545 msgctxt "abbreviated month name with day" msgid "Nov" msgstr "Ноя" -#: glib/gdatetime.c:579 +#: glib/gdatetime.c:547 msgctxt "abbreviated month name with day" msgid "Dec" msgstr "Дек" #. Translators: 'before midday' indicator -#: glib/gdatetime.c:596 +#: glib/gdatetime.c:564 msgctxt "GDateTime" msgid "AM" msgstr "ДП (AM)" #. Translators: 'after midday' indicator -#: glib/gdatetime.c:599 +#: glib/gdatetime.c:567 msgctxt "GDateTime" msgid "PM" msgstr "ПП (PM)" @@ -5064,120 +5070,124 @@ msgstr "ПП (PM)" msgid "Error opening directory “%s”: %s" msgstr "Произошла ошибка при открытии каталога «%s»: %s" -#: glib/gfileutils.c:753 glib/gfileutils.c:845 -#, c-format -msgid "Could not allocate %lu byte to read file “%s”" -msgid_plural "Could not allocate %lu bytes to read file “%s”" -msgstr[0] "Не удалось выделить %lu байт для чтения файла «%s»" -msgstr[1] "Не удалось выделить %lu байта для чтения файла «%s»" -msgstr[2] "Не удалось выделить %lu байт для чтения файла «%s»" +#: glib/gfileutils.c:753 glib/gfileutils.c:857 +msgid "Could not allocate %" +msgid_plural "Could not allocate %" +msgstr[0] "Не удалось распределить %" +msgstr[1] "Не удалось распределить %" +msgstr[2] "Не удалось распределить %" #: glib/gfileutils.c:770 #, c-format msgid "Error reading file “%s”: %s" msgstr "Ошибка при чтении файла «%s»: %s" -#: glib/gfileutils.c:806 +#: glib/gfileutils.c:806 glib/gfileutils.c:840 #, c-format msgid "File “%s” is too large" msgstr "Файл «%s» слишком велик" -#: glib/gfileutils.c:870 +#: glib/gfileutils.c:882 #, c-format msgid "Failed to read from file “%s”: %s" msgstr "Не удалось прочитать из файла «%s»: %s" -#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1472 +#: glib/gfileutils.c:932 glib/gfileutils.c:1007 glib/gfileutils.c:1514 #, c-format msgid "Failed to open file “%s”: %s" msgstr "Не удалось открыть файл «%s»: %s" -#: glib/gfileutils.c:933 +#: glib/gfileutils.c:945 #, c-format msgid "Failed to get attributes of file “%s”: fstat() failed: %s" msgstr "Не удалось получить атрибуты файла «%s»: сбой в функции fstat(): %s" -#: glib/gfileutils.c:964 +#: glib/gfileutils.c:976 #, c-format msgid "Failed to open file “%s”: fdopen() failed: %s" msgstr "Не удалось открыть файл «%s»: сбой в функции fdopen(): %s" -#: glib/gfileutils.c:1065 +#: glib/gfileutils.c:1077 #, c-format msgid "Failed to rename file “%s” to “%s”: g_rename() failed: %s" msgstr "" "Не удалось переименовать файл «%s» в «%s»: сбой в функции g_rename(): %s" -#: glib/gfileutils.c:1179 +#: glib/gfileutils.c:1176 +#, c-format +msgid "Failed to write file “%s”: ftruncate() failed: %s" +msgstr "Не удалось записать файл «%s»: сбой в функции ftruncate(): %s" + +#: glib/gfileutils.c:1221 #, c-format msgid "Failed to write file “%s”: write() failed: %s" msgstr "Не удалось записать файл «%s»: сбой в функции write(): %s" -#: glib/gfileutils.c:1200 +#: glib/gfileutils.c:1242 #, c-format msgid "Failed to write file “%s”: fsync() failed: %s" msgstr "Не удалось записать файл «%s»: сбой в функции fsync(): %s" -#: glib/gfileutils.c:1361 glib/gfileutils.c:1776 +#: glib/gfileutils.c:1403 glib/gfileutils.c:1820 #, c-format msgid "Failed to create file “%s”: %s" msgstr "Не удалось создать файл «%s»: %s" -#: glib/gfileutils.c:1406 +#: glib/gfileutils.c:1448 #, c-format msgid "Existing file “%s” could not be removed: g_unlink() failed: %s" msgstr "" "Не удалось удалить существующий файл «%s»: сбой в функции g_unlink(): %s" -#: glib/gfileutils.c:1741 +#: glib/gfileutils.c:1785 #, c-format msgid "Template “%s” invalid, should not contain a “%s”" msgstr "Шаблон «%s» недопустим: он не должен содержать «%s»" -#: glib/gfileutils.c:1754 +#: glib/gfileutils.c:1798 #, c-format msgid "Template “%s” doesn’t contain XXXXXX" msgstr "Шаблон «%s» не содержит XXXXXX" -#: glib/gfileutils.c:2348 glib/gfileutils.c:2377 +#: glib/gfileutils.c:2392 glib/gfileutils.c:2421 #, c-format msgid "Failed to read the symbolic link “%s”: %s" msgstr "Не удалось прочитать символьную ссылку «%s»: %s" -#: glib/giochannel.c:1408 +#: glib/giochannel.c:1397 #, c-format msgid "Could not open converter from “%s” to “%s”: %s" msgstr "Не удалось открыть преобразователь из «%s» в «%s»: %s" -#: glib/giochannel.c:1761 +#: glib/giochannel.c:1750 msgid "Can’t do a raw read in g_io_channel_read_line_string" msgstr "" "Невозможно выполнить непосредственное чтение в функции " "g_io_channel_read_line_string" -#: glib/giochannel.c:1808 glib/giochannel.c:2066 glib/giochannel.c:2153 +#: glib/giochannel.c:1797 glib/giochannel.c:2055 glib/giochannel.c:2142 msgid "Leftover unconverted data in read buffer" msgstr "В буфере чтения остались непреобразованные данные" -#: glib/giochannel.c:1889 glib/giochannel.c:1966 +#: glib/giochannel.c:1878 glib/giochannel.c:1955 msgid "Channel terminates in a partial character" msgstr "Канал закрывается на неполном символе" -#: glib/giochannel.c:1952 +#: glib/giochannel.c:1941 msgid "Can’t do a raw read in g_io_channel_read_to_end" msgstr "" "Невозможно выполнить непосредственное чтение в функции " "g_io_channel_read_to_end" -#: glib/gkeyfile.c:802 +#: glib/gkeyfile.c:791 msgid "Valid key file could not be found in search dirs" msgstr "В каталогах поиска не удалось найти допустимый файл ключей" -#: glib/gkeyfile.c:839 +#: glib/gkeyfile.c:828 msgid "Not a regular file" msgstr "Не является обычным файлом" -#: glib/gkeyfile.c:1297 +#: glib/gkeyfile.c:1286 #, c-format msgid "" "Key file contains line “%s” which is not a key-value pair, group, or comment" @@ -5185,44 +5195,44 @@ msgstr "" "Файл ключей содержит строку «%s», которая не является парой «ключ-значение», " "группой или комментарием" -#: glib/gkeyfile.c:1354 +#: glib/gkeyfile.c:1343 #, c-format msgid "Invalid group name: %s" msgstr "Недопустимое имя группы: %s" -#: glib/gkeyfile.c:1378 +#: glib/gkeyfile.c:1367 msgid "Key file does not start with a group" msgstr "Файл ключей не начинается с группы" -#: glib/gkeyfile.c:1402 +#: glib/gkeyfile.c:1391 #, c-format msgid "Invalid key name: %.*s" msgstr "Недопустимое имя ключа: %.*s" -#: glib/gkeyfile.c:1430 +#: glib/gkeyfile.c:1419 #, c-format msgid "Key file contains unsupported encoding “%s”" msgstr "Файл ключей содержит неподдерживаемую кодировку «%s»" -#: glib/gkeyfile.c:1678 glib/gkeyfile.c:1851 glib/gkeyfile.c:3298 -#: glib/gkeyfile.c:3400 glib/gkeyfile.c:3505 glib/gkeyfile.c:3634 -#: glib/gkeyfile.c:3777 glib/gkeyfile.c:4026 glib/gkeyfile.c:4100 +#: glib/gkeyfile.c:1667 glib/gkeyfile.c:1840 glib/gkeyfile.c:3287 +#: glib/gkeyfile.c:3389 glib/gkeyfile.c:3494 glib/gkeyfile.c:3623 +#: glib/gkeyfile.c:3766 glib/gkeyfile.c:4015 glib/gkeyfile.c:4089 #, c-format msgid "Key file does not have group “%s”" msgstr "Файл ключей не содержит группу «%s»" -#: glib/gkeyfile.c:1806 +#: glib/gkeyfile.c:1795 #, c-format msgid "Key file does not have key “%s” in group “%s”" msgstr "Файл ключей не содержит ключа «%s» в группе «%s»" -#: glib/gkeyfile.c:1968 glib/gkeyfile.c:2084 +#: glib/gkeyfile.c:1957 glib/gkeyfile.c:2073 #, c-format msgid "Key file contains key “%s” with value “%s” which is not UTF-8" msgstr "" "Файл ключей содержит ключ «%s», значение которого «%s» не в кодировке UTF-8" -#: glib/gkeyfile.c:1988 glib/gkeyfile.c:2104 glib/gkeyfile.c:2543 +#: glib/gkeyfile.c:1977 glib/gkeyfile.c:2093 glib/gkeyfile.c:2532 #, c-format msgid "" "Key file contains key “%s” which has a value that cannot be interpreted." @@ -5230,7 +5240,7 @@ msgstr "" "Файл ключей содержит ключ «%s», значение которого не удалось " "интерпретировать." -#: glib/gkeyfile.c:2758 glib/gkeyfile.c:3127 +#: glib/gkeyfile.c:2747 glib/gkeyfile.c:3116 #, c-format msgid "" "Key file contains key “%s” in group “%s” which has a value that cannot be " @@ -5239,36 +5249,36 @@ msgstr "" "Файл ключей содержит ключ «%s» в группе «%s», значение которого не удалось " "интерпретировать." -#: glib/gkeyfile.c:2836 glib/gkeyfile.c:2913 +#: glib/gkeyfile.c:2825 glib/gkeyfile.c:2902 #, c-format msgid "Key “%s” in group “%s” has value “%s” where %s was expected" msgstr "Значение ключа «%s» в группе «%s» имеет значение «%s», но ожидалось %s" -#: glib/gkeyfile.c:4356 +#: glib/gkeyfile.c:4345 msgid "Key file contains escape character at end of line" msgstr "Файл ключей содержит символ escape в конце строки" -#: glib/gkeyfile.c:4378 +#: glib/gkeyfile.c:4367 #, c-format msgid "Key file contains invalid escape sequence “%s”" msgstr "Файл ключей содержит неверную экранирующую последовательность «%s»" -#: glib/gkeyfile.c:4530 +#: glib/gkeyfile.c:4519 #, c-format msgid "Value “%s” cannot be interpreted as a number." msgstr "Не удалось преобразовать значение «%s» в число." -#: glib/gkeyfile.c:4544 +#: glib/gkeyfile.c:4533 #, c-format msgid "Integer value “%s” out of range" msgstr "Целочисленное значение «%s» выходит за пределы" -#: glib/gkeyfile.c:4577 +#: glib/gkeyfile.c:4566 #, c-format msgid "Value “%s” cannot be interpreted as a float number." msgstr "Не удалось преобразовать «%s» в число с плавающей запятой." -#: glib/gkeyfile.c:4616 +#: glib/gkeyfile.c:4605 #, c-format msgid "Value “%s” cannot be interpreted as a boolean." msgstr "Не удалось преобразовать «%s» в булево значение." @@ -5289,33 +5299,33 @@ msgstr "Не удалось отобразить файл «%s%s%s%s»: сбой msgid "Failed to open file “%s”: open() failed: %s" msgstr "Не удалось открыть файл «%s»: сбой в функции open(): %s" -#: glib/gmarkup.c:398 glib/gmarkup.c:440 +#: glib/gmarkup.c:344 glib/gmarkup.c:386 #, c-format msgid "Error on line %d char %d: " msgstr "Ошибка в строке %d на символе %d: " -#: glib/gmarkup.c:462 glib/gmarkup.c:545 +#: glib/gmarkup.c:408 glib/gmarkup.c:491 #, c-format msgid "Invalid UTF-8 encoded text in name — not valid “%s”" msgstr "" "Недопустимый UTF-8 текст в имени — неправильная последовательность «%s»" -#: glib/gmarkup.c:473 +#: glib/gmarkup.c:419 #, c-format msgid "“%s” is not a valid name" msgstr "Имя «%s» недопустимо" -#: glib/gmarkup.c:489 +#: glib/gmarkup.c:435 #, c-format msgid "“%s” is not a valid name: “%c”" msgstr "Имя «%s» недопустимо: «%c»" -#: glib/gmarkup.c:613 +#: glib/gmarkup.c:559 #, c-format msgid "Error on line %d: %s" msgstr "Ошибка в строке %d: %s" -#: glib/gmarkup.c:690 +#: glib/gmarkup.c:636 #, c-format msgid "" "Failed to parse “%-.*s”, which should have been a digit inside a character " @@ -5324,7 +5334,7 @@ msgstr "" "Не удалось разобрать строку «%-.*s», которая должна быть числом внутри кода " "символа (например ê) — возможно, число слишком велико" -#: glib/gmarkup.c:702 +#: glib/gmarkup.c:648 msgid "" "Character reference did not end with a semicolon; most likely you used an " "ampersand character without intending to start an entity — escape ampersand " @@ -5333,24 +5343,24 @@ msgstr "" "Код символа не оканчивается точкой с запятой; похоже, символ «&» был " "использован не для обозначения начала конструкции — экранируйте его как &" -#: glib/gmarkup.c:728 +#: glib/gmarkup.c:674 #, c-format msgid "Character reference “%-.*s” does not encode a permitted character" msgstr "Код «%-.*s» не определяет допустимый символ" -#: glib/gmarkup.c:766 +#: glib/gmarkup.c:712 msgid "" "Empty entity “&;” seen; valid entities are: & " < > '" msgstr "" "Обнаружена пустая конструкция «&;»; допустимыми конструкциями являются: " "& " < > '" -#: glib/gmarkup.c:774 +#: glib/gmarkup.c:720 #, c-format msgid "Entity name “%-.*s” is not known" msgstr "Имя сущности «%-.*s» неизвестно" -#: glib/gmarkup.c:779 +#: glib/gmarkup.c:725 msgid "" "Entity did not end with a semicolon; most likely you used an ampersand " "character without intending to start an entity — escape ampersand as &" @@ -5359,11 +5369,11 @@ msgstr "" "использован не для обозначения начала конструкции — экранируйте его как " "«&" -#: glib/gmarkup.c:1193 +#: glib/gmarkup.c:1139 msgid "Document must begin with an element (e.g. )" msgstr "Документ должен начинаться с элемента (например )" -#: glib/gmarkup.c:1233 +#: glib/gmarkup.c:1179 #, c-format msgid "" "“%s” is not a valid character following a “<” character; it may not begin an " @@ -5372,7 +5382,7 @@ msgstr "" "Символ «%s» является недопустимым после символа «<»; этот символ не может " "начинать имя элемента" -#: glib/gmarkup.c:1276 +#: glib/gmarkup.c:1222 #, c-format msgid "" "Odd character “%s”, expected a “>” character to end the empty-element tag " @@ -5381,12 +5391,12 @@ msgstr "" "Встретился лишний символ «%s», ожидался символ «>» для завершения пустого " "элемента тэга «%s»" -#: glib/gmarkup.c:1346 +#: glib/gmarkup.c:1292 #, c-format msgid "Too many attributes in element “%s”" msgstr "Слишком много атрибутов для элемента «%s»" -#: glib/gmarkup.c:1366 +#: glib/gmarkup.c:1312 #, c-format msgid "" "Odd character “%s”, expected a “=” after attribute name “%s” of element “%s”" @@ -5394,7 +5404,7 @@ msgstr "" "Встретился лишний символ «%s», ожидался символ «=» после имени атрибута «%s» " "элемента «%s»" -#: glib/gmarkup.c:1408 +#: glib/gmarkup.c:1354 #, c-format msgid "" "Odd character “%s”, expected a “>” or “/” character to end the start tag of " @@ -5405,7 +5415,7 @@ msgstr "" "открывающего тэга элемента «%s», либо, возможно, атрибут; может быть, был " "использован недопустимый символ в имени атрибута" -#: glib/gmarkup.c:1453 +#: glib/gmarkup.c:1399 #, c-format msgid "" "Odd character “%s”, expected an open quote mark after the equals sign when " @@ -5414,7 +5424,7 @@ msgstr "" "Встретился лишний символ «%s», ожидалась открывающая двойная кавычка после " "знака равенства при присваивании значения атрибуту «%s» элемента «%s»" -#: glib/gmarkup.c:1587 +#: glib/gmarkup.c:1533 #, c-format msgid "" "“%s” is not a valid character following the characters “»" -#: glib/gmarkup.c:1637 +#: glib/gmarkup.c:1583 #, c-format msgid "Element “%s” was closed, no element is currently open" msgstr "Элемент «%s» был закрыт, ни один элемент в настоящий момент не открыт" -#: glib/gmarkup.c:1646 +#: glib/gmarkup.c:1592 #, c-format msgid "Element “%s” was closed, but the currently open element is “%s”" msgstr "" "Элемент «%s» был закрыт, но открытым в настоящий момент является элемент «%s»" -#: glib/gmarkup.c:1799 +#: glib/gmarkup.c:1745 msgid "Document was empty or contained only whitespace" msgstr "Документ был пуст или содержал только пробелы" -#: glib/gmarkup.c:1813 +#: glib/gmarkup.c:1759 msgid "Document ended unexpectedly just after an open angle bracket “<”" msgstr "" "Документ неожиданно окончился сразу же после открывающей угловой скобки «<»" -#: glib/gmarkup.c:1821 glib/gmarkup.c:1866 +#: glib/gmarkup.c:1767 glib/gmarkup.c:1812 #, c-format msgid "" "Document ended unexpectedly with elements still open — “%s” was the last " @@ -5461,7 +5471,7 @@ msgstr "" "Документ неожиданно окончился, когда ещё были открыты элементы — «%s» был " "последним открытым элементом" -#: glib/gmarkup.c:1829 +#: glib/gmarkup.c:1775 #, c-format msgid "" "Document ended unexpectedly, expected to see a close angle bracket ending " @@ -5469,19 +5479,19 @@ msgid "" msgstr "" "Документ неожиданно окончился, ожидалась закрывающая тэг <%s/> угловая скобка" -#: glib/gmarkup.c:1835 +#: glib/gmarkup.c:1781 msgid "Document ended unexpectedly inside an element name" msgstr "Документ неожиданно окончился внутри имени элемента" -#: glib/gmarkup.c:1841 +#: glib/gmarkup.c:1787 msgid "Document ended unexpectedly inside an attribute name" msgstr "Документ неожиданно окончился внутри имени атрибута" -#: glib/gmarkup.c:1846 +#: glib/gmarkup.c:1792 msgid "Document ended unexpectedly inside an element-opening tag." msgstr "Документ неожиданно окончился внутри открывающего элемент тэга." -#: glib/gmarkup.c:1852 +#: glib/gmarkup.c:1798 msgid "" "Document ended unexpectedly after the equals sign following an attribute " "name; no attribute value" @@ -5489,262 +5499,262 @@ msgstr "" "Документ неожиданно окончился после знака равенства, следующего за именем " "атрибута; значение атрибута не указано" -#: glib/gmarkup.c:1859 +#: glib/gmarkup.c:1805 msgid "Document ended unexpectedly while inside an attribute value" msgstr "Документ неожиданно окончился внутри значения атрибута" -#: glib/gmarkup.c:1876 +#: glib/gmarkup.c:1822 #, c-format msgid "Document ended unexpectedly inside the close tag for element “%s”" msgstr "Документ неожиданно окончился внутри тэга, закрывающего элемент «%s»" -#: glib/gmarkup.c:1880 +#: glib/gmarkup.c:1826 msgid "" "Document ended unexpectedly inside the close tag for an unopened element" msgstr "Документ неожиданно окончился внутри закрывающего элемент тэга" -#: glib/gmarkup.c:1886 +#: glib/gmarkup.c:1832 msgid "Document ended unexpectedly inside a comment or processing instruction" msgstr "" "Документ неожиданно окончился внутри комментария или инструкции обработки" -#: glib/goption.c:875 +#: glib/goption.c:716 msgid "[OPTION…]" msgstr "[ПАРАМЕТР…]" -#: glib/goption.c:991 +#: glib/goption.c:832 msgid "Help Options:" msgstr "Параметры справки:" -#: glib/goption.c:992 +#: glib/goption.c:833 msgid "Show help options" msgstr "Показать параметры справки" -#: glib/goption.c:998 +#: glib/goption.c:839 msgid "Show all help options" msgstr "Показать все параметры справки" -#: glib/goption.c:1061 +#: glib/goption.c:902 msgid "Application Options:" msgstr "Параметры приложения:" -#: glib/goption.c:1063 +#: glib/goption.c:904 msgid "Options:" msgstr "Параметры:" -#: glib/goption.c:1127 glib/goption.c:1197 +#: glib/goption.c:968 glib/goption.c:1038 #, c-format msgid "Cannot parse integer value “%s” for %s" msgstr "Не удалось разобрать целочисленное значение «%s» для %s" -#: glib/goption.c:1137 glib/goption.c:1205 +#: glib/goption.c:978 glib/goption.c:1046 #, c-format msgid "Integer value “%s” for %s out of range" msgstr "Целочисленное значение «%s» для %s выходит за пределы" -#: glib/goption.c:1162 +#: glib/goption.c:1003 #, c-format msgid "Cannot parse double value “%s” for %s" msgstr "Не удалось разобрать дробное значение двойной точности «%s» для %s" -#: glib/goption.c:1170 +#: glib/goption.c:1011 #, c-format msgid "Double value “%s” for %s out of range" msgstr "Дробное значение двойной точности «%s» для %s выходит за пределы" -#: glib/goption.c:1462 glib/goption.c:1541 +#: glib/goption.c:1303 glib/goption.c:1382 #, c-format msgid "Error parsing option %s" msgstr "Произошла ошибка при разборе параметра %s" -#: glib/goption.c:1563 glib/goption.c:1676 +#: glib/goption.c:1404 glib/goption.c:1517 #, c-format msgid "Missing argument for %s" msgstr "Отсутствует аргумент для %s" -#: glib/goption.c:2186 +#: glib/goption.c:2024 #, c-format msgid "Unknown option %s" msgstr "Неизвестный параметр %s" -#: glib/gregex.c:480 +#: glib/gregex.c:478 msgid "corrupted object" msgstr "повреждённый объект" -#: glib/gregex.c:482 +#: glib/gregex.c:480 msgid "out of memory" msgstr "закончилась память" -#: glib/gregex.c:497 +#: glib/gregex.c:495 msgid "internal error" msgstr "внутренняя ошибка" -#: glib/gregex.c:499 +#: glib/gregex.c:497 msgid "the pattern contains items not supported for partial matching" msgstr "" "шаблон содержит элементы, которые не поддерживаются при поиске частичного " "совпадения" -#: glib/gregex.c:501 +#: glib/gregex.c:499 msgid "back references as conditions are not supported for partial matching" msgstr "" "условия в виде обратных ссылок при поиске частичного совпадения не " "поддерживаются" -#: glib/gregex.c:507 +#: glib/gregex.c:505 msgid "recursion limit reached" msgstr "достигнут предел рекурсии" -#: glib/gregex.c:509 +#: glib/gregex.c:507 msgid "bad offset" msgstr "неправильное смещение" -#: glib/gregex.c:511 +#: glib/gregex.c:509 msgid "recursion loop" msgstr "зацикливание рекурсии" #. should not happen in GRegex since we check modes before each match -#: glib/gregex.c:514 +#: glib/gregex.c:512 msgid "matching mode is requested that was not compiled for JIT" msgstr "запрашивается режим согласования, который не был скомпилирован для JIT" -#: glib/gregex.c:535 glib/gregex.c:1851 +#: glib/gregex.c:533 glib/gregex.c:1849 msgid "unknown error" msgstr "неизвестная ошибка" -#: glib/gregex.c:556 +#: glib/gregex.c:554 msgid "\\ at end of pattern" msgstr "\\ в конце шаблона" -#: glib/gregex.c:560 +#: glib/gregex.c:558 msgid "\\c at end of pattern" msgstr "\\c в конце шаблона" -#: glib/gregex.c:565 +#: glib/gregex.c:563 msgid "unrecognized character following \\" msgstr "неопознанный символ следует за \\" -#: glib/gregex.c:569 +#: glib/gregex.c:567 msgid "numbers out of order in {} quantifier" msgstr "числа в квантификаторе {} в неправильном порядке" -#: glib/gregex.c:573 +#: glib/gregex.c:571 msgid "number too big in {} quantifier" msgstr "слишком большое число в квантификаторе {}" -#: glib/gregex.c:577 +#: glib/gregex.c:575 msgid "missing terminating ] for character class" msgstr "отсутствует завершающая ] для класса символов" -#: glib/gregex.c:581 +#: glib/gregex.c:579 msgid "invalid escape sequence in character class" msgstr "неверное экранирование в классе символов" -#: glib/gregex.c:585 +#: glib/gregex.c:583 msgid "range out of order in character class" msgstr "диапазон в классе символов в неправильном порядке" -#: glib/gregex.c:590 +#: glib/gregex.c:588 msgid "nothing to repeat" msgstr "нечего повторять" -#: glib/gregex.c:594 +#: glib/gregex.c:592 msgid "unrecognized character after (? or (?-" msgstr "неопознанный символ после (? или (?-" -#: glib/gregex.c:598 +#: glib/gregex.c:596 msgid "POSIX named classes are supported only within a class" msgstr "Именованные классы POSIX поддерживаются только внутри класса" -#: glib/gregex.c:602 +#: glib/gregex.c:600 msgid "POSIX collating elements are not supported" msgstr "Сортировочные элементы POSIX не поддерживаются" -#: glib/gregex.c:608 +#: glib/gregex.c:606 msgid "missing terminating )" msgstr "отсутствует завершающая )" -#: glib/gregex.c:612 +#: glib/gregex.c:610 msgid "reference to non-existent subpattern" msgstr "ссылка на несуществующий подшаблон" -#: glib/gregex.c:616 +#: glib/gregex.c:614 msgid "missing ) after comment" msgstr "отсутствует ) после комментария" -#: glib/gregex.c:620 +#: glib/gregex.c:618 msgid "regular expression is too large" msgstr "слишком длинное регулярное выражение" -#: glib/gregex.c:624 +#: glib/gregex.c:622 msgid "malformed number or name after (?(" msgstr "ошибочное число или имя после (?(" -#: glib/gregex.c:628 +#: glib/gregex.c:626 msgid "lookbehind assertion is not fixed length" msgstr "lookbehind-утверждение не имеет фиксированную длину" -#: glib/gregex.c:632 +#: glib/gregex.c:630 msgid "conditional group contains more than two branches" msgstr "условная группа содержит более двух ветвей" -#: glib/gregex.c:636 +#: glib/gregex.c:634 msgid "assertion expected after (?(" msgstr "ожидалось утверждение после (?(" -#: glib/gregex.c:640 +#: glib/gregex.c:638 msgid "a numbered reference must not be zero" msgstr "номерная ссылка не может быть нулём" -#: glib/gregex.c:644 +#: glib/gregex.c:642 msgid "unknown POSIX class name" msgstr "неизвестное имя класса POSIX" -#: glib/gregex.c:649 +#: glib/gregex.c:647 msgid "character value in \\x{...} sequence is too large" msgstr "значение символа в последовательности \\x{...} слишком велико" -#: glib/gregex.c:653 +#: glib/gregex.c:651 msgid "\\C not allowed in lookbehind assertion" msgstr "\\C запрещено в lookbehind-утверждениях" -#: glib/gregex.c:657 +#: glib/gregex.c:655 msgid "missing terminator in subpattern name" msgstr "отсутствует завершающий символ в имени подшаблона" -#: glib/gregex.c:661 +#: glib/gregex.c:659 msgid "two named subpatterns have the same name" msgstr "два именованных подшаблона имеют одинаковое имя" -#: glib/gregex.c:665 +#: glib/gregex.c:663 msgid "malformed \\P or \\p sequence" msgstr "ошибочная последовательность \\P или \\p" -#: glib/gregex.c:669 +#: glib/gregex.c:667 msgid "unknown property name after \\P or \\p" msgstr "неизвестное имя свойства после \\P или \\p" -#: glib/gregex.c:673 +#: glib/gregex.c:671 msgid "subpattern name is too long (maximum 32 characters)" msgstr "имя подшаблона слишком длинное (не должно превышать 32 символа)" -#: glib/gregex.c:677 +#: glib/gregex.c:675 msgid "too many named subpatterns (maximum 10,000)" msgstr "слишком много именованных подшаблонов (не должно быть больше 10 000)" -#: glib/gregex.c:681 +#: glib/gregex.c:679 msgid "octal value is greater than \\377" msgstr "восьмеричное значение превышает \\377" -#: glib/gregex.c:685 +#: glib/gregex.c:683 msgid "DEFINE group contains more than one branch" msgstr "Группа DEFINE содержит более одной ветви" -#: glib/gregex.c:689 +#: glib/gregex.c:687 msgid "inconsistent NEWLINE options" msgstr "противоречивые параметры NEWLINE" -#: glib/gregex.c:693 +#: glib/gregex.c:691 msgid "" "\\g is not followed by a braced, angle-bracketed, or quoted name or number, " "or by a plain number" @@ -5752,122 +5762,122 @@ msgstr "" "за \\g не следует имя или число в скобках, угловых скобках или кавычках, или " "просто число" -#: glib/gregex.c:698 +#: glib/gregex.c:696 msgid "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" msgstr "нельзя указать параметр для (*ACCEPT), (*FAIL) или (*COMMIT)" -#: glib/gregex.c:702 +#: glib/gregex.c:700 msgid "(*VERB) not recognized" msgstr "значение (*VERB) не распознано" -#: glib/gregex.c:706 +#: glib/gregex.c:704 msgid "number is too big" msgstr "слишком большое число" -#: glib/gregex.c:710 +#: glib/gregex.c:708 msgid "missing subpattern name after (?&" msgstr "отсутствует имя подшаблона после (?&" -#: glib/gregex.c:714 +#: glib/gregex.c:712 msgid "different names for subpatterns of the same number are not allowed" msgstr "" "не допускаются использовать различные имена для подшаблонов с одинаковым " "номером" -#: glib/gregex.c:718 +#: glib/gregex.c:716 msgid "(*MARK) must have an argument" msgstr "для (*MARK) требуется параметр" -#: glib/gregex.c:722 +#: glib/gregex.c:720 msgid "\\c must be followed by an ASCII character" msgstr "за \\c должен быть символ ASCII" -#: glib/gregex.c:726 +#: glib/gregex.c:724 msgid "\\k is not followed by a braced, angle-bracketed, or quoted name" msgstr "за \\k не следует имя в скобках, угловых скобках или кавычках" -#: glib/gregex.c:730 +#: glib/gregex.c:728 msgid "\\N is not supported in a class" msgstr "\\N в классе не поддерживается" -#: glib/gregex.c:734 +#: glib/gregex.c:732 msgid "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" msgstr "слишком длинное имя в (*MARK), (*PRUNE), (*SKIP) или (*THEN)" -#: glib/gregex.c:738 glib/gregex.c:874 +#: glib/gregex.c:736 glib/gregex.c:872 msgid "code overflow" msgstr "переполнение кода" -#: glib/gregex.c:742 +#: glib/gregex.c:740 msgid "unrecognized character after (?P" msgstr "неопознанный символ после (?P" -#: glib/gregex.c:746 +#: glib/gregex.c:744 msgid "overran compiling workspace" msgstr "переполнение рабочего пространства компиляции" -#: glib/gregex.c:750 +#: glib/gregex.c:748 msgid "previously-checked referenced subpattern not found" msgstr "не найден ранее проверенный подшаблон со ссылкой" -#: glib/gregex.c:873 glib/gregex.c:1135 glib/gregex.c:2457 +#: glib/gregex.c:871 glib/gregex.c:1133 glib/gregex.c:2455 #, c-format msgid "Error while matching regular expression %s: %s" msgstr "" "Во время поиска совпадений с регулярным выражением %s возникла ошибка: %s" -#: glib/gregex.c:1735 +#: glib/gregex.c:1733 msgid "PCRE library is compiled without UTF8 support" msgstr "Библиотека PCRE собрана без поддержки UTF-8" -#: glib/gregex.c:1743 +#: glib/gregex.c:1741 msgid "PCRE library is compiled with incompatible options" msgstr "Библиотека PCRE собрана с несовместимыми параметрами" -#: glib/gregex.c:1860 +#: glib/gregex.c:1858 #, c-format msgid "Error while compiling regular expression ‘%s’ at char %s: %s" msgstr "" "Произошла ошибка при компиляции регулярного выражения '%s' у символа с " "номером %s: %s" -#: glib/gregex.c:2900 +#: glib/gregex.c:2898 msgid "hexadecimal digit or “}” expected" msgstr "ожидалась шестнадцатеричная цифра или символ «}»" -#: glib/gregex.c:2916 +#: glib/gregex.c:2914 msgid "hexadecimal digit expected" msgstr "ожидалась шестнадцатеричная цифра" -#: glib/gregex.c:2956 +#: glib/gregex.c:2954 msgid "missing “<” in symbolic reference" msgstr "в символьной ссылке отсутствует «<»" -#: glib/gregex.c:2965 +#: glib/gregex.c:2963 msgid "unfinished symbolic reference" msgstr "незаконченная символьная ссылка" -#: glib/gregex.c:2972 +#: glib/gregex.c:2970 msgid "zero-length symbolic reference" msgstr "символьная ссылка нулевой длины" -#: glib/gregex.c:2983 +#: glib/gregex.c:2981 msgid "digit expected" msgstr "ожидалась цифра" -#: glib/gregex.c:3001 +#: glib/gregex.c:2999 msgid "illegal symbolic reference" msgstr "недопустимая символьная ссылка" -#: glib/gregex.c:3064 +#: glib/gregex.c:3062 msgid "stray final “\\”" msgstr "лишний «\\» в конце" -#: glib/gregex.c:3068 +#: glib/gregex.c:3066 msgid "unknown escape sequence" msgstr "неизвестная экранирующая последовательность" -#: glib/gregex.c:3078 +#: glib/gregex.c:3076 #, c-format msgid "Error while parsing replacement text “%s” at char %lu: %s" msgstr "" @@ -5900,92 +5910,92 @@ msgstr "" msgid "Text was empty (or contained only whitespace)" msgstr "Текст был пуст (или содержал только пробелы)" -#: glib/gspawn.c:320 +#: glib/gspawn.c:303 #, c-format msgid "Failed to read data from child process (%s)" msgstr "Не удалось прочитать данные из дочернего процесса (%s)" -#: glib/gspawn.c:473 +#: glib/gspawn.c:456 #, c-format msgid "Unexpected error in reading data from a child process (%s)" msgstr "Неожиданная ошибка при чтении данных из дочернего процесса (%s)" -#: glib/gspawn.c:558 +#: glib/gspawn.c:536 #, c-format msgid "Unexpected error in waitpid() (%s)" msgstr "Произошла неожиданная ошибка в функции waitpid() (%s)" -#: glib/gspawn.c:1180 glib/gspawn-win32.c:1575 +#: glib/gspawn.c:1158 glib/gspawn-win32.c:1575 #, c-format msgid "Child process exited with code %ld" msgstr "Дочерний процесс завершился с кодом %ld" -#: glib/gspawn.c:1188 +#: glib/gspawn.c:1166 #, c-format msgid "Child process killed by signal %ld" msgstr "Дочерний процесс убит по сигналу %ld" -#: glib/gspawn.c:1195 +#: glib/gspawn.c:1173 #, c-format msgid "Child process stopped by signal %ld" msgstr "Дочерний процесс остановлен по сигналу %ld" -#: glib/gspawn.c:1202 +#: glib/gspawn.c:1180 #, c-format msgid "Child process exited abnormally" msgstr "Дочерний процесс аварийно завершил работу" -#: glib/gspawn.c:2032 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 +#: glib/gspawn.c:2017 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 #, c-format msgid "Failed to read from child pipe (%s)" msgstr "Не удалось выполнить чтение из дочернего канала (%s)" -#: glib/gspawn.c:2404 +#: glib/gspawn.c:2396 #, c-format msgid "Failed to spawn child process “%s” (%s)" msgstr "Не удалось запустить дочерний процесс \"%s\" (%s)" -#: glib/gspawn.c:2530 +#: glib/gspawn.c:2520 #, c-format msgid "Failed to fork (%s)" msgstr "Функция fork завершилась неудачно (%s)" -#: glib/gspawn.c:2690 glib/gspawn-win32.c:503 +#: glib/gspawn.c:2681 glib/gspawn-win32.c:503 #, c-format msgid "Failed to change to directory “%s” (%s)" msgstr "Не удалось сменить каталог на «%s» (%s)" -#: glib/gspawn.c:2700 +#: glib/gspawn.c:2691 #, c-format msgid "Failed to execute child process “%s” (%s)" msgstr "Не удалось выполнить дочерний процесс \"%s\" (%s)" -#: glib/gspawn.c:2710 +#: glib/gspawn.c:2701 #, c-format msgid "Failed to open file to remap file descriptor (%s)" msgstr "Не удалось открыть файл для изменения дескриптора файла (%s)" -#: glib/gspawn.c:2718 +#: glib/gspawn.c:2709 #, c-format msgid "Failed to duplicate file descriptor for child process (%s)" msgstr "Не удалось дублировать дескриптор файла для дочернего процесса (%s)" -#: glib/gspawn.c:2727 +#: glib/gspawn.c:2718 #, c-format msgid "Failed to fork child process (%s)" msgstr "При создании дочернего процесса функция fork завершилась неудачно (%s)" -#: glib/gspawn.c:2735 +#: glib/gspawn.c:2726 #, c-format msgid "Failed to close file descriptor for child process (%s)" msgstr "Не удалось закрыть дескриптор файла для дочернего процесса (%s)" -#: glib/gspawn.c:2743 +#: glib/gspawn.c:2734 #, c-format msgid "Unknown error executing child process “%s”" msgstr "Произошла неизвестная ошибка при выполнении дочернего процесса «%s»" -#: glib/gspawn.c:2767 +#: glib/gspawn.c:2758 #, c-format msgid "Failed to read enough data from child pid pipe (%s)" msgstr "" @@ -6139,133 +6149,133 @@ msgid "Character out of range for UTF-16" msgstr "Символ находится вне диапазона для UTF-16" #. Translators: A unit symbol for size formatting, showing for example: "13.0 kB" -#: glib/gutils.c:2966 +#: glib/gutils.c:2974 msgid "kB" msgstr "кБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 MB" -#: glib/gutils.c:2968 +#: glib/gutils.c:2976 msgid "MB" msgstr "МБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 GB" -#: glib/gutils.c:2970 +#: glib/gutils.c:2978 msgid "GB" msgstr "ГБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 TB" -#: glib/gutils.c:2972 +#: glib/gutils.c:2980 msgid "TB" msgstr "ТБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 PB" -#: glib/gutils.c:2974 +#: glib/gutils.c:2982 msgid "PB" msgstr "ПБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 EB" -#: glib/gutils.c:2976 +#: glib/gutils.c:2984 msgid "EB" msgstr "ЭБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 KiB" -#: glib/gutils.c:2980 +#: glib/gutils.c:2988 msgid "KiB" msgstr "КиБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 MiB" -#: glib/gutils.c:2982 +#: glib/gutils.c:2990 msgid "MiB" msgstr "МиБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 GiB" -#: glib/gutils.c:2984 +#: glib/gutils.c:2992 msgid "GiB" msgstr "ГиБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 TiB" -#: glib/gutils.c:2986 +#: glib/gutils.c:2994 msgid "TiB" msgstr "ТиБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 PiB" -#: glib/gutils.c:2988 +#: glib/gutils.c:2996 msgid "PiB" msgstr "ПиБ" #. Translators: A unit symbol for size formatting, showing for example: "13.0 EiB" -#: glib/gutils.c:2990 +#: glib/gutils.c:2998 msgid "EiB" msgstr "ЭиБ" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 kb" -#: glib/gutils.c:2994 -msgid "kb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 kbit" +#: glib/gutils.c:3002 +msgid "kbit" msgstr "кбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mb" -#: glib/gutils.c:2996 -msgid "Mb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mbit" +#: glib/gutils.c:3004 +msgid "Mbit" msgstr "Мбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gb" -#: glib/gutils.c:2998 -msgid "Gb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gbit" +#: glib/gutils.c:3006 +msgid "Gbit" msgstr "Гбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tb" -#: glib/gutils.c:3000 -msgid "Tb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tbit" +#: glib/gutils.c:3008 +msgid "Tbit" msgstr "Тбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pb" -#: glib/gutils.c:3002 -msgid "Pb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pbit" +#: glib/gutils.c:3010 +msgid "Pbit" msgstr "Пбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eb" -#: glib/gutils.c:3004 -msgid "Eb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Ebit" +#: glib/gutils.c:3012 +msgid "Ebit" msgstr "Эбит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Kib" -#: glib/gutils.c:3008 -msgid "Kib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Kibit" +#: glib/gutils.c:3016 +msgid "Kibit" msgstr "Кибит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mib" -#: glib/gutils.c:3010 -msgid "Mib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mibit" +#: glib/gutils.c:3018 +msgid "Mibit" msgstr "Мибит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gib" -#: glib/gutils.c:3012 -msgid "Gib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gibit" +#: glib/gutils.c:3020 +msgid "Gibit" msgstr "Гибит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tib" -#: glib/gutils.c:3014 -msgid "Tib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tibit" +#: glib/gutils.c:3022 +msgid "Tibit" msgstr "Тибит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pib" -#: glib/gutils.c:3016 -msgid "Pib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pibit" +#: glib/gutils.c:3024 +msgid "Pibit" msgstr "Пибит" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eib" -#: glib/gutils.c:3018 -msgid "Eib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eibit" +#: glib/gutils.c:3026 +msgid "Eibit" msgstr "Эибит" -#: glib/gutils.c:3056 +#: glib/gutils.c:3064 msgid "byte" msgid_plural "bytes" msgstr[0] "байт" msgstr[1] "байта" msgstr[2] "байт" -#: glib/gutils.c:3060 +#: glib/gutils.c:3068 msgid "bit" msgid_plural "bits" msgstr[0] "бит" @@ -6274,7 +6284,7 @@ msgstr[2] "бит" #. Translators: The "%u" is replaced with the size value, like "13"; it could #. * be part of "13 bytes", but only the number is requested this time. -#: glib/gutils.c:3068 +#: glib/gutils.c:3076 #, c-format msgctxt "format-size" msgid "%u" @@ -6282,7 +6292,7 @@ msgstr "%u" #. Translators: The first "%u" is replaced with the value, the "%s" with a unit of the value. #. * The order can be changed with "%$2s %$1u". An example: "13 bytes" -#: glib/gutils.c:3073 +#: glib/gutils.c:3081 #, c-format msgctxt "format-size" msgid "%u %s" @@ -6290,7 +6300,7 @@ msgstr "%u %s" #. Translators: The "%.1f" is replaced with the size value, like "13.0"; it could #. * be part of "13.0 MB", but only the number is requested this time. -#: glib/gutils.c:3109 +#: glib/gutils.c:3117 #, c-format msgctxt "format-size" msgid "%.1f" @@ -6299,14 +6309,14 @@ msgstr "%.1f" #. Translators: The first "%.1f" is replaced with the value, the "%s" with a unit of the value. #. * The order can be changed with "%$2s %$1.1f". Keep the no-break space between the value and #. * the unit symbol. An example: "13.0 MB" -#: glib/gutils.c:3115 +#: glib/gutils.c:3123 #, c-format msgctxt "format-size" msgid "%.1f %s" msgstr "%.1f %s" #. Translators: the %s in "%s bytes" will always be replaced by a number. -#: glib/gutils.c:3155 +#: glib/gutils.c:3163 #, c-format msgid "%s byte" msgid_plural "%s bytes" @@ -6315,7 +6325,7 @@ msgstr[1] "%s байта" msgstr[2] "%s байт" #. Translators: the %s in "%s bits" will always be replaced by a number. -#: glib/gutils.c:3160 +#: glib/gutils.c:3168 #, c-format msgid "%s bit" msgid_plural "%s bits" @@ -6323,7 +6333,7 @@ msgstr[0] "%s бит" msgstr[1] "%s бита" msgstr[2] "%s бит" -#: glib/gutils.c:3201 +#: glib/gutils.c:3209 #, c-format msgid "%u byte" msgid_plural "%u bytes" @@ -6336,36 +6346,79 @@ msgstr[2] "%u байт" #. * compatibility. Users will not see this string unless a program is using this deprecated function. #. * Please translate as literally as possible. #. -#: glib/gutils.c:3214 +#: glib/gutils.c:3222 #, c-format msgid "%.1f KB" msgstr "%.1f КБ" -#: glib/gutils.c:3219 +#: glib/gutils.c:3227 #, c-format msgid "%.1f MB" msgstr "%.1f МБ" -#: glib/gutils.c:3224 +#: glib/gutils.c:3232 #, c-format msgid "%.1f GB" msgstr "%.1f ГБ" -#: glib/gutils.c:3229 +#: glib/gutils.c:3237 #, c-format msgid "%.1f TB" msgstr "%.1f ТБ" -#: glib/gutils.c:3234 +#: glib/gutils.c:3242 #, c-format msgid "%.1f PB" msgstr "%.1f ПБ" -#: glib/gutils.c:3239 +#: glib/gutils.c:3247 #, c-format msgid "%.1f EB" msgstr "%.1f ЭБ" +#, c-format +#~ msgid "Could not allocate %lu byte to read file “%s”" +#~ msgid_plural "Could not allocate %lu bytes to read file “%s”" +#~ msgstr[0] "Не удалось выделить %lu байт для чтения файла «%s»" +#~ msgstr[1] "Не удалось выделить %lu байта для чтения файла «%s»" +#~ msgstr[2] "Не удалось выделить %lu байт для чтения файла «%s»" + +#~ msgid "kb" +#~ msgstr "кбит" + +#~ msgid "Mb" +#~ msgstr "Мбит" + +#~ msgid "Gb" +#~ msgstr "Гбит" + +#~ msgid "Tb" +#~ msgstr "Тбит" + +#~ msgid "Pb" +#~ msgstr "Пбит" + +#~ msgid "Eb" +#~ msgstr "Эбит" + +#~ msgid "Kib" +#~ msgstr "Кибит" + +#~ msgid "Mib" +#~ msgstr "Мибит" + +#~ msgid "Gib" +#~ msgstr "Гибит" + +#~ msgid "Tib" +#~ msgstr "Тибит" + +#~ msgid "Pib" +#~ msgstr "Пибит" + +#~ msgid "Eib" +#~ msgstr "Эибит" + #~ msgid "backtracking limit reached" #~ msgstr "достигнут предел обратного хода" diff --git a/po/tr.po b/po/tr.po index ce8f351..21edfe7 100644 --- a/po/tr.po +++ b/po/tr.po @@ -18,8 +18,8 @@ msgid "" msgstr "" "Project-Id-Version: glib\n" "Report-Msgid-Bugs-To: https://gitlab.gnome.org/GNOME/glib/issues\n" -"POT-Creation-Date: 2023-09-18 01:28+0000\n" -"PO-Revision-Date: 2023-09-28 01:19+0300\n" +"POT-Creation-Date: 2023-10-22 23:35+0000\n" +"PO-Revision-Date: 2023-10-24 02:04+0300\n" "Last-Translator: Sabri Ünal \n" "Language-Team: Turkish \n" "Language: tr\n" @@ -27,7 +27,7 @@ msgstr "" "Content-Type: text/plain; charset=UTF-8\n" "Content-Transfer-Encoding: 8bit\n" "Plural-Forms: nplurals=1; plural=0;\n" -"X-Generator: Poedit 3.3.2\n" +"X-Generator: Poedit 3.4\n" "X-POOTLE-MTIME: 1433280446.000000\n" #: gio/gappinfo.c:339 @@ -49,23 +49,23 @@ msgstr "‘%s’ içerik türü için öntanımlı uygulama bulunamadı" msgid "Failed to find default application for URI Scheme ‘%s’" msgstr "‘%s’ URI Şeması için öntanımlı uygulama bulunamadı" -#: gio/gapplication.c:506 +#: gio/gapplication.c:502 msgid "GApplication Options:" msgstr "GApplication Seçenekleri:" -#: gio/gapplication.c:506 +#: gio/gapplication.c:502 msgid "Show GApplication options" msgstr "GApplication seçeneklerini göster" -#: gio/gapplication.c:551 +#: gio/gapplication.c:547 msgid "Enter GApplication service mode (use from D-Bus service files)" msgstr "GApplication hizmet kipi girin (D-Bus hizmet dosyalarından kullan)" -#: gio/gapplication.c:563 +#: gio/gapplication.c:559 msgid "Override the application’s ID" msgstr "Uygulama kimliğini çiğne" -#: gio/gapplication.c:575 +#: gio/gapplication.c:571 msgid "Replace the running instance" msgstr "Çalışan örneği değiştir" @@ -282,7 +282,7 @@ msgstr "" "bilinmeyen komut: %s\n" "\n" -#: gio/gbufferedinputstream.c:422 gio/gbufferedinputstream.c:500 +#: gio/gbufferedinputstream.c:418 gio/gbufferedinputstream.c:496 #: gio/ginputstream.c:181 gio/ginputstream.c:381 gio/ginputstream.c:651 #: gio/ginputstream.c:1056 gio/goutputstream.c:225 gio/goutputstream.c:1052 #: gio/gpollableinputstream.c:221 gio/gpollableoutputstream.c:293 @@ -290,65 +290,65 @@ msgstr "" msgid "Too large count value passed to %s" msgstr "%s için çok büyük sayaç değeri geçildi" -#: gio/gbufferedinputstream.c:893 gio/gbufferedoutputstream.c:577 -#: gio/gdataoutputstream.c:564 +#: gio/gbufferedinputstream.c:889 gio/gbufferedoutputstream.c:573 +#: gio/gdataoutputstream.c:559 msgid "Seek not supported on base stream" msgstr "Taban akış üzerinde arama desteklenmez" -#: gio/gbufferedinputstream.c:940 +#: gio/gbufferedinputstream.c:936 msgid "Cannot truncate GBufferedInputStream" msgstr "GBufferedInputStreamsonu kesilemiyor" -#: gio/gbufferedinputstream.c:985 gio/ginputstream.c:1246 gio/giostream.c:302 +#: gio/gbufferedinputstream.c:981 gio/ginputstream.c:1246 gio/giostream.c:302 #: gio/goutputstream.c:2208 msgid "Stream is already closed" msgstr "Akış zaten kapalı" -#: gio/gbufferedoutputstream.c:614 gio/gdataoutputstream.c:594 +#: gio/gbufferedoutputstream.c:610 gio/gdataoutputstream.c:589 msgid "Truncate not supported on base stream" msgstr "Taban akış üzerinde sonunun kesilmesi desteklenmiyor" -#: gio/gcancellable.c:326 gio/gdbusconnection.c:1867 gio/gdbusprivate.c:1434 +#: gio/gcancellable.c:326 gio/gdbusconnection.c:1861 gio/gdbusprivate.c:1432 #: gio/gsimpleasyncresult.c:873 gio/gsimpleasyncresult.c:899 #, c-format msgid "Operation was cancelled" msgstr "İşlem iptal edildi" -#: gio/gcharsetconverter.c:262 +#: gio/gcharsetconverter.c:255 msgid "Invalid object, not initialized" msgstr "Geçersiz nesne, ilklendirilmemiş" -#: gio/gcharsetconverter.c:283 gio/gcharsetconverter.c:311 +#: gio/gcharsetconverter.c:276 gio/gcharsetconverter.c:304 msgid "Incomplete multibyte sequence in input" msgstr "Girdide tamamlanmamış çokbaytlı dizi" -#: gio/gcharsetconverter.c:317 gio/gcharsetconverter.c:326 +#: gio/gcharsetconverter.c:310 gio/gcharsetconverter.c:319 msgid "Not enough space in destination" msgstr "Hedefte yeterli alan yok" -#: gio/gcharsetconverter.c:344 gio/gdatainputstream.c:850 -#: gio/gdatainputstream.c:1268 glib/gconvert.c:450 glib/gconvert.c:882 +#: gio/gcharsetconverter.c:337 gio/gdatainputstream.c:846 +#: gio/gdatainputstream.c:1264 glib/gconvert.c:351 glib/gconvert.c:783 #: glib/giochannel.c:1576 glib/giochannel.c:1618 glib/giochannel.c:2478 #: glib/gutf8.c:958 glib/gutf8.c:1412 msgid "Invalid byte sequence in conversion input" msgstr "Dönüşüm girdisinde geçersiz bayt dizisi" -#: gio/gcharsetconverter.c:349 glib/gconvert.c:458 glib/gconvert.c:796 +#: gio/gcharsetconverter.c:342 glib/gconvert.c:359 glib/gconvert.c:697 #: glib/giochannel.c:1583 glib/giochannel.c:2493 #, c-format msgid "Error during conversion: %s" msgstr "Dönüşüm sırasında hata oluştu: %s" -#: gio/gcharsetconverter.c:447 gio/gsocket.c:1164 +#: gio/gcharsetconverter.c:440 gio/gsocket.c:1164 msgid "Cancellable initialization not supported" msgstr "Ä°ptal edilebilir başlatma desteklenmiyor" -#: gio/gcharsetconverter.c:458 glib/gconvert.c:323 glib/giochannel.c:1404 +#: gio/gcharsetconverter.c:451 glib/gconvert.c:224 glib/giochannel.c:1404 #, c-format msgid "Conversion from character set “%s” to “%s” is not supported" msgstr "“%s” karakter kümesinden “%s” karakter kümesine dönüşüm desteklenmiyor" -#: gio/gcharsetconverter.c:462 glib/gconvert.c:327 +#: gio/gcharsetconverter.c:455 glib/gconvert.c:228 #, c-format msgid "Could not open converter from “%s” to “%s”" msgstr "“%s”den “%s”e dönüştürücü açılamıyor" @@ -367,27 +367,27 @@ msgstr "Bilinmeyen tür" msgid "%s filetype" msgstr "%s dosya türü" -#: gio/gcredentials.c:337 +#: gio/gcredentials.c:327 msgid "GCredentials contains invalid data" msgstr "GCredentials geçersiz veri içeriyor" -#: gio/gcredentials.c:397 gio/gcredentials.c:688 +#: gio/gcredentials.c:387 gio/gcredentials.c:678 msgid "GCredentials is not implemented on this OS" msgstr "Bu işletim sisteminde GCredentials sağlanmamış" -#: gio/gcredentials.c:552 gio/gcredentials.c:570 +#: gio/gcredentials.c:542 gio/gcredentials.c:560 msgid "There is no GCredentials support for your platform" msgstr "Platformunuz için GCredentials desteği yok" -#: gio/gcredentials.c:628 +#: gio/gcredentials.c:618 msgid "GCredentials does not contain a process ID on this OS" msgstr "GCredentials bu işletim sisteminde süreç kimliği içermez" -#: gio/gcredentials.c:682 +#: gio/gcredentials.c:672 msgid "Credentials spoofing is not possible on this OS" msgstr "Bu işletim sisteminde kimlik sızdırma olanaksızdır" -#: gio/gdatainputstream.c:306 +#: gio/gdatainputstream.c:302 msgid "Unexpected early end-of-stream" msgstr "Beklenmeyen erken akış-sonu" @@ -536,7 +536,7 @@ msgid "Cannot determine session bus address (not implemented for this OS)" msgstr "" "Oturum veri yolu adresi saptanamıyor (bu işletim sistemi için uygulanmadı)" -#: gio/gdbusaddress.c:1380 gio/gdbusconnection.c:7339 +#: gio/gdbusaddress.c:1380 gio/gdbusconnection.c:7333 #, c-format msgid "" "Cannot determine bus address from DBUS_STARTER_BUS_TYPE environment variable " @@ -545,7 +545,7 @@ msgstr "" "DBUS_STARTER_BUS_TYPE ortam değişkeninden veri yolu adresi saptanamıyor — " "bilinmeyen değer “%s”" -#: gio/gdbusaddress.c:1389 gio/gdbusconnection.c:7348 +#: gio/gdbusaddress.c:1389 gio/gdbusconnection.c:7342 msgid "" "Cannot determine bus address because the DBUS_STARTER_BUS_TYPE environment " "variable is not set" @@ -556,7 +556,7 @@ msgstr "" #: gio/gdbusaddress.c:1399 #, c-format msgid "Unknown bus type %d" -msgstr "Bilinmeyen veriyolu türü %d" +msgstr "Bilinmeyen veri yolu türü %d" #: gio/gdbusauth.c:294 msgid "Unexpected lack of content trying to read a line" @@ -607,9 +607,9 @@ msgstr "“%s” dizini oluşturulurken hata: %s" #: gio/gdbusauthmechanismsha1.c:368 gio/gfile.c:1102 gio/gfile.c:1340 #: gio/gfile.c:1478 gio/gfile.c:1716 gio/gfile.c:1771 gio/gfile.c:1829 #: gio/gfile.c:1913 gio/gfile.c:1970 gio/gfile.c:2034 gio/gfile.c:2089 -#: gio/gfile.c:3949 gio/gfile.c:4088 gio/gfile.c:4500 gio/gfile.c:4970 -#: gio/gfile.c:5382 gio/gfile.c:5467 gio/gfile.c:5557 gio/gfile.c:5654 -#: gio/gfile.c:5741 gio/gfile.c:5842 gio/gfile.c:9000 gio/gfile.c:9090 +#: gio/gfile.c:3953 gio/gfile.c:4092 gio/gfile.c:4504 gio/gfile.c:4974 +#: gio/gfile.c:5386 gio/gfile.c:5471 gio/gfile.c:5561 gio/gfile.c:5658 +#: gio/gfile.c:5745 gio/gfile.c:5846 gio/gfile.c:9000 gio/gfile.c:9090 #: gio/gfile.c:9174 gio/win32/gwinhttpfile.c:453 msgid "Operation not supported" msgstr "İşlem desteklenmiyor" @@ -675,99 +675,99 @@ msgstr "“%s” anahtarlığını yazma için açarken hata: " msgid "(Additionally, releasing the lock for “%s” also failed: %s) " msgstr "(Ayrıca, “%s” için kilit açılamadı: %s) " -#: gio/gdbusconnection.c:590 gio/gdbusconnection.c:2415 +#: gio/gdbusconnection.c:584 gio/gdbusconnection.c:2409 msgid "The connection is closed" msgstr "Bağlantı kapalı" -#: gio/gdbusconnection.c:1899 +#: gio/gdbusconnection.c:1893 msgid "Timeout was reached" msgstr "Zaman aşımı gerçekleşti" -#: gio/gdbusconnection.c:2538 +#: gio/gdbusconnection.c:2532 msgid "" "Unsupported flags encountered when constructing a client-side connection" msgstr "" "Ä°stemci taraflı bağlantı kurulurken desteklenmeyen etiketlerle karşılaşıldı" -#: gio/gdbusconnection.c:4277 gio/gdbusconnection.c:4631 +#: gio/gdbusconnection.c:4271 gio/gdbusconnection.c:4625 #, c-format msgid "" "No such interface “org.freedesktop.DBus.Properties” on object at path %s" msgstr "" "%s yolundaki nesnede “org.freedesktop.DBus.Properties” gibi bir arayüz yok" -#: gio/gdbusconnection.c:4422 +#: gio/gdbusconnection.c:4416 #, c-format msgid "No such property “%s”" msgstr "“%s” gibi bir özellik yok" -#: gio/gdbusconnection.c:4434 +#: gio/gdbusconnection.c:4428 #, c-format msgid "Property “%s” is not readable" msgstr "“%s” özelliği okunabilir değil" -#: gio/gdbusconnection.c:4445 +#: gio/gdbusconnection.c:4439 #, c-format msgid "Property “%s” is not writable" msgstr "“%s” özelliği yazılabilir değil" -#: gio/gdbusconnection.c:4465 +#: gio/gdbusconnection.c:4459 #, c-format msgid "Error setting property “%s”: Expected type “%s” but got “%s”" msgstr "“%s” özelliği ayarlanırken hata: “%s” türü beklendi, “%s” elde edildi" -#: gio/gdbusconnection.c:4570 gio/gdbusconnection.c:4785 -#: gio/gdbusconnection.c:6762 +#: gio/gdbusconnection.c:4564 gio/gdbusconnection.c:4779 +#: gio/gdbusconnection.c:6756 #, c-format msgid "No such interface “%s”" msgstr "“%s” gibi bir arabirim yok" -#: gio/gdbusconnection.c:5001 gio/gdbusconnection.c:7279 +#: gio/gdbusconnection.c:4995 gio/gdbusconnection.c:7273 #, c-format msgid "No such interface “%s” on object at path %s" msgstr "%2$s yolundaki nesnede “%1$s” gibi bir arayüz yok" -#: gio/gdbusconnection.c:5102 +#: gio/gdbusconnection.c:5096 #, c-format msgid "No such method “%s”" msgstr "“%s” gibi bir anahtar yok" -#: gio/gdbusconnection.c:5133 +#: gio/gdbusconnection.c:5127 #, c-format msgid "Type of message, “%s”, does not match expected type “%s”" msgstr "“%s” iletisinin türü, beklenen “%s” türü ile örtüşmüyor" -#: gio/gdbusconnection.c:5336 +#: gio/gdbusconnection.c:5330 #, c-format msgid "An object is already exported for the interface %s at %s" msgstr "%2$s konumundaki %1$s arayüzü için bir nesne zaten dışa aktarıldı" -#: gio/gdbusconnection.c:5563 +#: gio/gdbusconnection.c:5557 #, c-format msgid "Unable to retrieve property %s.%s" msgstr "%s.%s özelliği alınamadı" -#: gio/gdbusconnection.c:5619 +#: gio/gdbusconnection.c:5613 #, c-format msgid "Unable to set property %s.%s" msgstr "%s.%s özelliği ayarlanamadı" -#: gio/gdbusconnection.c:5798 +#: gio/gdbusconnection.c:5792 #, c-format msgid "Method “%s” returned type “%s”, but expected “%s”" msgstr "“%s” yöntemi “%s” türü döndürdü, ancak “%s” bekleniyordu" -#: gio/gdbusconnection.c:6874 +#: gio/gdbusconnection.c:6868 #, c-format msgid "Method “%s” on interface “%s” with signature “%s” does not exist" msgstr "“%3$s” imzalı “%2$s” arayüzü üzerinde “%1$s” yöntemi yok" -#: gio/gdbusconnection.c:6995 +#: gio/gdbusconnection.c:6989 #, c-format msgid "A subtree is already exported for %s" msgstr "%s için bir alt ağaç zaten dışa aktarılmış" -#: gio/gdbusconnection.c:7287 +#: gio/gdbusconnection.c:7281 #, c-format msgid "Object does not exist at path “%s”" msgstr "Nesne, “%s” yolunda yok" @@ -963,23 +963,23 @@ msgstr "“%s” türünden bir gövdeyle dönüş hatası" msgid "Error return with empty body" msgstr "Boş gövdeyle dönüş hatası" -#: gio/gdbusprivate.c:2201 +#: gio/gdbusprivate.c:2199 #, c-format msgid "(Type any character to close this window)\n" msgstr "(Pencereyi kapatmak için herhangi bir karakter girin)\n" -#: gio/gdbusprivate.c:2387 +#: gio/gdbusprivate.c:2385 #, c-format msgid "Session dbus not running, and autolaunch failed" msgstr "Dbus oturumu çalışmıyor ve kendiliğinden başlatılamadı" -#: gio/gdbusprivate.c:2410 +#: gio/gdbusprivate.c:2408 #, c-format msgid "Unable to get Hardware profile: %s" msgstr "Donanım profili alınamıyor: %s" #. Translators: Both placeholders are file paths -#: gio/gdbusprivate.c:2461 +#: gio/gdbusprivate.c:2464 #, c-format msgid "Unable to load %s or %s: " msgstr "%s ya da %s yüklenemedi: " @@ -1074,11 +1074,11 @@ msgstr "Hata: %s geçerli bir nesne yolu değil\n" #: gio/gdbus-tool.c:405 msgid "Connect to the system bus" -msgstr "Sistem veriyoluna bağlan" +msgstr "Sistem veri yoluna bağlan" #: gio/gdbus-tool.c:406 msgid "Connect to the session bus" -msgstr "Oturum veriyoluna bağlan" +msgstr "Oturum veri yoluna bağlan" #: gio/gdbus-tool.c:407 msgid "Connect to given D-Bus address" @@ -1140,7 +1140,7 @@ msgstr "Bağlanırken hata: %s\n" #: gio/gdbus-tool.c:705 #, c-format msgid "Error: %s is not a valid unique bus name.\n" -msgstr "Hata: %s geçerli bir özgün veriyolu adı değil\n" +msgstr "Hata: %s geçerli bir özgün veri yolu adı değil\n" #: gio/gdbus-tool.c:724 gio/gdbus-tool.c:1045 gio/gdbus-tool.c:1879 msgid "Error: Object path is not specified\n" @@ -1310,43 +1310,43 @@ msgstr "Hata: %s geçerli bilinen bir veri yolu adı değil.\n" msgid "Not authorized to change debug settings" msgstr "Hata ayıklama ayarlarını değiştirmeye yetkili değil" -#: gio/gdesktopappinfo.c:2242 gio/gdesktopappinfo.c:5226 +#: gio/gdesktopappinfo.c:2243 gio/gdesktopappinfo.c:5227 msgid "Unnamed" msgstr "Adlandırılmamış" -#: gio/gdesktopappinfo.c:2652 +#: gio/gdesktopappinfo.c:2653 msgid "Desktop file didn’t specify Exec field" msgstr "Desktop dosyası Exec alanı belirtmemiş" -#: gio/gdesktopappinfo.c:2942 +#: gio/gdesktopappinfo.c:2943 msgid "Unable to find terminal required for application" msgstr "Uygulama için gerekli uçbirim bulunamadı" -#: gio/gdesktopappinfo.c:3002 +#: gio/gdesktopappinfo.c:3003 #, c-format msgid "Program ‘%s’ not found in $PATH" msgstr "‘%s’ programı $PATH içinde bulunamadı" -#: gio/gdesktopappinfo.c:3738 +#: gio/gdesktopappinfo.c:3739 #, c-format msgid "Can’t create user application configuration folder %s: %s" msgstr "Kullanıcı uygulaması yapılandırma klasörü %s oluşturulamıyor: %s" -#: gio/gdesktopappinfo.c:3742 +#: gio/gdesktopappinfo.c:3743 #, c-format msgid "Can’t create user MIME configuration folder %s: %s" msgstr "Kullanıcı MIME yapılandırma klasörü %s oluşturulamıyor: %s" -#: gio/gdesktopappinfo.c:3984 gio/gdesktopappinfo.c:4008 +#: gio/gdesktopappinfo.c:3985 gio/gdesktopappinfo.c:4009 msgid "Application information lacks an identifier" msgstr "Uygulama bilgisinde tanımlayıcı eksik" -#: gio/gdesktopappinfo.c:4244 +#: gio/gdesktopappinfo.c:4245 #, c-format msgid "Can’t create user desktop file %s" msgstr "Kullanıcı masaüstü dosyası %s oluşturulamıyor" -#: gio/gdesktopappinfo.c:4380 +#: gio/gdesktopappinfo.c:4381 #, c-format msgid "Custom definition for %s" msgstr "%s için özel tanım" @@ -1435,51 +1435,51 @@ msgstr "Hedef dosya var" msgid "Can’t recursively copy directory" msgstr "Dizin iç içe kopyalanamıyor" -#: gio/gfile.c:3044 gio/gfile.c:3092 +#: gio/gfile.c:3048 gio/gfile.c:3096 #, c-format msgid "Copy file range not supported" msgstr "Dosya kopyalama kapsamı desteklenmiyor" -#: gio/gfile.c:3050 gio/gfile.c:3161 +#: gio/gfile.c:3054 gio/gfile.c:3165 #, c-format msgid "Error splicing file: %s" msgstr "Dosya uç uca eklenirken hata: %s" -#: gio/gfile.c:3157 +#: gio/gfile.c:3161 msgid "Splice not supported" msgstr "Splice desteklenmiyor" -#: gio/gfile.c:3321 +#: gio/gfile.c:3325 msgid "Copy (reflink/clone) between mounts is not supported" msgstr "" "Bağlı sistemler arasında kopyalama (referans bağlantı/çoğaltmak) " "desteklenmiyor" -#: gio/gfile.c:3325 +#: gio/gfile.c:3329 msgid "Copy (reflink/clone) is not supported or invalid" msgstr "Kopyalama desteklenmiyor ya da geçersiz" -#: gio/gfile.c:3330 +#: gio/gfile.c:3334 msgid "Copy (reflink/clone) is not supported or didn’t work" msgstr "Kopyalama (bağlama/klonlama) destenlenmiyor ya da çalışmadı" -#: gio/gfile.c:3395 +#: gio/gfile.c:3399 msgid "Can’t copy special file" msgstr "Özel dosya kopyalanamıyor" -#: gio/gfile.c:4314 +#: gio/gfile.c:4318 msgid "Invalid symlink value given" msgstr "Geçersiz simgesel bağ değeri verildi" -#: gio/gfile.c:4324 glib/gfileutils.c:2392 +#: gio/gfile.c:4328 glib/gfileutils.c:2424 msgid "Symbolic links not supported" msgstr "Simgesel bağlar desteklenmiyor" -#: gio/gfile.c:4611 +#: gio/gfile.c:4615 msgid "Trash not supported" msgstr "Çöp desteklenmiyor" -#: gio/gfile.c:4723 +#: gio/gfile.c:4727 #, c-format msgid "File names cannot contain “%c”" msgstr "Dosya adları “%c” içeremez" @@ -1539,7 +1539,7 @@ msgid "Truncate not supported on stream" msgstr "Akış üzerinde sonunun kesilmesi desteklenmiyor" #: gio/ghttpproxy.c:93 gio/gresolver.c:535 gio/gresolver.c:688 -#: glib/gconvert.c:1842 +#: glib/gconvert.c:1743 msgid "Invalid hostname" msgstr "Geçersiz makine adı" @@ -1659,7 +1659,7 @@ msgstr "Taşındığında dosyayla tut" msgid "“version” takes no arguments" msgstr "“version” hiçbir argüman almaz" -#: gio/gio-tool.c:209 gio/gio-tool.c:225 glib/goption.c:871 +#: gio/gio-tool.c:209 gio/gio-tool.c:225 glib/goption.c:711 msgid "Usage:" msgstr "Kullanım:" @@ -1778,54 +1778,58 @@ msgstr "" msgid "No locations given" msgstr "Konum verilmedi" -#: gio/gio-tool-copy.c:45 gio/gio-tool-move.c:40 +#: gio/gio-tool-copy.c:46 gio/gio-tool-move.c:40 msgid "No target directory" msgstr "Hedef dizin yok" -#: gio/gio-tool-copy.c:46 gio/gio-tool-move.c:41 +#: gio/gio-tool-copy.c:47 gio/gio-tool-move.c:41 msgid "Show progress" msgstr "Ä°lerlemeyi göster" -#: gio/gio-tool-copy.c:47 gio/gio-tool-move.c:42 +#: gio/gio-tool-copy.c:48 gio/gio-tool-move.c:42 msgid "Prompt before overwrite" msgstr "Üzerine yazmadan önce onay iste" -#: gio/gio-tool-copy.c:48 +#: gio/gio-tool-copy.c:49 msgid "Preserve all attributes" msgstr "Tüm öznitelikleri koru" -#: gio/gio-tool-copy.c:49 gio/gio-tool-move.c:43 gio/gio-tool-save.c:51 +#: gio/gio-tool-copy.c:50 gio/gio-tool-move.c:43 gio/gio-tool-save.c:51 msgid "Backup existing destination files" msgstr "Var olan hedef dosyaları yedekle" -#: gio/gio-tool-copy.c:50 +#: gio/gio-tool-copy.c:51 msgid "Never follow symbolic links" msgstr "Simgesel bağlantıları asla takip etme" -#: gio/gio-tool-copy.c:51 +#: gio/gio-tool-copy.c:52 msgid "Use default permissions for the destination" msgstr "Hedef için öntanımlı izinleri kullan" -#: gio/gio-tool-copy.c:76 gio/gio-tool-move.c:69 +#: gio/gio-tool-copy.c:53 +msgid "Use default file modification timestamps for the destination" +msgstr "Hedef için öntanımlı dosya değişiklik zaman damgalarını kullan" + +#: gio/gio-tool-copy.c:78 gio/gio-tool-move.c:69 #, c-format msgid "Transferred %s out of %s (%s/s)" msgstr "%s/%s aktarıldı (%s/s)" #. Translators: commandline placeholder -#: gio/gio-tool-copy.c:102 gio/gio-tool-move.c:96 +#: gio/gio-tool-copy.c:104 gio/gio-tool-move.c:96 msgid "SOURCE" msgstr "KAYNAK" #. Translators: commandline placeholder -#: gio/gio-tool-copy.c:102 gio/gio-tool-move.c:96 gio/gio-tool-save.c:162 +#: gio/gio-tool-copy.c:104 gio/gio-tool-move.c:96 gio/gio-tool-save.c:162 msgid "DESTINATION" msgstr "HEDEF" -#: gio/gio-tool-copy.c:107 +#: gio/gio-tool-copy.c:109 msgid "Copy one or more files from SOURCE to DESTINATION." msgstr "Bir veya daha çok dosyayı KAYNAK’tan HEDEF’e taşı." -#: gio/gio-tool-copy.c:109 +#: gio/gio-tool-copy.c:111 msgid "" "gio copy is similar to the traditional cp utility, but using GIO\n" "locations instead of local files: for example, you can use something\n" @@ -1835,12 +1839,12 @@ msgstr "" "yerine GIO konumlarını kullanır: örneğin, smb://sunucu/kaynak/dosya.txt\n" "gibi bir şeyi konum olarak kullanabilirsiniz." -#: gio/gio-tool-copy.c:151 +#: gio/gio-tool-copy.c:153 #, c-format msgid "Destination %s is not a directory" msgstr "%s konumu bir dizin değildir" -#: gio/gio-tool-copy.c:198 gio/gio-tool-move.c:188 +#: gio/gio-tool-copy.c:202 gio/gio-tool-move.c:188 #, c-format msgid "%s: overwrite “%s”? " msgstr "%s: “%s” üzerine yazılsın mı? " @@ -3275,25 +3279,25 @@ msgstr "“%s” dosyası açılamadı: Windows Hatası %lu" msgid "Error setting modification or access time for file “%s”: %lu" msgstr "“%s” dosyasına değiştirme veya erişim süresi atanırken hata: %lu" -#: gio/glocalfileinfo.c:2950 +#: gio/glocalfileinfo.c:2970 #, c-format msgid "Error setting modification or access time: %s" msgstr "Değiştirme veya erişim süresi atanırken hata: %s" -#: gio/glocalfileinfo.c:2973 +#: gio/glocalfileinfo.c:2993 msgid "SELinux context must be non-NULL" msgstr "SELinux bağlamı NULL olmamalı" -#: gio/glocalfileinfo.c:2980 +#: gio/glocalfileinfo.c:3000 msgid "SELinux is not enabled on this system" msgstr "SELinux bu sistede etkin değil" -#: gio/glocalfileinfo.c:2990 +#: gio/glocalfileinfo.c:3010 #, c-format msgid "Error setting SELinux context: %s" msgstr "SELinux bağlamı atanırken hata: %s" -#: gio/glocalfileinfo.c:3087 +#: gio/glocalfileinfo.c:3107 #, c-format msgid "Setting attribute %s not supported" msgstr "Öznitelik %s ataması desteklenmiyor" @@ -3918,7 +3922,7 @@ msgid "Socket is already closed" msgstr "Yuva zaten kapalı" #: gio/gsocket.c:449 gio/gsocket.c:3238 gio/gsocket.c:4469 gio/gsocket.c:4527 -#: gio/gthreadedresolver.c:1445 +#: gio/gthreadedresolver.c:1452 msgid "Socket I/O timed out" msgstr "Yuva G/Ç zaman aşımı" @@ -4203,12 +4207,12 @@ msgstr "SOCKSv5 vekil sunucusu verilen adres türünü desteklemiyor." msgid "Unknown SOCKSv5 proxy error." msgstr "Bilinmeyen SOCKSv5 vekil hatası." -#: gio/gtestdbus.c:614 glib/gspawn-win32.c:433 +#: gio/gtestdbus.c:611 glib/gspawn-win32.c:433 #, c-format msgid "Failed to create pipe for communicating with child process (%s)" msgstr "Alt süreçle haberleşme için boru oluşturulamadı (%s)" -#: gio/gtestdbus.c:621 +#: gio/gtestdbus.c:618 #, c-format msgid "Pipes are not supported in this platform" msgstr "Borular bu platformda desteklenmiyor" @@ -4462,149 +4466,149 @@ msgstr "Bir dbus hizmeti çalıştır" msgid "Wrong args\n" msgstr "Yanlış değişkenler\n" -#: glib/gbookmarkfile.c:861 +#: glib/gbookmarkfile.c:816 #, c-format msgid "Unexpected attribute “%s” for element “%s”" msgstr "“%2$s” ögesi için beklenmeyen “%1$s” özniteliği" -#: glib/gbookmarkfile.c:872 glib/gbookmarkfile.c:952 glib/gbookmarkfile.c:962 -#: glib/gbookmarkfile.c:1075 +#: glib/gbookmarkfile.c:827 glib/gbookmarkfile.c:907 glib/gbookmarkfile.c:917 +#: glib/gbookmarkfile.c:1030 #, c-format msgid "Attribute “%s” of element “%s” not found" msgstr "“%2$s” ögesinde “%1$s” özniteliği bulunamadı" -#: glib/gbookmarkfile.c:1284 glib/gbookmarkfile.c:1349 -#: glib/gbookmarkfile.c:1413 glib/gbookmarkfile.c:1423 +#: glib/gbookmarkfile.c:1239 glib/gbookmarkfile.c:1304 +#: glib/gbookmarkfile.c:1368 glib/gbookmarkfile.c:1378 #, c-format msgid "Unexpected tag “%s”, tag “%s” expected" msgstr "Beklenmeyen etiket “%s”, “%s” bekleniyordu" -#: glib/gbookmarkfile.c:1309 glib/gbookmarkfile.c:1323 -#: glib/gbookmarkfile.c:1391 glib/gbookmarkfile.c:1437 +#: glib/gbookmarkfile.c:1264 glib/gbookmarkfile.c:1278 +#: glib/gbookmarkfile.c:1346 glib/gbookmarkfile.c:1392 #, c-format msgid "Unexpected tag “%s” inside “%s”" msgstr "“%2$s” içinde beklenmeyen etiket “%1$s”" -#: glib/gbookmarkfile.c:1717 +#: glib/gbookmarkfile.c:1672 #, c-format msgid "Invalid date/time ‘%s’ in bookmark file" msgstr "Yer imi dosyasında geçersiz tarih/saat ‘%s’" -#: glib/gbookmarkfile.c:1956 +#: glib/gbookmarkfile.c:1911 msgid "No valid bookmark file found in data dirs" msgstr "Veri dizinlerinde geçerli bir yer imi dosyası bulunamadı" -#: glib/gbookmarkfile.c:2157 +#: glib/gbookmarkfile.c:2112 #, c-format msgid "A bookmark for URI “%s” already exists" msgstr "“%s” URI’si için bir yer imi zaten var" -#: glib/gbookmarkfile.c:2206 glib/gbookmarkfile.c:2364 -#: glib/gbookmarkfile.c:2449 glib/gbookmarkfile.c:2529 -#: glib/gbookmarkfile.c:2614 glib/gbookmarkfile.c:2748 -#: glib/gbookmarkfile.c:2881 glib/gbookmarkfile.c:3016 -#: glib/gbookmarkfile.c:3058 glib/gbookmarkfile.c:3155 -#: glib/gbookmarkfile.c:3276 glib/gbookmarkfile.c:3470 -#: glib/gbookmarkfile.c:3611 glib/gbookmarkfile.c:3830 -#: glib/gbookmarkfile.c:3919 glib/gbookmarkfile.c:4008 -#: glib/gbookmarkfile.c:4127 +#: glib/gbookmarkfile.c:2161 glib/gbookmarkfile.c:2319 +#: glib/gbookmarkfile.c:2404 glib/gbookmarkfile.c:2484 +#: glib/gbookmarkfile.c:2569 glib/gbookmarkfile.c:2703 +#: glib/gbookmarkfile.c:2836 glib/gbookmarkfile.c:2971 +#: glib/gbookmarkfile.c:3013 glib/gbookmarkfile.c:3110 +#: glib/gbookmarkfile.c:3231 glib/gbookmarkfile.c:3425 +#: glib/gbookmarkfile.c:3566 glib/gbookmarkfile.c:3785 +#: glib/gbookmarkfile.c:3874 glib/gbookmarkfile.c:3963 +#: glib/gbookmarkfile.c:4082 #, c-format msgid "No bookmark found for URI “%s”" msgstr "“%s” URI’si için bir yer imi bulunamadı" -#: glib/gbookmarkfile.c:2538 +#: glib/gbookmarkfile.c:2493 #, c-format msgid "No MIME type defined in the bookmark for URI “%s”" msgstr "“%s” URI’si için yer iminde hiçbir MIME türü belirtilmedi" -#: glib/gbookmarkfile.c:2623 +#: glib/gbookmarkfile.c:2578 #, c-format msgid "No private flag has been defined in bookmark for URI “%s”" msgstr "“%s” URI’si için yer iminde özel bayrak tanımlanmadı" -#: glib/gbookmarkfile.c:3164 +#: glib/gbookmarkfile.c:3119 #, c-format msgid "No groups set in bookmark for URI “%s”" msgstr "“%s” URI’si için yer iminde küme tanımlanmadı" -#: glib/gbookmarkfile.c:3632 glib/gbookmarkfile.c:3840 +#: glib/gbookmarkfile.c:3587 glib/gbookmarkfile.c:3795 #, c-format msgid "No application with name “%s” registered a bookmark for “%s”" msgstr "“%s” adında hiçbir uygulama “%s” için yer imi kaydetmedi" -#: glib/gbookmarkfile.c:3863 +#: glib/gbookmarkfile.c:3818 #, c-format msgid "Failed to expand exec line “%s” with URI “%s”" msgstr "Exec satırı “%s”, “%s” URI’si ile genişletilemedi" -#: glib/gconvert.c:469 +#: glib/gconvert.c:370 msgid "Unrepresentable character in conversion input" msgstr "Dönüşüm girdisi içinde temsil edilemez karakter" -#: glib/gconvert.c:496 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 +#: glib/gconvert.c:397 glib/gutf8.c:954 glib/gutf8.c:1167 glib/gutf8.c:1304 #: glib/gutf8.c:1408 msgid "Partial character sequence at end of input" msgstr "Girdinin sonunda parçalı karakter dizisi" -#: glib/gconvert.c:767 +#: glib/gconvert.c:668 #, c-format msgid "Cannot convert fallback “%s” to codeset “%s”" msgstr "" "Geridönüş karakter kümesi “%s”, “%s” karakter kümesine dönüştürülemiyor" -#: glib/gconvert.c:939 +#: glib/gconvert.c:840 msgid "Embedded NUL byte in conversion input" msgstr "Dönüşüm girdisinde gömülü NUL baytı" -#: glib/gconvert.c:960 +#: glib/gconvert.c:861 msgid "Embedded NUL byte in conversion output" msgstr "Dönüşüm çıktısında gömülü NUL baytı" -#: glib/gconvert.c:1698 +#: glib/gconvert.c:1599 #, c-format msgid "The URI “%s” is not an absolute URI using the “file” scheme" msgstr "“%s” URI’si, “file” şemasını kullanan kesin bir URI değil" -#: glib/gconvert.c:1728 +#: glib/gconvert.c:1629 #, c-format msgid "The URI “%s” is invalid" msgstr "“%s” URI’si geçersiz" -#: glib/gconvert.c:1741 +#: glib/gconvert.c:1642 #, c-format msgid "The hostname of the URI “%s” is invalid" msgstr "“%s” URI’sinin ana makine adı geçersiz" -#: glib/gconvert.c:1758 +#: glib/gconvert.c:1659 #, c-format msgid "The URI “%s” contains invalidly escaped characters" msgstr "“%s” URI’si geçersiz olarak çıkış yapılmış karakterler içeriyor" -#: glib/gconvert.c:1832 +#: glib/gconvert.c:1733 #, c-format msgid "The pathname “%s” is not an absolute path" msgstr "Yol adı “%s”, kesin bir yol değil" #. Translators: this is the preferred format for expressing the date and the time -#: glib/gdatetime.c:228 +#: glib/gdatetime.c:196 msgctxt "GDateTime" msgid "%a %b %e %H:%M:%S %Y" msgstr "%a %d %b %Y %T %Z" #. Translators: this is the preferred format for expressing the date -#: glib/gdatetime.c:231 +#: glib/gdatetime.c:199 msgctxt "GDateTime" msgid "%m/%d/%y" msgstr "%d/%m/%y" #. Translators: this is the preferred format for expressing the time -#: glib/gdatetime.c:234 +#: glib/gdatetime.c:202 msgctxt "GDateTime" msgid "%H:%M:%S" msgstr "%H:%M:%S" #. Translators: this is the preferred format for expressing 12 hour time -#: glib/gdatetime.c:237 +#: glib/gdatetime.c:205 msgctxt "GDateTime" msgid "%I:%M:%S %p" msgstr "%I:%M:%S %p" @@ -4625,62 +4629,62 @@ msgstr "%I:%M:%S %p" #. * non-European) there is no difference between the standalone and #. * complete date form. #. -#: glib/gdatetime.c:276 +#: glib/gdatetime.c:244 msgctxt "full month name" msgid "January" msgstr "Ocak" -#: glib/gdatetime.c:278 +#: glib/gdatetime.c:246 msgctxt "full month name" msgid "February" msgstr "Şubat" -#: glib/gdatetime.c:280 +#: glib/gdatetime.c:248 msgctxt "full month name" msgid "March" msgstr "Mart" -#: glib/gdatetime.c:282 +#: glib/gdatetime.c:250 msgctxt "full month name" msgid "April" msgstr "Nisan" -#: glib/gdatetime.c:284 +#: glib/gdatetime.c:252 msgctxt "full month name" msgid "May" msgstr "Mayıs" -#: glib/gdatetime.c:286 +#: glib/gdatetime.c:254 msgctxt "full month name" msgid "June" msgstr "Haziran" -#: glib/gdatetime.c:288 +#: glib/gdatetime.c:256 msgctxt "full month name" msgid "July" msgstr "Temmuz" -#: glib/gdatetime.c:290 +#: glib/gdatetime.c:258 msgctxt "full month name" msgid "August" msgstr "Ağustos" -#: glib/gdatetime.c:292 +#: glib/gdatetime.c:260 msgctxt "full month name" msgid "September" msgstr "Eylül" -#: glib/gdatetime.c:294 +#: glib/gdatetime.c:262 msgctxt "full month name" msgid "October" msgstr "Ekim" -#: glib/gdatetime.c:296 +#: glib/gdatetime.c:264 msgctxt "full month name" msgid "November" msgstr "Kasım" -#: glib/gdatetime.c:298 +#: glib/gdatetime.c:266 msgctxt "full month name" msgid "December" msgstr "Aralık" @@ -4702,132 +4706,132 @@ msgstr "Aralık" #. * other platform. Here are abbreviated month names in a form #. * appropriate when they are used standalone. #. -#: glib/gdatetime.c:330 +#: glib/gdatetime.c:298 msgctxt "abbreviated month name" msgid "Jan" msgstr "Oca" -#: glib/gdatetime.c:332 +#: glib/gdatetime.c:300 msgctxt "abbreviated month name" msgid "Feb" msgstr "Şub" -#: glib/gdatetime.c:334 +#: glib/gdatetime.c:302 msgctxt "abbreviated month name" msgid "Mar" msgstr "Mar" -#: glib/gdatetime.c:336 +#: glib/gdatetime.c:304 msgctxt "abbreviated month name" msgid "Apr" msgstr "Nis" -#: glib/gdatetime.c:338 +#: glib/gdatetime.c:306 msgctxt "abbreviated month name" msgid "May" msgstr "May" -#: glib/gdatetime.c:340 +#: glib/gdatetime.c:308 msgctxt "abbreviated month name" msgid "Jun" msgstr "Haz" -#: glib/gdatetime.c:342 +#: glib/gdatetime.c:310 msgctxt "abbreviated month name" msgid "Jul" msgstr "Tem" -#: glib/gdatetime.c:344 +#: glib/gdatetime.c:312 msgctxt "abbreviated month name" msgid "Aug" msgstr "Ağu" -#: glib/gdatetime.c:346 +#: glib/gdatetime.c:314 msgctxt "abbreviated month name" msgid "Sep" msgstr "Eyl" -#: glib/gdatetime.c:348 +#: glib/gdatetime.c:316 msgctxt "abbreviated month name" msgid "Oct" msgstr "Eki" -#: glib/gdatetime.c:350 +#: glib/gdatetime.c:318 msgctxt "abbreviated month name" msgid "Nov" msgstr "Kas" -#: glib/gdatetime.c:352 +#: glib/gdatetime.c:320 msgctxt "abbreviated month name" msgid "Dec" msgstr "Ara" -#: glib/gdatetime.c:367 +#: glib/gdatetime.c:335 msgctxt "full weekday name" msgid "Monday" msgstr "Pazartesi" -#: glib/gdatetime.c:369 +#: glib/gdatetime.c:337 msgctxt "full weekday name" msgid "Tuesday" msgstr "Salı" -#: glib/gdatetime.c:371 +#: glib/gdatetime.c:339 msgctxt "full weekday name" msgid "Wednesday" msgstr "Çarşamba" -#: glib/gdatetime.c:373 +#: glib/gdatetime.c:341 msgctxt "full weekday name" msgid "Thursday" msgstr "Perşembe" -#: glib/gdatetime.c:375 +#: glib/gdatetime.c:343 msgctxt "full weekday name" msgid "Friday" msgstr "Cuma" -#: glib/gdatetime.c:377 +#: glib/gdatetime.c:345 msgctxt "full weekday name" msgid "Saturday" msgstr "Cumartesi" -#: glib/gdatetime.c:379 +#: glib/gdatetime.c:347 msgctxt "full weekday name" msgid "Sunday" msgstr "Pazar" -#: glib/gdatetime.c:394 +#: glib/gdatetime.c:362 msgctxt "abbreviated weekday name" msgid "Mon" msgstr "Pzt" -#: glib/gdatetime.c:396 +#: glib/gdatetime.c:364 msgctxt "abbreviated weekday name" msgid "Tue" msgstr "Sal" -#: glib/gdatetime.c:398 +#: glib/gdatetime.c:366 msgctxt "abbreviated weekday name" msgid "Wed" msgstr "Çar" -#: glib/gdatetime.c:400 +#: glib/gdatetime.c:368 msgctxt "abbreviated weekday name" msgid "Thu" msgstr "Per" -#: glib/gdatetime.c:402 +#: glib/gdatetime.c:370 msgctxt "abbreviated weekday name" msgid "Fri" msgstr "Cum" -#: glib/gdatetime.c:404 +#: glib/gdatetime.c:372 msgctxt "abbreviated weekday name" msgid "Sat" msgstr "Cmt" -#: glib/gdatetime.c:406 +#: glib/gdatetime.c:374 msgctxt "abbreviated weekday name" msgid "Sun" msgstr "Paz" @@ -4849,62 +4853,62 @@ msgstr "Paz" #. * (western European, non-European) there is no difference between the #. * standalone and complete date form. #. -#: glib/gdatetime.c:470 +#: glib/gdatetime.c:438 msgctxt "full month name with day" msgid "January" msgstr "Ocak" -#: glib/gdatetime.c:472 +#: glib/gdatetime.c:440 msgctxt "full month name with day" msgid "February" msgstr "Şubat" -#: glib/gdatetime.c:474 +#: glib/gdatetime.c:442 msgctxt "full month name with day" msgid "March" msgstr "Mart" -#: glib/gdatetime.c:476 +#: glib/gdatetime.c:444 msgctxt "full month name with day" msgid "April" msgstr "Nisan" -#: glib/gdatetime.c:478 +#: glib/gdatetime.c:446 msgctxt "full month name with day" msgid "May" msgstr "Mayıs" -#: glib/gdatetime.c:480 +#: glib/gdatetime.c:448 msgctxt "full month name with day" msgid "June" msgstr "Haziran" -#: glib/gdatetime.c:482 +#: glib/gdatetime.c:450 msgctxt "full month name with day" msgid "July" msgstr "Temmuz" -#: glib/gdatetime.c:484 +#: glib/gdatetime.c:452 msgctxt "full month name with day" msgid "August" msgstr "Ağustos" -#: glib/gdatetime.c:486 +#: glib/gdatetime.c:454 msgctxt "full month name with day" msgid "September" msgstr "Eylül" -#: glib/gdatetime.c:488 +#: glib/gdatetime.c:456 msgctxt "full month name with day" msgid "October" msgstr "Ekim" -#: glib/gdatetime.c:490 +#: glib/gdatetime.c:458 msgctxt "full month name with day" msgid "November" msgstr "Kasım" -#: glib/gdatetime.c:492 +#: glib/gdatetime.c:460 msgctxt "full month name with day" msgid "December" msgstr "Aralık" @@ -4926,74 +4930,74 @@ msgstr "Aralık" #. * month names almost ready to copy and paste here. In other systems #. * due to a bug the result is incorrect in some languages. #. -#: glib/gdatetime.c:557 +#: glib/gdatetime.c:525 msgctxt "abbreviated month name with day" msgid "Jan" msgstr "Oca" -#: glib/gdatetime.c:559 +#: glib/gdatetime.c:527 msgctxt "abbreviated month name with day" msgid "Feb" msgstr "Şub" -#: glib/gdatetime.c:561 +#: glib/gdatetime.c:529 msgctxt "abbreviated month name with day" msgid "Mar" msgstr "Mar" -#: glib/gdatetime.c:563 +#: glib/gdatetime.c:531 msgctxt "abbreviated month name with day" msgid "Apr" msgstr "Nis" -#: glib/gdatetime.c:565 +#: glib/gdatetime.c:533 msgctxt "abbreviated month name with day" msgid "May" msgstr "May" -#: glib/gdatetime.c:567 +#: glib/gdatetime.c:535 msgctxt "abbreviated month name with day" msgid "Jun" msgstr "Haz" -#: glib/gdatetime.c:569 +#: glib/gdatetime.c:537 msgctxt "abbreviated month name with day" msgid "Jul" msgstr "Tem" -#: glib/gdatetime.c:571 +#: glib/gdatetime.c:539 msgctxt "abbreviated month name with day" msgid "Aug" msgstr "Ağu" -#: glib/gdatetime.c:573 +#: glib/gdatetime.c:541 msgctxt "abbreviated month name with day" msgid "Sep" msgstr "Eyl" -#: glib/gdatetime.c:575 +#: glib/gdatetime.c:543 msgctxt "abbreviated month name with day" msgid "Oct" msgstr "Eki" -#: glib/gdatetime.c:577 +#: glib/gdatetime.c:545 msgctxt "abbreviated month name with day" msgid "Nov" msgstr "Kas" -#: glib/gdatetime.c:579 +#: glib/gdatetime.c:547 msgctxt "abbreviated month name with day" msgid "Dec" msgstr "Ara" #. Translators: 'before midday' indicator -#: glib/gdatetime.c:596 +#: glib/gdatetime.c:564 msgctxt "GDateTime" msgid "AM" msgstr "ÖÖ" #. Translators: 'after midday' indicator -#: glib/gdatetime.c:599 +#: glib/gdatetime.c:567 msgctxt "GDateTime" msgid "PM" msgstr "ÖS" @@ -5024,7 +5028,7 @@ msgstr "“%s” dosyası çok büyük" msgid "Failed to read from file “%s”: %s" msgstr "“%s” dosyasından okunamadı: %s" -#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1472 +#: glib/gfileutils.c:920 glib/gfileutils.c:995 glib/gfileutils.c:1502 #, c-format msgid "Failed to open file “%s”: %s" msgstr "“%s” dosyası açılamadı: %s" @@ -5045,37 +5049,42 @@ msgid "Failed to rename file “%s” to “%s”: g_rename() failed: %s" msgstr "" "“%s” dosyasının adı “%s” olarak değiştirilemedi: g_rename() başarısız: %s" -#: glib/gfileutils.c:1179 +#: glib/gfileutils.c:1164 +#, c-format +msgid "Failed to write file “%s”: ftruncate() failed: %s" +msgstr "“%s” dosyasına yazılamadı: ftruncate() başarısız: %s" + +#: glib/gfileutils.c:1209 #, c-format msgid "Failed to write file “%s”: write() failed: %s" msgstr "“%s” dosyasına yazılamadı: write() başarısız: %s" -#: glib/gfileutils.c:1200 +#: glib/gfileutils.c:1230 #, c-format msgid "Failed to write file “%s”: fsync() failed: %s" msgstr "“%s” dosyasına yazılamadı: fsync() başarısız: %s" -#: glib/gfileutils.c:1361 glib/gfileutils.c:1776 +#: glib/gfileutils.c:1391 glib/gfileutils.c:1808 #, c-format msgid "Failed to create file “%s”: %s" msgstr "“%s” dosyası oluşturulamadı: %s" -#: glib/gfileutils.c:1406 +#: glib/gfileutils.c:1436 #, c-format msgid "Existing file “%s” could not be removed: g_unlink() failed: %s" msgstr "Var olan dosya “%s” kaldırılamadı: g_unlink() başarısızlığı: %s" -#: glib/gfileutils.c:1741 +#: glib/gfileutils.c:1773 #, c-format msgid "Template “%s” invalid, should not contain a “%s”" msgstr "“%s” şablonu geçersiz, “%s” içermemeli" -#: glib/gfileutils.c:1754 +#: glib/gfileutils.c:1786 #, c-format msgid "Template “%s” doesn’t contain XXXXXX" msgstr "“%s” şablonu XXXXXX içermiyor" -#: glib/gfileutils.c:2348 glib/gfileutils.c:2377 +#: glib/gfileutils.c:2380 glib/gfileutils.c:2409 #, c-format msgid "Failed to read the symbolic link “%s”: %s" msgstr "“%s” simgesel bağı okunamadı: %s" @@ -5101,15 +5110,15 @@ msgstr "Kanal kısmi bir karakterde sonlanıyor" msgid "Can’t do a raw read in g_io_channel_read_to_end" msgstr "g_io_channel_read_to_end içinde ham okuma başarısız" -#: glib/gkeyfile.c:802 +#: glib/gkeyfile.c:792 msgid "Valid key file could not be found in search dirs" msgstr "Arama dizinlerinde geçerli anahtar dosyası bulunamadı" -#: glib/gkeyfile.c:839 +#: glib/gkeyfile.c:829 msgid "Not a regular file" msgstr "Normal dosya değil" -#: glib/gkeyfile.c:1297 +#: glib/gkeyfile.c:1287 #, c-format msgid "" "Key file contains line “%s” which is not a key-value pair, group, or comment" @@ -5117,50 +5126,50 @@ msgstr "" "Anahtar dosyası; anahtar-değer çifti, küme veya yorum olmayan “%s” satırını " "içeriyor" -#: glib/gkeyfile.c:1354 +#: glib/gkeyfile.c:1344 #, c-format msgid "Invalid group name: %s" msgstr "Geçersiz küme adı: %s" -#: glib/gkeyfile.c:1378 +#: glib/gkeyfile.c:1368 msgid "Key file does not start with a group" msgstr "Anahtar dosyası kümeyle başlamıyor" -#: glib/gkeyfile.c:1402 +#: glib/gkeyfile.c:1392 #, c-format msgid "Invalid key name: %.*s" msgstr "Geçersiz anahtar adı: %.*s" -#: glib/gkeyfile.c:1430 +#: glib/gkeyfile.c:1420 #, c-format msgid "Key file contains unsupported encoding “%s”" msgstr "Anahtar dosya desteklenmeyen “%s” kodlamasını içeriyor" -#: glib/gkeyfile.c:1678 glib/gkeyfile.c:1851 glib/gkeyfile.c:3298 -#: glib/gkeyfile.c:3400 glib/gkeyfile.c:3505 glib/gkeyfile.c:3634 -#: glib/gkeyfile.c:3777 glib/gkeyfile.c:4026 glib/gkeyfile.c:4100 +#: glib/gkeyfile.c:1668 glib/gkeyfile.c:1841 glib/gkeyfile.c:3288 +#: glib/gkeyfile.c:3390 glib/gkeyfile.c:3495 glib/gkeyfile.c:3624 +#: glib/gkeyfile.c:3767 glib/gkeyfile.c:4016 glib/gkeyfile.c:4090 #, c-format msgid "Key file does not have group “%s”" msgstr "Anahtar dosyasında “%s” kümesi yok" -#: glib/gkeyfile.c:1806 +#: glib/gkeyfile.c:1796 #, c-format msgid "Key file does not have key “%s” in group “%s”" msgstr "Anahtar dosyası, “%2$s” kümesinde “%1$s” anahtarı içermiyor" -#: glib/gkeyfile.c:1968 glib/gkeyfile.c:2084 +#: glib/gkeyfile.c:1958 glib/gkeyfile.c:2074 #, c-format msgid "Key file contains key “%s” with value “%s” which is not UTF-8" msgstr "Anahtar dosyası, UTF-8 olmayan “%s” anahtarını “%s” değeriyle içeriyor" -#: glib/gkeyfile.c:1988 glib/gkeyfile.c:2104 glib/gkeyfile.c:2543 +#: glib/gkeyfile.c:1978 glib/gkeyfile.c:2094 glib/gkeyfile.c:2533 #, c-format msgid "" "Key file contains key “%s” which has a value that cannot be interpreted." msgstr "" "Anahtar dosyası yorumlanamayan bir değere sahip olan “%s” anahtarını içerir." -#: glib/gkeyfile.c:2758 glib/gkeyfile.c:3127 +#: glib/gkeyfile.c:2748 glib/gkeyfile.c:3117 #, c-format msgid "" "Key file contains key “%s” in group “%s” which has a value that cannot be " @@ -5169,38 +5178,38 @@ msgstr "" "“%2$s” kümesindeki anahtar dosyası, yorumlanamayan “%1$s” anahtarını " "içeriyor." -#: glib/gkeyfile.c:2836 glib/gkeyfile.c:2913 +#: glib/gkeyfile.c:2826 glib/gkeyfile.c:2903 #, c-format msgid "Key “%s” in group “%s” has value “%s” where %s was expected" msgstr "" "“%2$s” kümesindeki “%1$s” anahtarı “%4$s” değerine sahip olması beklenirken " "“%3$s” değerine sahip" -#: glib/gkeyfile.c:4357 +#: glib/gkeyfile.c:4346 msgid "Key file contains escape character at end of line" msgstr "Anahtar dosyası satır sonunda çıkış karakteri içeriyor" -#: glib/gkeyfile.c:4394 +#: glib/gkeyfile.c:4368 #, c-format msgid "Key file contains invalid escape sequence “%s”" msgstr "“%s” anahtar dosyası geçersiz çıkış dizisi içeriyor" -#: glib/gkeyfile.c:4545 +#: glib/gkeyfile.c:4520 #, c-format msgid "Value “%s” cannot be interpreted as a number." msgstr "“%s” değeri bir sayı olarak yorumlanamıyor." -#: glib/gkeyfile.c:4559 +#: glib/gkeyfile.c:4534 #, c-format msgid "Integer value “%s” out of range" msgstr "“%s”, tamsayı değeri aralık dışında" -#: glib/gkeyfile.c:4592 +#: glib/gkeyfile.c:4567 #, c-format msgid "Value “%s” cannot be interpreted as a float number." msgstr "“%s” değeri bir gerçel sayı olarak yorumlanamıyor." -#: glib/gkeyfile.c:4631 +#: glib/gkeyfile.c:4606 #, c-format msgid "Value “%s” cannot be interpreted as a boolean." msgstr "“%s” değeri mantıksal değer olarak yorumlanamıyor." @@ -5221,32 +5230,32 @@ msgstr "%s%s%s%s için eşleme oluşturulamadı: mmap() başarısız: %s" msgid "Failed to open file “%s”: open() failed: %s" msgstr "“%s” dosyası açılamadı: open() başarısız: %s" -#: glib/gmarkup.c:398 glib/gmarkup.c:440 +#: glib/gmarkup.c:344 glib/gmarkup.c:386 #, c-format msgid "Error on line %d char %d: " msgstr "Satır %d karakter %d hatalı: " -#: glib/gmarkup.c:462 glib/gmarkup.c:545 +#: glib/gmarkup.c:408 glib/gmarkup.c:491 #, c-format msgid "Invalid UTF-8 encoded text in name — not valid “%s”" msgstr "Adda geçersiz UTF-8 kodlu metin — geçerli olmayan “%s”" -#: glib/gmarkup.c:473 +#: glib/gmarkup.c:419 #, c-format msgid "“%s” is not a valid name" msgstr "“%s” geçerli bir ad değil" -#: glib/gmarkup.c:489 +#: glib/gmarkup.c:435 #, c-format msgid "“%s” is not a valid name: “%c”" msgstr "“%s” geçerli bir ad değil: “%c”" -#: glib/gmarkup.c:613 +#: glib/gmarkup.c:559 #, c-format msgid "Error on line %d: %s" msgstr "Satır %d hata içeriyor: %s" -#: glib/gmarkup.c:690 +#: glib/gmarkup.c:636 #, c-format msgid "" "Failed to parse “%-.*s”, which should have been a digit inside a character " @@ -5255,7 +5264,7 @@ msgstr "" "Karakter referansı içinde bir rakam olması gereken “%-.*s” ayrıştırılamadı, " "(örneğin; ê) — rakam çok büyük olabilir" -#: glib/gmarkup.c:702 +#: glib/gmarkup.c:648 msgid "" "Character reference did not end with a semicolon; most likely you used an " "ampersand character without intending to start an entity — escape ampersand " @@ -5265,23 +5274,23 @@ msgstr "" "özvarlık başlatmak istemeksizin “ve” imi kullandınız — “ve” imini & " "olarak kullanabilirsiniz" -#: glib/gmarkup.c:728 +#: glib/gmarkup.c:674 #, c-format msgid "Character reference “%-.*s” does not encode a permitted character" msgstr "Karakter referansı “%-.*s” izin verilen karakteri kodlamıyor" -#: glib/gmarkup.c:766 +#: glib/gmarkup.c:712 msgid "" "Empty entity “&;” seen; valid entities are: & " < > '" msgstr "" "Boş özvarlık “&;” görüldü; geçerli ögeler: & " < > '" -#: glib/gmarkup.c:774 +#: glib/gmarkup.c:720 #, c-format msgid "Entity name “%-.*s” is not known" msgstr "Varlık adı “%-.*s” bilinmiyor" -#: glib/gmarkup.c:779 +#: glib/gmarkup.c:725 msgid "" "Entity did not end with a semicolon; most likely you used an ampersand " "character without intending to start an entity — escape ampersand as &" @@ -5290,11 +5299,11 @@ msgstr "" "başlatmak istemeksizin “ve” imi kullandınız — “ve” imini & olarak " "kullanabilirsiniz" -#: glib/gmarkup.c:1193 +#: glib/gmarkup.c:1139 msgid "Document must begin with an element (e.g. )" msgstr "Belge bir öge ile başlamalıdır (örneğin )" -#: glib/gmarkup.c:1233 +#: glib/gmarkup.c:1179 #, c-format msgid "" "“%s” is not a valid character following a “<” character; it may not begin an " @@ -5303,7 +5312,7 @@ msgstr "" "“<” karakterinden sonra gelen “%s” geçerli bir karakter değil; bir öge adı " "başlatmamalı" -#: glib/gmarkup.c:1276 +#: glib/gmarkup.c:1222 #, c-format msgid "" "Odd character “%s”, expected a “>” character to end the empty-element tag " @@ -5311,12 +5320,12 @@ msgid "" msgstr "" "Tuhaf karakter “%s”, “%s” boş öge etiketinin sonunda “>” karakteri bekledi" -#: glib/gmarkup.c:1346 +#: glib/gmarkup.c:1292 #, c-format msgid "Too many attributes in element “%s”" msgstr "“%s” ögesinde çok fazla öznitelik var" -#: glib/gmarkup.c:1366 +#: glib/gmarkup.c:1312 #, c-format msgid "" "Odd character “%s”, expected a “=” after attribute name “%s” of element “%s”" @@ -5324,7 +5333,7 @@ msgstr "" "Tuhaf karakter “%1$s”, “%3$s” ögesinin “%2$s” özniteliğinin sonunda “=” " "karakteri bekledi" -#: glib/gmarkup.c:1408 +#: glib/gmarkup.c:1354 #, c-format msgid "" "Odd character “%s”, expected a “>” or “/” character to end the start tag of " @@ -5335,7 +5344,7 @@ msgstr "" "“>”, “/” karakteri veya bir öznitelik bekledi; öznitelik adında geçersiz bir " "karakter kullanmış olabilirsiniz" -#: glib/gmarkup.c:1453 +#: glib/gmarkup.c:1399 #, c-format msgid "" "Odd character “%s”, expected an open quote mark after the equals sign when " @@ -5344,7 +5353,7 @@ msgstr "" "Tuhaf karakter “%1$s”, “%3$s” ögesindeki “%2$s” özniteliği için değer " "verildiğinde eşittir iminden sonra tırnak imi beklendi" -#: glib/gmarkup.c:1587 +#: glib/gmarkup.c:1533 #, c-format msgid "" "“%s” is not a valid character following the characters “”" -#: glib/gmarkup.c:1637 +#: glib/gmarkup.c:1583 #, c-format msgid "Element “%s” was closed, no element is currently open" msgstr "“%s” ögesi kapatılmış, hiçbir öge şu anda açık değil" -#: glib/gmarkup.c:1646 +#: glib/gmarkup.c:1592 #, c-format msgid "Element “%s” was closed, but the currently open element is “%s”" msgstr "“%s” ögesi kapatılmış, ancak “%s” şu an açık olan ögedir" -#: glib/gmarkup.c:1799 +#: glib/gmarkup.c:1745 msgid "Document was empty or contained only whitespace" msgstr "Belge boş veya yalnızca boşluk karakteri içeriyor" -#: glib/gmarkup.c:1813 +#: glib/gmarkup.c:1759 msgid "Document ended unexpectedly just after an open angle bracket “<”" msgstr "" "Belge, açık açı parantezi “<” iminden hemen sonra beklenmedik biçimde " "sonlandı" -#: glib/gmarkup.c:1821 glib/gmarkup.c:1866 +#: glib/gmarkup.c:1767 glib/gmarkup.c:1812 #, c-format msgid "" "Document ended unexpectedly with elements still open — “%s” was the last " @@ -5391,7 +5400,7 @@ msgstr "" "Belge, ögeleri hala açıkken beklenmedik biçimde sonlandı - son açılan öge: " "“%s”" -#: glib/gmarkup.c:1829 +#: glib/gmarkup.c:1775 #, c-format msgid "" "Document ended unexpectedly, expected to see a close angle bracket ending " @@ -5400,19 +5409,19 @@ msgstr "" "Belge beklenmedik biçimde sonlandı, etiketi bitiren kapalı açı parantezi ile " "biten <%s/> beklendi" -#: glib/gmarkup.c:1835 +#: glib/gmarkup.c:1781 msgid "Document ended unexpectedly inside an element name" msgstr "Belge bir öge adının içinde beklenmedik biçimde sonlandı" -#: glib/gmarkup.c:1841 +#: glib/gmarkup.c:1787 msgid "Document ended unexpectedly inside an attribute name" msgstr "Belge bir öznitelik adı içinde beklenmedik biçimde sonlandı" -#: glib/gmarkup.c:1846 +#: glib/gmarkup.c:1792 msgid "Document ended unexpectedly inside an element-opening tag." msgstr "Belge bir öge-açma etiketi içinde beklenmedik biçimde sonlandı." -#: glib/gmarkup.c:1852 +#: glib/gmarkup.c:1798 msgid "" "Document ended unexpectedly after the equals sign following an attribute " "name; no attribute value" @@ -5420,261 +5429,261 @@ msgstr "" "Belge öznitelik adını takip eden eşittir iminden sonra beklenmedik biçimde " "sonlandı; öznitelik değeri yok" -#: glib/gmarkup.c:1859 +#: glib/gmarkup.c:1805 msgid "Document ended unexpectedly while inside an attribute value" msgstr "Belge bir öznitelik değeri içinde iken beklenmedik biçimde sonlandı" -#: glib/gmarkup.c:1876 +#: glib/gmarkup.c:1822 #, c-format msgid "Document ended unexpectedly inside the close tag for element “%s”" msgstr "" "Belge, “%s” ögesinin kapatma etiketi içinde beklenmedik biçimde sonlandı" -#: glib/gmarkup.c:1880 +#: glib/gmarkup.c:1826 msgid "" "Document ended unexpectedly inside the close tag for an unopened element" msgstr "" "Belge, açık olmayan bir öge için kapatma etiketi içinde beklenmedik biçimde " "sonlandı" -#: glib/gmarkup.c:1886 +#: glib/gmarkup.c:1832 msgid "Document ended unexpectedly inside a comment or processing instruction" msgstr "" "Belge bir yorum veya işlem talimatı içindeyken beklenmedik biçimde sonlandı" -#: glib/goption.c:875 +#: glib/goption.c:715 msgid "[OPTION…]" msgstr "[SEÇENEK…]" -#: glib/goption.c:991 +#: glib/goption.c:831 msgid "Help Options:" msgstr "Yardım Seçenekleri:" -#: glib/goption.c:992 +#: glib/goption.c:832 msgid "Show help options" msgstr "Yardım seçeneklerini göster" -#: glib/goption.c:998 +#: glib/goption.c:838 msgid "Show all help options" msgstr "Tüm yardım seçeneklerini göster" -#: glib/goption.c:1061 +#: glib/goption.c:901 msgid "Application Options:" msgstr "Uygulama Seçenekleri:" -#: glib/goption.c:1063 +#: glib/goption.c:903 msgid "Options:" msgstr "Seçenekler:" -#: glib/goption.c:1127 glib/goption.c:1197 +#: glib/goption.c:967 glib/goption.c:1037 #, c-format msgid "Cannot parse integer value “%s” for %s" msgstr "%2$s için tamsayı değeri “%1$s” ayrıştırılamıyor" -#: glib/goption.c:1137 glib/goption.c:1205 +#: glib/goption.c:977 glib/goption.c:1045 #, c-format msgid "Integer value “%s” for %s out of range" msgstr "%2$s için tamsayı değeri “%1$s” aralık dışında" -#: glib/goption.c:1162 +#: glib/goption.c:1002 #, c-format msgid "Cannot parse double value “%s” for %s" msgstr "%2$s için double değeri “%1$s” ayrıştırılamıyor" -#: glib/goption.c:1170 +#: glib/goption.c:1010 #, c-format msgid "Double value “%s” for %s out of range" msgstr "%2$s için double değeri “%1$s” aralık dışında" -#: glib/goption.c:1462 glib/goption.c:1541 +#: glib/goption.c:1302 glib/goption.c:1381 #, c-format msgid "Error parsing option %s" msgstr "%s seçeneği işlenirken hata" -#: glib/goption.c:1563 glib/goption.c:1676 +#: glib/goption.c:1403 glib/goption.c:1516 #, c-format msgid "Missing argument for %s" msgstr "%s için argüman eksik" -#: glib/goption.c:2186 +#: glib/goption.c:2026 #, c-format msgid "Unknown option %s" msgstr "Bilinmeyen seçenek %s" -#: glib/gregex.c:480 +#: glib/gregex.c:478 msgid "corrupted object" msgstr "bozuk nesne" -#: glib/gregex.c:482 +#: glib/gregex.c:480 msgid "out of memory" msgstr "yetersiz bellek" -#: glib/gregex.c:497 +#: glib/gregex.c:495 msgid "internal error" msgstr "iç hata" -#: glib/gregex.c:499 +#: glib/gregex.c:497 msgid "the pattern contains items not supported for partial matching" msgstr "doku (pattern), kısmi eşleme için desteklenmeyen ögeler içeriyor" -#: glib/gregex.c:501 +#: glib/gregex.c:499 msgid "back references as conditions are not supported for partial matching" msgstr "koşul olarak geri referanslar kısmi eşleme için desteklenmiyor" -#: glib/gregex.c:507 +#: glib/gregex.c:505 msgid "recursion limit reached" msgstr "iç içe yineleme sınırına ulaşıldı" -#: glib/gregex.c:509 +#: glib/gregex.c:507 msgid "bad offset" msgstr "geçersiz ofset" -#: glib/gregex.c:511 +#: glib/gregex.c:509 msgid "recursion loop" msgstr "yineleme döngüsü" #. should not happen in GRegex since we check modes before each match -#: glib/gregex.c:514 +#: glib/gregex.c:512 msgid "matching mode is requested that was not compiled for JIT" msgstr "JIT için derlenmemiş eşleşme kipi istendi" -#: glib/gregex.c:535 glib/gregex.c:1851 +#: glib/gregex.c:533 glib/gregex.c:1849 msgid "unknown error" msgstr "bilinmeyen hata" -#: glib/gregex.c:556 +#: glib/gregex.c:554 msgid "\\ at end of pattern" msgstr "\\ desenin sonunda" -#: glib/gregex.c:560 +#: glib/gregex.c:558 msgid "\\c at end of pattern" msgstr "\\c desenin sonunda" -#: glib/gregex.c:565 +#: glib/gregex.c:563 msgid "unrecognized character following \\" msgstr "\\ imini takiben anlaşılamayan karakter" -#: glib/gregex.c:569 +#: glib/gregex.c:567 msgid "numbers out of order in {} quantifier" msgstr "sayılar {} niceliği içerisinde sıra dışı" -#: glib/gregex.c:573 +#: glib/gregex.c:571 msgid "number too big in {} quantifier" msgstr "sayılar {} niceliği içerisinde çok büyük" -#: glib/gregex.c:577 +#: glib/gregex.c:575 msgid "missing terminating ] for character class" msgstr "karakter sınıfı için eksik sonlanan ]" -#: glib/gregex.c:581 +#: glib/gregex.c:579 msgid "invalid escape sequence in character class" msgstr "karakter sınıfında geçersiz dizi" -#: glib/gregex.c:585 +#: glib/gregex.c:583 msgid "range out of order in character class" msgstr "karakter sınıfında sıra dışı kapsam" -#: glib/gregex.c:590 +#: glib/gregex.c:588 msgid "nothing to repeat" msgstr "yinelenecek bir şey yok" -#: glib/gregex.c:594 +#: glib/gregex.c:592 msgid "unrecognized character after (? or (?-" msgstr "(? ya da (?- sonrası tanınmayan karakter" -#: glib/gregex.c:598 +#: glib/gregex.c:596 msgid "POSIX named classes are supported only within a class" msgstr "POSIX adlandırılmış sınıflar yalnızca bir sınıf içinde desteklenir" -#: glib/gregex.c:602 +#: glib/gregex.c:600 msgid "POSIX collating elements are not supported" msgstr "POSIX karşılaştırma ögeleri desteklenmiyor" -#: glib/gregex.c:608 +#: glib/gregex.c:606 msgid "missing terminating )" msgstr "eksik sonlandıran )" -#: glib/gregex.c:612 +#: glib/gregex.c:610 msgid "reference to non-existent subpattern" msgstr "var olmayan alt desene referans" -#: glib/gregex.c:616 +#: glib/gregex.c:614 msgid "missing ) after comment" msgstr "açıklama sonrası eksik )" -#: glib/gregex.c:620 +#: glib/gregex.c:618 msgid "regular expression is too large" msgstr "düzenli ifade çok uzun" -#: glib/gregex.c:624 +#: glib/gregex.c:622 msgid "malformed number or name after (?(" msgstr "(?( sonrası bozuk rakam ya da ad" -#: glib/gregex.c:628 +#: glib/gregex.c:626 msgid "lookbehind assertion is not fixed length" msgstr "geribakma iddiası sabit uzunlukta değil" -#: glib/gregex.c:632 +#: glib/gregex.c:630 msgid "conditional group contains more than two branches" msgstr "koşul kümesi ikiden daha çok dal içeriyor" -#: glib/gregex.c:636 +#: glib/gregex.c:634 msgid "assertion expected after (?(" msgstr "(?( sonrası ifade beklendi" -#: glib/gregex.c:640 +#: glib/gregex.c:638 msgid "a numbered reference must not be zero" msgstr "numaralandırılmış kaynak sıfır olmamalıdır" -#: glib/gregex.c:644 +#: glib/gregex.c:642 msgid "unknown POSIX class name" msgstr "bilinmeyen POSIX sınıf adı" -#: glib/gregex.c:649 +#: glib/gregex.c:647 msgid "character value in \\x{...} sequence is too large" msgstr "\\x{...} dizisi içerisinde karakter değeri çok büyük" -#: glib/gregex.c:653 +#: glib/gregex.c:651 msgid "\\C not allowed in lookbehind assertion" msgstr "\\C geriye bakma iddiası içerisinde izin verilmiyor" -#: glib/gregex.c:657 +#: glib/gregex.c:655 msgid "missing terminator in subpattern name" msgstr "alt desen adı içerisinde eksik sonlandırıcı" -#: glib/gregex.c:661 +#: glib/gregex.c:659 msgid "two named subpatterns have the same name" msgstr "iki adlı alt desenler aynı ada sahip" -#: glib/gregex.c:665 +#: glib/gregex.c:663 msgid "malformed \\P or \\p sequence" msgstr "bozulmuş \\P ya da \\p dizisi" -#: glib/gregex.c:669 +#: glib/gregex.c:667 msgid "unknown property name after \\P or \\p" msgstr "\\P ya da \\p sonrası bilinmeyen özellik adı" -#: glib/gregex.c:673 +#: glib/gregex.c:671 msgid "subpattern name is too long (maximum 32 characters)" msgstr "alt desen adı çok uzun (en çok 32 karakter)" -#: glib/gregex.c:677 +#: glib/gregex.c:675 msgid "too many named subpatterns (maximum 10,000)" msgstr "çok fazla adlandırılmış alt desen (en çok 10.000)" -#: glib/gregex.c:681 +#: glib/gregex.c:679 msgid "octal value is greater than \\377" msgstr "sekizlik değer \\377’den daha büyük" -#: glib/gregex.c:685 +#: glib/gregex.c:683 msgid "DEFINE group contains more than one branch" msgstr "DEFINE kümesi birden çok dal içeriyor" -#: glib/gregex.c:689 +#: glib/gregex.c:687 msgid "inconsistent NEWLINE options" msgstr "kararsız NEWLINE seçenekleri" -#: glib/gregex.c:693 +#: glib/gregex.c:691 msgid "" "\\g is not followed by a braced, angle-bracketed, or quoted name or number, " "or by a plain number" @@ -5682,119 +5691,119 @@ msgstr "" "\\g bir parantezli ad ya da tercihten parentezli sıfır olmayan sayı " "tarafından takip edilmiyor" -#: glib/gregex.c:698 +#: glib/gregex.c:696 msgid "an argument is not allowed for (*ACCEPT), (*FAIL), or (*COMMIT)" msgstr "(*ACCEPT), (*FAIL) ya da (*COMMIT) için bir argümana izin verilmez" -#: glib/gregex.c:702 +#: glib/gregex.c:700 msgid "(*VERB) not recognized" msgstr "(*VERB) tanınamadı" -#: glib/gregex.c:706 +#: glib/gregex.c:704 msgid "number is too big" msgstr "sayı çok büyük" -#: glib/gregex.c:710 +#: glib/gregex.c:708 msgid "missing subpattern name after (?&" msgstr "(?& den sonra eksik alt desen adı" -#: glib/gregex.c:714 +#: glib/gregex.c:712 msgid "different names for subpatterns of the same number are not allowed" msgstr "aynı sayıya izin verilmeyen alt desenler için farklı adlar" -#: glib/gregex.c:718 +#: glib/gregex.c:716 msgid "(*MARK) must have an argument" msgstr "(*MARK) bir argüman almalı" -#: glib/gregex.c:722 +#: glib/gregex.c:720 msgid "\\c must be followed by an ASCII character" msgstr "\\c karakteri ASCII karakterleri tarafından takip edilmelidir" -#: glib/gregex.c:726 +#: glib/gregex.c:724 msgid "\\k is not followed by a braced, angle-bracketed, or quoted name" msgstr "" "\\k bir parantezli ad ya da tercihten parentezli sıfır olmayan sayı " "tarafından takip edilmiyor" -#: glib/gregex.c:730 +#: glib/gregex.c:728 msgid "\\N is not supported in a class" msgstr "\\N bir sınıfta desteklenmez" -#: glib/gregex.c:734 +#: glib/gregex.c:732 msgid "name is too long in (*MARK), (*PRUNE), (*SKIP), or (*THEN)" msgstr "(*MARK), (*PRUNE), (*SKIP) ya da (*THEN) içinde ad çok uzun" -#: glib/gregex.c:738 glib/gregex.c:874 +#: glib/gregex.c:736 glib/gregex.c:872 msgid "code overflow" msgstr "kod akış taşması" -#: glib/gregex.c:742 +#: glib/gregex.c:740 msgid "unrecognized character after (?P" msgstr "(?P sonrası tanımlanmayan karakter" -#: glib/gregex.c:746 +#: glib/gregex.c:744 msgid "overran compiling workspace" msgstr "derleme çalışma alanı kaplandı" -#: glib/gregex.c:750 +#: glib/gregex.c:748 msgid "previously-checked referenced subpattern not found" msgstr "önceden denetlenmiş referanslı alt desen bulunamadı" -#: glib/gregex.c:873 glib/gregex.c:1135 glib/gregex.c:2457 +#: glib/gregex.c:871 glib/gregex.c:1133 glib/gregex.c:2455 #, c-format msgid "Error while matching regular expression %s: %s" msgstr "Düzenli ifade %s eşleşirken hata: %s" -#: glib/gregex.c:1735 +#: glib/gregex.c:1733 msgid "PCRE library is compiled without UTF8 support" msgstr "PCRE kütüphanesi UTF8 desteği olmadan derlenmiş" -#: glib/gregex.c:1743 +#: glib/gregex.c:1741 msgid "PCRE library is compiled with incompatible options" msgstr "PCRE kütüphanesi uyuşmayan seçenekler ile derlenmiş" -#: glib/gregex.c:1860 +#: glib/gregex.c:1858 #, c-format msgid "Error while compiling regular expression ‘%s’ at char %s: %s" msgstr "Düzenli ifade ‘%s’ derlenirken karakter %s hatalı: %s" -#: glib/gregex.c:2900 +#: glib/gregex.c:2898 msgid "hexadecimal digit or “}” expected" msgstr "onaltılı rakam ya da “}” beklendi" -#: glib/gregex.c:2916 +#: glib/gregex.c:2914 msgid "hexadecimal digit expected" msgstr "onaltılı rakam beklendi" -#: glib/gregex.c:2956 +#: glib/gregex.c:2954 msgid "missing “<” in symbolic reference" msgstr "simgesel referansda eksik “<”" -#: glib/gregex.c:2965 +#: glib/gregex.c:2963 msgid "unfinished symbolic reference" msgstr "tamamlanmamış simgesel referans" -#: glib/gregex.c:2972 +#: glib/gregex.c:2970 msgid "zero-length symbolic reference" msgstr "sıfır-uzunlukta simgesel referans" -#: glib/gregex.c:2983 +#: glib/gregex.c:2981 msgid "digit expected" msgstr "rakam beklendi" -#: glib/gregex.c:3001 +#: glib/gregex.c:2999 msgid "illegal symbolic reference" msgstr "geçersiz simgesel referans" -#: glib/gregex.c:3064 +#: glib/gregex.c:3062 msgid "stray final “\\”" msgstr "son “\\” kayıp" -#: glib/gregex.c:3068 +#: glib/gregex.c:3066 msgid "unknown escape sequence" msgstr "geçersiz çıkış dizisi" -#: glib/gregex.c:3078 +#: glib/gregex.c:3076 #, c-format msgid "Error while parsing replacement text “%s” at char %lu: %s" msgstr "Yerine koyma metni “%s” işlenirken karakter %lu hatalı: %s" @@ -5822,92 +5831,92 @@ msgstr "%c için eşleşen alıntı bulunmadan metin bitti. (Metin: “%s”)" msgid "Text was empty (or contained only whitespace)" msgstr "Metin boştu (veya yalnızca boşluk içeriyordu)" -#: glib/gspawn.c:320 +#: glib/gspawn.c:303 #, c-format msgid "Failed to read data from child process (%s)" msgstr "Alt süreçten bilgi okunamadı (%s)" -#: glib/gspawn.c:473 +#: glib/gspawn.c:456 #, c-format msgid "Unexpected error in reading data from a child process (%s)" msgstr "Alt süreçten bilgi okurken beklenmeyen hata oluştu (%s)" -#: glib/gspawn.c:558 +#: glib/gspawn.c:536 #, c-format msgid "Unexpected error in waitpid() (%s)" msgstr "waitpid() (%s) içinde beklenmeyen hata" -#: glib/gspawn.c:1180 glib/gspawn-win32.c:1575 +#: glib/gspawn.c:1158 glib/gspawn-win32.c:1575 #, c-format msgid "Child process exited with code %ld" msgstr "Alt işlem %ld kodu ile sonlandı" -#: glib/gspawn.c:1188 +#: glib/gspawn.c:1166 #, c-format msgid "Child process killed by signal %ld" msgstr "Alt işlem, %ld sinyali ile sonlandı" -#: glib/gspawn.c:1195 +#: glib/gspawn.c:1173 #, c-format msgid "Child process stopped by signal %ld" msgstr "Alt işlem %ld sinyali ile durduruldu" -#: glib/gspawn.c:1202 +#: glib/gspawn.c:1180 #, c-format msgid "Child process exited abnormally" msgstr "Alt işlem anormal bir biçimde sonlandı" -#: glib/gspawn.c:2032 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 +#: glib/gspawn.c:2017 glib/gspawn-win32.c:472 glib/gspawn-win32.c:480 #, c-format msgid "Failed to read from child pipe (%s)" msgstr "Alt süreç borusundan okunamadı (%s)" -#: glib/gspawn.c:2404 +#: glib/gspawn.c:2396 #, c-format msgid "Failed to spawn child process “%s” (%s)" msgstr "“%s” alt süreci üretilemedi (%s)" -#: glib/gspawn.c:2530 +#: glib/gspawn.c:2520 #, c-format msgid "Failed to fork (%s)" msgstr "Çatallamadı (%s)" -#: glib/gspawn.c:2690 glib/gspawn-win32.c:503 +#: glib/gspawn.c:2681 glib/gspawn-win32.c:503 #, c-format msgid "Failed to change to directory “%s” (%s)" msgstr "“%s” dizinine değiştirilemedi (%s)" -#: glib/gspawn.c:2700 +#: glib/gspawn.c:2691 #, c-format msgid "Failed to execute child process “%s” (%s)" msgstr "“%s” alt süreç çalıştırılamadı (%s)" -#: glib/gspawn.c:2710 +#: glib/gspawn.c:2701 #, c-format msgid "Failed to open file to remap file descriptor (%s)" msgstr "Dosya tanımlayıcıyı yeniden eşlemek için dosya açılamadı (%s)" -#: glib/gspawn.c:2718 +#: glib/gspawn.c:2709 #, c-format msgid "Failed to duplicate file descriptor for child process (%s)" msgstr "Alt süreç için dosya tanımlayıcı çoğaltılamadı (%s)" -#: glib/gspawn.c:2727 +#: glib/gspawn.c:2718 #, c-format msgid "Failed to fork child process (%s)" msgstr "Alt süreç çatallanamadı (%s)" -#: glib/gspawn.c:2735 +#: glib/gspawn.c:2726 #, c-format msgid "Failed to close file descriptor for child process (%s)" msgstr "Alt süreç için dosya tanımlayıcı kapatılamadı (%s)" -#: glib/gspawn.c:2743 +#: glib/gspawn.c:2734 #, c-format msgid "Unknown error executing child process “%s”" msgstr "Alt süreç “%s” çalıştırılırken bilinmeyen hata oluştu" -#: glib/gspawn.c:2767 +#: glib/gspawn.c:2758 #, c-format msgid "Failed to read enough data from child pid pipe (%s)" msgstr "Alt süreç borusundan yeterli bilgi okunamadı (%s)" @@ -6116,65 +6125,65 @@ msgstr "PiB" msgid "EiB" msgstr "EiB" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 kb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 kbit" #: glib/gutils.c:2994 -msgid "kb" -msgstr "kb" +msgid "kbit" +msgstr "kbit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mbit" #: glib/gutils.c:2996 -msgid "Mb" -msgstr "Mb" +msgid "Mbit" +msgstr "Mbit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gbit" #: glib/gutils.c:2998 -msgid "Gb" -msgstr "Gb" +msgid "Gbit" +msgstr "Gbit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tbit" #: glib/gutils.c:3000 -msgid "Tb" -msgstr "Tb" +msgid "Tbit" +msgstr "Tbit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pbit" #: glib/gutils.c:3002 -msgid "Pb" -msgstr "Pb" +msgid "Pbit" +msgstr "Pbit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eb" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Ebit" #: glib/gutils.c:3004 -msgid "Eb" -msgstr "Eb" +msgid "Ebit" +msgstr "Ebit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Kib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Kibit" #: glib/gutils.c:3008 -msgid "Kib" -msgstr "Kib" +msgid "Kibit" +msgstr "Kibit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Mibit" #: glib/gutils.c:3010 -msgid "Mib" -msgstr "Mib" +msgid "Mibit" +msgstr "Mibit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Gibit" #: glib/gutils.c:3012 -msgid "Gib" -msgstr "Gib" +msgid "Gibit" +msgstr "Gibit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Tibit" #: glib/gutils.c:3014 -msgid "Tib" -msgstr "Tib" +msgid "Tibit" +msgstr "Tibit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Pibit" #: glib/gutils.c:3016 -msgid "Pib" -msgstr "Pib" +msgid "Pibit" +msgstr "Pibit" -#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eib" +#. Translators: A unit symbol for size formatting, showing for example: "13.0 Eibit" #: glib/gutils.c:3018 -msgid "Eib" -msgstr "Eib" +msgid "Eibit" +msgstr "Eibit" #: glib/gutils.c:3056 msgid "byte" @@ -6274,7 +6283,42 @@ msgstr "%.1f PB" msgid "%.1f EB" msgstr "%.1f EB" -#, c-format +#~ msgid "kb" +#~ msgstr "kb" + +#~ msgid "Mb" +#~ msgstr "Mb" + +#~ msgid "Gb" +#~ msgstr "Gb" + +#~ msgid "Tb" +#~ msgstr "Tb" + +#~ msgid "Pb" +#~ msgstr "Pb" + +#~ msgid "Eb" +#~ msgstr "Eb" + +#~ msgid "Kib" +#~ msgstr "Kib" + +#~ msgid "Mib" +#~ msgstr "Mib" + +#~ msgid "Gib" +#~ msgstr "Gib" + +#~ msgid "Tib" +#~ msgstr "Tib" + +#~ msgid "Pib" +#~ msgstr "Pib" + +#~ msgid "Eib" +#~ msgstr "Eib" + #~ msgid "The local file URI “%s” may not include a “#”" #~ msgstr "Yerel dosya URI’si “%s”, “#” içeremez" diff --git a/subprojects/gi-docgen.wrap b/subprojects/gi-docgen.wrap new file mode 100644 index 0000000..022c7ac --- /dev/null +++ b/subprojects/gi-docgen.wrap @@ -0,0 +1,5 @@ +[wrap-git] +directory=gi-docgen +url=https://gitlab.gnome.org/GNOME/gi-docgen.git +revision=2023.1 +depth=1 diff --git a/tools/glib.supp b/tools/glib.supp index 9ff78cc..bddfe60 100644 --- a/tools/glib.supp +++ b/tools/glib.supp @@ -867,7 +867,7 @@ { g_get_system_data_dirs Memcheck:Leak - match-leak-kinds:reachable + match-leak-kinds:definite,reachable fun:malloc ... fun:g_build_system_data_dirs @@ -878,7 +878,7 @@ { g_get_user_data_dir Memcheck:Leak - match-leak-kinds:reachable + match-leak-kinds:definite,reachable fun:realloc ... fun:g_build_user_data_dir @@ -889,13 +889,23 @@ { g_get_home_dir Memcheck:Leak - match-leak-kinds:reachable + match-leak-kinds:definite,reachable fun:malloc ... fun:g_build_home_dir fun:g_get_home_dir } +# gcontenttype.c caches a one-time allocation global array of @global_mime_dirs. +{ + content_type_mime_dirs_realloc + Memcheck:Leak + match-leak-kinds:reachable + fun:realloc + ... + fun:_g_content_type_set_mime_dirs_locked +} + # gdesktopappinfo.c caches a one-time allocation global table of @desktop_file_dirs. { desktop_file_dirs_malloc @@ -1268,3 +1278,47 @@ ... fun:xdg_mime_init } + +# One-time allocations for default log writer lock and domains +{ + should_drop_message_rw_lock + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:g_rw_lock_impl_new + fun:g_rw_lock_get_impl + fun:g_rw_lock_reader_lock + fun:should_drop_message +} + +{ + should_drop_message_strdup + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:g_malloc + fun:g_strdup + fun:g_strdup_inline + fun:should_drop_message +} + +{ + g_log_writer_default_set_debug_strdup + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:g_malloc + fun:g_strdup_inline + fun:g_log_writer_default_set_debug_domains +} + +{ + g_log_writer_default_set_debug_rw_lock + Memcheck:Leak + match-leak-kinds: reachable + fun:malloc + fun:g_rw_lock_impl_new + fun:g_rw_lock_get_impl + fun:g_rw_lock_writer_lock + fun:g_log_writer_default_set_debug_domains +} -- 2.7.4