mirror of
https://github.com/Fishwaldo/meta-kde-gear.git
synced 2025-03-15 19:31:31 +00:00
add akonadi
This commit is contained in:
commit
e947254cf1
22 changed files with 27750 additions and 0 deletions
17
COPYING.MIT
Normal file
17
COPYING.MIT
Normal file
|
@ -0,0 +1,17 @@
|
|||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
41
README
Normal file
41
README
Normal file
|
@ -0,0 +1,41 @@
|
|||
This README file contains information on the contents of the meta-kde-gear layer.
|
||||
|
||||
Please see the corresponding sections below for details.
|
||||
|
||||
Dependencies
|
||||
============
|
||||
|
||||
URI: <first dependency>
|
||||
branch: <branch name>
|
||||
|
||||
URI: <second dependency>
|
||||
branch: <branch name>
|
||||
|
||||
.
|
||||
.
|
||||
.
|
||||
|
||||
Patches
|
||||
=======
|
||||
|
||||
Please submit any patches against the meta-kde-gear layer to the xxxx mailing list (xxxx@zzzz.org)
|
||||
and cc: the maintainer:
|
||||
|
||||
Maintainer: XXX YYYYYY <xxx.yyyyyy@zzzzz.com>
|
||||
|
||||
Table of Contents
|
||||
=================
|
||||
|
||||
I. Adding the meta-kde-gear layer to your build
|
||||
II. Misc
|
||||
|
||||
|
||||
I. Adding the meta-kde-gear layer to your build
|
||||
=================================================
|
||||
|
||||
Run 'bitbake-layers add-layer meta-kde-gear'
|
||||
|
||||
II. Misc
|
||||
========
|
||||
|
||||
--- replace with specific information about the meta-kde-gear layer ---
|
13
conf/layer.conf
Normal file
13
conf/layer.conf
Normal file
|
@ -0,0 +1,13 @@
|
|||
# We have a conf and classes directory, add to BBPATH
|
||||
BBPATH .= ":${LAYERDIR}"
|
||||
|
||||
# We have recipes-* directories, add to BBFILES
|
||||
BBFILES += "${LAYERDIR}/recipes-*/*/*.bb \
|
||||
${LAYERDIR}/recipes-*/*/*.bbappend"
|
||||
|
||||
BBFILE_COLLECTIONS += "meta-kde-gear"
|
||||
BBFILE_PATTERN_meta-kde-gear = "^${LAYERDIR}/"
|
||||
BBFILE_PRIORITY_meta-kde-gear = "6"
|
||||
|
||||
LAYERDEPENDS_meta-kde-gear = "core"
|
||||
LAYERSERIES_COMPAT_meta-kde-gear = "kirkstone"
|
36
recipes-application/akonadi/akonadi.inc
Normal file
36
recipes-application/akonadi/akonadi.inc
Normal file
|
@ -0,0 +1,36 @@
|
|||
SUMMARY = "akonadi"
|
||||
DESCRIPTION = "TODO"
|
||||
HOMEPAGE = "https://invent.kde.org/akonadi/"
|
||||
LICENSE = "MIT & BSD-2-Clause & BSD-3-Clause & LGPL-2.0+ & (LGPL-2.1 | LGPL-3.0 | LicenseRef-KDE-Accepted-LGPL)"
|
||||
|
||||
inherit cmake_kdeapp
|
||||
inherit kcoreaddons
|
||||
inherit kconfig
|
||||
inherit kauth
|
||||
inherit mime-xdg
|
||||
inherit reuse_license_checksums
|
||||
inherit cmake_qt5
|
||||
|
||||
KF5_REUSE_LICENSECHECK_ENABLED="1"
|
||||
|
||||
DEPENDS = " \
|
||||
protocolgen-native \
|
||||
kconfigwidgets \
|
||||
kiconthemes \
|
||||
kitemmodels \
|
||||
kio \
|
||||
sqlite3 \
|
||||
libxslt-native \
|
||||
docbook-xsl-stylesheets-native \
|
||||
"
|
||||
|
||||
FILES:${PN} = " \
|
||||
${sysconfdir}/apparmor.d/* \
|
||||
${sysconfdir}/xdg/akonadi/* \
|
||||
${datadir}/mime/packages/akonadi* \
|
||||
${datadir}/kf5/akonadi* \
|
||||
${datadir}/akonadi/* \
|
||||
${libdir}/libKPim5Akonadi* \
|
||||
${bindir}/akonadi* \
|
||||
${bindir}/asapcat \
|
||||
"
|
3
recipes-application/akonadi/akonadi_23.04.0.bb
Normal file
3
recipes-application/akonadi/akonadi_23.04.0.bb
Normal file
|
@ -0,0 +1,3 @@
|
|||
require ${PN}.inc
|
||||
SRC_URI = "https://download.kde.org/stable/release-service/23.04.0/src/akonadi-23.04.0.tar.xz"
|
||||
SRC_URI[sha256sum] = "e528c3d737c742b2e359345b71f18f65d7973761714716d64b58d35e11094ece"
|
38
recipes-application/akonadi/protocolgen/CMakeLists.txt
Normal file
38
recipes-application/akonadi/protocolgen/CMakeLists.txt
Normal file
|
@ -0,0 +1,38 @@
|
|||
cmake_minimum_required(VERSION 3.1.0)
|
||||
|
||||
project(protocolgen)
|
||||
|
||||
find_package(ECM CONFIG REQUIRED)
|
||||
|
||||
include(FeatureSummary)
|
||||
|
||||
find_package(Qt5 COMPONENTS Core REQUIRED)
|
||||
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||
set(CMAKE_CXX_EXTENSIONS OFF)
|
||||
|
||||
add_executable(protocolgen)
|
||||
target_sources(protocolgen PRIVATE
|
||||
main.cpp
|
||||
cppgenerator.cpp
|
||||
cpphelper.cpp
|
||||
nodetree.cpp
|
||||
typehelper.cpp
|
||||
xmlparser.cpp
|
||||
cppgenerator.h
|
||||
cpphelper.h
|
||||
nodetree.h
|
||||
typehelper.h
|
||||
xmlparser.h
|
||||
)
|
||||
|
||||
target_link_libraries(protocolgen
|
||||
Qt::Core
|
||||
)
|
||||
|
||||
add_definitions(-DQT_USE_QSTRINGBUILDER)
|
||||
add_definitions(-DQT_CORE_LIB)
|
||||
add_definitions(-DQT_NO_DEBUG)
|
||||
|
||||
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
|
446
recipes-application/akonadi/protocolgen/LGPL-2.0-or-later.txt
Normal file
446
recipes-application/akonadi/protocolgen/LGPL-2.0-or-later.txt
Normal file
|
@ -0,0 +1,446 @@
|
|||
GNU LIBRARY GENERAL PUBLIC LICENSE
|
||||
|
||||
Version 2, June 1991 Copyright (C) 1991 Free Software Foundation, Inc.
|
||||
|
||||
51 Franklin St, 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 library GPL. It is numbered 2 because
|
||||
it goes with version 2 of the ordinary GPL.]
|
||||
|
||||
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 Library General Public License, applies to some specially
|
||||
designated Free Software Foundation software, and to any other libraries whose
|
||||
authors decide to use it. You can use it for your libraries, too.
|
||||
|
||||
When we speak of free software, we are referring to freedom, 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 or use pieces of it in new free programs; and that
|
||||
you know you can do these things.
|
||||
|
||||
To protect your rights, we need to make restrictions that forbid anyone to
|
||||
deny you these rights or to ask you to surrender the 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
|
||||
a program 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.
|
||||
|
||||
Our method of protecting your rights has two steps: (1) copyright the library,
|
||||
and (2) offer you this license which gives you legal permission to copy, distribute
|
||||
and/or modify the library.
|
||||
|
||||
Also, for each distributor's protection, we want to make certain that everyone
|
||||
understands that there is no warranty for this free library. If the library
|
||||
is modified by someone else and passed on, we want its recipients to know
|
||||
that what they have is not the original version, so that any problems introduced
|
||||
by others will not reflect on the original authors' reputations.
|
||||
|
||||
Finally, any free program is threatened constantly by software patents. We
|
||||
wish to avoid the danger that companies distributing free software will individually
|
||||
obtain patent licenses, thus in effect transforming the program into proprietary
|
||||
software. To prevent this, we have made it clear that any patent must be licensed
|
||||
for everyone's free use or not licensed at all.
|
||||
|
||||
Most GNU software, including some libraries, is covered by the ordinary GNU
|
||||
General Public License, which was designed for utility programs. This license,
|
||||
the GNU Library General Public License, applies to certain designated libraries.
|
||||
This license is quite different from the ordinary one; be sure to read it
|
||||
in full, and don't assume that anything in it is the same as in the ordinary
|
||||
license.
|
||||
|
||||
The reason we have a separate public license for some libraries is that they
|
||||
blur the distinction we usually make between modifying or adding to a program
|
||||
and simply using it. Linking a program with a library, without changing the
|
||||
library, is in some sense simply using the library, and is analogous to running
|
||||
a utility program or application program. However, in a textual and legal
|
||||
sense, the linked executable is a combined work, a derivative of the original
|
||||
library, and the ordinary General Public License treats it as such.
|
||||
|
||||
Because of this blurred distinction, using the ordinary General Public License
|
||||
for libraries did not effectively promote software sharing, because most developers
|
||||
did not use the libraries. We concluded that weaker conditions might promote
|
||||
sharing better.
|
||||
|
||||
However, unrestricted linking of non-free programs would deprive the users
|
||||
of those programs of all benefit from the free status of the libraries themselves.
|
||||
This Library General Public License is intended to permit developers of non-free
|
||||
programs to use free libraries, while preserving your freedom as a user of
|
||||
such programs to change the free libraries that are incorporated in them.
|
||||
(We have not seen how to achieve this as regards changes in header files,
|
||||
but we have achieved it as regards changes in the actual functions of the
|
||||
Library.) The hope is that this will lead to faster development of free libraries.
|
||||
|
||||
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, while the latter only works together with the library.
|
||||
|
||||
Note that it is possible for a library to be covered by the ordinary General
|
||||
Public License rather than by this special one.
|
||||
|
||||
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
|
||||
|
||||
0. This License Agreement applies to any software library which contains a
|
||||
notice placed by the copyright holder or other authorized party saying it
|
||||
may be distributed under the terms of this Library 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 compile 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) 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.
|
||||
|
||||
c) 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.
|
||||
|
||||
d) 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 source code 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 to 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 Library 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 Library 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 Library General Public License for more
|
||||
details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public License
|
||||
along with this library; if not, write to the Free Software Foundation, Inc.,
|
||||
51 Franklin St, 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!
|
841
recipes-application/akonadi/protocolgen/cppgenerator.cpp
Normal file
841
recipes-application/akonadi/protocolgen/cppgenerator.cpp
Normal file
|
@ -0,0 +1,841 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "cppgenerator.h"
|
||||
#include "cpphelper.h"
|
||||
#include "nodetree.h"
|
||||
#include "typehelper.h"
|
||||
|
||||
#include <QDebug>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
CppGenerator::CppGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
CppGenerator::~CppGenerator()
|
||||
{
|
||||
}
|
||||
|
||||
bool CppGenerator::generate(Node const *node)
|
||||
{
|
||||
Q_ASSERT(node->type() == Node::Document);
|
||||
|
||||
mHeaderFile.setFileName(QStringLiteral("protocol_gen.h"));
|
||||
if (!mHeaderFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
std::cerr << qPrintable(mHeaderFile.errorString()) << std::endl;
|
||||
return false;
|
||||
}
|
||||
mHeader.setDevice(&mHeaderFile);
|
||||
|
||||
mImplFile.setFileName(QStringLiteral("protocol_gen.cpp"));
|
||||
if (!mImplFile.open(QIODevice::WriteOnly | QIODevice::Truncate)) {
|
||||
std::cerr << qPrintable(mImplFile.errorString()) << std::endl;
|
||||
return false;
|
||||
}
|
||||
mImpl.setDevice(&mImplFile);
|
||||
|
||||
return generateDocument(static_cast<DocumentNode const *>(node));
|
||||
}
|
||||
|
||||
void CppGenerator::writeHeaderHeader(DocumentNode const *node)
|
||||
{
|
||||
mHeader << "// This is an auto-generated file.\n"
|
||||
"// Any changes to this file will be overwritten\n"
|
||||
"\n"
|
||||
"// clazy:excludeall=function-args-by-value\n"
|
||||
"\n"
|
||||
"namespace Akonadi {\n"
|
||||
"namespace Protocol {\n"
|
||||
"\n"
|
||||
"AKONADIPRIVATE_EXPORT int version();\n"
|
||||
"\n";
|
||||
|
||||
// Forward declarations
|
||||
for (const auto *child : std::as_const(node->children())) {
|
||||
if (child->type() == Node::Class) {
|
||||
mHeader << "class " << static_cast<const ClassNode *>(child)->className() << ";\n";
|
||||
}
|
||||
}
|
||||
|
||||
mHeader << "\n"
|
||||
"} // namespace Protocol\n"
|
||||
"} // namespace Akonadi\n\n";
|
||||
}
|
||||
|
||||
void CppGenerator::writeHeaderFooter(DocumentNode const * /*node*/)
|
||||
{
|
||||
// Nothing to do
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplHeader(DocumentNode const *node)
|
||||
{
|
||||
mImpl << "// This is an auto-generated file.\n"
|
||||
"// Any changes to this file will be overwritten\n"
|
||||
"\n"
|
||||
"// clazy:excludeall=function-args-by-value\n"
|
||||
"\n"
|
||||
"namespace Akonadi {\n"
|
||||
"namespace Protocol {\n"
|
||||
"\n"
|
||||
"int version()\n"
|
||||
"{\n"
|
||||
" return "
|
||||
<< node->version()
|
||||
<< ";\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplFooter(DocumentNode const * /*unused*/)
|
||||
{
|
||||
mImpl << "} // namespace Protocol\n"
|
||||
"} // namespace Akonadi\n";
|
||||
}
|
||||
|
||||
bool CppGenerator::generateDocument(DocumentNode const *node)
|
||||
{
|
||||
writeHeaderHeader(node);
|
||||
writeImplHeader(node);
|
||||
|
||||
writeImplSerializer(node);
|
||||
|
||||
for (const auto *classNode : node->children()) {
|
||||
if (!generateClass(static_cast<ClassNode const *>(classNode))) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
writeHeaderFooter(node);
|
||||
writeImplFooter(node);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplSerializer(DocumentNode const *node)
|
||||
{
|
||||
mImpl << "void serialize(DataStream &stream, const CommandPtr &cmd)\n"
|
||||
"{\n"
|
||||
" switch (static_cast<int>(cmd->type() | (cmd->isResponse() ? Command::_ResponseBit : 0))) {\n"
|
||||
" case Command::Invalid:\n"
|
||||
" stream << cmdCast<Command>(cmd);\n"
|
||||
" break;\n"
|
||||
" case Command::Invalid | Command::_ResponseBit:\n"
|
||||
" stream << cmdCast<Response>(cmd);\n"
|
||||
" break;\n";
|
||||
for (const auto *child : std::as_const(node->children())) {
|
||||
const auto *classNode = static_cast<ClassNode const *>(child);
|
||||
if (classNode->classType() == ClassNode::Response) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< " | Command::_ResponseBit:\n"
|
||||
" stream << cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" break;\n";
|
||||
} else if (classNode->classType() == ClassNode::Command) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< ":\n"
|
||||
" stream << cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" break;\n";
|
||||
} else if (classNode->classType() == ClassNode::Notification) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< "Notification:\n"
|
||||
" stream << cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" break;\n";
|
||||
}
|
||||
}
|
||||
mImpl << " }\n"
|
||||
"}\n\n";
|
||||
|
||||
mImpl << "CommandPtr deserialize(QIODevice *device)\n"
|
||||
"{\n"
|
||||
" DataStream stream(device);\n"
|
||||
" stream.waitForData(sizeof(Command::Type));\n"
|
||||
" Command::Type cmdType;\n"
|
||||
" if (Q_UNLIKELY(device->peek((char *) &cmdType, sizeof(Command::Type)) != sizeof(Command::Type))) {\n"
|
||||
" throw ProtocolException(\"Failed to peek command type\");\n"
|
||||
" }\n"
|
||||
" CommandPtr cmd;\n"
|
||||
" if (cmdType & Command::_ResponseBit) {\n"
|
||||
" cmd = Factory::response(Command::Type(cmdType & ~Command::_ResponseBit));\n"
|
||||
" } else {\n"
|
||||
" cmd = Factory::command(cmdType);\n"
|
||||
" }\n\n"
|
||||
" switch (static_cast<int>(cmdType)) {\n"
|
||||
" case Command::Invalid:\n"
|
||||
" stream >> cmdCast<Command>(cmd);\n"
|
||||
" return cmd;\n"
|
||||
" case Command::Invalid | Command::_ResponseBit:\n"
|
||||
" stream >> cmdCast<Response>(cmd);\n"
|
||||
" return cmd;\n";
|
||||
for (const auto *child : std::as_const(node->children())) {
|
||||
const auto *classNode = static_cast<ClassNode const *>(child);
|
||||
if (classNode->classType() == ClassNode::Response) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< " | Command::_ResponseBit:\n"
|
||||
" stream >> cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" return cmd;\n";
|
||||
} else if (classNode->classType() == ClassNode::Command) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< ":\n"
|
||||
" stream >> cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" return cmd;\n";
|
||||
} else if (classNode->classType() == ClassNode::Notification) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< "Notification:\n"
|
||||
" stream >> cmdCast<"
|
||||
<< classNode->className()
|
||||
<< ">(cmd);\n"
|
||||
" return cmd;\n";
|
||||
}
|
||||
}
|
||||
mImpl << " }\n"
|
||||
" return CommandPtr::create();\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
mImpl << "QString debugString(const Command &cmd)\n"
|
||||
"{\n"
|
||||
" QString out;\n"
|
||||
" switch (static_cast<int>(cmd.type() | (cmd.isResponse() ? Command::_ResponseBit : 0))) {\n"
|
||||
" case Command::Invalid:\n"
|
||||
" QDebug(&out).noquote() << static_cast<const Command &>(cmd);\n"
|
||||
" return out;\n"
|
||||
" case Command::Invalid | Command::_ResponseBit:\n"
|
||||
" QDebug(&out).noquote() << static_cast<const Response &>(cmd);\n"
|
||||
" return out;\n";
|
||||
for (const auto *child : std::as_const(node->children())) {
|
||||
const auto *classNode = static_cast<ClassNode const *>(child);
|
||||
if (classNode->classType() == ClassNode::Response) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< " | Command::_ResponseBit:\n"
|
||||
" QDebug(&out).noquote() << static_cast<const "
|
||||
<< classNode->className()
|
||||
<< " &>(cmd);\n"
|
||||
" return out;\n";
|
||||
} else if (classNode->classType() == ClassNode::Command) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< ":\n"
|
||||
" QDebug(&out).noquote() << static_cast<const "
|
||||
<< classNode->className()
|
||||
<< " &>(cmd);\n"
|
||||
" return out;\n";
|
||||
} else if (classNode->classType() == ClassNode::Notification) {
|
||||
mImpl << " case Command::" << classNode->name()
|
||||
<< "Notification:\n"
|
||||
" QDebug(&out).noquote() << static_cast<const "
|
||||
<< classNode->className()
|
||||
<< " &>(cmd);\n"
|
||||
" return out;\n";
|
||||
}
|
||||
}
|
||||
mImpl << " }\n"
|
||||
" return QString();\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
void CppGenerator::writeHeaderEnum(EnumNode const *node)
|
||||
{
|
||||
mHeader << " enum " << node->name() << " {\n";
|
||||
for (const auto *enumChild : node->children()) {
|
||||
Q_ASSERT(enumChild->type() == Node::EnumValue);
|
||||
const auto *const valueNode = static_cast<EnumValueNode const *>(enumChild);
|
||||
mHeader << " " << valueNode->name();
|
||||
if (!valueNode->value().isEmpty()) {
|
||||
mHeader << " = " << valueNode->value();
|
||||
}
|
||||
mHeader << ",\n";
|
||||
}
|
||||
mHeader << " };\n";
|
||||
if (node->enumType() == EnumNode::TypeFlag) {
|
||||
mHeader << " Q_DECLARE_FLAGS(" << node->name() << "s, " << node->name() << ")\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void CppGenerator::writeHeaderClass(ClassNode const *node)
|
||||
{
|
||||
// Begin class
|
||||
const QString parentClass = node->parentClassName();
|
||||
const bool isTypeClass = node->classType() == ClassNode::Class;
|
||||
|
||||
mHeader << "namespace Akonadi {\n"
|
||||
"namespace Protocol {\n\n"
|
||||
"AKONADIPRIVATE_EXPORT DataStream &operator<<(DataStream &stream, const "
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
"AKONADIPRIVATE_EXPORT DataStream &operator>>(DataStream &stream, "
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
"AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const "
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
"\n"
|
||||
"using "
|
||||
<< node->className() << "Ptr = QSharedPointer<" << node->className()
|
||||
<< ">;\n"
|
||||
"\n";
|
||||
if (isTypeClass) {
|
||||
mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << "\n";
|
||||
} else {
|
||||
mHeader << "class AKONADIPRIVATE_EXPORT " << node->className() << " : public " << parentClass << "\n";
|
||||
}
|
||||
mHeader << "{\n\n"
|
||||
"public:\n";
|
||||
|
||||
// Enums
|
||||
for (const auto *child : node->children()) {
|
||||
if (child->type() == Node::Enum) {
|
||||
const auto *const enumNode = static_cast<EnumNode const *>(child);
|
||||
writeHeaderEnum(enumNode);
|
||||
}
|
||||
}
|
||||
|
||||
// Ctors, dtor
|
||||
for (const auto *child : std::as_const(node->children())) {
|
||||
if (child->type() == Node::Ctor) {
|
||||
const auto *const ctor = static_cast<const CtorNode *>(child);
|
||||
const auto args = ctor->arguments();
|
||||
mHeader << " explicit " << node->className() << "(";
|
||||
for (int i = 0; i < args.count(); ++i) {
|
||||
const auto &arg = args[i];
|
||||
if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) {
|
||||
mHeader << arg.type << " " << arg.name;
|
||||
} else {
|
||||
mHeader << "const " << arg.type << " &" << arg.name;
|
||||
}
|
||||
if (!arg.defaultValue.isEmpty()) {
|
||||
mHeader << " = " << arg.defaultValue;
|
||||
}
|
||||
if (i < args.count() - 1) {
|
||||
mHeader << ", ";
|
||||
}
|
||||
}
|
||||
mHeader << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
mHeader << " " << node->className() << "(const " << node->className()
|
||||
<< " &) = default;\n"
|
||||
" "
|
||||
<< node->className() << "(" << node->className()
|
||||
<< " &&) = default;\n"
|
||||
" ~"
|
||||
<< node->className()
|
||||
<< "() = default;\n"
|
||||
"\n"
|
||||
" "
|
||||
<< node->className() << " &operator=(const " << node->className()
|
||||
<< " &) = default;\n"
|
||||
" "
|
||||
<< node->className() << " &operator=(" << node->className()
|
||||
<< " &&) = default;\n"
|
||||
" bool operator==(const "
|
||||
<< node->className()
|
||||
<< " &other) const;\n"
|
||||
" inline bool operator!=(const "
|
||||
<< node->className() << " &other) const { return !operator==(other); }\n";
|
||||
|
||||
// Properties
|
||||
for (const auto *child : node->children()) {
|
||||
if (child->type() == Node::Property) {
|
||||
const auto *const prop = static_cast<PropertyNode const *>(child);
|
||||
if (prop->asReference()) {
|
||||
mHeader << " inline const " << prop->type() << " &" << prop->name() << "() const { return " << prop->mVariableName()
|
||||
<< "; }\n"
|
||||
" inline "
|
||||
<< prop->type() << " &" << prop->name() << "() { return " << prop->mVariableName() << "; }\n";
|
||||
} else {
|
||||
mHeader << " inline " << prop->type() << " " << prop->name() << "() const { return " << prop->mVariableName() << "; }\n";
|
||||
}
|
||||
if (!prop->readOnly()) {
|
||||
if (auto *setter = prop->setter()) {
|
||||
mHeader << " void " << setter->name << "(const " << setter->type << " &" << prop->name() << ");\n";
|
||||
} else if (!prop->dependencies().isEmpty()) {
|
||||
QString varType;
|
||||
if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
|
||||
varType = QLatin1Char('(') + prop->type() + QLatin1Char(' ');
|
||||
} else {
|
||||
varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &");
|
||||
}
|
||||
mHeader << " void " << prop->setterName() << varType << prop->name() << ");\n";
|
||||
} else {
|
||||
QString varType;
|
||||
if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
|
||||
varType = QLatin1Char('(') + prop->type() + QLatin1Char(' ');
|
||||
} else {
|
||||
varType = QLatin1String("(const ") + prop->type() + QLatin1String(" &");
|
||||
}
|
||||
mHeader << " inline void " << prop->setterName() << varType << prop->name() << ") { " << prop->mVariableName() << " = " << prop->name()
|
||||
<< "; }\n";
|
||||
if (!TypeHelper::isNumericType(prop->type()) && !TypeHelper::isBoolType(prop->type())) {
|
||||
mHeader << " inline void " << prop->setterName() << "(" << prop->type() << " &&" << prop->name() << ") { " << prop->mVariableName()
|
||||
<< " = std::move(" << prop->name() << "); }\n";
|
||||
}
|
||||
}
|
||||
}
|
||||
mHeader << "\n";
|
||||
}
|
||||
}
|
||||
mHeader << " void toJson(QJsonObject &stream) const;\n";
|
||||
|
||||
// End of class
|
||||
mHeader << "protected:\n";
|
||||
const auto properties = node->properties();
|
||||
for (const auto *prop : properties) {
|
||||
mHeader << " " << prop->type() << " " << prop->mVariableName();
|
||||
const auto defaultValue = prop->defaultValue();
|
||||
const bool isDefaultValue = !defaultValue.isEmpty();
|
||||
const bool isNumeric = TypeHelper::isNumericType(prop->type());
|
||||
const bool isBool = TypeHelper::isBoolType(prop->type());
|
||||
if (isDefaultValue) {
|
||||
mHeader << " = " << defaultValue;
|
||||
} else if (isNumeric) {
|
||||
mHeader << " = 0";
|
||||
} else if (isBool) {
|
||||
mHeader << " = false";
|
||||
}
|
||||
mHeader << ";\n";
|
||||
}
|
||||
|
||||
mHeader << "\n"
|
||||
"private:\n"
|
||||
" friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator<<(Akonadi::Protocol::DataStream &stream, const Akonadi::Protocol::"
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
" friend AKONADIPRIVATE_EXPORT Akonadi::Protocol::DataStream &operator>>(Akonadi::Protocol::DataStream &stream, Akonadi::Protocol::"
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
" friend AKONADIPRIVATE_EXPORT QDebug operator<<(QDebug dbg, const Akonadi::Protocol::"
|
||||
<< node->className()
|
||||
<< " &obj);\n"
|
||||
"};\n\n"
|
||||
"} // namespace Protocol\n"
|
||||
"} // namespace Akonadi\n"
|
||||
"\n";
|
||||
mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << ")\n\n";
|
||||
if (node->classType() != ClassNode::Class) {
|
||||
mHeader << "Q_DECLARE_METATYPE(Akonadi::Protocol::" << node->className() << "Ptr)\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplSerializer(PropertyNode const *node, const char *streamingOperator)
|
||||
{
|
||||
const auto deps = node->dependencies();
|
||||
if (deps.isEmpty()) {
|
||||
mImpl << " stream " << streamingOperator << " obj." << node->mVariableName() << ";\n";
|
||||
} else {
|
||||
mImpl << " if (";
|
||||
auto it = deps.cend();
|
||||
while (1 + 1 == 2) {
|
||||
--it;
|
||||
const QString mVar = it.key();
|
||||
mImpl << "(obj."
|
||||
<< "m" << mVar[0].toUpper()
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
<< mVar.midRef(1)
|
||||
#else
|
||||
<< QStringView(mVar).mid(1)
|
||||
#endif
|
||||
<< " & " << it.value() << ")";
|
||||
if (it == deps.cbegin()) {
|
||||
break;
|
||||
} else {
|
||||
mImpl << " && ";
|
||||
}
|
||||
}
|
||||
mImpl << ") {\n"
|
||||
" stream "
|
||||
<< streamingOperator << " obj." << node->mVariableName()
|
||||
<< ";\n"
|
||||
" }\n";
|
||||
}
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplClass(ClassNode const *node)
|
||||
{
|
||||
const QString parentClass = node->parentClassName();
|
||||
const auto &children = node->children();
|
||||
const auto properties = node->properties();
|
||||
|
||||
// Ctors
|
||||
for (const auto *child : children) {
|
||||
if (child->type() == Node::Ctor) {
|
||||
const auto *const ctor = static_cast<CtorNode const *>(child);
|
||||
const auto args = ctor->arguments();
|
||||
mImpl << node->className() << "::" << node->className() << "(";
|
||||
for (int i = 0; i < args.count(); ++i) {
|
||||
const auto &arg = args[i];
|
||||
if (TypeHelper::isNumericType(arg.type) || TypeHelper::isBoolType(arg.type)) {
|
||||
mImpl << arg.type << " " << arg.name;
|
||||
} else {
|
||||
mImpl << "const " << arg.type << " &" << arg.name;
|
||||
}
|
||||
if (i < args.count() - 1) {
|
||||
mImpl << ", ";
|
||||
}
|
||||
}
|
||||
mImpl << ")\n";
|
||||
char startChar = ',';
|
||||
if (!parentClass.isEmpty()) {
|
||||
const QString type = node->name() + ((node->classType() == ClassNode::Notification) ? QStringLiteral("Notification") : QString());
|
||||
mImpl << " : " << parentClass << "(Command::" << type << ")\n";
|
||||
} else {
|
||||
startChar = ':';
|
||||
}
|
||||
for (const auto *prop : properties) {
|
||||
auto arg = std::find_if(args.cbegin(), args.cend(), [prop](const CtorNode::Argument &arg) {
|
||||
return arg.name == prop->name();
|
||||
});
|
||||
if (arg != args.cend()) {
|
||||
mImpl << " " << startChar << " " << prop->mVariableName() << "(" << arg->name << ")\n";
|
||||
startChar = ',';
|
||||
}
|
||||
}
|
||||
mImpl << "{\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
}
|
||||
}
|
||||
|
||||
// Comparison operator
|
||||
mImpl << "bool " << node->className() << "::operator==(const " << node->className()
|
||||
<< " &other) const\n"
|
||||
"{\n";
|
||||
mImpl << " return true // simplifies generation\n";
|
||||
if (!parentClass.isEmpty()) {
|
||||
mImpl << " && " << parentClass << "::operator==(other)\n";
|
||||
}
|
||||
for (const auto *prop : properties) {
|
||||
if (prop->isPointer()) {
|
||||
mImpl << " && *" << prop->mVariableName() << " == *other." << prop->mVariableName() << "\n";
|
||||
} else if (TypeHelper::isContainer(prop->type())) {
|
||||
mImpl << " && containerComparator(" << prop->mVariableName() << ", other." << prop->mVariableName() << ")\n";
|
||||
} else {
|
||||
mImpl << " && " << prop->mVariableName() << " == other." << prop->mVariableName() << "\n";
|
||||
}
|
||||
}
|
||||
mImpl << " ;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
// non-trivial setters
|
||||
for (const auto *prop : properties) {
|
||||
if (prop->readOnly()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (auto *const setter = prop->setter()) {
|
||||
mImpl << "void " << node->className() << "::" << setter->name << "(const " << setter->type
|
||||
<< " &val)\n"
|
||||
"{\n";
|
||||
if (!setter->append.isEmpty()) {
|
||||
mImpl << " m" << setter->append[0].toUpper()
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
<< setter->append.midRef(1)
|
||||
#else
|
||||
<< QStringView(setter->append).mid(1)
|
||||
#endif
|
||||
<< " << val;\n";
|
||||
}
|
||||
if (!setter->remove.isEmpty()) {
|
||||
const QString mVar = QLatin1String("m") + setter->remove[0].toUpper()
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
+ setter->remove.midRef(1);
|
||||
#else
|
||||
+ QStringView(setter->remove).mid(1);
|
||||
#endif
|
||||
mImpl << " auto it = std::find(" << mVar << ".begin(), " << mVar
|
||||
<< ".end(), val);\n"
|
||||
" if (it != "
|
||||
<< mVar
|
||||
<< ".end()) {\n"
|
||||
" "
|
||||
<< mVar
|
||||
<< ".erase(it);\n"
|
||||
" }\n";
|
||||
}
|
||||
writeImplPropertyDependencies(prop);
|
||||
mImpl << "}\n\n";
|
||||
} else if (!prop->dependencies().isEmpty()) {
|
||||
if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
|
||||
mImpl << "void " << node->className() << "::" << prop->setterName() << "(" << prop->type()
|
||||
<< " val)\n"
|
||||
"{\n"
|
||||
" "
|
||||
<< prop->mVariableName() << " = val;\n";
|
||||
|
||||
} else {
|
||||
mImpl << "void " << node->className() << "::" << prop->setterName() << "(const " << prop->type()
|
||||
<< " &val)\n"
|
||||
"{\n"
|
||||
" "
|
||||
<< prop->mVariableName() << " = val;\n";
|
||||
}
|
||||
writeImplPropertyDependencies(prop);
|
||||
mImpl << "}\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
// serialize
|
||||
auto serializeProperties = properties;
|
||||
CppHelper::sortMembersForSerialization(serializeProperties);
|
||||
|
||||
mImpl << "DataStream &operator<<(DataStream &stream, const " << node->className()
|
||||
<< " &obj)\n"
|
||||
"{\n";
|
||||
if (!parentClass.isEmpty()) {
|
||||
mImpl << " stream << static_cast<const " << parentClass << " &>(obj);\n";
|
||||
}
|
||||
for (const auto *prop : std::as_const(serializeProperties)) {
|
||||
writeImplSerializer(prop, "<<");
|
||||
}
|
||||
mImpl << " return stream;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
// deserialize
|
||||
mImpl << "DataStream &operator>>(DataStream &stream, " << node->className()
|
||||
<< " &obj)\n"
|
||||
"{\n";
|
||||
if (!parentClass.isEmpty()) {
|
||||
mImpl << " stream >> static_cast<" << parentClass << " &>(obj);\n";
|
||||
}
|
||||
for (const auto *prop : std::as_const(serializeProperties)) {
|
||||
writeImplSerializer(prop, ">>");
|
||||
}
|
||||
mImpl << " return stream;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
// debug
|
||||
mImpl << "QDebug operator<<(QDebug dbg, const " << node->className()
|
||||
<< " &obj)\n"
|
||||
"{\n";
|
||||
if (!parentClass.isEmpty()) {
|
||||
mImpl << " dbg.noquote() << static_cast<const " << parentClass << " &>(obj)\n";
|
||||
} else {
|
||||
mImpl << " dbg.noquote()\n";
|
||||
}
|
||||
|
||||
for (const auto *prop : std::as_const(serializeProperties)) {
|
||||
if (prop->isPointer()) {
|
||||
mImpl << " << \"" << prop->name() << ":\" << *obj." << prop->mVariableName() << " << \"\\n\"\n";
|
||||
} else if (TypeHelper::isContainer(prop->type())) {
|
||||
mImpl << " << \"" << prop->name()
|
||||
<< ": [\\n\";\n"
|
||||
" for (const auto &type : std::as_const(obj."
|
||||
<< prop->mVariableName()
|
||||
<< ")) {\n"
|
||||
" dbg.noquote() << \" \" << ";
|
||||
if (TypeHelper::isPointerType(TypeHelper::containerType(prop->type()))) {
|
||||
mImpl << "*type";
|
||||
} else {
|
||||
mImpl << "type";
|
||||
}
|
||||
mImpl << " << \"\\n\";\n"
|
||||
" }\n"
|
||||
" dbg.noquote() << \"]\\n\"\n";
|
||||
} else {
|
||||
mImpl << " << \"" << prop->name() << ":\" << obj." << prop->mVariableName() << " << \"\\n\"\n";
|
||||
}
|
||||
}
|
||||
mImpl << " ;\n"
|
||||
" return dbg;\n"
|
||||
"}\n"
|
||||
"\n";
|
||||
|
||||
// toJson
|
||||
mImpl << "void " << node->className()
|
||||
<< "::toJson(QJsonObject &json) const\n"
|
||||
"{\n";
|
||||
if (!parentClass.isEmpty()) {
|
||||
mImpl << " static_cast<const " << parentClass << " *>(this)->toJson(json);\n";
|
||||
} else if (serializeProperties.isEmpty()) {
|
||||
mImpl << " Q_UNUSED(json)\n";
|
||||
}
|
||||
for (const auto *prop : std::as_const(serializeProperties)) {
|
||||
if (prop->isPointer()) {
|
||||
mImpl << " {\n"
|
||||
" QJsonObject jsonObject;\n"
|
||||
" "
|
||||
<< prop->mVariableName()
|
||||
<< "->toJson(jsonObject);\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = jsonObject;\n"
|
||||
" }\n";
|
||||
} else if (TypeHelper::isContainer(prop->type())) {
|
||||
const auto &containerType = TypeHelper::containerType(prop->type());
|
||||
mImpl << " {\n"
|
||||
" QJsonArray jsonArray;\n"
|
||||
" for (const auto &type : std::as_const("
|
||||
<< prop->mVariableName() << ")) {\n";
|
||||
if (TypeHelper::isPointerType(containerType)) {
|
||||
mImpl << " QJsonObject jsonObject;\n"
|
||||
" type->toJson(jsonObject); /* "
|
||||
<< containerType
|
||||
<< " */\n"
|
||||
" jsonArray.append(jsonObject);\n";
|
||||
} else if (TypeHelper::isNumericType(containerType) || TypeHelper::isBoolType(containerType)) {
|
||||
mImpl << " jsonArray.append(type); /* " << containerType << " */\n";
|
||||
} else if (containerType == QLatin1String("QByteArray")) {
|
||||
mImpl << " jsonArray.append(QString::fromUtf8(type)); /* " << containerType << "*/\n";
|
||||
} else if (TypeHelper::isBuiltInType(containerType)) {
|
||||
if (TypeHelper::containerType(prop->type()) == QLatin1String("Akonadi::Protocol::ChangeNotification::Relation")) {
|
||||
mImpl << " QJsonObject jsonObject;\n"
|
||||
" type.toJson(jsonObject); /* "
|
||||
<< containerType
|
||||
<< " */\n"
|
||||
" jsonArray.append(jsonObject);\n";
|
||||
} else {
|
||||
mImpl << " jsonArray.append(type); /* " << containerType << " */\n";
|
||||
}
|
||||
} else {
|
||||
mImpl << " QJsonObject jsonObject;\n"
|
||||
" type.toJson(jsonObject); /* "
|
||||
<< containerType
|
||||
<< " */\n"
|
||||
" jsonArray.append(jsonObject);\n";
|
||||
}
|
||||
mImpl << " }\n"
|
||||
<< " json[QStringLiteral(\"" << prop->name() << "\")] = jsonArray;\n"
|
||||
<< " }\n";
|
||||
} else if (prop->type() == QLatin1String("uint")) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = static_cast<int>(" << prop->mVariableName() << ");/* " << prop->type() << " */\n";
|
||||
} else if (TypeHelper::isNumericType(prop->type()) || TypeHelper::isBoolType(prop->type())) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ";/* " << prop->type() << " */\n";
|
||||
} else if (TypeHelper::isBuiltInType(prop->type())) {
|
||||
if (prop->type() == QLatin1String("QStringList")) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = QJsonArray::fromStringList(" << prop->mVariableName() << ");/* "
|
||||
<< prop->type() << " */\n";
|
||||
} else if (prop->type() == QLatin1String("QDateTime")) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ".toString()/* " << prop->type() << " */;\n";
|
||||
} else if (prop->type() == QLatin1String("QByteArray")) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = QString::fromUtf8(" << prop->mVariableName() << ")/* " << prop->type()
|
||||
<< " */;\n";
|
||||
} else if (prop->type() == QLatin1String("Scope")) {
|
||||
mImpl << " {\n"
|
||||
" QJsonObject jsonObject;\n"
|
||||
" "
|
||||
<< prop->mVariableName() << ".toJson(jsonObject); /* " << prop->type()
|
||||
<< " */\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name() << "\")] = "
|
||||
<< "jsonObject;\n"
|
||||
" }\n";
|
||||
} else if (prop->type() == QLatin1String("Tristate")) {
|
||||
mImpl << " switch (" << prop->mVariableName()
|
||||
<< ") {\n;"
|
||||
" case Tristate::True:\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = QStringLiteral(\"True\");\n"
|
||||
" break;\n"
|
||||
" case Tristate::False:\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = QStringLiteral(\"False\");\n"
|
||||
" break;\n"
|
||||
" case Tristate::Undefined:\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = QStringLiteral(\"Undefined\");\n"
|
||||
" break;\n"
|
||||
" }\n";
|
||||
} else if (prop->type() == QLatin1String("Akonadi::Protocol::Attributes")) {
|
||||
mImpl << " {\n"
|
||||
" QJsonObject jsonObject;\n"
|
||||
" auto i = "
|
||||
<< prop->mVariableName()
|
||||
<< ".constBegin();\n"
|
||||
" const auto &end = "
|
||||
<< prop->mVariableName()
|
||||
<< ".constEnd();\n"
|
||||
" while (i != end) {\n"
|
||||
" jsonObject[QString::fromUtf8(i.key())] = QString::fromUtf8(i.value());\n"
|
||||
" ++i;\n"
|
||||
" }\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = jsonObject;\n"
|
||||
" }\n";
|
||||
} else if (prop->type() == QLatin1String("ModifySubscriptionCommand::ModifiedParts")
|
||||
|| prop->type() == QLatin1String("ModifyTagCommand::ModifiedParts")
|
||||
|| prop->type() == QLatin1String("ModifyCollectionCommand::ModifiedParts")
|
||||
|| prop->type() == QLatin1String("ModifyItemsCommand::ModifiedParts")
|
||||
|| prop->type() == QLatin1String("CreateItemCommand::MergeModes")) {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = static_cast<int>(" << prop->mVariableName() << ");/* " << prop->type()
|
||||
<< "*/\n";
|
||||
} else {
|
||||
mImpl << " json[QStringLiteral(\"" << prop->name() << "\")] = " << prop->mVariableName() << ";/* " << prop->type() << "*/\n";
|
||||
}
|
||||
} else {
|
||||
mImpl << " {\n"
|
||||
" QJsonObject jsonObject;\n"
|
||||
" "
|
||||
<< prop->mVariableName() << ".toJson(jsonObject); /* " << prop->type()
|
||||
<< " */\n"
|
||||
" json[QStringLiteral(\""
|
||||
<< prop->name()
|
||||
<< "\")] = jsonObject;\n"
|
||||
" }\n";
|
||||
}
|
||||
}
|
||||
mImpl << "}\n"
|
||||
"\n";
|
||||
}
|
||||
|
||||
void CppGenerator::writeImplPropertyDependencies(const PropertyNode *node)
|
||||
{
|
||||
const auto deps = node->dependencies();
|
||||
QString key;
|
||||
QStringList values;
|
||||
QString enumType;
|
||||
for (auto it = deps.cbegin(), end = deps.cend(); it != end; ++it) {
|
||||
if (key != it.key()) {
|
||||
key = it.key();
|
||||
const auto children = node->parent()->children();
|
||||
for (const auto *child : children) {
|
||||
if (child->type() == Node::Property && child != node) {
|
||||
const auto *prop = static_cast<const PropertyNode *>(child);
|
||||
if (prop->name() == key) {
|
||||
enumType = prop->type();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!values.isEmpty()) {
|
||||
mImpl << " m" << key[0].toUpper() << QStringView(key).mid(1) << " |= " << enumType << "(" << values.join(QLatin1String(" | ")) << ");\n";
|
||||
values.clear();
|
||||
}
|
||||
}
|
||||
values << *it;
|
||||
}
|
||||
|
||||
if (!values.isEmpty()) {
|
||||
mImpl << " m" << key[0].toUpper() << QStringView(key).mid(1) << " |= " << enumType << "(" << values.join(QLatin1String(" | ")) << ");\n";
|
||||
}
|
||||
}
|
||||
|
||||
bool CppGenerator::generateClass(ClassNode const *node)
|
||||
{
|
||||
writeHeaderClass(node);
|
||||
|
||||
mImpl << "\n\n/************************* " << node->className() << " *************************/\n\n";
|
||||
writeImplClass(node);
|
||||
|
||||
return true;
|
||||
}
|
49
recipes-application/akonadi/protocolgen/cppgenerator.h
Normal file
49
recipes-application/akonadi/protocolgen/cppgenerator.h
Normal file
|
@ -0,0 +1,49 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QFile>
|
||||
#include <QTextStream>
|
||||
|
||||
class Node;
|
||||
class DocumentNode;
|
||||
class ClassNode;
|
||||
class EnumNode;
|
||||
class PropertyNode;
|
||||
|
||||
class CppGenerator
|
||||
{
|
||||
public:
|
||||
explicit CppGenerator();
|
||||
~CppGenerator();
|
||||
|
||||
bool generate(Node const *node);
|
||||
|
||||
private:
|
||||
bool generateDocument(DocumentNode const *node);
|
||||
bool generateClass(ClassNode const *node);
|
||||
|
||||
private:
|
||||
void writeHeaderHeader(DocumentNode const *node);
|
||||
void writeHeaderFooter(DocumentNode const *node);
|
||||
void writeHeaderClass(ClassNode const *node);
|
||||
void writeHeaderEnum(EnumNode const *node);
|
||||
|
||||
void writeImplHeader(DocumentNode const *node);
|
||||
void writeImplFooter(DocumentNode const *node);
|
||||
void writeImplSerializer(DocumentNode const *node);
|
||||
void writeImplClass(ClassNode const *node);
|
||||
void writeImplSerializer(PropertyNode const *node, const char *streamingOperator);
|
||||
|
||||
void writeImplPropertyDependencies(PropertyNode const *node);
|
||||
|
||||
private:
|
||||
QFile mHeaderFile;
|
||||
QTextStream mHeader;
|
||||
QFile mImplFile;
|
||||
QTextStream mImpl;
|
||||
};
|
71
recipes-application/akonadi/protocolgen/cpphelper.cpp
Normal file
71
recipes-application/akonadi/protocolgen/cpphelper.cpp
Normal file
|
@ -0,0 +1,71 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "cpphelper.h"
|
||||
#include "nodetree.h"
|
||||
#include "typehelper.h"
|
||||
|
||||
#include <QHash>
|
||||
#include <QMap>
|
||||
#include <QMetaType>
|
||||
#include <QSet>
|
||||
#include <QSharedDataPointer>
|
||||
#include <QSharedPointer>
|
||||
namespace
|
||||
{
|
||||
class Dummy;
|
||||
|
||||
// FIXME: This is based on hacks and guesses, does not work for generated types
|
||||
// and does not consider alignment. It should be good enough (TM) for our needs,
|
||||
// but it would be nice to make it smarter, for example by looking up type sizes
|
||||
// from the Node tree and understanding enums and QFlags types.
|
||||
size_t typeSize(const QString &typeName)
|
||||
{
|
||||
static QHash<QByteArray, size_t> typeSizeLookup = {{"Scope", sizeof(QSharedDataPointer<Dummy>)},
|
||||
{"ScopeContext", sizeof(QSharedDataPointer<Dummy>)},
|
||||
{"QSharedPointer", sizeof(QSharedPointer<Dummy>)},
|
||||
{"Tristate", sizeof(qint8)},
|
||||
{"Akonadi::Protocol::Attributes", sizeof(QMap<int, Dummy>)},
|
||||
{"QSet", sizeof(QSet<Dummy>)},
|
||||
{"QVector", sizeof(QVector<Dummy>)}};
|
||||
|
||||
QByteArray tn;
|
||||
// Don't you just loooove hacks?
|
||||
// TODO: Extract underlying type during XML parsing
|
||||
if (typeName.startsWith(QLatin1String("Akonadi::Protocol")) && typeName.endsWith(QLatin1String("Ptr"))) {
|
||||
tn = "QSharedPointer";
|
||||
} else {
|
||||
tn = TypeHelper::isContainer(typeName) ? TypeHelper::containerName(typeName).toUtf8() : typeName.toUtf8();
|
||||
}
|
||||
auto it = typeSizeLookup.find(tn);
|
||||
if (it == typeSizeLookup.end()) {
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
const auto typeId = QMetaType::type(tn);
|
||||
#else
|
||||
const auto typeId = QMetaType::fromName(tn).id();
|
||||
#endif
|
||||
const int size = QMetaType(typeId).sizeOf();
|
||||
// for types of unknown size int
|
||||
it = typeSizeLookup.insert(tn, size ? size_t(size) : sizeof(int));
|
||||
}
|
||||
return *it;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CppHelper::sortMembers(QVector<PropertyNode const *> &props)
|
||||
{
|
||||
std::sort(props.begin(), props.end(), [](PropertyNode const *lhs, PropertyNode const *rhs) {
|
||||
return typeSize(lhs->type()) > typeSize(rhs->type());
|
||||
});
|
||||
}
|
||||
|
||||
void CppHelper::sortMembersForSerialization(QVector<PropertyNode const *> &props)
|
||||
{
|
||||
std::sort(props.begin(), props.end(), [](PropertyNode const *lhs, PropertyNode const *rhs) {
|
||||
return lhs->dependencies().isEmpty() > rhs->dependencies().isEmpty();
|
||||
});
|
||||
}
|
19
recipes-application/akonadi/protocolgen/cpphelper.h
Normal file
19
recipes-application/akonadi/protocolgen/cpphelper.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class PropertyNode;
|
||||
|
||||
#include <QVector>
|
||||
|
||||
namespace CppHelper
|
||||
{
|
||||
void sortMembers(QVector<PropertyNode const *> &props);
|
||||
|
||||
void sortMembersForSerialization(QVector<PropertyNode const *> &props);
|
||||
|
||||
} // namespace CppHelper
|
41
recipes-application/akonadi/protocolgen/main.cpp
Normal file
41
recipes-application/akonadi/protocolgen/main.cpp
Normal file
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include <QCommandLineParser>
|
||||
#include <QCoreApplication>
|
||||
|
||||
#include "cppgenerator.h"
|
||||
#include "xmlparser.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
QCoreApplication app(argc, argv);
|
||||
|
||||
QCommandLineParser parser;
|
||||
parser.addPositionalArgument(QStringLiteral("file"), QStringLiteral("File"));
|
||||
parser.addHelpOption();
|
||||
parser.process(app);
|
||||
|
||||
const auto args = parser.positionalArguments();
|
||||
if (args.isEmpty()) {
|
||||
std::cerr << "No file specified" << std::endl;
|
||||
return 1;
|
||||
}
|
||||
|
||||
XmlParser xmlParser;
|
||||
if (!xmlParser.parse(args[0])) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
CppGenerator cppGenerator;
|
||||
if (!cppGenerator.generate(xmlParser.tree())) {
|
||||
return -2;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
306
recipes-application/akonadi/protocolgen/nodetree.cpp
Normal file
306
recipes-application/akonadi/protocolgen/nodetree.cpp
Normal file
|
@ -0,0 +1,306 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "nodetree.h"
|
||||
#include "cpphelper.h"
|
||||
#include "typehelper.h"
|
||||
|
||||
Node::Node(NodeType type, Node *parent)
|
||||
: mParent(parent)
|
||||
, mType(type)
|
||||
{
|
||||
if (parent) {
|
||||
parent->appendNode(this);
|
||||
}
|
||||
}
|
||||
|
||||
Node::~Node()
|
||||
{
|
||||
qDeleteAll(mChildren);
|
||||
}
|
||||
|
||||
Node::NodeType Node::type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
Node *Node::parent() const
|
||||
{
|
||||
return mParent;
|
||||
}
|
||||
|
||||
void Node::appendNode(Node *child)
|
||||
{
|
||||
child->mParent = this;
|
||||
mChildren.push_back(child);
|
||||
}
|
||||
|
||||
const QVector<Node const *> &Node::children() const
|
||||
{
|
||||
return mChildren;
|
||||
}
|
||||
|
||||
DocumentNode::DocumentNode(int version)
|
||||
: Node(Document, nullptr)
|
||||
, mVersion(version)
|
||||
{
|
||||
}
|
||||
|
||||
int DocumentNode::version() const
|
||||
{
|
||||
return mVersion;
|
||||
}
|
||||
|
||||
ClassNode::ClassNode(const QString &name, ClassType type, DocumentNode *parent)
|
||||
: Node(Node::Class, parent)
|
||||
, mName(name)
|
||||
, mClassType(type)
|
||||
{
|
||||
}
|
||||
|
||||
QString ClassNode::name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
ClassNode::ClassType ClassNode::classType() const
|
||||
{
|
||||
return mClassType;
|
||||
}
|
||||
|
||||
QString ClassNode::className() const
|
||||
{
|
||||
switch (mClassType) {
|
||||
case Class:
|
||||
return mName;
|
||||
case Command:
|
||||
return mName + QStringLiteral("Command");
|
||||
case Response:
|
||||
return mName + QStringLiteral("Response");
|
||||
case Notification:
|
||||
return mName + QStringLiteral("Notification");
|
||||
default:
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
}
|
||||
|
||||
QString ClassNode::parentClassName() const
|
||||
{
|
||||
switch (mClassType) {
|
||||
case Class:
|
||||
return QString();
|
||||
case Command:
|
||||
return QStringLiteral("Command");
|
||||
case Response:
|
||||
return QStringLiteral("Response");
|
||||
case Notification:
|
||||
return QStringLiteral("ChangeNotification");
|
||||
case Invalid:
|
||||
Q_ASSERT(false);
|
||||
return QString();
|
||||
}
|
||||
Q_UNREACHABLE();
|
||||
}
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
ClassNode::ClassType ClassNode::elementNameToType(const QStringRef &name)
|
||||
#else
|
||||
ClassNode::ClassType ClassNode::elementNameToType(QStringView name)
|
||||
#endif
|
||||
{
|
||||
if (name == QLatin1String("class")) {
|
||||
return Class;
|
||||
} else if (name == QLatin1String("command")) {
|
||||
return Command;
|
||||
} else if (name == QLatin1String("response")) {
|
||||
return Response;
|
||||
} else if (name == QLatin1String("notification")) {
|
||||
return Notification;
|
||||
} else {
|
||||
return Invalid;
|
||||
}
|
||||
}
|
||||
|
||||
QVector<PropertyNode const *> ClassNode::properties() const
|
||||
{
|
||||
QVector<const PropertyNode *> rv;
|
||||
for (const auto node : std::as_const(mChildren)) {
|
||||
if (node->type() == Node::Property) {
|
||||
rv << static_cast<PropertyNode const *>(node);
|
||||
}
|
||||
}
|
||||
CppHelper::sortMembers(rv);
|
||||
return rv;
|
||||
}
|
||||
|
||||
CtorNode::CtorNode(const QVector<Argument> &args, ClassNode *parent)
|
||||
: Node(Ctor, parent)
|
||||
, mArgs(args)
|
||||
{
|
||||
}
|
||||
|
||||
CtorNode::~CtorNode()
|
||||
{
|
||||
}
|
||||
|
||||
QVector<CtorNode::Argument> CtorNode::arguments() const
|
||||
{
|
||||
return mArgs;
|
||||
}
|
||||
|
||||
void CtorNode::setArgumentType(const QString &name, const QString &type)
|
||||
{
|
||||
for (auto &arg : mArgs) {
|
||||
if (arg.name == name) {
|
||||
arg.type = type;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
EnumNode::EnumNode(const QString &name, EnumType type, ClassNode *parent)
|
||||
: Node(Enum, parent)
|
||||
, mName(name)
|
||||
, mEnumType(type)
|
||||
{
|
||||
}
|
||||
|
||||
QString EnumNode::name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
EnumNode::EnumType EnumNode::enumType() const
|
||||
{
|
||||
return mEnumType;
|
||||
}
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
EnumNode::EnumType EnumNode::elementNameToType(const QStringRef &name)
|
||||
#else
|
||||
EnumNode::EnumType EnumNode::elementNameToType(QStringView name)
|
||||
#endif
|
||||
{
|
||||
if (name == QLatin1String("enum")) {
|
||||
return TypeEnum;
|
||||
} else if (name == QLatin1String("flag")) {
|
||||
return TypeFlag;
|
||||
} else {
|
||||
return TypeInvalid;
|
||||
}
|
||||
}
|
||||
|
||||
EnumValueNode::EnumValueNode(const QString &name, EnumNode *parent)
|
||||
: Node(EnumValue, parent)
|
||||
, mName(name)
|
||||
, mValue()
|
||||
{
|
||||
}
|
||||
|
||||
QString EnumValueNode::name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void EnumValueNode::setValue(const QString &value)
|
||||
{
|
||||
mValue = value;
|
||||
}
|
||||
|
||||
QString EnumValueNode::value() const
|
||||
{
|
||||
return mValue;
|
||||
}
|
||||
|
||||
PropertyNode::PropertyNode(const QString &name, const QString &type, ClassNode *parent)
|
||||
: Node(Property, parent)
|
||||
, mName(name)
|
||||
, mType(type)
|
||||
, mSetter(nullptr)
|
||||
, mReadOnly(false)
|
||||
, mAsReference(false)
|
||||
{
|
||||
}
|
||||
|
||||
PropertyNode::~PropertyNode()
|
||||
{
|
||||
delete mSetter;
|
||||
}
|
||||
|
||||
QString PropertyNode::type() const
|
||||
{
|
||||
return mType;
|
||||
}
|
||||
|
||||
QString PropertyNode::name() const
|
||||
{
|
||||
return mName;
|
||||
}
|
||||
|
||||
void PropertyNode::setDefaultValue(const QString &defaultValue)
|
||||
{
|
||||
mDefaultValue = defaultValue;
|
||||
}
|
||||
|
||||
QString PropertyNode::defaultValue() const
|
||||
{
|
||||
return mDefaultValue;
|
||||
}
|
||||
|
||||
bool PropertyNode::readOnly() const
|
||||
{
|
||||
return mReadOnly;
|
||||
}
|
||||
|
||||
void PropertyNode::setReadOnly(bool readOnly)
|
||||
{
|
||||
mReadOnly = readOnly;
|
||||
}
|
||||
|
||||
bool PropertyNode::asReference() const
|
||||
{
|
||||
return mAsReference;
|
||||
}
|
||||
|
||||
void PropertyNode::setAsReference(bool asReference)
|
||||
{
|
||||
mAsReference = asReference;
|
||||
}
|
||||
|
||||
bool PropertyNode::isPointer() const
|
||||
{
|
||||
return TypeHelper::isPointerType(mType);
|
||||
}
|
||||
|
||||
QMultiMap<QString, QString> PropertyNode::dependencies() const
|
||||
{
|
||||
return mDepends;
|
||||
}
|
||||
|
||||
void PropertyNode::addDependency(const QString &enumVar, const QString &enumValue)
|
||||
{
|
||||
mDepends.insert(enumVar, enumValue);
|
||||
}
|
||||
|
||||
void PropertyNode::setSetter(Setter *setter)
|
||||
{
|
||||
mSetter = setter;
|
||||
}
|
||||
|
||||
PropertyNode::Setter *PropertyNode::setter() const
|
||||
{
|
||||
return mSetter;
|
||||
}
|
||||
|
||||
QString PropertyNode::mVariableName() const
|
||||
{
|
||||
return QStringLiteral("m") + mName[0].toUpper() + QStringView(mName).mid(1);
|
||||
}
|
||||
|
||||
QString PropertyNode::setterName() const
|
||||
{
|
||||
return QStringLiteral("set") + mName[0].toUpper() + QStringView(mName).mid(1);
|
||||
}
|
191
recipes-application/akonadi/protocolgen/nodetree.h
Normal file
191
recipes-application/akonadi/protocolgen/nodetree.h
Normal file
|
@ -0,0 +1,191 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QMultiMap>
|
||||
#include <QVector>
|
||||
|
||||
class Node
|
||||
{
|
||||
public:
|
||||
enum NodeType {
|
||||
Document,
|
||||
Class,
|
||||
Ctor,
|
||||
Enum,
|
||||
EnumValue,
|
||||
Property,
|
||||
};
|
||||
|
||||
Node(NodeType type, Node *parent);
|
||||
Node(const Node &) = delete;
|
||||
Node(Node &&) = delete;
|
||||
virtual ~Node();
|
||||
|
||||
Node &operator=(const Node &) = delete;
|
||||
Node &operator=(Node &&) = delete;
|
||||
|
||||
NodeType type() const;
|
||||
Node *parent() const;
|
||||
|
||||
void appendNode(Node *child);
|
||||
|
||||
const QVector<Node const *> &children() const;
|
||||
|
||||
protected:
|
||||
Node *mParent;
|
||||
QVector<Node const *> mChildren;
|
||||
NodeType mType;
|
||||
};
|
||||
|
||||
class DocumentNode : public Node
|
||||
{
|
||||
public:
|
||||
DocumentNode(int version);
|
||||
|
||||
int version() const;
|
||||
|
||||
private:
|
||||
int mVersion;
|
||||
};
|
||||
|
||||
class PropertyNode;
|
||||
class ClassNode : public Node
|
||||
{
|
||||
public:
|
||||
enum ClassType {
|
||||
Invalid,
|
||||
Class,
|
||||
Command,
|
||||
Response,
|
||||
Notification,
|
||||
};
|
||||
|
||||
ClassNode(const QString &name, ClassType type, DocumentNode *parent);
|
||||
QString name() const;
|
||||
ClassType classType() const;
|
||||
QString className() const;
|
||||
QString parentClassName() const;
|
||||
QVector<PropertyNode const *> properties() const;
|
||||
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
static ClassType elementNameToType(const QStringRef &name);
|
||||
#else
|
||||
static ClassType elementNameToType(QStringView name);
|
||||
#endif
|
||||
|
||||
private:
|
||||
QString mName;
|
||||
ClassType mClassType;
|
||||
};
|
||||
|
||||
class CtorNode : public Node
|
||||
{
|
||||
public:
|
||||
struct Argument {
|
||||
QString name;
|
||||
QString type;
|
||||
QString defaultValue;
|
||||
|
||||
QString mVariableName() const
|
||||
{
|
||||
return QStringLiteral("m") + name[0].toUpper() + QStringView(name).mid(1);
|
||||
}
|
||||
};
|
||||
|
||||
CtorNode(const QVector<Argument> &args, ClassNode *parent);
|
||||
~CtorNode() override;
|
||||
|
||||
QVector<Argument> arguments() const;
|
||||
void setArgumentType(const QString &name, const QString &type);
|
||||
|
||||
private:
|
||||
QVector<Argument> mArgs;
|
||||
};
|
||||
|
||||
class EnumNode : public Node
|
||||
{
|
||||
public:
|
||||
enum EnumType {
|
||||
TypeInvalid,
|
||||
TypeEnum,
|
||||
TypeFlag,
|
||||
};
|
||||
|
||||
EnumNode(const QString &name, EnumType type, ClassNode *parent);
|
||||
|
||||
QString name() const;
|
||||
EnumType enumType() const;
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
static EnumType elementNameToType(const QStringRef &name);
|
||||
#else
|
||||
static EnumType elementNameToType(QStringView name);
|
||||
#endif
|
||||
private:
|
||||
QString mName;
|
||||
EnumType mEnumType;
|
||||
};
|
||||
|
||||
class EnumValueNode : public Node
|
||||
{
|
||||
public:
|
||||
EnumValueNode(const QString &name, EnumNode *parent);
|
||||
|
||||
QString name() const;
|
||||
void setValue(const QString &value);
|
||||
QString value() const;
|
||||
|
||||
private:
|
||||
QString mName;
|
||||
QString mValue;
|
||||
};
|
||||
|
||||
class PropertyNode : public Node
|
||||
{
|
||||
public:
|
||||
struct Setter {
|
||||
QString name;
|
||||
QString type;
|
||||
QString append;
|
||||
QString remove;
|
||||
};
|
||||
|
||||
PropertyNode(const QString &name, const QString &type, ClassNode *parent);
|
||||
~PropertyNode() override;
|
||||
|
||||
QString type() const;
|
||||
QString name() const;
|
||||
|
||||
void setDefaultValue(const QString &defaultValue);
|
||||
QString defaultValue() const;
|
||||
|
||||
bool readOnly() const;
|
||||
void setReadOnly(bool readOnly);
|
||||
|
||||
bool asReference() const;
|
||||
void setAsReference(bool asReference);
|
||||
|
||||
bool isPointer() const;
|
||||
|
||||
QMultiMap<QString, QString> dependencies() const;
|
||||
void addDependency(const QString &enumVar, const QString &enumValue);
|
||||
|
||||
Setter *setter() const;
|
||||
void setSetter(Setter *setter);
|
||||
|
||||
QString mVariableName() const;
|
||||
QString setterName() const;
|
||||
|
||||
private:
|
||||
QString mName;
|
||||
QString mType;
|
||||
QString mDefaultValue;
|
||||
QMultiMap<QString, QString> mDepends;
|
||||
Setter *mSetter;
|
||||
bool mReadOnly;
|
||||
bool mAsReference;
|
||||
};
|
25095
recipes-application/akonadi/protocolgen/test
Normal file
25095
recipes-application/akonadi/protocolgen/test
Normal file
File diff suppressed because one or more lines are too long
91
recipes-application/akonadi/protocolgen/typehelper.cpp
Normal file
91
recipes-application/akonadi/protocolgen/typehelper.cpp
Normal file
|
@ -0,0 +1,91 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "typehelper.h"
|
||||
#include "nodetree.h"
|
||||
|
||||
#include <QMetaType>
|
||||
#include <QString>
|
||||
|
||||
bool TypeHelper::isNumericType(const QString &name)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
const int metaTypeId = QMetaType::type(qPrintable(name));
|
||||
#else
|
||||
const int metaTypeId = QMetaType::fromName(qPrintable(name)).id();
|
||||
#endif
|
||||
if (metaTypeId == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (metaTypeId) {
|
||||
case QMetaType::Int:
|
||||
case QMetaType::UInt:
|
||||
case QMetaType::Double:
|
||||
case QMetaType::Long:
|
||||
case QMetaType::LongLong:
|
||||
case QMetaType::Short:
|
||||
case QMetaType::ULong:
|
||||
case QMetaType::ULongLong:
|
||||
case QMetaType::UShort:
|
||||
case QMetaType::Float:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeHelper::isBoolType(const QString &name)
|
||||
{
|
||||
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
|
||||
const int metaTypeId = QMetaType::type(qPrintable(name));
|
||||
#else
|
||||
const int metaTypeId = QMetaType::fromName(qPrintable(name)).id();
|
||||
#endif
|
||||
if (metaTypeId == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (metaTypeId) {
|
||||
case QMetaType::Bool:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool TypeHelper::isBuiltInType(const QString &type)
|
||||
{
|
||||
// TODO: should be smarter than this....
|
||||
return !type.startsWith(QLatin1String("Akonadi::Protocol")) || type == QLatin1String("Akonadi::Protocol::Attributes") // typedef to QMap
|
||||
|| (type.startsWith(QLatin1String("Akonadi::Protocol")) // enums
|
||||
&& type.count(QStringLiteral("::")) > 2);
|
||||
}
|
||||
|
||||
bool TypeHelper::isContainer(const QString &type)
|
||||
{
|
||||
const int tplB = type.indexOf(QLatin1Char('<'));
|
||||
const int tplE = type.lastIndexOf(QLatin1Char('>'));
|
||||
return tplB > -1 && tplE > -1 && tplB < tplE;
|
||||
}
|
||||
|
||||
QString TypeHelper::containerType(const QString &type)
|
||||
{
|
||||
const int tplB = type.indexOf(QLatin1Char('<'));
|
||||
const int tplE = type.indexOf(QLatin1Char('>'));
|
||||
return type.mid(tplB + 1, tplE - tplB - 1);
|
||||
}
|
||||
|
||||
QString TypeHelper::containerName(const QString &type)
|
||||
{
|
||||
const int tplB = type.indexOf(QLatin1Char('<'));
|
||||
return type.left(tplB);
|
||||
}
|
||||
|
||||
bool TypeHelper::isPointerType(const QString &type)
|
||||
{
|
||||
return type.endsWith(QLatin1String("Ptr"));
|
||||
}
|
27
recipes-application/akonadi/protocolgen/typehelper.h
Normal file
27
recipes-application/akonadi/protocolgen/typehelper.h
Normal file
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
class QString;
|
||||
|
||||
namespace TypeHelper
|
||||
{
|
||||
bool isNumericType(const QString &name);
|
||||
bool isBoolType(const QString &name);
|
||||
|
||||
/**
|
||||
* Returns true if @p node is of C++ or Qt type, C++ if it's a generated type
|
||||
*/
|
||||
bool isBuiltInType(const QString &type);
|
||||
|
||||
bool isContainer(const QString &type);
|
||||
|
||||
QString containerType(const QString &type);
|
||||
QString containerName(const QString &type);
|
||||
bool isPointerType(const QString &type);
|
||||
|
||||
}
|
276
recipes-application/akonadi/protocolgen/xmlparser.cpp
Normal file
276
recipes-application/akonadi/protocolgen/xmlparser.cpp
Normal file
|
@ -0,0 +1,276 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#include "xmlparser.h"
|
||||
#include "nodetree.h"
|
||||
|
||||
#include <QFile>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#define qPrintableRef(x) reinterpret_cast<const char *>((x).unicode())
|
||||
|
||||
XmlParser::XmlParser()
|
||||
{
|
||||
}
|
||||
|
||||
XmlParser::~XmlParser()
|
||||
{
|
||||
}
|
||||
|
||||
Node const *XmlParser::tree() const
|
||||
{
|
||||
return mTree.get();
|
||||
}
|
||||
|
||||
bool XmlParser::parse(const QString &filename)
|
||||
{
|
||||
QFile file(filename);
|
||||
if (!file.open(QIODevice::ReadOnly)) {
|
||||
std::cerr << qPrintable(file.errorString());
|
||||
return false;
|
||||
}
|
||||
|
||||
mReader.setDevice(&file);
|
||||
while (!mReader.atEnd()) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement() && mReader.name() == QLatin1String("protocol")) {
|
||||
if (!parseProtocol()) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseProtocol()
|
||||
{
|
||||
Q_ASSERT(mReader.name() == QLatin1String("protocol"));
|
||||
|
||||
const auto attrs = mReader.attributes();
|
||||
if (!attrs.hasAttribute(QLatin1String("version"))) {
|
||||
printError(QStringLiteral("Missing \"version\" attribute in <protocol> tag!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto documentNode = std::make_unique<DocumentNode>(attrs.value(QLatin1String("version")).toInt());
|
||||
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("protocol"))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
const auto elemName = mReader.name();
|
||||
if (elemName == QLatin1String("class") || elemName == QLatin1String("command") || elemName == QLatin1String("response")
|
||||
|| elemName == QLatin1String("notification")) {
|
||||
if (!parseCommand(documentNode.get())) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mTree = std::move(documentNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseCommand(DocumentNode *documentNode)
|
||||
{
|
||||
const auto attrs = mReader.attributes();
|
||||
if (!attrs.hasAttribute(QLatin1String("name"))) {
|
||||
printError(QStringLiteral("Missing \"name\" attribute in command tag!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto classNode = new ClassNode(attrs.value(QLatin1String("name")).toString(), ClassNode::elementNameToType(mReader.name()), documentNode);
|
||||
new CtorNode({}, classNode);
|
||||
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && classNode->classType() == ClassNode::elementNameToType(mReader.name()))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
if (mReader.name() == QLatin1String("ctor")) {
|
||||
if (!parseCtor(classNode)) {
|
||||
return false;
|
||||
}
|
||||
} else if (mReader.name() == QLatin1String("enum") || mReader.name() == QLatin1String("flag")) {
|
||||
if (!parseEnum(classNode)) {
|
||||
return false;
|
||||
}
|
||||
} else if (mReader.name() == QLatin1String("param")) {
|
||||
if (!parseParam(classNode)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseCtor(ClassNode *classNode)
|
||||
{
|
||||
QVector<CtorNode::Argument> args;
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && (mReader.name() == QLatin1String("ctor")))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
if (mReader.name() == QLatin1String("arg")) {
|
||||
const auto attrs = mReader.attributes();
|
||||
const QString name = attrs.value(QLatin1String("name")).toString();
|
||||
const QString def = attrs.value(QLatin1String("default")).toString();
|
||||
args << CtorNode::Argument{name, QString(), def};
|
||||
} else {
|
||||
printError(QStringLiteral("Unsupported tag: ").append(mReader.name()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
new CtorNode(args, classNode);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseEnum(ClassNode *classNode)
|
||||
{
|
||||
const auto attrs = mReader.attributes();
|
||||
if (!attrs.hasAttribute(QLatin1String("name"))) {
|
||||
printError(QStringLiteral("Missing \"name\" attribute in enum/flag tag!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto enumNode = new EnumNode(attrs.value(QLatin1String("name")).toString(), EnumNode::elementNameToType(mReader.name()), classNode);
|
||||
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && (enumNode->enumType() == EnumNode::elementNameToType(mReader.name())))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
if (mReader.name() == QLatin1String("value")) {
|
||||
if (!parseEnumValue(enumNode)) {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
printError(QStringLiteral("Invalid tag inside of enum/flag tag: ").append(mReader.name()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseEnumValue(EnumNode *enumNode)
|
||||
{
|
||||
Q_ASSERT(mReader.name() == QLatin1String("value"));
|
||||
|
||||
const auto attrs = mReader.attributes();
|
||||
if (!attrs.hasAttribute(QLatin1String("name"))) {
|
||||
printError(QStringLiteral("Missing \"name\" attribute in <value> tag!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
auto valueNode = new EnumValueNode(attrs.value(QLatin1String("name")).toString(), enumNode);
|
||||
if (attrs.hasAttribute(QLatin1String("value"))) {
|
||||
valueNode->setValue(attrs.value(QLatin1String("value")).toString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseParam(ClassNode *classNode)
|
||||
{
|
||||
Q_ASSERT(mReader.name() == QLatin1String("param"));
|
||||
|
||||
const auto attrs = mReader.attributes();
|
||||
if (!attrs.hasAttribute(QLatin1String("name"))) {
|
||||
printError(QStringLiteral("Missing \"name\" attribute in <param> tag!"));
|
||||
return false;
|
||||
}
|
||||
if (!attrs.hasAttribute(QLatin1String("type"))) {
|
||||
printError(QStringLiteral("Missing \"type\" attribute in <param> tag!"));
|
||||
return false;
|
||||
}
|
||||
|
||||
const auto name = attrs.value(QLatin1String("name")).toString();
|
||||
const auto type = attrs.value(QLatin1String("type")).toString();
|
||||
|
||||
for (const auto child : classNode->children()) {
|
||||
if (child->type() == Node::Ctor) {
|
||||
auto ctor = const_cast<CtorNode *>(static_cast<const CtorNode *>(child));
|
||||
ctor->setArgumentType(name, type);
|
||||
}
|
||||
}
|
||||
|
||||
auto paramNode = new PropertyNode(name, type, classNode);
|
||||
|
||||
if (attrs.hasAttribute(QLatin1String("default"))) {
|
||||
paramNode->setDefaultValue(attrs.value(QLatin1String("default")).toString());
|
||||
}
|
||||
if (attrs.hasAttribute(QLatin1String("readOnly"))) {
|
||||
paramNode->setReadOnly(attrs.value(QLatin1String("readOnly")) == QLatin1String("true"));
|
||||
}
|
||||
if (attrs.hasAttribute(QLatin1String("asReference"))) {
|
||||
paramNode->setAsReference(attrs.value(QLatin1String("asReference")) == QLatin1String("true"));
|
||||
}
|
||||
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("param"))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
if (mReader.name() == QLatin1String("setter")) {
|
||||
if (!parseSetter(paramNode)) {
|
||||
return false;
|
||||
}
|
||||
} else if (mReader.name() == QLatin1String("depends")) {
|
||||
auto dependsAttrs = mReader.attributes();
|
||||
if (!dependsAttrs.hasAttribute(QLatin1String("enum"))) {
|
||||
printError(QStringLiteral("Missing \"enum\" attribute in <depends> tag!"));
|
||||
return false;
|
||||
}
|
||||
if (!dependsAttrs.hasAttribute(QLatin1String("value"))) {
|
||||
printError(QStringLiteral("Missing \"value\" attribute in <depends> tag!"));
|
||||
return false;
|
||||
}
|
||||
paramNode->addDependency(dependsAttrs.value(QLatin1String("enum")).toString(), dependsAttrs.value(QLatin1String("value")).toString());
|
||||
} else {
|
||||
printError(QStringLiteral("Unknown tag: ").append(mReader.name()));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool XmlParser::parseSetter(PropertyNode *parent)
|
||||
{
|
||||
const auto attrs = mReader.attributes();
|
||||
auto setter = new PropertyNode::Setter;
|
||||
setter->name = attrs.value(QLatin1String("name")).toString();
|
||||
setter->type = attrs.value(QLatin1String("type")).toString();
|
||||
|
||||
while (!mReader.atEnd() && !(mReader.isEndElement() && mReader.name() == QLatin1String("setter"))) {
|
||||
mReader.readNext();
|
||||
if (mReader.isStartElement()) {
|
||||
if (mReader.name() == QLatin1String("append")) {
|
||||
setter->append = mReader.attributes().value(QLatin1String("name")).toString();
|
||||
} else if (mReader.name() == QLatin1String("remove")) {
|
||||
setter->remove = mReader.attributes().value(QLatin1String("name")).toString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
parent->setSetter(setter);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void XmlParser::printError(const QString &error)
|
||||
{
|
||||
std::cerr << "Error:" << mReader.lineNumber() << ":" << mReader.columnNumber() << ": " << qPrintable(error) << std::endl;
|
||||
}
|
43
recipes-application/akonadi/protocolgen/xmlparser.h
Normal file
43
recipes-application/akonadi/protocolgen/xmlparser.h
Normal file
|
@ -0,0 +1,43 @@
|
|||
/*
|
||||
SPDX-FileCopyrightText: 2017 Daniel Vrátil <dvratil@kde.og>
|
||||
|
||||
SPDX-License-Identifier: LGPL-2.0-or-later
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QXmlStreamReader>
|
||||
|
||||
#include <memory>
|
||||
|
||||
class Node;
|
||||
class DocumentNode;
|
||||
class EnumNode;
|
||||
class ClassNode;
|
||||
class PropertyNode;
|
||||
|
||||
class XmlParser
|
||||
{
|
||||
public:
|
||||
explicit XmlParser();
|
||||
~XmlParser();
|
||||
|
||||
bool parse(const QString &filename);
|
||||
|
||||
Node const *tree() const;
|
||||
|
||||
private:
|
||||
bool parseProtocol();
|
||||
bool parseCommand(DocumentNode *parent);
|
||||
bool parseEnum(ClassNode *parent);
|
||||
bool parseEnumValue(EnumNode *parent);
|
||||
bool parseParam(ClassNode *parent);
|
||||
bool parseCtor(ClassNode *parent);
|
||||
bool parseSetter(PropertyNode *parent);
|
||||
|
||||
void printError(const QString &error);
|
||||
|
||||
private:
|
||||
QXmlStreamReader mReader;
|
||||
std::unique_ptr<Node> mTree;
|
||||
};
|
41
recipes-application/akonadi/protocolgen_23.04.0.bb
Normal file
41
recipes-application/akonadi/protocolgen_23.04.0.bb
Normal file
|
@ -0,0 +1,41 @@
|
|||
SUMMARY = "akonadi-protocolgen"
|
||||
DESCRIPTION = "Build Tool for akonadi"
|
||||
HOMEPAGE = "https://invent.kde.org/akonadi/"
|
||||
LICENSE = "LGPL-2.0+"
|
||||
|
||||
SRC_URI = " \
|
||||
file://LGPL-2.0-or-later.txt;subdir=protocolgen-23.04.0 \
|
||||
file://CMakeLists.txt;subdir=protocolgen-23.04.0 \
|
||||
file://cppgenerator.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://cppgenerator.h;subdir=protocolgen-23.04.0 \
|
||||
file://cpphelper.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://cpphelper.h;subdir=protocolgen-23.04.0 \
|
||||
file://main.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://nodetree.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://nodetree.h;subdir=protocolgen-23.04.0 \
|
||||
file://typehelper.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://typehelper.h;subdir=protocolgen-23.04.0 \
|
||||
file://xmlparser.cpp;subdir=protocolgen-23.04.0 \
|
||||
file://xmlparser.h;subdir=protocolgen-23.04.0 \
|
||||
"
|
||||
|
||||
LIC_FILES_CHKSUM = "file://LGPL-2.0-or-later.txt;md5=6d2d9952d88b50a51a5c73dc431d06c7"
|
||||
|
||||
inherit cmake
|
||||
inherit cmake_qt5
|
||||
inherit cmake_kf5
|
||||
inherit cmake_kdeapp
|
||||
|
||||
DEPENDS:= " \
|
||||
qtbase \
|
||||
cmake \
|
||||
extra-cmake-modules-native \
|
||||
"
|
||||
|
||||
do_install() {
|
||||
install -d ${D}${bindir}
|
||||
install ${B}/protocolgen ${D}${bindir}
|
||||
}
|
||||
|
||||
|
||||
BBCLASSEXTEND="native nativesdk"
|
10
recipes-core/packagegroup/packagegroup-kde-gear-pim.bb
Normal file
10
recipes-core/packagegroup/packagegroup-kde-gear-pim.bb
Normal file
|
@ -0,0 +1,10 @@
|
|||
DESCRIPTION = "KDE Gear PIM Packages"
|
||||
|
||||
inherit packagegroup
|
||||
|
||||
PACKAGES = " \
|
||||
packagegroup-kde-gear-pim \
|
||||
"
|
||||
RDEPENDS:packagegroup-star64-plasma = " \
|
||||
akonadi \
|
||||
"
|
55
scripts/add-app.sh
Executable file
55
scripts/add-app.sh
Executable file
|
@ -0,0 +1,55 @@
|
|||
#!/bin/bash
|
||||
#
|
||||
# add/remove KDE Gear release recipes
|
||||
#
|
||||
# SPDX-FileCopyrightText: 2019 Volker Krause <vkrause@kde.org>
|
||||
# SPDX-FileCopyrightText: 2021 Andreas Cord-Landwehr <cordlandwehr@kde.org>
|
||||
#
|
||||
# SPDX-License-Identifier: MIT
|
||||
|
||||
function usage()
|
||||
{
|
||||
echo "$1 [add-tarball|remove|update] <app> <version>"
|
||||
exit 1
|
||||
}
|
||||
|
||||
command=$1
|
||||
if [ -z "$command" ]; then usage $0; fi
|
||||
|
||||
app=$2
|
||||
if [ -z "$app" ]; then usage $0; fi
|
||||
|
||||
version=$3
|
||||
if [ -z "$version" ]; then usage $0; fi
|
||||
|
||||
base=`dirname $0`/../recipes-application
|
||||
|
||||
case $command in
|
||||
add-tarball)
|
||||
name="${base}/${app}"
|
||||
url="https://download.kde.org/stable/release-service/${version}/src/${app}-${version}.tar.xz"
|
||||
sha256=$(curl -s "${url}.sha256" | cut -d" " -f1)
|
||||
echo "${url} : ${sha256}"
|
||||
mkdir -p ${name}
|
||||
cat <<EOM > "${name}/${app}_${version}.bb"
|
||||
require \${PN}.inc
|
||||
SRC_URI = "${url}"
|
||||
SRC_URI[sha256sum] = "${sha256}"
|
||||
EOM
|
||||
cat <<EOM > "${name}/${app}.inc"
|
||||
SUMMARY = "${app}"
|
||||
DESCRIPTION = "TODO"
|
||||
HOMEPAGE = "https://invent.kde.org/${app}/"
|
||||
LICENSE = "MIT & BSD-2-Clause & BSD-3-Clause & LGPL-2.0+ & (LGPL-2.1 | LGPL-3.0 | LicenseRef-KDE-Accepted-LGPL)"
|
||||
|
||||
KF5_REUSE_LICENSECHECK_ENABLED="1"
|
||||
|
||||
inherit cmake_kdeapp
|
||||
inherit mime-xdg
|
||||
EOM
|
||||
#git add $name
|
||||
;;
|
||||
*)
|
||||
usage $0
|
||||
;;
|
||||
esac
|
Loading…
Add table
Reference in a new issue