diff options
author | Cosimo Alfarano <cosimo.alfarano@collabora.co.uk> | 2009-12-04 21:14:58 -0200 |
---|---|---|
committer | Cosimo Alfarano <cosimo.alfarano@collabora.co.uk> | 2009-12-04 21:14:58 -0200 |
commit | 8fb9c3d6136c533cb5f240740f357647019b22ab (patch) | |
tree | d377aa717c5df7859a962dfd051aa6a40ffb4229 | |
parent | 35c657537049f36e2d6fa445008a498dde4c8423 (diff) |
Completed importing and refactoring of EmpathyLogStore
* removed any call which would make TPL depending on libempathy
* copied empathy-time.[hc]
* added some empathy's utility function to tpl_utils.[ch]
* added support for automake/autoconf using empathy's one as basis:
currently TPL depends on telepathy-glib and libxmp-2.0 (and theirs
deps)
* added AUTHORS COPYING INSTALL README and NEWS files (empty)
61 files changed, 7512 insertions, 167 deletions
diff --git a/AUTHORS b/AUTHORS new file mode 100644 index 000000000..e69de29bb --- /dev/null +++ b/AUTHORS diff --git a/COPYING b/COPYING new file mode 100644 index 000000000..94a9ed024 --- /dev/null +++ b/COPYING @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/> + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, 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 +them 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 prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If 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 convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU 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 +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "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 PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM 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 PROGRAM (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 PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state 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 program's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + <program> Copyright (C) <year> <name of author> + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +<http://www.gnu.org/licenses/>. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +<http://www.gnu.org/philosophy/why-not-lgpl.html>. diff --git a/INSTALL b/INSTALL new file mode 100644 index 000000000..2550dab75 --- /dev/null +++ b/INSTALL @@ -0,0 +1,302 @@ +Installation Instructions +************************* + +Copyright (C) 1994, 1995, 1996, 1999, 2000, 2001, 2002, 2004, 2005, +2006, 2007, 2008, 2009 Free Software Foundation, Inc. + + This file is free documentation; the Free Software Foundation gives +unlimited permission to copy, distribute and modify it. + +Basic Installation +================== + + Briefly, the shell commands `./configure; make; make install' should +configure, build, and install this package. The following +more-detailed instructions are generic; see the `README' file for +instructions specific to this package. + + The `configure' shell script attempts to guess correct values for +various system-dependent variables used during compilation. It uses +those values to create a `Makefile' in each directory of the package. +It may also create one or more `.h' files containing system-dependent +definitions. Finally, it creates a shell script `config.status' that +you can run in the future to recreate the current configuration, and a +file `config.log' containing compiler output (useful mainly for +debugging `configure'). + + It can also use an optional file (typically called `config.cache' +and enabled with `--cache-file=config.cache' or simply `-C') that saves +the results of its tests to speed up reconfiguring. Caching is +disabled by default to prevent problems with accidental use of stale +cache files. + + If you need to do unusual things to compile the package, please try +to figure out how `configure' could check whether to do them, and mail +diffs or instructions to the address given in the `README' so they can +be considered for the next release. If you are using the cache, and at +some point `config.cache' contains results you don't want to keep, you +may remove or edit it. + + The file `configure.ac' (or `configure.in') is used to create +`configure' by a program called `autoconf'. You need `configure.ac' if +you want to change it or regenerate `configure' using a newer version +of `autoconf'. + +The simplest way to compile this package is: + + 1. `cd' to the directory containing the package's source code and type + `./configure' to configure the package for your system. + + Running `configure' might take a while. While running, it prints + some messages telling which features it is checking for. + + 2. Type `make' to compile the package. + + 3. Optionally, type `make check' to run any self-tests that come with + the package. + + 4. Type `make install' to install the programs and any data files and + documentation. + + 5. You can remove the program binaries and object files from the + source code directory by typing `make clean'. To also remove the + files that `configure' created (so you can compile the package for + a different kind of computer), type `make distclean'. There is + also a `make maintainer-clean' target, but that is intended mainly + for the package's developers. If you use it, you may have to get + all sorts of other programs in order to regenerate files that came + with the distribution. + + 6. Often, you can also type `make uninstall' to remove the installed + files again. + +Compilers and Options +===================== + + Some systems require unusual options for compilation or linking that +the `configure' script does not know about. Run `./configure --help' +for details on some of the pertinent environment variables. + + You can give `configure' initial values for configuration parameters +by setting variables in the command line or in the environment. Here +is an example: + + ./configure CC=c99 CFLAGS=-g LIBS=-lposix + + *Note Defining Variables::, for more details. + +Compiling For Multiple Architectures +==================================== + + You can compile the package for more than one kind of computer at the +same time, by placing the object files for each architecture in their +own directory. To do this, you can use GNU `make'. `cd' to the +directory where you want the object files and executables to go and run +the `configure' script. `configure' automatically checks for the +source code in the directory that `configure' is in and in `..'. + + With a non-GNU `make', it is safer to compile the package for one +architecture at a time in the source code directory. After you have +installed the package for one architecture, use `make distclean' before +reconfiguring for another architecture. + + On MacOS X 10.5 and later systems, you can create libraries and +executables that work on multiple system types--known as "fat" or +"universal" binaries--by specifying multiple `-arch' options to the +compiler but only a single `-arch' option to the preprocessor. Like +this: + + ./configure CC="gcc -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CXX="g++ -arch i386 -arch x86_64 -arch ppc -arch ppc64" \ + CPP="gcc -E" CXXCPP="g++ -E" + + This is not guaranteed to produce working output in all cases, you +may have to build one architecture at a time and combine the results +using the `lipo' tool if you have problems. + +Installation Names +================== + + By default, `make install' installs the package's commands under +`/usr/local/bin', include files under `/usr/local/include', etc. You +can specify an installation prefix other than `/usr/local' by giving +`configure' the option `--prefix=PREFIX'. + + You can specify separate installation prefixes for +architecture-specific files and architecture-independent files. If you +pass the option `--exec-prefix=PREFIX' to `configure', the package uses +PREFIX as the prefix for installing programs and libraries. +Documentation and other data files still use the regular prefix. + + In addition, if you use an unusual directory layout you can give +options like `--bindir=DIR' to specify different values for particular +kinds of files. Run `configure --help' for a list of the directories +you can set and what kinds of files go in them. + + If the package supports it, you can cause programs to be installed +with an extra prefix or suffix on their names by giving `configure' the +option `--program-prefix=PREFIX' or `--program-suffix=SUFFIX'. + +Optional Features +================= + + Some packages pay attention to `--enable-FEATURE' options to +`configure', where FEATURE indicates an optional part of the package. +They may also pay attention to `--with-PACKAGE' options, where PACKAGE +is something like `gnu-as' or `x' (for the X Window System). The +`README' should mention any `--enable-' and `--with-' options that the +package recognizes. + + For packages that use the X Window System, `configure' can usually +find the X include and library files automatically, but if it doesn't, +you can use the `configure' options `--x-includes=DIR' and +`--x-libraries=DIR' to specify their locations. + +Particular systems +================== + + On HP-UX, the default C compiler is not ANSI C compatible. If GNU +CC is not installed, it is recommended to use the following options in +order to use an ANSI C compiler: + + ./configure CC="cc -Ae -D_XOPEN_SOURCE=500" + +and if that doesn't work, install pre-built binaries of GCC for HP-UX. + + On OSF/1 a.k.a. Tru64, some versions of the default C compiler cannot +parse its `<wchar.h>' header file. The option `-nodtk' can be used as +a workaround. If GNU CC is not installed, it is therefore recommended +to try + + ./configure CC="cc" + +and if that doesn't work, try + + ./configure CC="cc -nodtk" + + On Solaris, don't put `/usr/ucb' early in your `PATH'. This +directory contains several dysfunctional programs; working variants of +these programs are available in `/usr/bin'. So, if you need `/usr/ucb' +in your `PATH', put it _after_ `/usr/bin'. + + On Haiku, software installed for all users goes in `/boot/common', +not `/usr/local'. It is recommended to use the following options: + + ./configure --prefix=/boot/common + +Specifying the System Type +========================== + + There may be some features `configure' cannot figure out +automatically, but needs to determine by the type of machine the package +will run on. Usually, assuming the package is built to be run on the +_same_ architectures, `configure' can figure that out, but if it prints +a message saying it cannot guess the machine type, give it the +`--build=TYPE' option. TYPE can either be a short name for the system +type, such as `sun4', or a canonical name which has the form: + + CPU-COMPANY-SYSTEM + +where SYSTEM can have one of these forms: + + OS + KERNEL-OS + + See the file `config.sub' for the possible values of each field. If +`config.sub' isn't included in this package, then this package doesn't +need to know the machine type. + + If you are _building_ compiler tools for cross-compiling, you should +use the option `--target=TYPE' to select the type of system they will +produce code for. + + If you want to _use_ a cross compiler, that generates code for a +platform different from the build platform, you should specify the +"host" platform (i.e., that on which the generated programs will +eventually be run) with `--host=TYPE'. + +Sharing Defaults +================ + + If you want to set default values for `configure' scripts to share, +you can create a site shell script called `config.site' that gives +default values for variables like `CC', `cache_file', and `prefix'. +`configure' looks for `PREFIX/share/config.site' if it exists, then +`PREFIX/etc/config.site' if it exists. Or, you can set the +`CONFIG_SITE' environment variable to the location of the site script. +A warning: not all `configure' scripts look for a site script. + +Defining Variables +================== + + Variables not defined in a site shell script can be set in the +environment passed to `configure'. However, some packages may run +configure again during the build, and the customized values of these +variables may be lost. In order to avoid this problem, you should set +them in the `configure' command line, using `VAR=value'. For example: + + ./configure CC=/usr/local2/bin/gcc + +causes the specified `gcc' to be used as the C compiler (unless it is +overridden in the site shell script). + +Unfortunately, this technique does not work for `CONFIG_SHELL' due to +an Autoconf bug. Until the bug is fixed you can use this workaround: + + CONFIG_SHELL=/bin/bash /bin/bash ./configure CONFIG_SHELL=/bin/bash + +`configure' Invocation +====================== + + `configure' recognizes the following options to control how it +operates. + +`--help' +`-h' + Print a summary of all of the options to `configure', and exit. + +`--help=short' +`--help=recursive' + Print a summary of the options unique to this package's + `configure', and exit. The `short' variant lists options used + only in the top level, while the `recursive' variant lists options + also present in any nested packages. + +`--version' +`-V' + Print the version of Autoconf used to generate the `configure' + script, and exit. + +`--cache-file=FILE' + Enable the cache: use and save the results of the tests in FILE, + traditionally `config.cache'. FILE defaults to `/dev/null' to + disable caching. + +`--config-cache' +`-C' + Alias for `--cache-file=config.cache'. + +`--quiet' +`--silent' +`-q' + Do not print messages saying which checks are being made. To + suppress all normal output, redirect it to `/dev/null' (any error + messages will still be shown). + +`--srcdir=DIR' + Look for the package's source code in directory DIR. Usually + `configure' can determine that directory automatically. + +`--prefix=DIR' + Use DIR as the installation prefix. *Note Installation Names:: + for more details, including other options available for fine-tuning + the installation locations. + +`--no-create' +`-n' + Run the configure checks, but stop before creating any output + files. + +`configure' also accepts some other, not widely useful, options. Run +`configure --help' for more details. + diff --git a/Makefile.am b/Makefile.am new file mode 100644 index 000000000..cfcae7353 --- /dev/null +++ b/Makefile.am @@ -0,0 +1,43 @@ +SUBDIRS = tools src + +ACLOCAL_AMFLAGS = -I m4 + +DISTCHECK_CONFIGURE_FLAGS = \ + --disable-scrollkeeper \ + --disable-schemas-install + +EXTRA_DIST = \ + ChangeLog \ + ChangeLog.old \ + README \ + CONTRIBUTORS \ + autogen.sh + +DISTCLEANFILES = \ + ChangeLog + +# Workaround broken scrollkeeper that doesn't remove its files on +# uninstall. +distuninstallcheck_listfiles = find . -type f -print | grep -v '^\./var/scrollkeeper' + +distclean-local: + if test "x$(srdcir)" = "x."; then :; else \ + rm -f ChangeLog; \ + fi + +ChangeLog: + @echo Creating $@ + @if test -d "$(srcdir)/.git"; then \ + (GIT_DIR=$(top_srcdir)/.git ./missing --run git log EMPATHY_2_27_1.. --stat) | fmt --split-only > $@.tmp \ + && mv -f $@.tmp $@ \ + || ($(RM) $@.tmp; \ + echo Failed to generate ChangeLog, your ChangeLog may be outdated >&2; \ + (test -f $@ || echo git-log is required to generate this file >> $@)); \ + else \ + test -f $@ || \ + (echo A git checkout and git-log is required to generate ChangeLog >&2 && \ + echo A git checkout and git-log is required to generate this file >> $@); \ + fi + +.PHONY: ChangeLog + diff --git a/autogen.sh b/autogen.sh new file mode 100755 index 000000000..4973c4c16 --- /dev/null +++ b/autogen.sh @@ -0,0 +1,20 @@ +#!/bin/sh +# Run this to generate all the initial makefiles, etc. + +srcdir=`dirname $0` +test -z "$srcdir" && srcdir=. + +PKG_NAME="TelepathyLogger" +REQUIRED_AUTOMAKE_VERSION=1.9 + +(test -f $srcdir/configure.ac) || { + echo -n "**Error**: Directory "\`$srcdir\'" does not look like the" + echo " top-level gnome directory" + exit 1 +} + +which gnome-autogen.sh || { + echo "You need to install gnome-common from the GNOME CVS" + exit 1 +} +USE_GNOME2_MACROS=1 USE_COMMON_DOC_BUILD=yes . gnome-autogen.sh diff --git a/configure.ac b/configure.ac new file mode 100644 index 000000000..53ff7534e --- /dev/null +++ b/configure.ac @@ -0,0 +1,482 @@ +dnl If not 1, append datestamp to the version number +m4_define(tpl_released, 0) + +m4_define([tpl_major_version], [0]) +m4_define([tpl_minor_version], [1]) +m4_define([tpl_micro_version], [0]) +m4_define([tpl_nano_version], [0]) + +dnl Display the nano_version only if it's not '0' +m4_define([tpl_base_version], + [tpl_major_version.tpl_minor_version.tpl_micro_version]) +m4_define([tpl_full_version], + [m4_if(tpl_nano_version, 0, [tpl_base_version], + [tpl_base_version].[tpl_nano_version])]) + +m4_define(tpl_maybe_datestamp, + m4_esyscmd([if test x]tpl_released[ != x1; then date +.%Y%m%d | tr -d '\n\r'; fi])) + +m4_define(tpl_version, tpl_full_version[]tpl_maybe_datestamp) + + +AC_INIT(TelepathyLogger, tpl_version, http://telepathy.freedesktop.org/wiki/Logger) + + +AC_PREREQ(2.59) +AC_COPYRIGHT([ + Copyright (C) 2003-2007 Imendio AB + Copyright (C) 2007-2008 Collabora Ltd. +]) + +# Minimal version required +GLIB_REQUIRED=2.22.0 +#GTK_REQUIRED=2.18.0 +#GCONF_REQUIRED=1.2.0 +TELEPATHY_GLIB_REQUIRED=0.9.0 +#ENCHANT_REQUIRED=1.2.0 +#ISO_CODES_REQUIRED=0.35 +#LIBNOTIFY_REQUIRED=0.4.4 +#LIBCANBERRA_GTK_REQUIRED=0.4 +#LIBCHAMPLAIN_REQUIRED=0.4 +#LIBCHAMPLAIN_GTK_REQUIRED=0.4 +#CLUTTER_GTK_REQUIRED=0.10 +#GEOCLUE_REQUIRED=0.11 +#WEBKIT_REQUIRED=1.1.15 +#KEYRING_REQUIRED=2.22 +#NETWORK_MANAGER_REQUIRED=0.7.0 +#NAUTILUS_SENDTO_REQUIRED=2.28.1 + +# Use --enable-maintainer-mode to disabled deprecated symbols +GNOME_MAINTAINER_MODE_DEFINES + +# Warning if GLib/GDK/GTK headers are included +AC_DEFINE(G_DISABLE_SINGLE_INCLUDES, [], [Disable single includes for GLib]) +AC_DEFINE(GDK_PIXBUF_DISABLE_SINGLE_INCLUDES, [], [Disable single includes for GDK pixbuf]) +#AC_DEFINE(GTK_DISABLE_SINGLE_INCLUDES, [], [Disable single includes for GTK]) + +AC_CONFIG_MACRO_DIR([m4]) +AC_CONFIG_HEADERS([config.h]) +AC_CONFIG_SRCDIR([configure.ac]) +AC_CONFIG_AUX_DIR(.) + +GNOME_COMMON_INIT + +AM_INIT_AUTOMAKE(1.9 dist-bzip2 no-define -Wno-portability) +AC_ISC_POSIX +AC_PROG_CC +AC_HEADER_STDC +AM_PROG_LIBTOOL +AM_PROG_MKDIR_P +AM_PATH_GLIB_2_0 +AC_PATH_XTRA +IT_PROG_INTLTOOL([0.35.0]) +GNOME_DOC_INIT([0.17.3]) +IDT_COMPILE_WARNINGS +AC_PATH_PROG(DBUS_BINDING_TOOL, dbus-binding-tool) +AC_PATH_PROG(GCONFTOOL, gconftool-2) +AM_GCONF_SOURCE_2 +GLIB_GENMARSHAL=`$PKG_CONFIG glib-2.0 --variable=glib_genmarshal` +AC_SUBST(GLIB_GENMARSHAL) + +AC_CHECK_PROGS([XSLTPROC], [xsltproc]) +if test -z "$XSLTPROC"; then + AC_MSG_ERROR([xsltproc (from libxslt) is required]) +fi +#AM_PATH_PYTHON([2.3]) + +TPL_ARG_VALGRIND + + +# ----------------------------------------------------------- +# Error flags +# ----------------------------------------------------------- +AS_COMPILER_FLAG(-Wall, ERROR_CFLAGS="-Wall", ERROR_CFLAGS="") +AS_COMPILER_FLAG(-Werror, werror=yes, werror=no) + +AC_ARG_ENABLE(Werror, + AC_HELP_STRING([--disable-Werror],[compile without -Werror (normally enabled in development builds)]), + werror=$enableval, :) + +AS_COMPILER_FLAG(-Wextra, wextra=yes, wextra=no) +AS_COMPILER_FLAG(-Wno-missing-field-initializers, + wno_missing_field_initializers=yes, + wno_missing_field_initializers=no) +AS_COMPILER_FLAG(-Wno-unused-parameter, + wno_unused_parameter=yes, + wno_unused_parameter=no) + +ifelse(tpl_released, 1, [], + [ + if test x$werror = xyes; then + ERROR_CFLAGS="$ERROR_CFLAGS -Werror" + fi + if test x$wextra = xyes -a \ + x$wno_missing_field_initializers = xyes -a \ + x$wno_unused_parameter = xyes; then + ERROR_CFLAGS="$ERROR_CFLAGS -Wextra -Wno-missing-field-initializers -Wno-unused-parameter" + fi + ]) + +AS_COMPILER_FLAG(-std=c99, ERROR_CFLAGS="$ERROR_CFLAGS -std=c99") +#AS_COMPILER_FLAG(-Wdeclaration-after-statement, ERROR_CFLAGS="$ERROR_CFLAGS -Wdeclaration-after-statement") +AS_COMPILER_FLAG(-Wshadow, ERROR_CFLAGS="$ERROR_CFLAGS -Wshadow") +AS_COMPILER_FLAG(-Wmissing-prototypes, ERROR_CFLAGS="$ERROR_CFLAGS -Wmissing-prototypes") +AS_COMPILER_FLAG(-Wmissing-declarations, ERROR_CFLAGS="$ERROR_CFLAGS -Wmissing-declarations") +# Disabled because some GTK+ headers (like gtkitemfactory.h) are bugged :( +#AS_COMPILER_FLAG(-Wstrict-prototypes, ERROR_CFLAGS="$ERROR_CFLAGS -Wstrict-prototypes") + +AC_SUBST(ERROR_CFLAGS) + +# ----------------------------------------------------------- +# Pkg-Config dependency checks +# ----------------------------------------------------------- + +PKG_CHECK_MODULES(LIBTPL, +[ + glib-2.0 >= $GLIB_REQUIRED + gobject-2.0 + libxml-2.0 + telepathy-glib >= $TELEPATHY_GLIB_REQUIRED +]) +## Removed libs +# gio-2.0 >= $GLIB_REQUIRED +# gio-unix-2.0 >= $GLIB_REQUIRED +# telepathy-farsight +# farsight2-0.10 +# gstreamer-0.10 + +#PKG_CHECK_MODULES(LIBEMPATHYGTK, +#[ +# glib-2.0 >= $GLIB_REQUIRED +# gobject-2.0 +# gio-2.0 >= $GLIB_REQUIRED +# gconf-2.0 >= $GCONF_REQUIRED +# x11 +# gtk+-2.0 >= $GTK_REQUIRED +# libcanberra-gtk >= $LIBCANBERRA_GTK_REQUIRED +# telepathy-glib >= $TELEPATHY_GLIB_REQUIRED +# farsight2-0.10 +# gstreamer-0.10 +# gstreamer-interfaces-0.10 +#]) + +PKG_CHECK_MODULES(TPL, +[ + glib-2.0 >= $GLIB_REQUIRED + libxml-2.0 + gobject-2.0 + dbus-glib-1 + telepathy-glib >= $TELEPATHY_GLIB_REQUIRED +]) +### removed libs +# gio-2.0 >= $GLIB_REQUIRED +# gdk-x11-2.0 +# gtk+-2.0 >= $GTK_REQUIRED +# libebook-1.2 +# telepathy-farsight +# farsight2-0.10 +# gstreamer-0.10 +# unique-1.0 +# gnome-keyring-1 >= $KEYRING_REQUIRED + + +#PKG_CHECK_MODULES(LIBNOTIFY, libnotify >= $LIBNOTIFY_REQUIRED) + +# ----------------------------------------------------------- +# Enable debug +# ----------------------------------------------------------- + +AC_ARG_ENABLE(debug, + AC_HELP_STRING([--disable-debug],[compile without debug code]), + enable_debug=$enableval, enable_debug=yes ) + +if test x$enable_debug = xyes; then + AC_DEFINE(ENABLE_DEBUG, [], [Enable debug code]) +fi + +#DISABLED## ----------------------------------------------------------- +#DISABLED## Language Support +#DISABLED## ----------------------------------------------------------- +#DISABLED# +#DISABLED#GETTEXT_PACKAGE=telepathy_logger +#DISABLED#AC_SUBST(GETTEXT_PACKAGE) +#DISABLED#AC_DEFINE_UNQUOTED(GETTEXT_PACKAGE,"$GETTEXT_PACKAGE",[Gettext package name]) +#DISABLED# +#DISABLED#AM_GLIB_GNU_GETTEXT +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## Connectivity integration +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_WITH(connectivity, +#DISABLED# AS_HELP_STRING([--with-connectivity=@<:@nm/connman/auto/no@:>@], +#DISABLED# [build with connectivity support]), , +#DISABLED# with_connectivity=auto) +#DISABLED# +#DISABLED#if test "x$with_connectivity" = "xno"; then +#DISABLED# have_nm=no +#DISABLED# have_connman=no +#DISABLED# +#DISABLED#elif test "x$with_connectivity" = "xconnman"; then +#DISABLED# +#DISABLED# PKG_CHECK_MODULES(CONNMAN, +#DISABLED# [ +#DISABLED# dbus-glib-1 +#DISABLED# ], have_connman="yes", have_connman="no") +#DISABLED# +#DISABLED# if test "x$have_connman" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_CONNMAN, 1, [Define if you have connman dependencies]) +#DISABLED# have_nm=no +#DISABLED# fi +#DISABLED# +#DISABLED#else +#DISABLED# +#DISABLED# PKG_CHECK_MODULES(NETWORK_MANAGER, +#DISABLED# [ +#DISABLED# libnm_glib >= $NETWORK_MANAGER_REQUIRED +#DISABLED# ], have_nm="yes", have_nm="no") +#DISABLED# +#DISABLED# if test "x$have_nm" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_NM, 1, [Define if you have libnm-glib]) +#DISABLED# have_connman=no +#DISABLED# else +#DISABLED# PKG_CHECK_MODULES(NETWORK_MANAGER, +#DISABLED# [ +#DISABLED# libnm-glib >= $NETWORK_MANAGER_REQUIRED +#DISABLED# ], have_nm="yes", have_nm="no") +#DISABLED# +#DISABLED# if test "x$have_nm" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_NM, 1, [Define if you have libnm-glib]) +#DISABLED# have_connman=no +#DISABLED# fi +#DISABLED# fi +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$with_connectivity" = "xconnman" -a "x$have_connman" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find connman dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$with_connectivity" = "xnm" -a "x$have_nm" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find libnm-glib dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_NM, test "x$have_nm" = "xyes") +#DISABLED#AM_CONDITIONAL(HAVE_CONNMAN, test "x$have_connman" = "xyes") +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## Webkit +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(webkit, +#DISABLED# AS_HELP_STRING([--enable-webkit=@<:@no/yes/auto@:>@], +#DISABLED# [build with webkit support]), , +#DISABLED# enable_webkit=auto) +#DISABLED# +#DISABLED#if test "x$enable_webkit" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(WEBKIT, +#DISABLED# [ +#DISABLED# webkit-1.0 >= $WEBKIT_REQUIRED +#DISABLED# ], have_webkit="yes", have_webkit="no") +#DISABLED# +#DISABLED# if test "x$have_webkit" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_WEBKIT, 1, [Define if you have libwebkitgtk]) +#DISABLED# fi +#DISABLED#else +#DISABLED# have_webkit=no +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_webkit" = "xyes" -a "x$have_webkit" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find webkit dependencies.]) +#DISABLED#fi +#DISABLED#AM_CONDITIONAL(HAVE_WEBKIT, test "x$have_webkit" = "xyes") +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## spellchecking checks: enchant and iso-codes +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(spell, +#DISABLED# AS_HELP_STRING([--enable-spell=@<:@no/yes/auto@:>@], +#DISABLED# [Enable spell checking]), , +#DISABLED# enable_spell=auto) +#DISABLED# +#DISABLED#if test "x$enable_spell" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(ENCHANT, +#DISABLED# [ +#DISABLED# enchant >= $ENCHANT_REQUIRED, +#DISABLED# iso-codes >= $ISO_CODES_REQUIRED +#DISABLED# ], have_enchant="yes", have_enchant="no") +#DISABLED# +#DISABLED# if test "x$have_enchant" = "xyes"; then +#DISABLED# AC_MSG_CHECKING([whether iso-codes has iso-639 and iso-3166 domains]) +#DISABLED# if $PKG_CONFIG --variable=domains iso-codes | grep 639 > /dev/null && \ +#DISABLED# $PKG_CONFIG --variable=domains iso-codes | grep 3166 > /dev/null ; then +#DISABLED# AC_DEFINE_UNQUOTED(ISO_CODES_PREFIX, ["`$PKG_CONFIG --variable=prefix iso-codes`"], [ISO codes prefix]) +#DISABLED# AC_DEFINE(HAVE_ENCHANT, [], [Define if you have libenchant]) +#DISABLED# result=yes +#DISABLED# else +#DISABLED# result=no +#DISABLED# have_enchant="no" +#DISABLED# fi +#DISABLED# AC_MSG_RESULT([$result]) +#DISABLED# fi +#DISABLED#else +#DISABLED# have_enchant=no +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_spell" = "xyes" -a "x$have_enchant" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find spell dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_ENCHANT, test "x$have_enchant" = "xyes") +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## Map view checks: libchamplain +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(map, +#DISABLED# AS_HELP_STRING([--enable-map=@<:@no/yes/auto@:>@], +#DISABLED# [Enable map view]), , +#DISABLED# enable_map=auto) +#DISABLED# +#DISABLED#if test "x$enable_map" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(LIBCHAMPLAIN, +#DISABLED# [ +#DISABLED# champlain-0.4 >= $LIBCHAMPLAIN_REQUIRED, +#DISABLED# champlain-gtk-0.4 >= $LIBCHAMPLAIN_GTK_REQUIRED +#DISABLED# clutter-gtk-0.10 >= $CLUTTER_GTK_REQUIRED +#DISABLED# ], have_libchamplain="yes", have_libchamplain="no") +#DISABLED# +#DISABLED# if test "x$have_libchamplain" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_LIBCHAMPLAIN, 1, [Define if you have libchamplain]) +#DISABLED# fi +#DISABLED#else +#DISABLED# have_libchamplain=no +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_map" = "xyes" -a "x$have_libchamplain" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find map view dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_LIBCHAMPLAIN, test "x$have_libchamplain" = "xyes") +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## location checks: geoclue +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(location, +#DISABLED# AS_HELP_STRING([--enable-location=@<:@no/yes/auto@:>@], +#DISABLED# [Enable location awareness]), , +#DISABLED# enable_location=auto) +#DISABLED# +#DISABLED#if test "x$enable_location" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(GEOCLUE, +#DISABLED# [ +#DISABLED# geoclue >= $GEOCLUE_REQUIRED +#DISABLED# ], have_geoclue="yes", have_geoclue="no") +#DISABLED# +#DISABLED# if test "x$have_geoclue" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_GEOCLUE, 1, [Define if you have geoclue]) +#DISABLED# fi +#DISABLED#else +#DISABLED# have_geoclue="no" +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_location" = "xyes" -a "x$have_geoclue" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find location dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_GEOCLUE, test "x$have_geoclue" = "xyes") +#DISABLED#AC_SUBST(GEOCLUE_CFLAGS) +#DISABLED#AC_SUBST(GEOCLUE_LIBS) +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## moblin widgets support +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(moblin, +#DISABLED# AS_HELP_STRING([--enable-moblin=@<:no/yes@:>@], +#DISABLED# [Enable moblin widgets]), , +#DISABLED# enable_moblin=no) +#DISABLED# +#DISABLED#if test "x$enable_moblin" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(MOBLIN, +#DISABLED# [ +#DISABLED# nbtk-gtk-1.2 +#DISABLED# ], have_moblin="yes", have_moblin="no") +#DISABLED# +#DISABLED# if test "x$have_moblin" = "xyes"; then +#DISABLED# AC_DEFINE(HAVE_MOBLIN, 1, [Define if you have moblin]) +#DISABLED# fi +#DISABLED#else +#DISABLED# have_moblin="no" +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_moblin" = "xyes" -a "x$have_moblin" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find moblin dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_MOBLIN, test "x$have_moblin" = "xyes") +#DISABLED#AC_SUBST(MOBLIN_CFLAGS) +#DISABLED#AC_SUBST(MOBLIN_LIBS) +#DISABLED# +#DISABLED## ----------------------------------------------------------- +#DISABLED## nautilus-sendto +#DISABLED## ----------------------------------------------------------- +#DISABLED#AC_ARG_ENABLE(nautilus-sendto, +#DISABLED# AS_HELP_STRING([--enable-nautilus-sendto=@<:@no/yes/auto@:>@], +#DISABLED# [build nautilus-sendto plugin]), , +#DISABLED# enable_nautilus_sendto=auto) +#DISABLED# +#DISABLED#if test "x$enable_nautilus_sendto" != "xno"; then +#DISABLED# PKG_CHECK_MODULES(NST, +#DISABLED# [ +#DISABLED# nautilus-sendto >= $NAUTILUS_SENDTO_REQUIRED +#DISABLED# ], have_nst="yes", have_nst="no") +#DISABLED#else +#DISABLED# have_nst=no +#DISABLED#fi +#DISABLED# +#DISABLED#if test "x$enable_nautilus_sendto" = "xyes" -a "x$have_nst" != "xyes"; then +#DISABLED# AC_MSG_ERROR([Couldn't find nautilus-sendto dependencies.]) +#DISABLED#fi +#DISABLED# +#DISABLED#AM_CONDITIONAL(HAVE_NST, test "x$have_nst" = "xyes") + +# ----------------------------------------------------------- +# Coding style checks +# ----------------------------------------------------------- +AC_ARG_ENABLE(coding-style-checks, + AC_HELP_STRING([--disable-coding-style-checks], + [don't check coding style using grep]), + [ENABLE_CODING_STYLE_CHECKS=$enableval], [ENABLE_CODING_STYLE_CHECKS=yes]) + +AC_SUBST([ENABLE_CODING_STYLE_CHECKS]) +# ----------------------------------------------------------- + +SHAVE_INIT(.) + +AC_OUTPUT([ + Makefile + src/Makefile + tools/Makefile + shave + shave-libtool +]) + +echo " +Configure summary: + + Compiler....................: ${CC} + Compiler Flags..............: ${CFLAGS} ${ERROR_CFLAGS} + Prefix......................: ${prefix} + Shaved build................: ${enable_shave} + Coding style checks.........: ${ENABLE_CODING_STYLE_CHECKS} + + Features: + Spell checking (enchant)....: ${have_enchant} + Display maps (libchamplain).: ${have_libchamplain} + Location awareness (Geoclue): ${have_geoclue} + Adium themes (Webkit).......: ${have_webkit} + Moblin widgets .............: ${have_moblin} + + Connectivity: + NetworkManager integration..: ${have_nm} + ConnMan integration.........: ${have_connman} + + Extras: + Nautilus-sendto plugin......: ${have_nst} +" diff --git a/include/tpl-log-manager.h b/include/tpl-log-manager.h index 8a8995828..133bd2d23 100644 --- a/include/tpl-log-manager.h +++ b/include/tpl-log-manager.h @@ -21,47 +21,46 @@ * Authors: Xavier Claessens <xclaesse@gmail.com> */ -#ifndef __EMPATHY_LOG_MANAGER_H__ -#define __EMPATHY_LOG_MANAGER_H__ +#ifndef __TPL_LOG_MANAGER_H__ +#define __TPL_LOG_MANAGER_H__ #include <glib-object.h> -#include <empathy-message.h> -#include <empathy-dispatcher.h> +#include <tpl_log_entry_text.h> G_BEGIN_DECLS -#define EMPATHY_TYPE_LOG_MANAGER (empathy_log_manager_get_type ()) -#define EMPATHY_LOG_MANAGER(o) \ - (G_TYPE_CHECK_INSTANCE_CAST ((o), EMPATHY_TYPE_LOG_MANAGER, \ - EmpathyLogManager)) -#define EMPATHY_LOG_MANAGER_CLASS(k) \ - (G_TYPE_CHECK_CLASS_CAST ((k), EMPATHY_TYPE_LOG_MANAGER, \ - EmpathyLogManagerClass)) -#define EMPATHY_IS_LOG_MANAGER(o) \ - (G_TYPE_CHECK_INSTANCE_TYPE ((o), EMPATHY_TYPE_LOG_MANAGER)) -#define EMPATHY_IS_LOG_MANAGER_CLASS(k) \ - (G_TYPE_CHECK_CLASS_TYPE ((k), EMPATHY_TYPE_LOG_MANAGER)) -#define EMPATHY_LOG_MANAGER_GET_CLASS(o) \ - (G_TYPE_INSTANCE_GET_CLASS ((o), EMPATHY_TYPE_LOG_MANAGER, \ - EmpathyLogManagerClass)) +#define TPL_TYPE_LOG_MANAGER (tpl_log_manager_get_type ()) +#define TPL_LOG_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_CAST ((o), TPL_TYPE_LOG_MANAGER, \ + TplLogManager)) +#define TPL_LOG_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_CAST ((k), TPL_TYPE_LOG_MANAGER, \ + TplLogManagerClass)) +#define TPL_IS_LOG_MANAGER(o) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((o), TPL_TYPE_LOG_MANAGER)) +#define TPL_IS_LOG_MANAGER_CLASS(k) \ + (G_TYPE_CHECK_CLASS_TYPE ((k), TPL_TYPE_LOG_MANAGER)) +#define TPL_LOG_MANAGER_GET_CLASS(o) \ + (G_TYPE_INSTANCE_GET_CLASS ((o), TPL_TYPE_LOG_MANAGER, \ + TplLogManagerClass)) -typedef struct _EmpathyLogManager EmpathyLogManager; -typedef struct _EmpathyLogManagerClass EmpathyLogManagerClass; -typedef struct _EmpathyLogSearchHit EmpathyLogSearchHit; +typedef struct _TplLogManager TplLogManager; +typedef struct _TplLogManagerClass TplLogManagerClass; +typedef struct _TplLogSearchHit TplLogSearchHit; -struct _EmpathyLogManager +struct _TplLogManager { GObject parent; gpointer priv; }; -struct _EmpathyLogManagerClass +struct _TplLogManagerClass { GObjectClass parent_class; }; -struct _EmpathyLogSearchHit +struct _TplLogSearchHit { TpAccount *account; gchar *chat_id; @@ -70,34 +69,34 @@ struct _EmpathyLogSearchHit gchar *date; }; -typedef gboolean (*EmpathyLogMessageFilter) (EmpathyMessage *message, +typedef gboolean (*TplLogMessageFilter) (TplLogEntryText *message, gpointer user_data); -GType empathy_log_manager_get_type (void) G_GNUC_CONST; -EmpathyLogManager *empathy_log_manager_dup_singleton (void); -gboolean empathy_log_manager_add_message (EmpathyLogManager *manager, - const gchar *chat_id, gboolean chatroom, EmpathyMessage *message, +GType tpl_log_manager_get_type (void) G_GNUC_CONST; +TplLogManager *tpl_log_manager_dup_singleton (void); +gboolean tpl_log_manager_add_message (TplLogManager *manager, + const gchar *chat_id, gboolean chatroom, TplLogEntryText *message, GError **error); -gboolean empathy_log_manager_exists (EmpathyLogManager *manager, +gboolean tpl_log_manager_exists (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom); -GList *empathy_log_manager_get_dates (EmpathyLogManager *manager, +GList *tpl_log_manager_get_dates (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom); -GList *empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, +GList *tpl_log_manager_get_messages_for_date (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom, const gchar *date); -GList *empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager, +GList *tpl_log_manager_get_filtered_messages (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom, - guint num_messages, EmpathyLogMessageFilter filter, gpointer user_data); -GList *empathy_log_manager_get_chats (EmpathyLogManager *manager, + guint num_messages, TplLogMessageFilter filter, gpointer user_data); +GList *tpl_log_manager_get_chats (TplLogManager *manager, TpAccount *account); -GList *empathy_log_manager_search_new (EmpathyLogManager *manager, +GList *tpl_log_manager_search_new (TplLogManager *manager, const gchar *text); -void empathy_log_manager_search_free (GList *hits); -gchar *empathy_log_manager_get_date_readable (const gchar *date); -void empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit); -void empathy_log_manager_observe (EmpathyLogManager *log_manager, - EmpathyDispatcher *dispatcher); +void tpl_log_manager_search_free (GList *hits); +gchar *tpl_log_manager_get_date_readable (const gchar *date); +void tpl_log_manager_search_hit_free (TplLogSearchHit *hit); +//void tpl_log_manager_observe (TplLogManager *log_manager, +// EmpathyDispatcher *dispatcher); G_END_DECLS -#endif /* __EMPATHY_LOG_MANAGER_H__ */ +#endif /* __TPL_LOG_MANAGER_H__ */ diff --git a/include/tpl-log-store.h b/include/tpl-log-store.h index 8b8620d8a..230eeafc6 100644 --- a/include/tpl-log-store.h +++ b/include/tpl-log-store.h @@ -27,7 +27,6 @@ #include <telepathy-glib/account.h> -#include <empathy-message.h> #include <tpl-log-manager.h> #include <tpl_log_entry_text.h> @@ -70,10 +69,10 @@ struct _TplLogStoreInterface gboolean chatroom, TplLogEntryText *message); GList * (*get_filtered_messages) (TplLogStore *self, TpAccount *account, const gchar *chat_id, gboolean chatroom, guint num_messages, - EmpathyLogMessageFilter filter, gpointer user_data); + TplLogMessageFilter filter, gpointer user_data); }; -GType tpl_log_store_get_type (void) G_GNUC_CONST; +GType tpl_log_store_get_type (void); const gchar *tpl_log_store_get_name (TplLogStore *self); gboolean tpl_log_store_exists (TplLogStore *self, @@ -96,7 +95,7 @@ void tpl_log_store_ack_message (TplLogStore *self, const gchar *chat_id, gboolean chatroom, TplLogEntryText *message); GList *tpl_log_store_get_filtered_messages (TplLogStore *self, TpAccount *account, const gchar *chat_id, gboolean chatroom, - guint num_messages, EmpathyLogMessageFilter filter, gpointer user_data); + guint num_messages, TplLogMessageFilter filter, gpointer user_data); G_END_DECLS diff --git a/include/tpl-time.h b/include/tpl-time.h new file mode 100644 index 000000000..5fc5cf316 --- /dev/null +++ b/include/tpl-time.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2004 Imendio AB + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + */ + +#ifndef __TPL_TIME_H__ +#define __TPL_TIME_H__ + +#ifndef __USE_XOPEN +#define __USE_XOPEN +#endif +#include <time.h> + +#include <glib.h> + +G_BEGIN_DECLS + +#define TPL_TIME_FORMAT_DISPLAY_SHORT "%H:%M" +#define TPL_TIME_FORMAT_DISPLAY_LONG "%a %d %b %Y" + +time_t tpl_time_get_current (void); +time_t tpl_time_get_local_time (struct tm *tm); +time_t tpl_time_parse (const gchar *str); +gchar *tpl_time_to_string_utc (time_t t, + const gchar *format); +gchar *tpl_time_to_string_local (time_t t, + const gchar *format); +gchar *tpl_time_to_string_relative (time_t t); + +G_END_DECLS + +#endif /* __TPL_TIME_H__ */ + diff --git a/include/tpl_contact.h b/include/tpl_contact.h index 0fe756d9a..47b01ccf6 100644 --- a/include/tpl_contact.h +++ b/include/tpl_contact.h @@ -43,7 +43,7 @@ typedef struct { GType tpl_contact_get_type (void); -TplContact *tpl_contact_new(); +TplContact *tpl_contact_new(void); #define ADD_GET(x,y) y tpl_contact_get_##x(TplContact *self) ADD_GET(contact, TpContact *); diff --git a/include/tpl_log_entry_text.h b/include/tpl_log_entry_text.h index 92c61b556..73ac86b59 100644 --- a/include/tpl_log_entry_text.h +++ b/include/tpl_log_entry_text.h @@ -55,8 +55,9 @@ typedef struct { GType tpl_log_entry_text_get_type (void); -TplLogEntryText *tpl_log_entry_text_new (); +TplLogEntryText *tpl_log_entry_text_new (void); +TpChannelTextMessageType tpl_log_entry_text_message_type_from_str (const gchar *type_str); const gchar *tpl_log_entry_text_message_type_to_str (TpChannelTextMessageType msg_type); diff --git a/include/tpl_utils.h b/include/tpl_utils.h index b0ea03c60..cb898f2c0 100644 --- a/include/tpl_utils.h +++ b/include/tpl_utils.h @@ -3,6 +3,9 @@ #include <glib-object.h> +#define TPL_GET_PRIV(obj,type) ((type##Priv *) ((type *) obj)->priv) +#define TPL_STR_EMPTY(x) ((x) == NULL || (x)[0] == '\0') + void _unref_object_if_not_null(void* data); void _ref_object_if_not_null(void* data); diff --git a/m4/.gitignore b/m4/.gitignore new file mode 100644 index 000000000..46125d52e --- /dev/null +++ b/m4/.gitignore @@ -0,0 +1,9 @@ +gtk-doc.m4 +intltool.m4 +gnome-doc-utils.m4 +libtool.m4 +ltoptions.m4 +ltsugar.m4 +ltversion.m4 +lt~obsolete.m4 + diff --git a/m4/as-compiler-flag.m4 b/m4/as-compiler-flag.m4 new file mode 100644 index 000000000..605708a5a --- /dev/null +++ b/m4/as-compiler-flag.m4 @@ -0,0 +1,33 @@ +dnl as-compiler-flag.m4 0.1.0 + +dnl autostars m4 macro for detection of compiler flags + +dnl David Schleef <ds@schleef.org> + +dnl $Id: as-compiler-flag.m4,v 1.1 2005/06/18 18:02:46 burgerman Exp $ + +dnl AS_COMPILER_FLAG(CFLAGS, ACTION-IF-ACCEPTED, [ACTION-IF-NOT-ACCEPTED]) +dnl Tries to compile with the given CFLAGS. +dnl Runs ACTION-IF-ACCEPTED if the compiler can compile with the flags, +dnl and ACTION-IF-NOT-ACCEPTED otherwise. + +AC_DEFUN([AS_COMPILER_FLAG], +[ + AC_MSG_CHECKING([to see if compiler understands $1]) + + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS $1" + + AC_TRY_COMPILE([ ], [], [flag_ok=yes], [flag_ok=no]) + CFLAGS="$save_CFLAGS" + + if test "X$flag_ok" = Xyes ; then + $2 + true + else + $3 + true + fi + AC_MSG_RESULT([$flag_ok]) +]) + diff --git a/m4/empathy-args.m4 b/m4/empathy-args.m4 new file mode 100644 index 000000000..3daacbaba --- /dev/null +++ b/m4/empathy-args.m4 @@ -0,0 +1,19 @@ +dnl configure-time options for Empathy + +dnl EMPATHY_ARG_VALGRIND + +AC_DEFUN([EMPATHY_ARG_VALGRIND], +[ + dnl valgrind inclusion + AC_ARG_ENABLE(valgrind, + AC_HELP_STRING([--enable-valgrind],[enable valgrind checking and run-time detection]), + [ + case "${enableval}" in + yes|no) enable="${enableval}" ;; + *) AC_MSG_ERROR(bad value ${enableval} for --enable-valgrind) ;; + esac + ], + [enable=no]) + + EMPATHY_VALGRIND($enable, [2.1]) +]) diff --git a/m4/empathy-valgrind.m4 b/m4/empathy-valgrind.m4 new file mode 100644 index 000000000..7a44e103f --- /dev/null +++ b/m4/empathy-valgrind.m4 @@ -0,0 +1,31 @@ +dnl Detect Valgrind location and flags + +AC_DEFUN([EMPATHY_VALGRIND], +[ + enable=$1 + if test -n "$2"; then + valgrind_req=$2 + else + valgrind_req="2.1" + fi + + PKG_CHECK_MODULES(VALGRIND, valgrind > "$valgrind_req", + have_valgrind_runtime="yes", have_valgrind_runtime="no") + + AC_PATH_PROG(VALGRIND_PATH, valgrind) + + # Compile the instrumentation for valgrind only if the valgrind + # libraries are installed and the valgrind executable is found + if test "x$enable" = xyes && + test "$have_valgrind_runtime" = yes && + test -n "$VALGRIND_PATH" ; + then + AC_DEFINE(HAVE_VALGRIND, 1, [Define if valgrind should be used]) + AC_MSG_NOTICE(using compile-time instrumentation for valgrind) + fi + + AC_SUBST(VALGRIND_CFLAGS) + AC_SUBST(VALGRIND_LIBS) + + AM_CONDITIONAL(HAVE_VALGRIND, test -n "$VALGRIND_PATH") +]) diff --git a/m4/python.m4 b/m4/python.m4 new file mode 100644 index 000000000..fe901562d --- /dev/null +++ b/m4/python.m4 @@ -0,0 +1,66 @@ +## this one is commonly used with AM_PATH_PYTHONDIR ... +dnl AM_CHECK_PYMOD(MODNAME [,SYMBOL [,ACTION-IF-FOUND [,ACTION-IF-NOT-FOUND]]]) +dnl Check if a module containing a given symbol is visible to python. +AC_DEFUN([AM_CHECK_PYMOD], +[AC_REQUIRE([AM_PATH_PYTHON]) +py_mod_var=`echo $1['_']$2 | sed 'y%./+-%__p_%'` +AC_MSG_CHECKING(for ifelse([$2],[],,[$2 in ])python module $1) +AC_CACHE_VAL(py_cv_mod_$py_mod_var, [ +ifelse([$2],[], [prog=" +import sys +try: + import $1 +except ImportError: + sys.exit(1) +except: + sys.exit(0) +sys.exit(0)"], [prog=" +import $1 +$1.$2"]) +if $PYTHON -c "$prog" 1>&AC_FD_CC 2>&AC_FD_CC + then + eval "py_cv_mod_$py_mod_var=yes" + else + eval "py_cv_mod_$py_mod_var=no" + fi +]) +py_val=`eval "echo \`echo '$py_cv_mod_'$py_mod_var\`"` +if test "x$py_val" != xno; then + AC_MSG_RESULT(yes) + ifelse([$3], [],, [$3 +])dnl +else + AC_MSG_RESULT(no) + ifelse([$4], [],, [$4 +])dnl +fi +]) + +dnl a macro to check for ability to create python extensions +dnl AM_CHECK_PYTHON_HEADERS([ACTION-IF-POSSIBLE], [ACTION-IF-NOT-POSSIBLE]) +dnl function also defines PYTHON_INCLUDES +AC_DEFUN([AM_CHECK_PYTHON_HEADERS], +[AC_REQUIRE([AM_PATH_PYTHON]) +AC_MSG_CHECKING(for headers required to compile python extensions) +dnl deduce PYTHON_INCLUDES +py_prefix=`$PYTHON -c "import sys; print sys.prefix"` +py_exec_prefix=`$PYTHON -c "import sys; print sys.exec_prefix"` +if test -x "$PYTHON-config"; then +PYTHON_INCLUDES=`$PYTHON-config --includes 2>/dev/null` +else +PYTHON_INCLUDES="-I${py_prefix}/include/python${PYTHON_VERSION}" +if test "$py_prefix" != "$py_exec_prefix"; then + PYTHON_INCLUDES="$PYTHON_INCLUDES -I${py_exec_prefix}/include/python${PYTHON_VERSION}" +fi +fi +AC_SUBST(PYTHON_INCLUDES) +dnl check if the headers exist: +save_CPPFLAGS="$CPPFLAGS" +CPPFLAGS="$CPPFLAGS $PYTHON_INCLUDES" +AC_TRY_CPP([#include <Python.h>],dnl +[AC_MSG_RESULT(found) +$1],dnl +[AC_MSG_RESULT(not found) +$2]) +CPPFLAGS="$save_CPPFLAGS" +]) diff --git a/m4/shave.m4 b/m4/shave.m4 new file mode 100644 index 000000000..0a3509e59 --- /dev/null +++ b/m4/shave.m4 @@ -0,0 +1,77 @@ +dnl Make automake/libtool output more friendly to humans +dnl Damien Lespiau <damien.lespiau@gmail.com> +dnl +dnl SHAVE_INIT([shavedir],[default_mode]) +dnl +dnl shavedir: the directory where the shave scripts are, it defaults to +dnl $(top_builddir) +dnl default_mode: (enable|disable) default shave mode. This parameter +dnl controls shave's behaviour when no option has been +dnl given to configure. It defaults to disable. +dnl +dnl * SHAVE_INIT should be called late in your configure.(ac|in) file (just +dnl before AC_CONFIG_FILE/AC_OUTPUT is perfect. This macro rewrites CC and +dnl LIBTOOL, you don't want the configure tests to have these variables +dnl re-defined. +dnl * This macro requires GNU make's -s option. + +AC_DEFUN([_SHAVE_ARG_ENABLE], +[ + AC_ARG_ENABLE([shave], + AS_HELP_STRING( + [--enable-shave], + [use shave to make the build pretty [[default=$1]]]),, + [enable_shave=$1] + ) +]) + +AC_DEFUN([SHAVE_INIT], +[ + dnl you can tweak the default value of enable_shave + m4_if([$2], [enable], [_SHAVE_ARG_ENABLE(yes)], [_SHAVE_ARG_ENABLE(no)]) + + if test x"$enable_shave" = xyes; then + dnl where can we find the shave scripts? + m4_if([$1],, + [shavedir="$ac_pwd"], + [shavedir="$ac_pwd/$1"]) + AC_SUBST(shavedir) + + dnl make is now quiet + AC_SUBST([MAKEFLAGS], [-s]) + AC_SUBST([AM_MAKEFLAGS], ['`test -z $V && echo -s`']) + + dnl we need sed + AC_CHECK_PROG(SED,sed,sed,false) + + dnl substitute libtool + SHAVE_SAVED_LIBTOOL=$LIBTOOL + LIBTOOL="${SHELL} ${shavedir}/shave-libtool '${SHAVE_SAVED_LIBTOOL}'" + AC_SUBST(LIBTOOL) + + dnl substitute cc/cxx + SHAVE_SAVED_CC=$CC + SHAVE_SAVED_CXX=$CXX + SHAVE_SAVED_FC=$FC + SHAVE_SAVED_F77=$F77 + SHAVE_SAVED_OBJC=$OBJC + CC="${SHELL} ${shavedir}/shave cc ${SHAVE_SAVED_CC}" + CXX="${SHELL} ${shavedir}/shave cxx ${SHAVE_SAVED_CXX}" + FC="${SHELL} ${shavedir}/shave fc ${SHAVE_SAVED_FC}" + F77="${SHELL} ${shavedir}/shave f77 ${SHAVE_SAVED_F77}" + OBJC="${SHELL} ${shavedir}/shave objc ${SHAVE_SAVED_OBJC}" + AC_SUBST(CC) + AC_SUBST(CXX) + AC_SUBST(FC) + AC_SUBST(F77) + AC_SUBST(OBJC) + + V=@ + else + V=1 + fi + Q='$(V:1=)' + AC_SUBST(V) + AC_SUBST(Q) +]) + diff --git a/po/Makefile.in.in b/po/Makefile.in.in new file mode 100644 index 000000000..402a25f7a --- /dev/null +++ b/po/Makefile.in.in @@ -0,0 +1,217 @@ +# Makefile for program source directory in GNU NLS utilities package. +# Copyright (C) 1995, 1996, 1997 by Ulrich Drepper <drepper@gnu.ai.mit.edu> +# Copyright (C) 2004-2008 Rodney Dawes <dobey.pwns@gmail.com> +# +# This file may be copied and used freely without restrictions. It may +# be used in projects which are not available under a GNU Public License, +# but which still want to provide support for the GNU gettext functionality. +# +# - Modified by Owen Taylor <otaylor@redhat.com> to use GETTEXT_PACKAGE +# instead of PACKAGE and to look for po2tbl in ./ not in intl/ +# +# - Modified by jacob berkman <jacob@ximian.com> to install +# Makefile.in.in and po2tbl.sed.in for use with glib-gettextize +# +# - Modified by Rodney Dawes <dobey.pwns@gmail.com> for use with intltool +# +# We have the following line for use by intltoolize: +# INTLTOOL_MAKEFILE + +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +PACKAGE = @PACKAGE@ +VERSION = @VERSION@ + +SHELL = @SHELL@ + +srcdir = @srcdir@ +top_srcdir = @top_srcdir@ +top_builddir = @top_builddir@ +VPATH = @srcdir@ + +prefix = @prefix@ +exec_prefix = @exec_prefix@ +datadir = @datadir@ +datarootdir = @datarootdir@ +libdir = @libdir@ +DATADIRNAME = @DATADIRNAME@ +itlocaledir = $(prefix)/$(DATADIRNAME)/locale +subdir = po +install_sh = @install_sh@ +# Automake >= 1.8 provides @mkdir_p@. +# Until it can be supposed, use the safe fallback: +mkdir_p = $(install_sh) -d + +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ + +GMSGFMT = @GMSGFMT@ +MSGFMT = @MSGFMT@ +XGETTEXT = @XGETTEXT@ +INTLTOOL_UPDATE = @INTLTOOL_UPDATE@ +INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@ +MSGMERGE = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --dist +GENPOT = INTLTOOL_EXTRACT=$(INTLTOOL_EXTRACT) srcdir=$(srcdir) $(INTLTOOL_UPDATE) --gettext-package $(GETTEXT_PACKAGE) --pot + +ALL_LINGUAS = @ALL_LINGUAS@ + +PO_LINGUAS=$(shell if test -r $(srcdir)/LINGUAS; then grep -v "^\#" $(srcdir)/LINGUAS; else echo "$(ALL_LINGUAS)"; fi) + +USER_LINGUAS=$(shell if test -n "$(LINGUAS)"; then LLINGUAS="$(LINGUAS)"; ALINGUAS="$(ALL_LINGUAS)"; for lang in $$LLINGUAS; do if test -n "`grep \^$$lang$$ $(srcdir)/LINGUAS 2>/dev/null`" -o -n "`echo $$ALINGUAS|tr ' ' '\n'|grep \^$$lang$$`"; then printf "$$lang "; fi; done; fi) + +USE_LINGUAS=$(shell if test -n "$(USER_LINGUAS)" -o -n "$(LINGUAS)"; then LLINGUAS="$(USER_LINGUAS)"; else if test -n "$(PO_LINGUAS)"; then LLINGUAS="$(PO_LINGUAS)"; else LLINGUAS="$(ALL_LINGUAS)"; fi; fi; for lang in $$LLINGUAS; do printf "$$lang "; done) + +POFILES=$(shell LINGUAS="$(PO_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.po "; done) + +DISTFILES = Makefile.in.in POTFILES.in $(POFILES) +EXTRA_DISTFILES = ChangeLog POTFILES.skip Makevars LINGUAS + +POTFILES = \ +# This comment gets stripped out + +CATALOGS=$(shell LINGUAS="$(USE_LINGUAS)"; for lang in $$LINGUAS; do printf "$$lang.gmo "; done) + +.SUFFIXES: +.SUFFIXES: .po .pox .gmo .mo .msg .cat + +.po.pox: + $(MAKE) $(GETTEXT_PACKAGE).pot + $(MSGMERGE) $< $(GETTEXT_PACKAGE).pot -o $*.pox + +.po.mo: + $(MSGFMT) -o $@ $< + +.po.gmo: + file=`echo $* | sed 's,.*/,,'`.gmo \ + && rm -f $$file && $(GMSGFMT) -o $$file $< + +.po.cat: + sed -f ../intl/po2msg.sed < $< > $*.msg \ + && rm -f $@ && gencat $@ $*.msg + + +all: all-@USE_NLS@ + +all-yes: $(CATALOGS) +all-no: + +$(GETTEXT_PACKAGE).pot: $(POTFILES) + $(GENPOT) + +install: install-data +install-data: install-data-@USE_NLS@ +install-data-no: all +install-data-yes: all + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + dir=$(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES; \ + $(mkdir_p) $$dir; \ + if test -r $$lang.gmo; then \ + $(INSTALL_DATA) $$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $$lang.gmo as $$dir/$(GETTEXT_PACKAGE).mo"; \ + else \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo $$dir/$(GETTEXT_PACKAGE).mo; \ + echo "installing $(srcdir)/$$lang.gmo as" \ + "$$dir/$(GETTEXT_PACKAGE).mo"; \ + fi; \ + if test -r $$lang.gmo.m; then \ + $(INSTALL_DATA) $$lang.gmo.m $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $$lang.gmo.m as $$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + if test -r $(srcdir)/$$lang.gmo.m ; then \ + $(INSTALL_DATA) $(srcdir)/$$lang.gmo.m \ + $$dir/$(GETTEXT_PACKAGE).mo.m; \ + echo "installing $(srcdir)/$$lang.gmo.m as" \ + "$$dir/$(GETTEXT_PACKAGE).mo.m"; \ + else \ + true; \ + fi; \ + fi; \ + done + +# Empty stubs to satisfy archaic automake needs +dvi info tags TAGS ID: + +# Define this as empty until I found a useful application. +install-exec installcheck: + +uninstall: + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo; \ + rm -f $(DESTDIR)$(itlocaledir)/$$lang/LC_MESSAGES/$(GETTEXT_PACKAGE).mo.m; \ + done + +check: all $(GETTEXT_PACKAGE).pot + rm -f missing notexist + srcdir=$(srcdir) $(INTLTOOL_UPDATE) -m + if [ -r missing -o -r notexist ]; then \ + exit 1; \ + fi + +mostlyclean: + rm -f *.pox $(GETTEXT_PACKAGE).pot *.old.po cat-id-tbl.tmp + rm -f .intltool-merge-cache + +clean: mostlyclean + +distclean: clean + rm -f Makefile Makefile.in POTFILES stamp-it + rm -f *.mo *.msg *.cat *.cat.m *.gmo + +maintainer-clean: distclean + @echo "This command is intended for maintainers to use;" + @echo "it deletes files that may require special tools to rebuild." + rm -f Makefile.in.in + +distdir = ../$(PACKAGE)-$(VERSION)/$(subdir) +dist distdir: $(DISTFILES) + dists="$(DISTFILES)"; \ + extra_dists="$(EXTRA_DISTFILES)"; \ + for file in $$extra_dists; do \ + test -f $(srcdir)/$$file && dists="$$dists $(srcdir)/$$file"; \ + done; \ + for file in $$dists; do \ + test -f $$file || file="$(srcdir)/$$file"; \ + ln $$file $(distdir) 2> /dev/null \ + || cp -p $$file $(distdir); \ + done + +update-po: Makefile + $(MAKE) $(GETTEXT_PACKAGE).pot + tmpdir=`pwd`; \ + linguas="$(USE_LINGUAS)"; \ + for lang in $$linguas; do \ + echo "$$lang:"; \ + result="`$(MSGMERGE) -o $$tmpdir/$$lang.new.po $$lang`"; \ + if $$result; then \ + if cmp $(srcdir)/$$lang.po $$tmpdir/$$lang.new.po >/dev/null 2>&1; then \ + rm -f $$tmpdir/$$lang.new.po; \ + else \ + if mv -f $$tmpdir/$$lang.new.po $$lang.po; then \ + :; \ + else \ + echo "msgmerge for $$lang.po failed: cannot move $$tmpdir/$$lang.new.po to $$lang.po" 1>&2; \ + rm -f $$tmpdir/$$lang.new.po; \ + exit 1; \ + fi; \ + fi; \ + else \ + echo "msgmerge for $$lang.gmo failed!"; \ + rm -f $$tmpdir/$$lang.new.po; \ + fi; \ + done + +Makefile POTFILES: stamp-it + @if test ! -f $@; then \ + rm -f stamp-it; \ + $(MAKE) stamp-it; \ + fi + +stamp-it: Makefile.in.in $(top_builddir)/config.status POTFILES.in + cd $(top_builddir) \ + && CONFIG_FILES=$(subdir)/Makefile.in CONFIG_HEADERS= CONFIG_LINKS= \ + $(SHELL) ./config.status + +# Tell versions [3.59,3.63) of GNU make not to export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/shave-libtool.in b/shave-libtool.in new file mode 100644 index 000000000..1f3a720c1 --- /dev/null +++ b/shave-libtool.in @@ -0,0 +1,69 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the real libtool to use +LIBTOOL="$1" +shift + +# if 1, don't print anything, the underlaying wrapper will do it +pass_though=0 + +# scan the arguments, keep the right ones for libtool, and discover the mode +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + preserved_args="$preserved_args $opt" + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +case "$mode" in +compile) + # shave will be called and print the actual CC/CXX/LINK line + preserved_args="$preserved_args --shave-mode=$mode" + pass_though=1 + ;; +link) + preserved_args="$preserved_args --shave-mode=$mode" + Q=" LINK " + ;; +*) + # let's u + # echo "*** libtool: Unimplemented mode: $mode, fill a bug report" + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_though -eq 0; then + echo "$Q$output" + fi + $LIBTOOL --silent $preserved_args +else + echo $LIBTOOL $preserved_args + $LIBTOOL $preserved_args +fi diff --git a/shave.in b/shave.in new file mode 100644 index 000000000..5c16f27ae --- /dev/null +++ b/shave.in @@ -0,0 +1,79 @@ +#!/bin/sh + +# we need sed +SED=@SED@ +if test -z "$SED" ; then +SED=sed +fi + +lt_unmangle () +{ + last_result=`echo $1 | $SED -e 's#.libs/##' -e 's#[0-9a-zA-Z_\-\.]*_la-##'` +} + +# the tool to wrap (cc, cxx, ar, ranlib, ..) +tool="$1" +shift + +# the reel tool (to call) +REEL_TOOL="$1" +shift + +pass_through=0 +preserved_args= +while test "$#" -gt 0; do + opt="$1" + shift + + case $opt in + --shave-mode=*) + mode=`echo $opt | $SED -e 's/[-_a-zA-Z0-9]*=//'` + ;; + -o) + lt_output="$1" + preserved_args="$preserved_args $opt" + ;; + *) + preserved_args="$preserved_args $opt" + ;; + esac +done + +# mode=link is handled in the libtool wrapper +case "$mode,$tool" in +link,*) + pass_through=1 + ;; +*,cxx) + Q=" CXX " + ;; +*,cc) + Q=" CC " + ;; +*,fc) + Q=" FC " + ;; +*,f77) + Q=" F77 " + ;; +*,objc) + Q=" OBJC " + ;; +*,*) + # should not happen + Q=" CC " + ;; +esac + +lt_unmangle "$lt_output" +output=$last_result + +if test -z $V; then + if test $pass_through -eq 0; then + echo "$Q$output" + fi + $REEL_TOOL $preserved_args +else + echo $REEL_TOOL $preserved_args + $REEL_TOOL $preserved_args +fi diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 000000000..656406185 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,108 @@ +include $(top_srcdir)/tools/shave.mk +include $(top_srcdir)/tools/flymake.mk + +AM_CPPFLAGS = \ + $(ERROR_CFLAGS) \ + -I$(top_srcdir) \ + -I$(top_srcdir)/include \ + -DG_LOG_DOMAIN=\"tpl\" \ + $(TPL_CFLAGS) \ + $(LIBTPL_CFLAGS) \ + $(DISABLE_DEPRECATED) \ + $(WARN_CFLAGS) + +LDADD = \ + $(TPL_LIBS) \ + $(LIBTPL_LIBS) +# $(top_builddir)/libempathy-gtk/libempathy-gtk.la \ +# $(top_builddir)/libempathy/libempathy.la \ +# $(top_builddir)/extensions/libemp-extensions.la \ +# $(LIBNOTIFY_LIBS) \ +# $(LIBCHAMPLAIN_LIBS) \ +# $(WEBKIT_LIBS) + +bin_PROGRAMS = \ + telepathy-logger + +BUILT_SOURCES= +# empathy-tube-dispatch-enumtypes.h \ +# empathy-tube-dispatch-enumtypes.c + +telepathy_logger_handwritten_source = \ + test.c \ + tpl_channel_data.c \ + tpl_contact.c \ + tpl_headless_logger_init.c \ + tpl_log_entry_text.c \ + tpl_observer.c \ + tpl_text_channel_data.c \ + tpl-time.c \ + tpl_utils.c \ + tpl-log-manager.c \ + tpl-log-store.c \ + tpl-log-store-empathy.c + +telepathy_logger_SOURCES = \ + $(telepathy_logger_handwritten_source) + +nodist_telepathy_logger_SOURCES = $(BUILT_SOURCES) + +check_c_sources = \ + $(telepathy_logger_handwritten_source) \ + $(telepathy_logger_logs_SOURCES) +include $(top_srcdir)/tools/check-coding-style.mk +check-local: check-coding-style + +#DISABLED#uidir = $(datadir)/telepathy-logger +#DISABLED#ui_DATA = \ +#DISABLED# empathy-accounts-dialog.ui \ +#DISABLED# empathy-call-window-fullscreen.ui \ +#DISABLED# empathy-call-window.ui \ +#DISABLED# empathy-chat-window.ui \ +#DISABLED# empathy-chatrooms-window.ui \ +#DISABLED# empathy-ft-manager.ui \ +#DISABLED# empathy-import-dialog.ui \ +#DISABLED# empathy-main-window.ui \ +#DISABLED# empathy-new-chatroom-dialog.ui \ +#DISABLED# empathy-preferences.ui \ +#DISABLED# empathy-status-icon.ui + +EXTRA_DIST = \ + $(autostart_DATA) \ + $(ui_DATA) + +#DISABLED#if HAVE_LIBCHAMPLAIN +#DISABLED#empathy_handwritten_source += \ +#DISABLED# empathy-map-view.c \ +#DISABLED# empathy-map-view.h +#DISABLED# +#DISABLED#ui_DATA += \ +#DISABLED# empathy-map-view.ui +#DISABLED#else +#DISABLED#EXTRA_DIST += \ +#DISABLED# empathy-map-view.c \ +#DISABLED# empathy-map-view.h \ +#DISABLED# empathy-map-view.ui +#DISABLED#endif + +dist_man_MANS = + +# rules for making the glib enum objects +%-enumtypes.h: %.h Makefile.in + $(QUIET_GEN)glib-mkenums \ + --fhead "#ifndef __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n#define __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__\n\n#include <glib-object.h>\n\nG_BEGIN_DECLS\n" \ + --fprod "/* enumerations from \"@filename@\" */\n" \ + --vhead "GType @enum_name@_get_type (void);\n#define $(shell echo $* | tr [:lower:]- [:upper:]_ | sed 's/_.*//')_TYPE_@ENUMSHORT@ (@enum_name@_get_type())\n" \ + --ftail "G_END_DECLS\n\n#endif /* __$(shell echo $* | tr [:lower:]- [:upper:]_)_ENUM_TYPES_H__ */" \ + $< > $@ + +%-enumtypes.c: %.h Makefile.in + $(QUIET_GEN)glib-mkenums \ + --fhead "#include <$*.h>\n#include <$*-enumtypes.h>" \ + --fprod "\n/* enumerations from \"@filename@\" */" \ + --vhead "GType\n@enum_name@_get_type (void)\n{\n static GType etype = 0;\n if (etype == 0) {\n static const G@Type@Value values[] = {" \ + --vprod " { @VALUENAME@, \"@VALUENAME@\", \"@VALUENAME@\" }," \ + --vtail " { 0, NULL, NULL }\n };\n etype = g_@type@_register_static (\"@EnumName@\", values);\n }\n return etype;\n}\n" \ + $< > $@ + +CLEANFILES = $(BUILT_SOURCES) diff --git a/src/compile.sh b/src/compile.sh index 53062d29a..27548cb29 100755 --- a/src/compile.sh +++ b/src/compile.sh @@ -2,17 +2,19 @@ PACKAGE_NAME="TpLogger" CC=${CC:-gcc} -CCOPTS="-DPACKAGE_NAME=\"${PACKAGE_NAME}\" --std=c99 -g -I/usr/include/libempathy -I../include -Wall -Werror" # -pedantic" -PKGS="telepathy-glib libempathy" +CCOPTS="-D__USE_POSIX -DPACKAGE_NAME=\"${PACKAGE_NAME}\" --std=c99 -g -I../include -Wall -Werror" # -pedantic" +PKGS="telepathy-glib libxml-2.0" MODULES="tpl_observer.c tpl_headless_logger_init.c tpl_channel_data.c tpl_text_channel_data.c tpl_contact.c tpl_utils.c - logstore/tpl-log-store.c - logstore/tpl-log-store-empathy.c + tpl-time.c + tpl-log-manager.c + tpl-log-store.c + tpl-log-store-empathy.c tpl_log_entry_text.c test.c" -EXECUTABLE="test" +EXECUTABLE="telepathy-logger" ${CC} ${CCOPTS} $(pkg-config --libs --cflags ${PKGS}) ${MODULES} \ diff --git a/src/logstore/empathy-log-manager.xsl b/src/empathy-log-manager.xsl index a934f3ab3..a934f3ab3 100644 --- a/src/logstore/empathy-log-manager.xsl +++ b/src/empathy-log-manager.xsl diff --git a/src/logstore/empathy-log-manager.c b/src/tpl-log-manager.c index 07ea521b5..642733a62 100644 --- a/src/logstore/empathy-log-manager.c +++ b/src/tpl-log-manager.c @@ -34,26 +34,29 @@ #include <tpl-log-manager.h> #include <tpl-log-store-empathy.h> #include <tpl-log-store.h> -#include <empathy-tp-chat.h> -#include <empathy-utils.h> +#include <tpl_utils.h> +#include <tpl-time.h> +//#include <empathy-tp-chat.h> -#define DEBUG_FLAG EMPATHY_DEBUG_OTHER -#include <empathy-debug.h> +//#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +//#include <empathy-debug.h> -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, EmpathyLogManager) +#define DEBUG g_debug + +#define GET_PRIV(obj) TPL_GET_PRIV (obj, TplLogManager) typedef struct { GList *stores; -} EmpathyLogManagerPriv; +} TplLogManagerPriv; -G_DEFINE_TYPE (EmpathyLogManager, empathy_log_manager, G_TYPE_OBJECT); +G_DEFINE_TYPE (TplLogManager, tpl_log_manager, G_TYPE_OBJECT); -static EmpathyLogManager * manager_singleton = NULL; +static TplLogManager * manager_singleton = NULL; static void log_manager_finalize (GObject *object) { - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; priv = GET_PRIV (object); @@ -67,7 +70,7 @@ log_manager_constructor (GType type, GObjectConstructParam *props) { GObject *retval; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; if (manager_singleton) { @@ -75,75 +78,75 @@ log_manager_constructor (GType type, } else { - retval = G_OBJECT_CLASS (empathy_log_manager_parent_class)->constructor + retval = G_OBJECT_CLASS (tpl_log_manager_parent_class)->constructor (type, n_props, props); - manager_singleton = EMPATHY_LOG_MANAGER (retval); + manager_singleton = TPL_LOG_MANAGER (retval); g_object_add_weak_pointer (retval, (gpointer *) &manager_singleton); priv = GET_PRIV (manager_singleton); priv->stores = g_list_append (priv->stores, - g_object_new (EMPATHY_TYPE_LOG_STORE_EMPATHY, NULL)); + g_object_new (TPL_TYPE_LOG_STORE_EMPATHY, NULL)); } return retval; } static void -empathy_log_manager_class_init (EmpathyLogManagerClass *klass) +tpl_log_manager_class_init (TplLogManagerClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); object_class->constructor = log_manager_constructor; object_class->finalize = log_manager_finalize; - g_type_class_add_private (object_class, sizeof (EmpathyLogManagerPriv)); + g_type_class_add_private (object_class, sizeof (TplLogManagerPriv)); } static void -empathy_log_manager_init (EmpathyLogManager *manager) +tpl_log_manager_init (TplLogManager *manager) { - EmpathyLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, - EMPATHY_TYPE_LOG_MANAGER, EmpathyLogManagerPriv); + TplLogManagerPriv *priv = G_TYPE_INSTANCE_GET_PRIVATE (manager, + TPL_TYPE_LOG_MANAGER, TplLogManagerPriv); manager->priv = priv; } -EmpathyLogManager * -empathy_log_manager_dup_singleton (void) +TplLogManager * +tpl_log_manager_dup_singleton (void) { - return g_object_new (EMPATHY_TYPE_LOG_MANAGER, NULL); + return g_object_new (TPL_TYPE_LOG_MANAGER, NULL); } gboolean -empathy_log_manager_add_message (EmpathyLogManager *manager, +tpl_log_manager_add_message (TplLogManager *manager, const gchar *chat_id, gboolean chatroom, - EmpathyMessage *message, + TplLogEntryText *message, GError **error) { - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; GList *l; gboolean out = FALSE; gboolean found = FALSE; /* TODO: When multiple log stores appear with add_message implementations * make this customisable. */ - const gchar *add_store = "Empathy"; + const gchar *add_store = "TpLogger"; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), FALSE); g_return_val_if_fail (chat_id != NULL, FALSE); - g_return_val_if_fail (EMPATHY_IS_MESSAGE (message), FALSE); + g_return_val_if_fail (TPL_IS_LOG_ENTRY_TEXT (message), FALSE); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - if (!tp_strdiff (empathy_log_store_get_name ( - EMPATHY_LOG_STORE (l->data)), add_store)) + if (!tp_strdiff (tpl_log_store_get_name ( + TPL_LOG_STORE (l->data)), add_store)) { - out = empathy_log_store_add_message (EMPATHY_LOG_STORE (l->data), + out = tpl_log_store_add_message (TPL_LOG_STORE (l->data), chat_id, chatroom, message, error); found = TRUE; break; @@ -157,22 +160,22 @@ empathy_log_manager_add_message (EmpathyLogManager *manager, } gboolean -empathy_log_manager_exists (EmpathyLogManager *manager, +tpl_log_manager_exists (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom) { GList *l; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), FALSE); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), FALSE); g_return_val_if_fail (chat_id != NULL, FALSE); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - if (empathy_log_store_exists (EMPATHY_LOG_STORE (l->data), + if (tpl_log_store_exists (TPL_LOG_STORE (l->data), account, chat_id, chatroom)) return TRUE; } @@ -181,27 +184,27 @@ empathy_log_manager_exists (EmpathyLogManager *manager, } GList * -empathy_log_manager_get_dates (EmpathyLogManager *manager, +tpl_log_manager_get_dates (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom) { GList *l, *out = NULL; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL); g_return_val_if_fail (chat_id != NULL, NULL); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data); + TplLogStore *store = TPL_LOG_STORE (l->data); GList *new; /* Insert dates of each store in the out list. Keep the out list sorted * and avoid to insert dups. */ - new = empathy_log_store_get_dates (store, account, chat_id, chatroom); + new = tpl_log_store_get_dates (store, account, chat_id, chatroom); while (new) { if (g_list_find_custom (out, new->data, (GCompareFunc) strcmp)) @@ -217,25 +220,25 @@ empathy_log_manager_get_dates (EmpathyLogManager *manager, } GList * -empathy_log_manager_get_messages_for_date (EmpathyLogManager *manager, +tpl_log_manager_get_messages_for_date (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom, const gchar *date) { GList *l, *out = NULL; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL); g_return_val_if_fail (chat_id != NULL, NULL); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data); + TplLogStore *store = TPL_LOG_STORE (l->data); - out = g_list_concat (out, empathy_log_store_get_messages_for_date ( + out = g_list_concat (out, tpl_log_store_get_messages_for_date ( store, account, chat_id, chatroom, date)); } @@ -246,32 +249,32 @@ static gint log_manager_message_date_cmp (gconstpointer a, gconstpointer b) { - EmpathyMessage *one = (EmpathyMessage *) a; - EmpathyMessage *two = (EmpathyMessage *) b; + TplLogEntryText *one = (TplLogEntryText *) a; + TplLogEntryText *two = (TplLogEntryText *) b; time_t one_time, two_time; - one_time = empathy_message_get_timestamp (one); - two_time = empathy_message_get_timestamp (two); + one_time = tpl_log_entry_text_get_timestamp (one); + two_time = tpl_log_entry_text_get_timestamp (two); /* Return -1 of message1 is older than message2 */ return one_time < two_time ? -1 : one_time - two_time; } GList * -empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager, +tpl_log_manager_get_filtered_messages (TplLogManager *manager, TpAccount *account, const gchar *chat_id, gboolean chatroom, guint num_messages, - EmpathyLogMessageFilter filter, + TplLogMessageFilter filter, gpointer user_data) { - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; GList *out = NULL; GList *l; guint i = 0; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL); g_return_val_if_fail (chat_id != NULL, NULL); priv = GET_PRIV (manager); @@ -280,10 +283,10 @@ empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager, * newest ones in the out list. Keep that list sorted: Older first. */ for (l = priv->stores; l; l = g_list_next (l)) { - EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data); + TplLogStore *store = TPL_LOG_STORE (l->data); GList *new; - new = empathy_log_store_get_filtered_messages (store, account, chat_id, + new = tpl_log_store_get_filtered_messages (store, account, chat_id, chatroom, num_messages, filter, user_data); while (new) { @@ -318,52 +321,52 @@ empathy_log_manager_get_filtered_messages (EmpathyLogManager *manager, } GList * -empathy_log_manager_get_chats (EmpathyLogManager *manager, +tpl_log_manager_get_chats (TplLogManager *manager, TpAccount *account) { GList *l, *out = NULL; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data); + TplLogStore *store = TPL_LOG_STORE (l->data); out = g_list_concat (out, - empathy_log_store_get_chats (store, account)); + tpl_log_store_get_chats (store, account)); } return out; } GList * -empathy_log_manager_search_new (EmpathyLogManager *manager, +tpl_log_manager_search_new (TplLogManager *manager, const gchar *text) { GList *l, *out = NULL; - EmpathyLogManagerPriv *priv; + TplLogManagerPriv *priv; - g_return_val_if_fail (EMPATHY_IS_LOG_MANAGER (manager), NULL); - g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL); + g_return_val_if_fail (TPL_IS_LOG_MANAGER (manager), NULL); + g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL); priv = GET_PRIV (manager); for (l = priv->stores; l; l = g_list_next (l)) { - EmpathyLogStore *store = EMPATHY_LOG_STORE (l->data); + TplLogStore *store = TPL_LOG_STORE (l->data); out = g_list_concat (out, - empathy_log_store_search_new (store, text)); + tpl_log_store_search_new (store, text)); } return out; } void -empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit) +tpl_log_manager_search_hit_free (TplLogSearchHit *hit) { if (hit->account != NULL) g_object_unref (hit->account); @@ -372,17 +375,17 @@ empathy_log_manager_search_hit_free (EmpathyLogSearchHit *hit) g_free (hit->filename); g_free (hit->chat_id); - g_slice_free (EmpathyLogSearchHit, hit); + g_slice_free (TplLogSearchHit, hit); } void -empathy_log_manager_search_free (GList *hits) +tpl_log_manager_search_free (GList *hits) { GList *l; for (l = hits; l; l = g_list_next (l)) { - empathy_log_manager_search_hit_free (l->data); + tpl_log_manager_search_hit_free (l->data); } g_list_free (hits); @@ -390,19 +393,20 @@ empathy_log_manager_search_free (GList *hits) /* Format is just date, 20061201. */ gchar * -empathy_log_manager_get_date_readable (const gchar *date) +tpl_log_manager_get_date_readable (const gchar *date) { time_t t; - t = empathy_time_parse (date); + t = tpl_time_parse (date); - return empathy_time_to_string_local (t, "%a %d %b %Y"); + return tpl_time_to_string_local (t, "%a %d %b %Y"); } +/* TPL: useless TODO remove static void log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat, - EmpathyMessage *message, - EmpathyLogManager *log_manager) + TplLogEntryText *message, + TplLogManager *log_manager) { GError *error = NULL; TpHandleType handle_type; @@ -411,7 +415,7 @@ log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat, channel = empathy_tp_chat_get_channel (tp_chat); tp_channel_get_handle (channel, &handle_type); - if (!empathy_log_manager_add_message (log_manager, + if (!tpl_log_manager_add_message (log_manager, tp_channel_get_identifier (channel), handle_type == TP_HANDLE_TYPE_ROOM, message, &error)) @@ -423,11 +427,13 @@ log_manager_chat_received_message_cb (EmpathyTpChat *tp_chat, g_error_free (error); } } +*/ +/* TPL: useless TODO remove static void log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher, EmpathyDispatchOperation *operation, - EmpathyLogManager *log_manager) + TplLogManager *log_manager) { GQuark channel_type; @@ -444,12 +450,13 @@ log_manager_dispatcher_observe_cb (EmpathyDispatcher *dispatcher, G_CALLBACK (log_manager_chat_received_message_cb), log_manager); } } - - +*/ +/* void -empathy_log_manager_observe (EmpathyLogManager *log_manager, +tpl_log_manager_observe (TplLogManager *log_manager, EmpathyDispatcher *dispatcher) { g_signal_connect (dispatcher, "observe", G_CALLBACK (log_manager_dispatcher_observe_cb), log_manager); } +*/ diff --git a/src/logstore/tpl-log-store-empathy.c b/src/tpl-log-store-empathy.c index 0409cfb37..4fde4ffe8 100644 --- a/src/logstore/tpl-log-store-empathy.c +++ b/src/tpl-log-store-empathy.c @@ -29,6 +29,9 @@ #include <stdlib.h> #include <glib/gstdio.h> +#include <libxml/parser.h> +#include <libxml/tree.h> + #include <glib-object.h> #include <telepathy-glib/account-manager.h> @@ -39,15 +42,15 @@ #include <tpl-log-store.h> #include <tpl-log-store-empathy.h> #include <tpl-log-manager.h> -#include <empathy-contact.h> -#include <empathy-time.h> -#include <empathy-utils.h> +#include <tpl-time.h> #include <tpl_log_entry_text.h> #include <tpl_contact.h> -#define DEBUG_FLAG EMPATHY_DEBUG_OTHER -#include <empathy-debug.h> +//#define DEBUG_FLAG EMPATHY_DEBUG_OTHER +//#include <empathy-debug.h> + +#define DEBUG g_debug #define LOG_DIR_CREATE_MODE (S_IRUSR | S_IWUSR | S_IXUSR) #define LOG_FILE_CREATE_MODE (S_IRUSR | S_IWUSR) @@ -64,7 +67,7 @@ "</log>\n" -#define GET_PRIV(obj) EMPATHY_GET_PRIV (obj, TplLogStoreEmpathy) +#define GET_PRIV(obj) TPL_GET_PRIV (obj, TplLogStoreEmpathy) typedef struct { gchar *basedir; @@ -108,8 +111,10 @@ tpl_log_store_empathy_init (TplLogStoreEmpathy *self) self->priv = priv; priv->basedir = g_build_path (G_DIR_SEPARATOR_S, g_get_user_data_dir (), - PACKAGE_NAME, "logs", NULL); + "TpLogger", "logs", NULL); + // TODO update to a more meaningful name when more than one LogStore + // implementation will exist, like TpXMLLogger and TPSQLiteLogger priv->name = g_strdup ("TpLogger"); priv->account_manager = tp_account_manager_dup (); } @@ -160,8 +165,8 @@ log_store_empathy_get_timestamp_filename (void) gchar *time_str; gchar *filename; - t = empathy_time_get_current (); - time_str = empathy_time_to_string_local (t, LOG_TIME_FORMAT); + t = tpl_time_get_current (); + time_str = tpl_time_to_string_local (t, LOG_TIME_FORMAT); filename = g_strconcat (time_str, LOG_FILENAME_SUFFIX, NULL); g_free (time_str); @@ -177,7 +182,7 @@ log_store_empathy_get_timestamp_from_message (TplLogEntryText *message) t = tpl_log_entry_text_get_timestamp (message); /* We keep the timestamps in the messages as UTC. */ - return empathy_time_to_string_utc (t, LOG_TIME_FORMAT_FULL); + return tpl_time_to_string_utc (t, LOG_TIME_FORMAT_FULL); } static gchar * @@ -232,8 +237,7 @@ log_store_empathy_add_message (TplLogStore *self, body_str = tpl_log_entry_text_get_message (message); msg_type = tpl_log_entry_text_get_message_type (message); - - if (EMP_STR_EMPTY (body_str)) + if (TPL_STR_EMPTY (body_str)) return FALSE; filename = log_store_empathy_get_filename (self, account, chat_id, chatroom); @@ -386,12 +390,12 @@ log_store_empathy_get_filename_for_date (TplLogStore *self, return filename; } -static EmpathyLogSearchHit * +static TplLogSearchHit * log_store_empathy_search_hit_new (TplLogStore *self, const gchar *filename) { TplLogStoreEmpathyPriv *priv = GET_PRIV (self); - EmpathyLogSearchHit *hit; + TplLogSearchHit *hit; gchar *account_name; const gchar *end; gchar **strv; @@ -404,7 +408,7 @@ log_store_empathy_search_hit_new (TplLogStore *self, strv = g_strsplit (filename, G_DIR_SEPARATOR_S, -1); len = g_strv_length (strv); - hit = g_slice_new0 (EmpathyLogSearchHit); + hit = g_slice_new0 (TplLogSearchHit); end = strstr (strv[len-1], LOG_FILENAME_SUFFIX); hit->date = g_strndup (strv[len-1], end - strv[len-1]); @@ -495,7 +499,7 @@ log_store_empathy_get_messages_for_file (TplLogStore *self, time_t t; gchar *sender_id; gchar *sender_name; - gchar *sender_avatar_token; + //gchar *sender_avatar_token; gchar *body; gchar *is_user_str; gboolean is_user = FALSE; @@ -511,8 +515,10 @@ log_store_empathy_get_messages_for_file (TplLogStore *self, time_ = (gchar *) xmlGetProp (node, (const xmlChar *) "time"); sender_id = (gchar *) xmlGetProp (node, (const xmlChar *) "id"); sender_name = (gchar *) xmlGetProp (node, (const xmlChar *) "name"); + /* sender_avatar_token = (gchar *) xmlGetProp (node, (const xmlChar *) "token"); + */ is_user_str = (gchar *) xmlGetProp (node, (const xmlChar *) "isuser"); msg_type_str = (gchar *) xmlGetProp (node, (const xmlChar *) "type"); cm_id_str = (gchar *) xmlGetProp (node, (const xmlChar *) "cm_id"); @@ -521,12 +527,12 @@ log_store_empathy_get_messages_for_file (TplLogStore *self, is_user = strcmp (is_user_str, "true") == 0; if (msg_type_str) - msg_type = empathy_message_type_from_str (msg_type_str); + msg_type = tpl_log_entry_text_message_type_from_str (msg_type_str); if (cm_id_str) cm_id = atoi (cm_id_str); - t = empathy_time_parse (time_); + t = tpl_time_parse (time_); //TODO remove me //sender = empathy_contact_new_for_log (account, sender_id, sender_name, // is_user); @@ -536,7 +542,7 @@ log_store_empathy_get_messages_for_file (TplLogStore *self, tpl_contact_set_alias(sender, sender_name); /* TODO remove avatar code - if (!EMP_STR_EMPTY (sender_avatar_token)) + if (!TPL_STR_EMPTY (sender_avatar_token)) empathy_contact_load_avatar_cache (sender, sender_avatar_token); */ @@ -562,7 +568,7 @@ log_store_empathy_get_messages_for_file (TplLogStore *self, xmlFree (is_user_str); xmlFree (msg_type_str); xmlFree (cm_id_str); - xmlFree (sender_avatar_token); + //xmlFree (sender_avatar_token); } DEBUG ("Parsed %d messages", g_list_length (messages)); @@ -626,7 +632,7 @@ log_store_empathy_search_new (TplLogStore *self, gchar *text_casefold; g_return_val_if_fail (TPL_IS_LOG_STORE (self), NULL); - g_return_val_if_fail (!EMP_STR_EMPTY (text), NULL); + g_return_val_if_fail (!TPL_STR_EMPTY (text), NULL); text_casefold = g_utf8_casefold (text, -1); @@ -655,7 +661,7 @@ log_store_empathy_search_new (TplLogStore *self, if (strstr (contents_casefold, text_casefold)) { - EmpathyLogSearchHit *hit; + TplLogSearchHit *hit; hit = log_store_empathy_search_hit_new (self, filename); @@ -697,7 +703,7 @@ log_store_empathy_get_chats_for_dir (TplLogStore *self, while ((name = g_dir_read_name (gdir)) != NULL) { - EmpathyLogSearchHit *hit; + TplLogSearchHit *hit; if (!is_chatroom && strcmp (name, LOG_DIR_CHATROOMS) == 0) { @@ -707,7 +713,7 @@ log_store_empathy_get_chats_for_dir (TplLogStore *self, g_free (filename); continue; } - hit = g_slice_new0 (EmpathyLogSearchHit); + hit = g_slice_new0 (TplLogSearchHit); hit->chat_id = g_strdup (name); hit->is_chatroom = is_chatroom; @@ -776,7 +782,7 @@ log_store_empathy_get_filtered_messages (TplLogStore *self, const gchar *chat_id, gboolean chatroom, guint num_messages, - EmpathyLogMessageFilter filter, + TplLogMessageFilter filter, gpointer user_data) { GList *dates, *l, *messages = NULL; diff --git a/src/logstore/tpl-log-store.c b/src/tpl-log-store.c index 0e439d469..d9d62cc52 100644 --- a/src/logstore/tpl-log-store.c +++ b/src/tpl-log-store.c @@ -161,7 +161,7 @@ tpl_log_store_get_filtered_messages (TplLogStore *self, const gchar *chat_id, gboolean chatroom, guint num_messages, - EmpathyLogMessageFilter filter, + TplLogMessageFilter filter, gpointer user_data) { diff --git a/src/tpl-time.c b/src/tpl-time.c new file mode 100644 index 000000000..e35c6c843 --- /dev/null +++ b/src/tpl-time.c @@ -0,0 +1,170 @@ +/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */ +/* + * Copyright (C) 2003-2007 Imendio AB + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program 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 + * General Public License for more details. + * + * You should have received a copy of the GNU General Public + * License along with this program; if not, write to the + * Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, + * Boston, MA 02110-1301 USA + * + * Authors: Richard Hult <richard@imendio.com> + */ + +#include <time.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <glib/gi18n.h> + +#include <tpl-time.h> + +/* Note: TplTime is always in UTC. */ + +time_t +tpl_time_get_current (void) +{ + return time (NULL); +} + +time_t +tpl_time_get_local_time (struct tm *tm) +{ + const gchar *tz; + time_t t; + + tz = g_getenv ("TZ"); + g_setenv ("TZ", "", TRUE); + + //TODO reenable + //tzset (); + + t = mktime (tm); + + if (tz) { + g_setenv ("TZ", tz, TRUE); + } else { + g_unsetenv ("TZ"); + } + + //TODO reenable + //tzset (); + + return t; +} + +/* The format is: "20021209T23:51:30" and is in UTC. 0 is returned on + * failure. The alternative format "20021209" is also accepted. + */ +time_t +tpl_time_parse (const gchar *str) +{ + struct tm tm; + gint year, month; + gint n_parsed; + + memset (&tm, 0, sizeof (struct tm)); + + n_parsed = sscanf (str, "%4d%2d%2dT%2d:%2d:%2d", + &year, &month, &tm.tm_mday, &tm.tm_hour, + &tm.tm_min, &tm.tm_sec); + if (n_parsed != 3 && n_parsed != 6) { + return 0; + } + + tm.tm_year = year - 1900; + tm.tm_mon = month - 1; + tm.tm_isdst = -1; + + return tpl_time_get_local_time (&tm); +} + +/* Converts the UTC timestamp to a string, also in UTC. Returns NULL on failure. */ +gchar * +tpl_time_to_string_utc (time_t t, + const gchar *format) +{ + gchar stamp[128]; + struct tm *tm; + + g_return_val_if_fail (format != NULL, NULL); + + tm = gmtime (&t); + if (strftime (stamp, sizeof (stamp), format, tm) == 0) { + return NULL; + } + + return g_strdup (stamp); +} + +/* Converts the UTC timestamp to a string, in local time. Returns NULL on failure. */ +gchar * +tpl_time_to_string_local (time_t t, + const gchar *format) +{ + gchar stamp[128]; + struct tm *tm; + + g_return_val_if_fail (format != NULL, NULL); + + tm = localtime (&t); + if (strftime (stamp, sizeof (stamp), format, tm) == 0) { + return NULL; + } + + return g_strdup (stamp); +} + +gchar * +tpl_time_to_string_relative (time_t then) +{ + time_t now; + gint seconds; + + now = time (NULL); + seconds = now - then; + + if (seconds > 0) { + if (seconds < 60) { + return g_strdup_printf (ngettext ("%d second ago", + "%d seconds ago", seconds), seconds); + } + else if (seconds < (60 * 60)) { + seconds /= 60; + return g_strdup_printf (ngettext ("%d minute ago", + "%d minutes ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24)) { + seconds /= 60 * 60; + return g_strdup_printf (ngettext ("%d hour ago", + "%d hours ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24 * 7)) { + seconds /= 60 * 60 * 24; + return g_strdup_printf (ngettext ("%d day ago", + "%d days ago", seconds), seconds); + } + else if (seconds < (60 * 60 * 24 * 30)) { + seconds /= 60 * 60 * 24 * 7; + return g_strdup_printf (ngettext ("%d week ago", + "%d weeks ago", seconds), seconds); + } + else { + seconds /= 60 * 60 * 24 * 30; + return g_strdup_printf (ngettext ("%d month ago", + "%d months ago", seconds), seconds); + } + } + else { + return g_strdup (_("in the future")); + } +} diff --git a/src/tpl_headless_logger_init.c b/src/tpl_headless_logger_init.c index a7b630dba..1f9061dd3 100644 --- a/src/tpl_headless_logger_init.c +++ b/src/tpl_headless_logger_init.c @@ -5,7 +5,7 @@ #include <tpl_observer.h> -#include <empathy-log-store-empathy.h> +#include <tpl-log-store-empathy.h> /* * Initialization of TPL (TelePathy Logger), it futurely set all the diff --git a/src/tpl_log_entry_text.c b/src/tpl_log_entry_text.c index d94324abd..66bd07111 100644 --- a/src/tpl_log_entry_text.c +++ b/src/tpl_log_entry_text.c @@ -22,6 +22,26 @@ TplLogEntryText *tpl_log_entry_text_new(void) { +TpChannelTextMessageType +tpl_log_entry_text_message_type_from_str (const gchar *type_str) +{ + if (g_strcmp0 (type_str, "normal") == 0) { + return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; + } + if (g_strcmp0 (type_str, "action") == 0) { + return TP_CHANNEL_TEXT_MESSAGE_TYPE_ACTION; + } + else if (g_strcmp0 (type_str, "notice") == 0) { + return TP_CHANNEL_TEXT_MESSAGE_TYPE_NOTICE; + } + else if (g_strcmp0 (type_str, "auto-reply") == 0) { + return TP_CHANNEL_TEXT_MESSAGE_TYPE_AUTO_REPLY; + } + + return TP_CHANNEL_TEXT_MESSAGE_TYPE_NORMAL; +} + + const gchar *tpl_log_entry_text_message_type_to_str (TpChannelTextMessageType msg_type) { switch (msg_type) { diff --git a/src/tpl_observer.c b/src/tpl_observer.c index 9842159dc..49ce80ae9 100644 --- a/src/tpl_observer.c +++ b/src/tpl_observer.c @@ -32,6 +32,13 @@ enum PROP_CHANNEL_FILTER }; +void _observe_channel_when_ready_cb(TpChannel *channel, + const GError *error, + gpointer user_data); +void _tp_connection_called_when_ready_cb(TpConnection *connection, + const GError *error, + gpointer user_data); + void _observe_channel_when_ready_cb(TpChannel *channel, const GError *error, @@ -121,8 +128,7 @@ tpl_observer_observe_channels (TpSvcClientObserver *self, } /* channels is of type a(oa{sv}) */ - int i; - for (i = 0; i < channels->len; i++) + for (guint i = 0; i < channels->len; i++) { GValueArray *channel = g_ptr_array_index (channels, i); TpChannel *tp_chan = NULL; @@ -162,6 +168,8 @@ tpl_observer_get_property (GObject *self, g_print(" :: get_property\n"); switch (property_id) { + GPtrArray *array; + GHashTable *map; case PROP_INTERFACES: g_print (" :: interfaces\n"); g_value_set_boxed (value, client_interfaces); @@ -171,8 +179,8 @@ tpl_observer_get_property (GObject *self, g_print (" :: channel-filter\n"); /* create an empty filter - which means all channels */ - GPtrArray *array = g_ptr_array_new (); - GHashTable *map = g_hash_table_new (NULL, NULL); + array = g_ptr_array_new (); + map = g_hash_table_new (NULL, NULL); g_ptr_array_add (array, map); g_value_set_boxed (value, array); @@ -189,8 +197,6 @@ tpl_observer_class_init (TplObserverClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); - object_class->get_property = tpl_observer_get_property; - /* D-Bus properties are exposed as GObject properties through the * TpDBusPropertiesMixin */ /* properties on the Client interface */ @@ -219,6 +225,7 @@ tpl_observer_class_init (TplObserverClass *klass) }, { NULL } }; + object_class->get_property = tpl_observer_get_property; g_object_class_install_property (object_class, PROP_INTERFACES, g_param_spec_boxed ("interfaces", diff --git a/src/tpl_text_channel_data.c b/src/tpl_text_channel_data.c index de5e92266..da8a51ec2 100644 --- a/src/tpl_text_channel_data.c +++ b/src/tpl_text_channel_data.c @@ -33,6 +33,24 @@ void _channel_on_sent_signal_cb (TpChannel *proxy, const gchar *arg_Text, gpointer user_data, GObject *weak_object); +void _channel_on_received_signal_cb (TpChannel *proxy, + guint arg_ID, + guint arg_Timestamp, + guint arg_Sender, + guint arg_Type, + guint arg_Flags, + const gchar *arg_Text, + gpointer user_data, + GObject *weak_object); +void _tpl_text_channel_connect_signals(TplTextChannel* self); +void _tpl_text_channel_set_ready_cb(TpConnection *connection, + guint n_contacts, + TpContact * const *contacts, + guint n_failed, + const TpHandle *failed, + const GError *error, + gpointer user_data, + GObject *weak_object); /* end of definitions */ @@ -58,7 +76,7 @@ void _channel_on_sent_signal_cb (TpChannel *proxy, TplLogEntryText *log; TplLogStoreEmpathy *logstore; - + /* Initialize data for TplContact */ me = tpl_text_channel_get_my_contact(tpl_text); remote = tpl_text_channel_get_remote_contact(tpl_text); @@ -99,6 +117,8 @@ void _channel_on_sent_signal_cb (TpChannel *proxy, arg_Text); + /* Initialize TplLogEntryText */ + log = tpl_log_entry_text_new(); tpl_log_entry_text_set_tpl_channel(log, tpl_text_channel_get_tpl_channel(tpl_text)); @@ -111,6 +131,7 @@ void _channel_on_sent_signal_cb (TpChannel *proxy, tpl_log_entry_text_set_timestamp(log, (time_t) arg_Timestamp); tpl_log_entry_text_set_id(log, 123); + /* Initialized LogStore and send the message */ logstore = g_object_new(TPL_TYPE_LOG_STORE_EMPATHY, NULL); if (!TPL_LOG_STORE_GET_INTERFACE(logstore)->add_message) { @@ -200,7 +221,8 @@ void _channel_on_received_signal_cb (TpChannel *proxy, /* connect signals to TplTextChannel instance */ -void _tpl_text_channel_connect_signals(TplTextChannel* self) { +void _tpl_text_channel_connect_signals(TplTextChannel* self) +{ GError *error=NULL; // Signals for Text channels // "lost-message" : Run Last / Has Details diff --git a/tools/.gitignore b/tools/.gitignore new file mode 100644 index 000000000..2578e9883 --- /dev/null +++ b/tools/.gitignore @@ -0,0 +1,3 @@ +_gen +extensions.html +telepathy-glib-env diff --git a/tools/Makefile.am b/tools/Makefile.am new file mode 100644 index 000000000..8662b44ae --- /dev/null +++ b/tools/Makefile.am @@ -0,0 +1,67 @@ +include $(top_srcdir)/tools/shave.mk + +abs_top_builddir = @abs_top_builddir@ + +noinst_SCRIPTS = telepathy-glib-env + +telepathy-glib-env: telepathy-glib-env.in Makefile + sed -e 's![@]abs_top_builddir[@]!$(abs_top_builddir)!' $< > $@ + chmod +x $@ + +EXTRA_DIST = \ + c-constants-gen.py \ + check-coding-style.mk \ + check-c-style.sh \ + check-misc.sh \ + check-whitespace.sh \ + doc-generator.xsl \ + flymake.mk \ + glib-client-gen.py \ + glib-client-marshaller-gen.py \ + glib-errors-enum-body-gen.py \ + glib-errors-enum-header-gen.py \ + glib-ginterface-gen.py \ + glib-gtypes-generator.py \ + glib-interfaces-gen.py \ + glib-signals-marshal-gen.py \ + gobject-foo.py \ + identity.xsl \ + lcov.am \ + libtpcodegen.py \ + libglibcodegen.py \ + make-version-script.py \ + telepathy.am \ + telepathy-glib-env.in \ + with-session-bus.sh + +CLEANFILES = libtpcodegen.pyc libtpcodegen.pyo libglibcodegen.pyc libglibcodegen.pyo $(noinst_SCRIPTS) + +all: $(EXTRA_DIST) + +libglibcodegen.py: libtpcodegen.py + $(QUIET_GEN)touch $@ +c-constants-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-client-marshaller-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-errors-enum-body-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-errors-enum-header-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-ginterface-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-gtypes-generator.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-interfaces-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ +glib-signals-marshal-gen.py: libglibcodegen.py + $(QUIET_GEN)touch $@ + +TELEPATHY_SPEC_SRCDIR = $(top_srcdir)/../telepathy-spec +maintainer-update-from-telepathy-spec: + set -e && cd $(srcdir) && \ + for x in $(EXTRA_DIST); do \ + if test -f $(TELEPATHY_SPEC_SRCDIR)/tools/$$x; then \ + cp $(TELEPATHY_SPEC_SRCDIR)/tools/$$x $$x; \ + fi; \ + done diff --git a/tools/c-constants-gen.py b/tools/c-constants-gen.py new file mode 100644 index 000000000..f338257aa --- /dev/null +++ b/tools/c-constants-gen.py @@ -0,0 +1,151 @@ +#!/usr/bin/python + +from sys import argv, stdout, stderr +import xml.dom.minidom + +from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ + get_descendant_text, get_by_path + +class Generator(object): + def __init__(self, prefix, dom): + self.prefix = prefix + '_' + self.spec = get_by_path(dom, "spec")[0] + + def __call__(self): + self.do_header() + self.do_body() + self.do_footer() + + # Header + def do_header(self): + stdout.write('/* Generated from ') + stdout.write(get_descendant_text(get_by_path(self.spec, 'title'))) + version = get_by_path(self.spec, "version") + if version: + stdout.write(', version ' + get_descendant_text(version)) + stdout.write('\n\n') + for copyright in get_by_path(self.spec, 'copyright'): + stdout.write(get_descendant_text(copyright)) + stdout.write('\n') + stdout.write(get_descendant_text(get_by_path(self.spec, 'license'))) + stdout.write('\n') + stdout.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) + stdout.write(""" + */ + +#ifdef __cplusplus +extern "C" { +#endif +\n""") + + # Body + def do_body(self): + for elem in self.spec.getElementsByTagNameNS(NS_TP, '*'): + if elem.localName == 'flags': + self.do_flags(elem) + elif elem.localName == 'enum': + self.do_enum(elem) + + def do_flags(self, flags): + name = flags.getAttribute('plural') or flags.getAttribute('name') + value_prefix = flags.getAttribute('singular') or \ + flags.getAttribute('value-prefix') or \ + flags.getAttribute('name') + stdout.write("""\ +/** + * +%s: +""" % (self.prefix + name).replace('_', '')) + for flag in get_by_path(flags, 'flag'): + self.do_gtkdoc(flag, value_prefix) + stdout.write(' *\n') + docstrings = get_by_path(flags, 'docstring') + if docstrings: + stdout.write("""\ + * <![CDATA[%s]]> + * +""" % get_descendant_text(docstrings).replace('\n', ' ')) + stdout.write("""\ + * Bitfield/set of flags generated from the Telepathy specification. + */ +typedef enum { +""") + for flag in get_by_path(flags, 'flag'): + self.do_val(flag, value_prefix) + stdout.write("""\ +} %s; + +""" % (self.prefix + name).replace('_', '')) + + def do_enum(self, enum): + name = enum.getAttribute('singular') or enum.getAttribute('name') + value_prefix = enum.getAttribute('singular') or \ + enum.getAttribute('value-prefix') or \ + enum.getAttribute('name') + name_plural = enum.getAttribute('plural') or \ + enum.getAttribute('name') + 's' + stdout.write("""\ +/** + * +%s: +""" % (self.prefix + name).replace('_', '')) + vals = get_by_path(enum, 'enumvalue') + for val in vals: + self.do_gtkdoc(val, value_prefix) + stdout.write(' *\n') + docstrings = get_by_path(enum, 'docstring') + if docstrings: + stdout.write("""\ + * <![CDATA[%s]]> + * +""" % get_descendant_text(docstrings).replace('\n', ' ')) + stdout.write("""\ + * Bitfield/set of flags generated from the Telepathy specification. + */ +typedef enum { +""") + for val in vals: + self.do_val(val, value_prefix) + stdout.write("""\ +} %(mixed-name)s; + +/** + * NUM_%(upper-plural)s: + * + * 1 higher than the highest valid value of #%(mixed-name)s. + */ +#define NUM_%(upper-plural)s (%(last-val)s+1) + +""" % {'mixed-name' : (self.prefix + name).replace('_', ''), + 'upper-plural' : (self.prefix + name_plural).upper(), + 'last-val' : vals[-1].getAttribute('value')}) + + def do_val(self, val, value_prefix): + name = val.getAttribute('name') + suffix = val.getAttribute('suffix') + use_name = (self.prefix + value_prefix + '_' + \ + (suffix or name)).upper() + assert not (name and suffix) or name == suffix, \ + 'Flag/enumvalue name %s != suffix %s' % (name, suffix) + stdout.write(' %s = %s,\n' % (use_name, val.getAttribute('value'))) + + def do_gtkdoc(self, node, value_prefix): + stdout.write(' * @') + stdout.write((self.prefix + value_prefix + '_' + + node.getAttribute('suffix')).upper()) + stdout.write(': <![CDATA[') + docstring = get_by_path(node, 'docstring') + stdout.write(get_descendant_text(docstring).replace('\n', ' ')) + stdout.write(']]>\n') + + # Footer + def do_footer(self): + stdout.write(""" +#ifdef __cplusplus +} +#endif +""") + +if __name__ == '__main__': + argv = argv[1:] + Generator(argv[0], xml.dom.minidom.parse(argv[1]))() diff --git a/tools/check-c-style.sh b/tools/check-c-style.sh new file mode 100644 index 000000000..dd62fb7ba --- /dev/null +++ b/tools/check-c-style.sh @@ -0,0 +1,56 @@ +#!/bin/sh +fail=0 + +( . "${tools_dir}"/check-misc.sh ) || fail=$? + +if grep -n '^ *GError *\*[[:alpha:]_][[:alnum:]_]* *;' "$@" +then + echo "^^^ The above files contain uninitialized GError*s - they should be" + echo " initialized to NULL" + fail=1 +fi + +# The first regex finds function calls like foo() (as opposed to foo ()). +# It attempts to ignore string constants (may cause false negatives). +# The second and third ignore block comments (gtkdoc uses foo() as markup). +# The fourth ignores cpp so you can +# #define foo(bar) (_real_foo (__FUNC__, bar)) (cpp insists on foo() style). +if grep -n '^[^"]*[[:lower:]](' "$@" \ + | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *\*' \ + | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: */\*' \ + | grep -v '^[-[:alnum:]_./]*:[[:digit:]]*: *#' +then + echo "^^^ Our coding style is to use function calls like foo (), not foo()" + fail=1 +fi + +if grep -En '[(][[:alnum:]_]+ ?\*[)][(]?[[:alpha:]_]' "$@"; then + echo "^^^ Our coding style is to have a space between a cast and the " + echo " thing being cast" + fail=1 +fi + +# this only spots casts +if grep -En '[(][[:alnum:]_]+\*+[)]' "$@"; then + echo "^^^ Our coding style is to have a space before the * of pointer types" + echo " (regex 1)" + fail=1 +fi +# ... and this only spots variable declarations and function return types +if grep -En '^ *(static |const |)* *[[:alnum:]_]+\*+([[:alnum:]_]|;|$)' \ + "$@"; then + echo "^^^ Our coding style is to have a space before the * of pointer types" + echo " (regex 2)" + fail=1 +fi + +if test -n "$CHECK_FOR_LONG_LINES" +then + if egrep -n '.{80,}' "$@" + then + echo "^^^ The above files contain long lines" + fail=1 + fi +fi + +exit $fail diff --git a/tools/check-coding-style.mk b/tools/check-coding-style.mk new file mode 100644 index 000000000..3fc92fc8d --- /dev/null +++ b/tools/check-coding-style.mk @@ -0,0 +1,17 @@ +check-coding-style: + @fail=0; \ + if test -n "$(check_misc_sources)"; then \ + tools_dir=$(top_srcdir)/tools \ + sh $(top_srcdir)/tools/check-misc.sh \ + $(check_misc_sources) || fail=1; \ + fi; \ + if test -n "$(check_c_sources)"; then \ + tools_dir=$(top_srcdir)/tools \ + sh $(top_srcdir)/tools/check-c-style.sh \ + $(check_c_sources) || fail=1; \ + fi;\ + if test yes = "$(ENABLE_CODING_STYLE_CHECKS)"; then \ + exit "$$fail";\ + else \ + exit 0;\ + fi diff --git a/tools/check-misc.sh b/tools/check-misc.sh new file mode 100644 index 000000000..89e8e871a --- /dev/null +++ b/tools/check-misc.sh @@ -0,0 +1,13 @@ +#!/bin/sh + +fail=0 + +( . "${tools_dir}"/check-whitespace.sh ) || fail=$? + +if egrep '(Free\s*Software\s*Foundation.*02139|02111-1307)' "$@" +then + echo "^^^ The above files contain the FSF's old address in GPL headers" + fail=1 +fi + +exit $fail diff --git a/tools/check-whitespace.sh b/tools/check-whitespace.sh new file mode 100644 index 000000000..489322f9c --- /dev/null +++ b/tools/check-whitespace.sh @@ -0,0 +1,24 @@ +#!/bin/sh + +fail=0 + +if grep -n ' $' "$@" +then + echo "^^^ The above files contain unwanted trailing spaces" + fail=1 +fi + +if grep -n ' $' "$@" +then + echo "^^^ The above files contain unwanted trailing tabs" + fail=1 +fi + +# TODO: enable tab checking once all Empathy switched to TP coding style +#if grep -n ' ' "$@" +#then +# echo "^^^ The above files contain tabs" +# fail=1 +#fi + +exit $fail diff --git a/tools/doc-generator.xsl b/tools/doc-generator.xsl new file mode 100644 index 000000000..76fc96964 --- /dev/null +++ b/tools/doc-generator.xsl @@ -0,0 +1,1199 @@ +<!-- Generate HTML documentation from the Telepathy specification. +The master copy of this stylesheet is in the Telepathy spec repository - +please make any changes there. + +Copyright (C) 2006-2008 Collabora Limited + +This library is free software; you can redistribute it and/or +modify it under the terms of the GNU Lesser General Public +License as published by the Free Software Foundation; either +version 2.1 of the License, or (at your option) any later version. + +This library is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +Lesser General Public License for more details. + +You should have received a copy of the GNU Lesser General Public +License along with this library; if not, write to the Free Software +Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA +--> + +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" + xmlns:tp="http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + xmlns:html="http://www.w3.org/1999/xhtml" + exclude-result-prefixes="tp html"> + <!--Don't move the declaration of the HTML namespace up here — XMLNSs + don't work ideally in the presence of two things that want to use the + absence of a prefix, sadly. --> + + <xsl:param name="allow-undefined-interfaces" select="false()"/> + + <xsl:template match="html:* | @*" mode="html"> + <xsl:copy> + <xsl:apply-templates mode="html"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="tp:type" mode="html"> + <xsl:call-template name="tp-type"> + <xsl:with-param name="tp-type" select="string(.)"/> + </xsl:call-template> + </xsl:template> + + <!-- tp:dbus-ref: reference a D-Bus interface, signal, method or property --> + <xsl:template match="tp:dbus-ref" mode="html"> + <xsl:variable name="name"> + <xsl:choose> + <xsl:when test="@namespace"> + <xsl:value-of select="@namespace"/> + <xsl:text>.</xsl:text> + </xsl:when> + </xsl:choose> + <xsl:value-of select="string(.)"/> + </xsl:variable> + + <xsl:choose> + <xsl:when test="//interface[@name=$name] + or //interface/method[concat(../@name, '.', @name)=$name] + or //interface/signal[concat(../@name, '.', @name)=$name] + or //interface/property[concat(../@name, '.', @name)=$name] + or //interface[@name=concat($name, '.DRAFT')] + or //interface/method[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + or //interface/signal[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + or //interface/property[ + concat(../@name, '.', @name)=concat($name, '.DRAFT')] + "> + <a xmlns="http://www.w3.org/1999/xhtml" href="#{$name}"> + <xsl:value-of select="string(.)"/> + </a> + </xsl:when> + + <xsl:when test="$allow-undefined-interfaces"> + <span xmlns="http://www.w3.org/1999/xhtml" title="defined elsewhere"> + <xsl:value-of select="string(.)"/> + </span> + </xsl:when> + + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: cannot find D-Bus interface, method, </xsl:text> + <xsl:text>signal or property called '</xsl:text> + <xsl:value-of select="$name"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <!-- tp:member-ref: reference a property of the current interface --> + <xsl:template match="tp:member-ref" mode="html"> + <xsl:variable name="prefix" select="concat(ancestor::interface/@name, + '.')"/> + <xsl:variable name="name" select="string(.)"/> + + <xsl:if test="not(ancestor::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: Cannot use tp:member-ref when not in an</xsl:text> + <xsl:text> <interface> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:choose> + <xsl:when test="ancestor::interface/signal[@name=$name]"/> + <xsl:when test="ancestor::interface/method[@name=$name]"/> + <xsl:when test="ancestor::interface/property[@name=$name]"/> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: interface </xsl:text> + <xsl:value-of select="ancestor::interface/@name"/> + <xsl:text> has no signal/method/property called </xsl:text> + <xsl:value-of select="$name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + + <a xmlns="http://www.w3.org/1999/xhtml" href="#{$prefix}{$name}"> + <xsl:value-of select="$name"/> + </a> + </xsl:template> + + <xsl:template match="*" mode="identity"> + <xsl:copy> + <xsl:apply-templates mode="identity"/> + </xsl:copy> + </xsl:template> + + <xsl:template match="tp:docstring"> + <xsl:apply-templates mode="html"/> + </xsl:template> + + <xsl:template match="tp:added"> + <p class="added" xmlns="http://www.w3.org/1999/xhtml">Added in + version <xsl:value-of select="@version"/>. + <xsl:apply-templates select="node()" mode="html"/></p> + </xsl:template> + + <xsl:template match="tp:changed"> + <xsl:choose> + <xsl:when test="node()"> + <p class="changed" xmlns="http://www.w3.org/1999/xhtml">Changed in + version <xsl:value-of select="@version"/>: + <xsl:apply-templates select="node()" mode="html"/></p> + </xsl:when> + <xsl:otherwise> + <p class="changed">Changed in version + <xsl:value-of select="@version"/></p> + </xsl:otherwise> + </xsl:choose> + </xsl:template> + + <xsl:template match="tp:deprecated"> + <p class="deprecated" xmlns="http://www.w3.org/1999/xhtml">Deprecated + since version <xsl:value-of select="@version"/>. + <xsl:apply-templates select="node()" mode="html"/></p> + </xsl:template> + + <xsl:template match="tp:rationale" mode="html"> + <div xmlns="http://www.w3.org/1999/xhtml" class="rationale"> + <xsl:apply-templates select="node()" mode="html"/> + </div> + </xsl:template> + + <xsl:template match="tp:errors"> + <h1 xmlns="http://www.w3.org/1999/xhtml">Errors</h1> + <xsl:apply-templates/> + </xsl:template> + + <xsl:template match="tp:generic-types"> + <h1 xmlns="http://www.w3.org/1999/xhtml">Generic types</h1> + <xsl:call-template name="do-types"/> + </xsl:template> + + <xsl:template name="do-types"> + <xsl:if test="tp:simple-type"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Simple types</h2> + <xsl:apply-templates select="tp:simple-type"/> + </xsl:if> + + <xsl:if test="tp:enum"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Enumerated types:</h2> + <xsl:apply-templates select="tp:enum"/> + </xsl:if> + + <xsl:if test="tp:flags"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Sets of flags:</h2> + <xsl:apply-templates select="tp:flags"/> + </xsl:if> + + <xsl:if test="tp:struct"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Structure types</h2> + <xsl:apply-templates select="tp:struct"/> + </xsl:if> + + <xsl:if test="tp:mapping"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Mapping types</h2> + <xsl:apply-templates select="tp:mapping"/> + </xsl:if> + + <xsl:if test="tp:external-type"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Types defined elsewhere</h2> + <dl><xsl:apply-templates select="tp:external-type"/></dl> + </xsl:if> + </xsl:template> + + <xsl:template match="tp:error"> + <h2 xmlns="http://www.w3.org/1999/xhtml"><a name="{concat(../@namespace, '.', translate(@name, ' ', ''))}"></a><xsl:value-of select="concat(../@namespace, '.', translate(@name, ' ', ''))"/></h2> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </xsl:template> + + <xsl:template match="/tp:spec/tp:copyright"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates mode="text"/> + </div> + </xsl:template> + <xsl:template match="/tp:spec/tp:license"> + <div xmlns="http://www.w3.org/1999/xhtml" class="license"> + <xsl:apply-templates mode="html"/> + </div> + </xsl:template> + + <xsl:template match="tp:copyright"/> + <xsl:template match="tp:license"/> + + <xsl:template match="interface"> + <h1 xmlns="http://www.w3.org/1999/xhtml"><a name="{@name}"></a><xsl:value-of select="@name"/></h1> + + <xsl:if test="@tp:causes-havoc"> + <p xmlns="http://www.w3.org/1999/xhtml" class="causes-havoc"> + This interface is <xsl:value-of select="@tp:causes-havoc"/> + and is likely to cause havoc to your API/ABI if bindings are generated. + Don't include it in libraries that care about compatibility. + </p> + </xsl:if> + + <xsl:if test="tp:requires"> + <p>Implementations of this interface must also implement:</p> + <ul xmlns="http://www.w3.org/1999/xhtml"> + <xsl:for-each select="tp:requires"> + <li><code><a href="#{@interface}"><xsl:value-of select="@interface"/></a></code></li> + </xsl:for-each> + </ul> + </xsl:if> + + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + + <xsl:choose> + <xsl:when test="method"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Methods:</h2> + <xsl:apply-templates select="method"/> + </xsl:when> + <xsl:otherwise> + <p xmlns="http://www.w3.org/1999/xhtml">Interface has no methods.</p> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="signal"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Signals:</h2> + <xsl:apply-templates select="signal"/> + </xsl:when> + <xsl:otherwise> + <p xmlns="http://www.w3.org/1999/xhtml">Interface has no signals.</p> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="tp:property"> + <h2 xmlns="http://www.w3.org/1999/xhtml">Telepathy Properties:</h2> + <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the + <a href="#org.freedesktop.Telepathy.Properties">Telepathy + Properties</a> interface.</p> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:property"/> + </dl> + </xsl:when> + <xsl:otherwise> + <p xmlns="http://www.w3.org/1999/xhtml">Interface has no Telepathy + properties.</p> + </xsl:otherwise> + </xsl:choose> + + <xsl:choose> + <xsl:when test="property"> + <h2 xmlns="http://www.w3.org/1999/xhtml">D-Bus core Properties:</h2> + <p xmlns="http://www.w3.org/1999/xhtml">Accessed using the + org.freedesktop.DBus.Properties interface.</p> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="property"/> + </dl> + </xsl:when> + <xsl:otherwise> + <p xmlns="http://www.w3.org/1999/xhtml">Interface has no D-Bus core + properties.</p> + </xsl:otherwise> + </xsl:choose> + + <xsl:call-template name="do-types"/> + + </xsl:template> + + <xsl:template match="tp:flags"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:flags type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:flags type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <h3> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> + </h3> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@value-prefix"> + <xsl:value-of select="@value-prefix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:for-each select="tp:flag"> + <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt> + <xsl:choose> + <xsl:when test="tp:docstring"> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </dd> + </xsl:when> + <xsl:otherwise> + <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </dl> + </xsl:template> + + <xsl:template match="tp:enum"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:enum type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:enum type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <h3 xmlns="http://www.w3.org/1999/xhtml"> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> + </h3> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:variable name="value-prefix"> + <xsl:choose> + <xsl:when test="@value-prefix"> + <xsl:value-of select="@value-prefix"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="@name"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + <xsl:for-each select="tp:enumvalue"> + <dt xmlns="http://www.w3.org/1999/xhtml"><code><xsl:value-of select="concat($value-prefix, '_', @suffix)"/> = <xsl:value-of select="@value"/></code></dt> + <xsl:choose> + <xsl:when test="tp:docstring"> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </dd> + </xsl:when> + <xsl:otherwise> + <dd xmlns="http://www.w3.org/1999/xhtml">(Undocumented)</dd> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + </dl> + </xsl:template> + + <xsl:template match="property"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: property </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a property of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on property </xsl:text> + <xsl:value-of select="concat(../@name, '.', @name)"/> + <xsl:text>: '</xsl:text> + <xsl:value-of select="@access"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:if> + + <dt xmlns="http://www.w3.org/1999/xhtml"> + <a name="{concat(../@name, '.', @name)}"> + <code><xsl:value-of select="@name"/></code> + </a> + <xsl:text> − </xsl:text> + <code><xsl:value-of select="@type"/></code> + <xsl:call-template name="parenthesized-tp-type"/> + <xsl:text>, </xsl:text> + <xsl:choose> + <xsl:when test="@access = 'read'"> + <xsl:text>read-only</xsl:text> + </xsl:when> + <xsl:when test="@access = 'write'"> + <xsl:text>write-only</xsl:text> + </xsl:when> + <xsl:when test="@access = 'readwrite'"> + <xsl:text>read/write</xsl:text> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: unknown or missing value for </xsl:text> + <xsl:text>@access on property </xsl:text> + <xsl:value-of select="concat(../@name, '.', @name)"/> + <xsl:text>: '</xsl:text> + <xsl:value-of select="@access"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </dd> + </xsl:template> + + <xsl:template match="tp:property"> + <dt xmlns="http://www.w3.org/1999/xhtml"> + <xsl:if test="@name"> + <code><xsl:value-of select="@name"/></code> − + </xsl:if> + <code><xsl:value-of select="@type"/></code> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </dd> + </xsl:template> + + <xsl:template match="tp:mapping"> + <div xmlns="http://www.w3.org/1999/xhtml" class="struct"> + <h3> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> − a{ + <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:text>: </xsl:text> + <xsl:value-of select="@name"/> + <xsl:if test="position() != last()"> → </xsl:if> + </xsl:for-each> + } + </h3> + <div class="docstring"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:if test="string(@array-name) != ''"> + <p>In bindings that need a separate name, arrays of + <xsl:value-of select="@name"/> should be called + <xsl:value-of select="@array-name"/>.</p> + </xsl:if> + </div> + <div> + <h4>Members</h4> + <dl> + <xsl:apply-templates select="tp:member" mode="members-in-docstring"/> + </dl> + </div> + </div> + </xsl:template> + + <xsl:template match="tp:docstring" mode="in-index"/> + + <xsl:template match="tp:simple-type | tp:enum | tp:flags | tp:external-type" + mode="in-index"> + − <xsl:value-of select="@type"/> + </xsl:template> + + <xsl:template match="tp:simple-type"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:simple-type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:simple-type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <div xmlns="http://www.w3.org/1999/xhtml" class="simple-type"> + <h3> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> − <xsl:value-of select="@type"/> + </h3> + <div class="docstring"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </div> + </div> + </xsl:template> + + <xsl:template match="tp:external-type"> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a tp:external-type </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @type on tp:external-type</xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <div xmlns="http://www.w3.org/1999/xhtml" class="external-type"> + <dt> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> − <xsl:value-of select="@type"/> + </dt> + <dd>Defined by: <xsl:value-of select="@from"/></dd> + </div> + </xsl:template> + + <xsl:template match="tp:struct" mode="in-index"> + − ( <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> ) + </xsl:template> + + <xsl:template match="tp:mapping" mode="in-index"> + − a{ <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:if test="position() != last()"> → </xsl:if> + </xsl:for-each> } + </xsl:template> + + <xsl:template match="tp:struct"> + <div xmlns="http://www.w3.org/1999/xhtml" class="struct"> + <h3> + <a name="type-{@name}"> + <xsl:value-of select="@name"/> + </a> − ( + <xsl:for-each select="tp:member"> + <xsl:value-of select="@type"/> + <xsl:text>: </xsl:text> + <xsl:value-of select="@name"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> + ) + </h3> + <div class="docstring"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </div> + <xsl:choose> + <xsl:when test="string(@array-name) != ''"> + <p>In bindings that need a separate name, arrays of + <xsl:value-of select="@name"/> should be called + <xsl:value-of select="@array-name"/>.</p> + </xsl:when> + <xsl:otherwise> + <p>Arrays of <xsl:value-of select="@name"/> don't generally + make sense.</p> + </xsl:otherwise> + </xsl:choose> + <div> + <h4>Members</h4> + <dl> + <xsl:apply-templates select="tp:member" mode="members-in-docstring"/> + </dl> + </div> + </div> + </xsl:template> + + <xsl:template match="method"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: method </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a method of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:for-each select="arg"> + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no type</xsl:text> + </xsl:message> + </xsl:if> + <xsl:choose> + <xsl:when test="@direction='in'"> + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an 'in' arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if> + </xsl:when> + <xsl:when test="@direction='out'"> + <!-- FIXME: This is commented out until someone with a lot of time + on their hands goes through the spec adding names to all the "out" + arguments + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="no"> + <xsl:text>INFO: an 'out' arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if>--> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of method </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has direction neither 'in' nor 'out'</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + + <div xmlns="http://www.w3.org/1999/xhtml" class="method"> + <h3 xmlns="http://www.w3.org/1999/xhtml"> + <a name="{concat(../@name, concat('.', @name))}"> + <xsl:value-of select="@name"/> + </a> ( + <xsl:for-each xmlns="" select="arg[@direction='in']"> + <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> + ) → + <xsl:choose> + <xsl:when test="arg[@direction='out']"> + <xsl:for-each xmlns="" select="arg[@direction='out']"> + <xsl:value-of select="@type"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> + </xsl:when> + <xsl:otherwise>nothing</xsl:otherwise> + </xsl:choose> + </h3> + <div xmlns="http://www.w3.org/1999/xhtml" class="docstring"> + <xsl:apply-templates select="tp:docstring" /> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </div> + + <xsl:if test="arg[@direction='in']"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h4>Parameters</h4> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="arg[@direction='in']" + mode="parameters-in-docstring"/> + </dl> + </div> + </xsl:if> + + <xsl:if test="arg[@direction='out']"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h4>Returns</h4> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="arg[@direction='out']" + mode="returns-in-docstring"/> + </dl> + </div> + </xsl:if> + + <xsl:if test="tp:possible-errors"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h4>Possible errors</h4> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:possible-errors/tp:error"/> + </dl> + </div> + </xsl:if> + + </div> + </xsl:template> + + <xsl:template name="tp-type"> + <xsl:param name="tp-type"/> + <xsl:param name="type"/> + + <xsl:variable name="single-type"> + <xsl:choose> + <xsl:when test="contains($tp-type, '[]')"> + <xsl:value-of select="substring-before($tp-type, '[]')"/> + </xsl:when> + <xsl:otherwise> + <xsl:value-of select="$tp-type"/> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:variable name="type-of-tp-type"> + <xsl:if test="contains($tp-type, '[]')"> + <!-- one 'a', plus one for each [ after the [], and delete all ] --> + <xsl:value-of select="concat('a', + translate(substring-after($tp-type, '[]'), '[]', 'a'))"/> + </xsl:if> + + <xsl:choose> + <xsl:when test="//tp:simple-type[@name=$single-type]"> + <xsl:value-of select="string(//tp:simple-type[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:struct[@name=$single-type]"> + <xsl:text>(</xsl:text> + <xsl:for-each select="//tp:struct[@name=$single-type]/tp:member"> + <xsl:value-of select="@type"/> + </xsl:for-each> + <xsl:text>)</xsl:text> + </xsl:when> + <xsl:when test="//tp:enum[@name=$single-type]"> + <xsl:value-of select="string(//tp:enum[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:flags[@name=$single-type]"> + <xsl:value-of select="string(//tp:flags[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:when test="//tp:mapping[@name=$single-type]"> + <xsl:text>a{</xsl:text> + <xsl:for-each select="//tp:mapping[@name=$single-type]/tp:member"> + <xsl:value-of select="@type"/> + </xsl:for-each> + <xsl:text>}</xsl:text> + </xsl:when> + <xsl:when test="//tp:external-type[@name=$single-type]"> + <xsl:value-of select="string(//tp:external-type[@name=$single-type]/@type)"/> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: Unable to find type '</xsl:text> + <xsl:value-of select="$tp-type"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:variable> + + <xsl:if test="string($type) != '' and + string($type-of-tp-type) != string($type)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: tp:type '</xsl:text> + <xsl:value-of select="$tp-type"/> + <xsl:text>' has D-Bus type '</xsl:text> + <xsl:value-of select="$type-of-tp-type"/> + <xsl:text>' but has been used with type='</xsl:text> + <xsl:value-of select="$type"/> + <xsl:text>' </xsl:text> + </xsl:message> + </xsl:if> + + <a href="#type-{$single-type}"><xsl:value-of select="$tp-type"/></a> + + </xsl:template> + + <xsl:template name="parenthesized-tp-type"> + <xsl:if test="@tp:type"> + <xsl:text> (</xsl:text> + <xsl:call-template name="tp-type"> + <xsl:with-param name="tp-type" select="@tp:type"/> + <xsl:with-param name="type" select="@type"/> + </xsl:call-template> + <xsl:text>)</xsl:text> + </xsl:if> + </xsl:template> + + <xsl:template match="tp:member" mode="members-in-docstring"> + <dt xmlns="http://www.w3.org/1999/xhtml"> + <code><xsl:value-of select="@name"/></code> − + <code><xsl:value-of select="@type"/></code> + <xsl:call-template name="parenthesized-tp-type"/> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring" /> + </xsl:when> + <xsl:otherwise> + <em>(undocumented)</em> + </xsl:otherwise> + </xsl:choose> + </dd> + </xsl:template> + + <xsl:template match="arg" mode="parameters-in-docstring"> + <dt xmlns="http://www.w3.org/1999/xhtml"> + <code><xsl:value-of select="@name"/></code> − + <code><xsl:value-of select="@type"/></code> + <xsl:call-template name="parenthesized-tp-type"/> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring" /> + </dd> + </xsl:template> + + <xsl:template match="arg" mode="returns-in-docstring"> + <dt xmlns="http://www.w3.org/1999/xhtml"> + <xsl:if test="@name"> + <code><xsl:value-of select="@name"/></code> − + </xsl:if> + <code><xsl:value-of select="@type"/></code> + <xsl:call-template name="parenthesized-tp-type"/> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="tp:docstring"/> + </dd> + </xsl:template> + + <xsl:template match="tp:possible-errors/tp:error"> + <dt xmlns="http://www.w3.org/1999/xhtml"> + <code><xsl:value-of select="@name"/></code> + </dt> + <dd xmlns="http://www.w3.org/1999/xhtml"> + <xsl:variable name="name" select="@name"/> + <xsl:choose> + <xsl:when test="tp:docstring"> + <xsl:apply-templates select="tp:docstring"/> + </xsl:when> + <xsl:when test="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"> + <xsl:apply-templates select="//tp:errors/tp:error[concat(../@namespace, '.', translate(@name, ' ', ''))=$name]/tp:docstring"/> <em xmlns="http://www.w3.org/1999/xhtml">(generic description)</em> + </xsl:when> + <xsl:otherwise> + (Undocumented.) + </xsl:otherwise> + </xsl:choose> + </dd> + </xsl:template> + + <xsl:template match="signal"> + + <xsl:if test="not(parent::interface)"> + <xsl:message terminate="yes"> + <xsl:text>ERR: signal </xsl:text> + <xsl:value-of select="@name"/> + <xsl:text> does not have an interface as parent </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: missing @name on a signal of </xsl:text> + <xsl:value-of select="../@name"/> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:if> + + <xsl:for-each select="arg"> + <xsl:if test="not(@type) or @type = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no type</xsl:text> + </xsl:message> + </xsl:if> + <xsl:if test="not(@name) or @name = ''"> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has no name</xsl:text> + </xsl:message> + </xsl:if> + <xsl:choose> + <xsl:when test="not(@direction)"/> + <xsl:when test="@direction='in'"> + <xsl:message terminate="no"> + <xsl:text>INFO: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has unnecessary direction 'in'</xsl:text> + </xsl:message> + </xsl:when> + <xsl:otherwise> + <xsl:message terminate="yes"> + <xsl:text>ERR: an arg of signal </xsl:text> + <xsl:value-of select="concat(../../@name, '.', ../@name)"/> + <xsl:text> has direction other than 'in'</xsl:text> + </xsl:message> + </xsl:otherwise> + </xsl:choose> + </xsl:for-each> + + <div xmlns="http://www.w3.org/1999/xhtml" class="signal"> + <h3 xmlns="http://www.w3.org/1999/xhtml"> + <a name="{concat(../@name, concat('.', @name))}"> + <xsl:value-of select="@name"/> + </a> ( + <xsl:for-each xmlns="" select="arg"> + <xsl:value-of select="@type"/>: <xsl:value-of select="@name"/> + <xsl:if test="position() != last()">, </xsl:if> + </xsl:for-each> + )</h3> + + <div xmlns="http://www.w3.org/1999/xhtml" class="docstring"> + <xsl:apply-templates select="tp:docstring"/> + <xsl:apply-templates select="tp:added"/> + <xsl:apply-templates select="tp:changed"/> + <xsl:apply-templates select="tp:deprecated"/> + </div> + + <xsl:if test="arg"> + <div xmlns="http://www.w3.org/1999/xhtml"> + <h4>Parameters</h4> + <dl xmlns="http://www.w3.org/1999/xhtml"> + <xsl:apply-templates select="arg" mode="parameters-in-docstring"/> + </dl> + </div> + </xsl:if> + </div> + </xsl:template> + + <xsl:output method="xml" indent="no" encoding="ascii" + omit-xml-declaration="yes" + doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" + doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" /> + + <xsl:template match="/tp:spec"> + <html xmlns="http://www.w3.org/1999/xhtml"> + <head> + <title> + <xsl:value-of select="tp:title"/> + <xsl:if test="tp:version"> + <xsl:text> version </xsl:text> + <xsl:value-of select="tp:version"/> + </xsl:if> + </title> + <style type="text/css"> + + body { + font-family: sans-serif; + margin: 2em; + height: 100%; + font-size: 1.2em; + } + h1 { + padding-top: 5px; + padding-bottom: 5px; + font-size: 1.6em; + background: #dadae2; + } + h2 { + font-size: 1.3em; + } + h3 { + font-size: 1.2em; + } + a:link, a:visited, a:link:hover, a:visited:hover { + font-weight: bold; + } + .topbox { + padding-top: 10px; + padding-left: 10px; + border-bottom: black solid 1px; + padding-bottom: 10px; + background: #dadae2; + font-size: 2em; + font-weight: bold; + color: #5c5c5c; + } + .topnavbox { + padding-left: 10px; + padding-top: 5px; + padding-bottom: 5px; + background: #abacba; + border-bottom: black solid 1px; + font-size: 1.2em; + } + .topnavbox a{ + color: black; + font-weight: normal; + } + .sidebar { + float: left; + /* width:9em; + border-right:#abacba solid 1px; + border-left: #abacba solid 1px; + height:100%; */ + border: #abacba solid 1px; + padding-left: 10px; + margin-left: 10px; + padding-right: 10px; + margin-right: 10px; + color: #5d5d5d; + background: #dadae2; + } + .sidebar a { + text-decoration: none; + border-bottom: #e29625 dotted 1px; + color: #e29625; + font-weight: normal; + } + .sidebar h1 { + font-size: 1.2em; + color: black; + } + .sidebar ul { + padding-left: 25px; + padding-bottom: 10px; + border-bottom: #abacba solid 1px; + } + .sidebar li { + padding-top: 2px; + padding-bottom: 2px; + } + .sidebar h2 { + font-style:italic; + font-size: 0.81em; + padding-left: 5px; + padding-right: 5px; + font-weight: normal; + } + .date { + font-size: 0.6em; + float: right; + font-style: italic; + } + .method, .signal, .property { + margin-left: 1em; + margin-right: 4em; + } + .rationale { + font-style: italic; + border-left: 0.25em solid #808080; + padding-left: 0.5em; + } + + .added { + color: #006600; + background: #ffffff; + } + .deprecated { + color: #ff0000; + background: #ffffff; + } + table, tr, td, th { + border: 1px solid #666; + } + + </style> + </head> + <body> + <h1 class="topbox"> + <xsl:value-of select="tp:title" /> + </h1> + <xsl:if test="tp:version"> + <h2>Version <xsl:value-of select="string(tp:version)"/></h2> + </xsl:if> + <xsl:apply-templates select="tp:copyright"/> + <xsl:apply-templates select="tp:license"/> + <xsl:apply-templates select="tp:docstring"/> + + <h2>Interfaces</h2> + <ul> + <xsl:for-each select="//node/interface"> + <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li> + </xsl:for-each> + </ul> + + <xsl:apply-templates select="//node"/> + <xsl:apply-templates select="tp:generic-types"/> + <xsl:apply-templates select="tp:errors"/> + + <h1>Index</h1> + <h2>Index of interfaces</h2> + <ul> + <xsl:for-each select="//node/interface"> + <li><code><a href="#{@name}"><xsl:value-of select="@name"/></a></code></li> + </xsl:for-each> + </ul> + <h2>Index of types</h2> + <ul> + <xsl:for-each select="//tp:simple-type | //tp:enum | //tp:flags | //tp:mapping | //tp:struct | //tp:external-type"> + <xsl:sort select="@name"/> + <li> + <code> + <a href="#type-{@name}"> + <xsl:value-of select="@name"/> + </a> + </code> + <xsl:apply-templates mode="in-index" select="."/> + </li> + </xsl:for-each> + </ul> + </body> + </html> + </xsl:template> + + <xsl:template match="node"> + <xsl:apply-templates /> + </xsl:template> + + <xsl:template match="text()"> + <xsl:if test="normalize-space(.) != ''"> + <xsl:message terminate="yes"> + <xsl:text>Stray text: {{{</xsl:text> + <xsl:value-of select="." /> + <xsl:text>}}} </xsl:text> + </xsl:message> + </xsl:if> + </xsl:template> + + <xsl:template match="*"> + <xsl:message terminate="yes"> + <xsl:text>Unrecognised element: {</xsl:text> + <xsl:value-of select="namespace-uri(.)" /> + <xsl:text>}</xsl:text> + <xsl:value-of select="local-name(.)" /> + <xsl:text> </xsl:text> + </xsl:message> + </xsl:template> +</xsl:stylesheet> + +<!-- vim:set sw=2 sts=2 et: --> diff --git a/tools/flymake.mk b/tools/flymake.mk new file mode 100644 index 000000000..020a7bfbf --- /dev/null +++ b/tools/flymake.mk @@ -0,0 +1,4 @@ +check-syntax: + $(CC) $(AM_CPPFLAGS) $(AM_CFLAGS) -fsyntax-only $(CHK_SOURCES) + +.PHONY: check-syntax diff --git a/tools/glib-client-gen.py b/tools/glib-client-gen.py new file mode 100644 index 000000000..701fcafeb --- /dev/null +++ b/tools/glib-client-gen.py @@ -0,0 +1,1157 @@ +#!/usr/bin/python + +# glib-client-gen.py: "I Can't Believe It's Not dbus-binding-tool" +# +# Generate GLib client wrappers from the Telepathy specification. +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2006-2008 Collabora Ltd. <http://www.collabora.co.uk/> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import os.path +import xml.dom.minidom +from getopt import gnu_getopt + +from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ + camelcase_to_lower, get_docstring, xml_escape + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix, basename, opts): + self.dom = dom + self.__header = [] + self.__body = [] + + self.prefix_lc = prefix.lower() + self.prefix_uc = prefix.upper() + self.prefix_mc = prefix.replace('_', '') + self.basename = basename + self.group = opts.get('--group', None) + self.iface_quark_prefix = opts.get('--iface-quark-prefix', None) + self.tp_proxy_api = tuple(map(int, + opts.get('--tp-proxy-api', '0').split('.'))) + self.proxy_cls = opts.get('--subclass', 'TpProxy') + ' *' + self.proxy_arg = opts.get('--subclass', 'void') + ' *' + self.proxy_assert = opts.get('--subclass-assert', 'TP_IS_PROXY') + self.proxy_doc = ('A #%s or subclass' + % opts.get('--subclass', 'TpProxy')) + if self.proxy_arg == 'void *': + self.proxy_arg = 'gpointer ' + + def h(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__header.append(s) + + def b(self, s): + if isinstance(s, unicode): + s = s.encode('utf-8') + self.__body.append(s) + + def get_iface_quark(self): + assert self.iface_dbus is not None + assert self.iface_uc is not None + if self.iface_quark_prefix is None: + return 'g_quark_from_static_string (\"%s\")' % self.iface_dbus + else: + return '%s_%s' % (self.iface_quark_prefix, self.iface_uc) + + def do_signal(self, iface, signal): + iface_lc = iface.lower() + + member = signal.getAttribute('name') + member_lc = camelcase_to_lower(member) + member_uc = member_lc.upper() + + arg_count = 0 + args = [] + out_args = [] + + for arg in signal.getElementsByTagName('arg'): + name = arg.getAttribute('name') + type = arg.getAttribute('type') + tp_type = arg.getAttribute('tp:type') + + if not name: + name = 'arg%u' % arg_count + arg_count += 1 + else: + name = 'arg_%s' % name + + info = type_to_gtype(type) + args.append((name, info, tp_type, arg)) + + callback_name = ('%s_%s_signal_callback_%s' + % (self.prefix_lc, iface_lc, member_lc)) + collect_name = ('_%s_%s_collect_args_of_%s' + % (self.prefix_lc, iface_lc, member_lc)) + invoke_name = ('_%s_%s_invoke_callback_for_%s' + % (self.prefix_lc, iface_lc, member_lc)) + + # Example: + # + # typedef void (*tp_cli_connection_signal_callback_new_channel) + # (TpConnection *proxy, const gchar *arg_object_path, + # const gchar *arg_channel_type, guint arg_handle_type, + # guint arg_handle, gboolean arg_suppress_handler, + # gpointer user_data, GObject *weak_object); + + self.b('/**') + self.b(' * %s:' % callback_name) + self.b(' * @proxy: The proxy on which %s_%s_connect_to_%s ()' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' * was called') + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' * @%s: %s' % (name, + xml_escape(get_docstring(elt) or '(Undocumented)'))) + + self.b(' * @user_data: User-supplied data') + self.b(' * @weak_object: User-supplied weakly referenced object') + self.b(' *') + self.b(' * Represents the signature of a callback for the signal %s.' + % member) + self.b(' */') + self.h('typedef void (*%s) (%sproxy,' + % (callback_name, self.proxy_cls)) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + + self.h(' gpointer user_data, GObject *weak_object);') + + if args: + self.b('static void') + self.b('%s (DBusGProxy *proxy G_GNUC_UNUSED,' % collect_name) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s%s%s,' % (const, ctype, name)) + + self.b(' TpProxySignalConnection *sc)') + self.b('{') + self.b(' GValueArray *args = g_value_array_new (%d);' % len(args)) + self.b(' GValue blank = { 0 };') + self.b(' guint i;') + self.b('') + self.b(' g_value_init (&blank, G_TYPE_INT);') + self.b('') + self.b(' for (i = 0; i < %d; i++)' % len(args)) + self.b(' g_value_array_append (args, &blank);') + self.b('') + + for i, arg in enumerate(args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' g_value_unset (args->values + %d);' % i) + self.b(' g_value_init (args->values + %d, %s);' % (i, gtype)) + + if gtype == 'G_TYPE_STRING': + self.b(' g_value_set_string (args->values + %d, %s);' + % (i, name)) + elif marshaller == 'BOXED': + self.b(' g_value_set_boxed (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_set_uchar (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_set_boolean (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_set_uint64 (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_set_double (args->values + %d, %s);' + % (i, name)) + else: + assert False, ("Don't know how to put %s in a GValue" + % gtype) + self.b('') + + self.b(' tp_proxy_signal_connection_v0_take_results (sc, args);') + self.b('}') + + self.b('static void') + self.b('%s (TpProxy *tpproxy,' % invoke_name) + self.b(' GError *error G_GNUC_UNUSED,') + self.b(' GValueArray *args,') + self.b(' GCallback generic_callback,') + self.b(' gpointer user_data,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' %s callback =' % callback_name) + self.b(' (%s) generic_callback;' % callback_name) + self.b('') + self.b(' if (callback != NULL)') + self.b(' callback (g_object_ref (tpproxy),') + + # FIXME: factor out into a function + for i, arg in enumerate(args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED': + self.b(' g_value_get_boxed (args->values + %d),' % i) + elif gtype == 'G_TYPE_STRING': + self.b(' g_value_get_string (args->values + %d),' % i) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_get_uchar (args->values + %d),' % i) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_get_boolean (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_get_uint (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_get_int (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_get_uint64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_get_int64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_get_double (args->values + %d),' % i) + else: + assert False, "Don't know how to get %s from a GValue" % gtype + + self.b(' user_data,') + self.b(' weak_object);') + self.b('') + + if len(args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + self.b('') + + self.b(' g_object_unref (tpproxy);') + self.b('}') + + # Example: + # + # TpProxySignalConnection * + # tp_cli_connection_connect_to_new_channel + # (TpConnection *proxy, + # tp_cli_connection_signal_callback_new_channel callback, + # gpointer user_data, + # GDestroyNotify destroy); + # + # destroy is invoked when the signal becomes disconnected. This + # is either because the signal has been disconnected explicitly + # by the user, because the TpProxy has become invalid and + # emitted the 'invalidated' signal, or because the weakly referenced + # object has gone away. + + self.b('/**') + self.b(' * %s_%s_connect_to_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' * @proxy: %s' % self.proxy_doc) + self.b(' * @callback: Callback to be called when the signal is') + self.b(' * received') + self.b(' * @user_data: User-supplied data for the callback') + self.b(' * @destroy: Destructor for the user-supplied data, which') + self.b(' * will be called when this signal is disconnected, or') + self.b(' * before this function returns %NULL') + self.b(' * @weak_object: A #GObject which will be weakly referenced; ') + self.b(' * if it is destroyed, this callback will automatically be') + self.b(' * disconnected') + self.b(' * @error: If not %NULL, used to raise an error if %NULL is') + self.b(' * returned') + self.b(' *') + self.b(' * Connect a handler to the signal %s.' % member) + self.b(' *') + self.b(' * %s' % xml_escape(get_docstring(signal) or '(Undocumented)')) + self.b(' *') + self.b(' * Returns: a #TpProxySignalConnection containing all of the') + self.b(' * above, which can be used to disconnect the signal; or') + self.b(' * %NULL if the proxy does not have the desired interface') + self.b(' * or has become invalid.') + self.b(' */') + self.h('TpProxySignalConnection *%s_%s_connect_to_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.h(' %s callback,' % callback_name) + self.h(' gpointer user_data,') + self.h(' GDestroyNotify destroy,') + self.h(' GObject *weak_object,') + self.h(' GError **error);') + + self.b('TpProxySignalConnection *') + self.b('%s_%s_connect_to_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.b(' %s callback,' % callback_name) + self.b(' gpointer user_data,') + self.b(' GDestroyNotify destroy,') + self.b(' GObject *weak_object,') + self.b(' GError **error)') + self.b('{') + self.b(' GType expected_types[%d] = {' % (len(args) + 1)) + + for arg in args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' %s,' % gtype) + + self.b(' G_TYPE_INVALID };') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), NULL);' + % self.proxy_assert) + self.b(' g_return_val_if_fail (callback != NULL, NULL);') + self.b('') + self.b(' return tp_proxy_signal_connection_v0_new ((TpProxy *) proxy,') + self.b(' %s, \"%s\",' % (self.get_iface_quark(), member)) + self.b(' expected_types,') + + if args: + self.b(' G_CALLBACK (%s),' % collect_name) + else: + self.b(' NULL, /* no args => no collector function */') + + self.b(' %s,' % invoke_name) + self.b(' G_CALLBACK (callback), user_data, destroy,') + self.b(' weak_object, error);') + self.b('}') + self.b('') + + self.h('') + + def do_method(self, iface, method): + iface_lc = iface.lower() + + member = method.getAttribute('name') + member_lc = camelcase_to_lower(member) + member_uc = member_lc.upper() + + in_count = 0 + ret_count = 0 + in_args = [] + out_args = [] + + for arg in method.getElementsByTagName('arg'): + name = arg.getAttribute('name') + direction = arg.getAttribute('direction') + type = arg.getAttribute('type') + tp_type = arg.getAttribute('tp:type') + + if direction != 'out': + if not name: + name = 'in%u' % in_count + in_count += 1 + else: + name = 'in_%s' % name + else: + if not name: + name = 'out%u' % ret_count + ret_count += 1 + else: + name = 'out_%s' % name + + info = type_to_gtype(type) + if direction != 'out': + in_args.append((name, info, tp_type, arg)) + else: + out_args.append((name, info, tp_type, arg)) + + # Async reply callback type + + # Example: + # void (*tp_cli_properties_interface_callback_for_get_properties) + # (TpProxy *proxy, + # const GPtrArray *out0, + # const GError *error, + # gpointer user_data, + # GObject *weak_object); + + self.b('/**') + self.b(' * %s_%s_callback_for_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' * @proxy: the proxy on which the call was made') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' * @%s: Used to return an \'out\' argument if @error is ' + '%%NULL: %s' + % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) + + self.b(' * @error: %NULL on success, or an error on failure') + self.b(' * @user_data: user-supplied data') + self.b(' * @weak_object: user-supplied object') + self.b(' *') + self.b(' * Signature of the callback called when a %s method call' + % member) + self.b(' * succeeds or fails.') + self.b(' */') + + callback_name = '%s_%s_callback_for_%s' % (self.prefix_lc, iface_lc, + member_lc) + + self.h('typedef void (*%s) (%sproxy,' + % (callback_name, self.proxy_cls)) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + + self.h(' const GError *error, gpointer user_data,') + self.h(' GObject *weak_object);') + self.h('') + + # Async callback implementation + + invoke_callback = '_%s_%s_invoke_callback_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + collect_callback = '_%s_%s_collect_callback_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + # The callback called by dbus-glib; this ends the call and collects + # the results into a GValueArray. + self.b('static void') + self.b('%s (DBusGProxy *proxy,' % collect_callback) + self.b(' DBusGProxyCall *call,') + self.b(' gpointer user_data)') + self.b('{') + self.b(' GError *error = NULL;') + + if len(out_args) > 0: + self.b(' GValueArray *args;') + self.b(' GValue blank = { 0 };') + self.b(' guint i;') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + # "We handle variants specially; the caller is expected to + # have already allocated storage for them". Thanks, + # dbus-glib... + if gtype == 'G_TYPE_VALUE': + self.b(' GValue *%s = g_new0 (GValue, 1);' % name) + else: + self.b(' %s%s;' % (ctype, name)) + + self.b('') + self.b(' dbus_g_proxy_end_call (proxy, call, &error,') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if gtype == 'G_TYPE_VALUE': + self.b(' %s, %s,' % (gtype, name)) + else: + self.b(' %s, &%s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID);') + + if len(out_args) == 0: + self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,' + 'NULL);') + else: + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' tp_proxy_pending_call_v0_take_results (user_data, error,') + self.b(' NULL);') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + if gtype == 'G_TYPE_VALUE': + self.b(' g_free (%s);' % name) + + self.b(' return;') + self.b(' }') + self.b('') + self.b(' args = g_value_array_new (%d);' % len(out_args)) + self.b(' g_value_init (&blank, G_TYPE_INT);') + self.b('') + self.b(' for (i = 0; i < %d; i++)' % len(out_args)) + self.b(' g_value_array_append (args, &blank);') + + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b('') + self.b(' g_value_unset (args->values + %d);' % i) + self.b(' g_value_init (args->values + %d, %s);' % (i, gtype)) + + if gtype == 'G_TYPE_STRING': + self.b(' g_value_take_string (args->values + %d, %s);' + % (i, name)) + elif marshaller == 'BOXED': + self.b(' g_value_take_boxed (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_set_uchar (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_set_boolean (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_set_int (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_set_uint (args->values + %d, %s);' + % (i, name)) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_set_double (args->values + %d, %s);' + % (i, name)) + else: + assert False, ("Don't know how to put %s in a GValue" + % gtype) + + self.b(' tp_proxy_pending_call_v0_take_results (user_data, ' + 'NULL, args);') + + self.b('}') + + self.b('static void') + self.b('%s (TpProxy *self,' % invoke_callback) + self.b(' GError *error,') + self.b(' GValueArray *args,') + self.b(' GCallback generic_callback,') + self.b(' gpointer user_data,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' %s callback = (%s) generic_callback;' + % (callback_name, callback_name)) + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' callback ((%s) self,' % self.proxy_cls) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED' or pointer: + self.b(' NULL,') + elif gtype == 'G_TYPE_DOUBLE': + self.b(' 0.0,') + else: + self.b(' 0,') + + self.b(' error, user_data, weak_object);') + self.b(' g_error_free (error);') + self.b(' return;') + self.b(' }') + + self.b(' callback ((%s) self,' % self.proxy_cls) + + # FIXME: factor out into a function + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if marshaller == 'BOXED': + self.b(' g_value_get_boxed (args->values + %d),' % i) + elif gtype == 'G_TYPE_STRING': + self.b(' g_value_get_string (args->values + %d),' % i) + elif gtype == 'G_TYPE_UCHAR': + self.b(' g_value_get_uchar (args->values + %d),' % i) + elif gtype == 'G_TYPE_BOOLEAN': + self.b(' g_value_get_boolean (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT': + self.b(' g_value_get_uint (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT': + self.b(' g_value_get_int (args->values + %d),' % i) + elif gtype == 'G_TYPE_UINT64': + self.b(' g_value_get_uint64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_INT64': + self.b(' g_value_get_int64 (args->values + %d),' % i) + elif gtype == 'G_TYPE_DOUBLE': + self.b(' g_value_get_double (args->values + %d),' % i) + else: + assert False, "Don't know how to get %s from a GValue" % gtype + + self.b(' error, user_data, weak_object);') + self.b('') + + if len(out_args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + + self.b('}') + self.b('') + + # Async stub + + # Example: + # TpProxyPendingCall * + # tp_cli_properties_interface_call_get_properties + # (gpointer proxy, + # gint timeout_ms, + # const GArray *in_properties, + # tp_cli_properties_interface_callback_for_get_properties callback, + # gpointer user_data, + # GDestroyNotify *destructor); + + self.h('TpProxyPendingCall *%s_%s_call_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.h(' gint timeout_ms,') + + self.b('/**') + self.b(' * %s_%s_call_%s:' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' * @proxy: the #TpProxy') + self.b(' * @timeout_ms: the timeout in milliseconds, or -1 to use the') + self.b(' * default') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' * @%s: Used to pass an \'in\' argument: %s' + % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) + + self.b(' * @callback: called when the method call succeeds or fails;') + self.b(' * may be %NULL to make a "fire and forget" call with no ') + self.b(' * reply tracking') + self.b(' * @user_data: user-supplied data passed to the callback;') + self.b(' * must be %NULL if @callback is %NULL') + self.b(' * @destroy: called with the user_data as argument, after the') + self.b(' * call has succeeded, failed or been cancelled;') + self.b(' * must be %NULL if @callback is %NULL') + self.b(' * @weak_object: If not %NULL, a #GObject which will be ') + self.b(' * weakly referenced; if it is destroyed, this call ') + self.b(' * will automatically be cancelled. Must be %NULL if ') + self.b(' * @callback is %NULL') + self.b(' *') + self.b(' * Start a %s method call.' % member) + self.b(' *') + self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.b(' *') + self.b(' * Returns: a #TpProxyPendingCall representing the call in') + self.b(' * progress. It is borrowed from the object, and will become') + self.b(' * invalid when the callback is called, the call is') + self.b(' * cancelled or the #TpProxy becomes invalid.') + self.b(' */') + self.b('TpProxyPendingCall *\n%s_%s_call_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.b(' gint timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + self.b(' %s%s%s,' % (const, ctype, name)) + + self.h(' %s callback,' % callback_name) + self.h(' gpointer user_data,') + self.h(' GDestroyNotify destroy,') + self.h(' GObject *weak_object);') + self.h('') + + self.b(' %s callback,' % callback_name) + self.b(' gpointer user_data,') + self.b(' GDestroyNotify destroy,') + self.b(' GObject *weak_object)') + self.b('{') + self.b(' GError *error = NULL;') + self.b(' GQuark interface = %s;' % self.get_iface_quark()) + self.b(' DBusGProxy *iface;') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), NULL);' + % self.proxy_assert) + self.b(' g_return_val_if_fail (callback != NULL || ' + 'user_data == NULL, NULL);') + self.b(' g_return_val_if_fail (callback != NULL || ' + 'destroy == NULL, NULL);') + self.b(' g_return_val_if_fail (callback != NULL || ' + 'weak_object == NULL, NULL);') + self.b('') + self.b(' iface = tp_proxy_borrow_interface_by_id (') + self.b(' (TpProxy *) proxy,') + self.b(' interface, &error);') + self.b('') + self.b(' if (iface == NULL)') + self.b(' {') + self.b(' if (callback != NULL)') + self.b(' callback (proxy,') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + if pointer: + self.b(' NULL,') + else: + self.b(' 0,') + + self.b(' error, user_data, weak_object);') + self.b('') + self.b(' if (destroy != NULL)') + self.b(' destroy (user_data);') + self.b('') + self.b(' g_error_free (error);') + self.b(' return NULL;') + self.b(' }') + self.b('') + self.b(' if (callback == NULL)') + self.b(' {') + self.b(' dbus_g_proxy_call_no_reply (iface, "%s",' % member) + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID);') + self.b(' return NULL;') + self.b(' }') + self.b(' else') + self.b(' {') + self.b(' TpProxyPendingCall *data;') + self.b('') + self.b(' data = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,') + self.b(' interface, "%s", iface,' % member) + self.b(' %s,' % invoke_callback) + self.b(' G_CALLBACK (callback), user_data, destroy,') + self.b(' weak_object, FALSE);') + self.b(' tp_proxy_pending_call_v0_take_pending_call (data,') + self.b(' dbus_g_proxy_begin_call_with_timeout (iface,') + self.b(' "%s",' % member) + self.b(' %s,' % collect_callback) + self.b(' data,') + self.b(' tp_proxy_pending_call_v0_completed,') + self.b(' timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID));') + self.b('') + self.b(' return data;') + self.b(' }') + self.b('}') + self.b('') + + # Reentrant blocking calls + # Example: + # gboolean tp_cli_properties_interface_run_get_properties + # (gpointer proxy, + # gint timeout_ms, + # const GArray *in_properties, + # GPtrArray **out0, + # GError **error, + # GMainLoop **loop); + + self.b('typedef struct {') + self.b(' GMainLoop *loop;') + self.b(' GError **error;') + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' %s*%s;' % (ctype, name)) + + self.b(' unsigned success:1;') + self.b(' unsigned completed:1;') + self.b('} _%s_%s_run_state_%s;' + % (self.prefix_lc, iface_lc, member_lc)) + + reentrant_invoke = '_%s_%s_finish_running_%s' % (self.prefix_lc, + iface_lc, + member_lc) + + self.b('static void') + self.b('%s (TpProxy *self G_GNUC_UNUSED,' % reentrant_invoke) + self.b(' GError *error,') + self.b(' GValueArray *args,') + self.b(' GCallback unused G_GNUC_UNUSED,') + self.b(' gpointer user_data G_GNUC_UNUSED,') + self.b(' GObject *unused2 G_GNUC_UNUSED)') + self.b('{') + self.b(' _%s_%s_run_state_%s *state = user_data;' + % (self.prefix_lc, iface_lc, member_lc)) + self.b('') + self.b(' state->success = (error == NULL);') + self.b(' state->completed = TRUE;') + self.b(' g_main_loop_quit (state->loop);') + self.b('') + self.b(' if (error != NULL)') + self.b(' {') + self.b(' if (state->error != NULL)') + self.b(' *state->error = error;') + self.b(' else') + self.b(' g_error_free (error);') + self.b('') + self.b(' return;') + self.b(' }') + self.b('') + + for i, arg in enumerate(out_args): + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' if (state->%s != NULL)' % name) + if marshaller == 'BOXED': + self.b(' *state->%s = g_value_dup_boxed (' + 'args->values + %d);' % (name, i)) + elif marshaller == 'STRING': + self.b(' *state->%s = g_value_dup_string ' + '(args->values + %d);' % (name, i)) + elif marshaller in ('UCHAR', 'BOOLEAN', 'INT', 'UINT', + 'INT64', 'UINT64', 'DOUBLE'): + self.b(' *state->%s = g_value_get_%s (args->values + %d);' + % (name, marshaller.lower(), i)) + else: + assert False, "Don't know how to copy %s" % gtype + + self.b('') + + if len(out_args) > 0: + self.b(' g_value_array_free (args);') + else: + self.b(' if (args != NULL)') + self.b(' g_value_array_free (args);') + + self.b('}') + self.b('') + + self.h('gboolean %s_%s_run_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.h(' gint timeout_ms,') + + self.b('/**') + self.b(' * %s_%s_run_%s:' % (self.prefix_lc, iface_lc, member_lc)) + self.b(' * @proxy: %s' % self.proxy_doc) + self.b(' * @timeout_ms: Timeout in milliseconds, or -1 for default') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' * @%s: Used to pass an \'in\' argument: %s' + % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.b(' * @%s: Used to return an \'out\' argument if %%TRUE is ' + 'returned: %s' + % (name, xml_escape(get_docstring(elt) or '(Undocumented)'))) + + self.b(' * @error: If not %NULL, used to return errors if %FALSE ') + self.b(' * is returned') + self.b(' * @loop: If not %NULL, set before re-entering ') + self.b(' * the main loop, to point to a #GMainLoop ') + self.b(' * which can be used to cancel this call with ') + self.b(' * g_main_loop_quit(), causing a return of ') + self.b(' * %FALSE with @error set to %TP_DBUS_ERROR_CANCELLED') + self.b(' *') + self.b(' * Call the method %s and run the main loop' % member) + self.b(' * until it returns. Before calling this method, you must') + self.b(' * add a reference to any borrowed objects you need to keep,') + self.b(' * and generally ensure that everything is in a consistent') + self.b(' * state.') + self.b(' *') + self.b(' * %s' % xml_escape(get_docstring(method) or '(Undocumented)')) + self.b(' *') + self.b(' * Returns: TRUE on success, FALSE and sets @error on error') + self.b(' */') + self.b('gboolean\n%s_%s_run_%s (%sproxy,' + % (self.prefix_lc, iface_lc, member_lc, self.proxy_arg)) + self.b(' gint timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.h(' %s%s%s,' % (const, ctype, name)) + self.b(' %s%s%s,' % (const, ctype, name)) + + for arg in out_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + self.h(' %s*%s,' % (ctype, name)) + self.b(' %s*%s,' % (ctype, name)) + + self.h(' GError **error,') + self.h(' GMainLoop **loop);') + self.h('') + + self.b(' GError **error,') + self.b(' GMainLoop **loop)') + self.b('{') + self.b(' DBusGProxy *iface;') + self.b(' GQuark interface = %s;' % self.get_iface_quark()) + self.b(' TpProxyPendingCall *pc;') + self.b(' _%s_%s_run_state_%s state = {' + % (self.prefix_lc, iface_lc, member_lc)) + self.b(' NULL /* loop */, error,') + + for arg in out_args: + name, info, tp_type, elt = arg + + self.b(' %s,' % name) + + self.b(' FALSE /* completed */, FALSE /* success */ };') + self.b('') + self.b(' g_return_val_if_fail (%s (proxy), FALSE);' + % self.proxy_assert) + self.b('') + self.b(' iface = tp_proxy_borrow_interface_by_id') + self.b(' ((TpProxy *) proxy, interface, error);') + self.b('') + self.b(' if (iface == NULL)') + self.b(' return FALSE;') + self.b('') + self.b(' state.loop = g_main_loop_new (NULL, FALSE);') + self.b('') + self.b(' pc = tp_proxy_pending_call_v0_new ((TpProxy *) proxy,') + self.b(' interface, "%s", iface,' % member) + self.b(' %s,' % reentrant_invoke) + self.b(' NULL, &state, NULL, NULL, TRUE);') + self.b('') + self.b(' if (loop != NULL)') + self.b(' *loop = state.loop;') + self.b('') + self.b(' tp_proxy_pending_call_v0_take_pending_call (pc,') + self.b(' dbus_g_proxy_begin_call_with_timeout (iface,') + self.b(' "%s",' % member) + self.b(' %s,' % collect_callback) + self.b(' pc,') + self.b(' tp_proxy_pending_call_v0_completed,') + self.b(' timeout_ms,') + + for arg in in_args: + name, info, tp_type, elt = arg + ctype, gtype, marshaller, pointer = info + + const = pointer and 'const ' or '' + + self.b(' %s, %s,' % (gtype, name)) + + self.b(' G_TYPE_INVALID));') + self.b('') + self.b(' if (!state.completed)') + self.b(' g_main_loop_run (state.loop);') + self.b('') + self.b(' if (!state.completed)') + self.b(' tp_proxy_pending_call_cancel (pc);') + self.b('') + self.b(' if (loop != NULL)') + self.b(' *loop = NULL;') + self.b('') + self.b(' g_main_loop_unref (state.loop);') + self.b('') + self.b(' return state.success;') + self.b('}') + self.b('') + + # leave a gap for the end of the method + self.b('') + self.h('') + + def do_signal_add(self, signal): + marshaller_items = [] + gtypes = [] + + for i in signal.getElementsByTagName('arg'): + name = i.getAttribute('name') + type = i.getAttribute('type') + info = type_to_gtype(type) + # type, GType, STRING, is a pointer + gtypes.append(info[1]) + + self.b(' dbus_g_proxy_add_signal (proxy, "%s",' + % signal.getAttribute('name')) + for gtype in gtypes: + self.b(' %s,' % gtype) + self.b(' G_TYPE_INVALID);') + + def do_interface(self, node): + ifaces = node.getElementsByTagName('interface') + assert len(ifaces) == 1 + iface = ifaces[0] + name = node.getAttribute('name').replace('/', '') + + self.iface = name + self.iface_lc = name.lower() + self.iface_uc = name.upper() + self.iface_mc = name.replace('_', '') + self.iface_dbus = iface.getAttribute('name') + + signals = node.getElementsByTagName('signal') + methods = node.getElementsByTagName('method') + + if signals: + self.b('static inline void') + self.b('%s_add_signals_for_%s (DBusGProxy *proxy)' + % (self.prefix_lc, name.lower())) + self.b('{') + + if self.tp_proxy_api >= (0, 7, 6): + self.b(' if (!tp_proxy_dbus_g_proxy_claim_for_signal_adding ' + '(proxy))') + self.b(' return;') + + for signal in signals: + self.do_signal_add(signal) + + self.b('}') + self.b('') + self.b('') + + for signal in signals: + self.do_signal(name, signal) + + for method in methods: + self.do_method(name, method) + + self.iface_dbus = None + + def __call__(self): + + self.h('G_BEGIN_DECLS') + self.h('') + + self.b('/* We don\'t want gtkdoc scanning this file, it\'ll get') + self.b(' * confused by seeing function definitions, so mark it as: */') + self.b('/*<private_header>*/') + self.b('') + + nodes = self.dom.getElementsByTagName('node') + nodes.sort(cmp_by_name) + + for node in nodes: + self.do_interface(node) + + if self.group is not None: + + self.b('/*') + self.b(' * %s_%s_add_signals:' % (self.prefix_lc, self.group)) + self.b(' * @self: the #TpProxy') + self.b(' * @quark: a quark whose string value is the interface') + self.b(' * name whose signals should be added') + self.b(' * @proxy: the D-Bus proxy to which to add the signals') + self.b(' * @unused: not used for anything') + self.b(' *') + self.b(' * Tell dbus-glib that @proxy has the signatures of all') + self.b(' * signals on the given interface, if it\'s one we') + self.b(' * support.') + self.b(' *') + self.b(' * This function should be used as a signal handler for') + self.b(' * #TpProxy::interface-added.') + self.b(' */') + self.b('static void') + self.b('%s_%s_add_signals (TpProxy *self G_GNUC_UNUSED,' + % (self.prefix_lc, self.group)) + self.b(' guint quark,') + self.b(' DBusGProxy *proxy,') + self.b(' gpointer unused G_GNUC_UNUSED)') + + self.b('{') + + for node in nodes: + iface = node.getElementsByTagName('interface')[0] + self.iface_dbus = iface.getAttribute('name') + signals = node.getElementsByTagName('signal') + if not signals: + continue + name = node.getAttribute('name').replace('/', '').lower() + self.iface_uc = name.upper() + self.b(' if (quark == %s)' % self.get_iface_quark()) + self.b(' %s_add_signals_for_%s (proxy);' + % (self.prefix_lc, name)) + + self.b('}') + self.b('') + + self.h('G_END_DECLS') + self.h('') + + open(self.basename + '.h', 'w').write('\n'.join(self.__header)) + open(self.basename + '-body.h', 'w').write('\n'.join(self.__body)) + + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + + +if __name__ == '__main__': + options, argv = gnu_getopt(sys.argv[1:], '', + ['group=', 'subclass=', 'subclass-assert=', + 'iface-quark-prefix=', 'tp-proxy-api=']) + + opts = {} + + for option, value in options: + opts[option] = value + + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom, argv[1], argv[2], opts)() diff --git a/tools/glib-client-marshaller-gen.py b/tools/glib-client-marshaller-gen.py new file mode 100644 index 000000000..54447255b --- /dev/null +++ b/tools/glib-client-marshaller-gen.py @@ -0,0 +1,59 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom +from string import ascii_letters, digits + + +from libglibcodegen import signal_to_marshal_name + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix): + self.dom = dom + self.marshallers = {} + self.prefix = prefix + + def do_signal(self, signal): + marshaller = signal_to_marshal_name(signal, self.prefix) + + assert '__' in marshaller + rhs = marshaller.split('__', 1)[1].split('_') + + self.marshallers[marshaller] = rhs + + def __call__(self): + signals = self.dom.getElementsByTagName('signal') + + for signal in signals: + self.do_signal(signal) + + print 'void' + print '%s_register_dbus_glib_marshallers (void)' % self.prefix + print '{' + + all = self.marshallers.keys() + all.sort() + for marshaller in all: + rhs = self.marshallers[marshaller] + + print ' dbus_g_object_register_marshaller (%s,' % marshaller + print ' G_TYPE_NONE, /* return */' + for type in rhs: + print ' G_TYPE_%s,' % type.replace('VOID', 'NONE') + print ' G_TYPE_INVALID);' + + print '}' + + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + +if __name__ == '__main__': + argv = sys.argv[1:] + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom, argv[1])() diff --git a/tools/glib-errors-enum-body-gen.py b/tools/glib-errors-enum-body-gen.py new file mode 100644 index 000000000..44863ee4c --- /dev/null +++ b/tools/glib-errors-enum-body-gen.py @@ -0,0 +1,62 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ + get_descendant_text + +class Generator(object): + def __init__(self, dom): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + + def do_header(self): + print '/* Generated from the Telepathy spec\n' + copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright') + for copyright in copyrights: + print get_descendant_text(copyright) + license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0] + print '\n' + get_descendant_text(license) + '\n*/' + + def do_enum_values(self): + for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): + print '' + nick = error.getAttribute('name').replace(' ', '') + name = camelcase_to_upper(nick.replace('.', '')) + ns = error.parentNode.getAttribute('namespace') + enum = 'TP_ERROR_' + name + print ' /* ' + ns + '.' + name + print ' ' + get_docstring(error) + print ' */' + print ' { %s, "%s", "%s" },' % (enum, enum, nick) + + + def do_get_type(self): + print """ +#include <_gen/telepathy-errors.h> + +GType +tp_error_get_type (void) +{ + static GType etype = 0; + if (G_UNLIKELY (etype == 0)) + { + static const GEnumValue values[] = {""" + self.do_enum_values() + print """\ + }; + + etype = g_enum_register_static ("TpError", values); + } + return etype; +} +""" + + def __call__(self): + self.do_header() + self.do_get_type() + +if __name__ == '__main__': + argv = sys.argv[1:] + Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-errors-enum-header-gen.py b/tools/glib-errors-enum-header-gen.py new file mode 100644 index 000000000..64939b414 --- /dev/null +++ b/tools/glib-errors-enum-header-gen.py @@ -0,0 +1,75 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom + +from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ + get_descendant_text + +class Generator(object): + def __init__(self, dom): + self.dom = dom + self.errors = self.dom.getElementsByTagNameNS(NS_TP, 'errors')[0] + + def do_header(self): + print '/* Generated from the Telepathy spec\n' + copyrights = self.errors.getElementsByTagNameNS(NS_TP, 'copyright') + for copyright in copyrights: + print get_descendant_text(copyright) + license = self.errors.getElementsByTagNameNS(NS_TP, 'license')[0] + print '\n' + get_descendant_text(license) + '\n*/' + + def do_gtkdoc(self): + for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): + ns = error.parentNode.getAttribute('namespace') + nick = error.getAttribute('name').replace(' ', '') + enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', '')) + print ' * @' + enum + ': ' + ns + '.' + nick + ':' + print ' * ' + get_docstring(error) + ' ' + + def do_enumnames(self): + for error in self.errors.getElementsByTagNameNS(NS_TP, 'error'): + nick = error.getAttribute('name').replace(' ', '') + enum = 'TP_ERROR_' + camelcase_to_upper(nick.replace('.', '')) + print ' ' + enum + ',' + + def do_get_type(self): + print """ +#include <glib-object.h> + +G_BEGIN_DECLS + +GType tp_error_get_type (void); + +/** + * TP_TYPE_ERROR: + * + * The GType of the Telepathy error enumeration. + */ +#define TP_TYPE_ERROR (tp_error_get_type()) +""" + + def do_enum(self): + print """\ +/** + * TpError:""" + self.do_gtkdoc() + print """\ + * + * Enumerated type representing the Telepathy D-Bus errors. + */ +typedef enum {""" + self.do_enumnames() + print """\ +} TpError; + +G_END_DECLS""" + + def __call__(self): + self.do_header() + self.do_get_type() + self.do_enum() + +if __name__ == '__main__': + argv = sys.argv[1:] + Generator(xml.dom.minidom.parse(argv[0]))() diff --git a/tools/glib-ginterface-gen.py b/tools/glib-ginterface-gen.py new file mode 100644 index 000000000..9eb7af5ce --- /dev/null +++ b/tools/glib-ginterface-gen.py @@ -0,0 +1,722 @@ +#!/usr/bin/python + +# glib-ginterface-gen.py: service-side interface generator +# +# Generate dbus-glib 0.x service GInterfaces from the Telepathy specification. +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2006, 2007 Collabora Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import os.path +import xml.dom.minidom + +from libglibcodegen import Signature, type_to_gtype, cmp_by_name, \ + camelcase_to_lower, NS_TP, dbus_gutils_wincaps_to_uscore, \ + signal_to_marshal_name, method_to_glue_marshal_name + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +class Generator(object): + + def __init__(self, dom, prefix, basename, signal_marshal_prefix, + headers, end_headers, not_implemented_func, + allow_havoc): + self.dom = dom + self.__header = [] + self.__body = [] + + assert prefix.endswith('_') + assert not signal_marshal_prefix.endswith('_') + + # The main_prefix, sub_prefix thing is to get: + # FOO_ -> (FOO_, _) + # FOO_SVC_ -> (FOO_, _SVC_) + # but + # FOO_BAR/ -> (FOO_BAR_, _) + # FOO_BAR/SVC_ -> (FOO_BAR_, _SVC_) + + if '/' in prefix: + main_prefix, sub_prefix = prefix.upper().split('/', 1) + prefix = prefix.replace('/', '_') + else: + main_prefix, sub_prefix = prefix.upper().split('_', 1) + + self.MAIN_PREFIX_ = main_prefix + '_' + self._SUB_PREFIX_ = '_' + sub_prefix + + self.Prefix_ = prefix + self.Prefix = prefix.replace('_', '') + self.prefix_ = prefix.lower() + self.PREFIX_ = prefix.upper() + + self.signal_marshal_prefix = signal_marshal_prefix + self.headers = headers + self.end_headers = end_headers + self.not_implemented_func = not_implemented_func + self.allow_havoc = allow_havoc + + def h(self, s): + self.__header.append(s) + + def b(self, s): + self.__body.append(s) + + def do_node(self, node): + node_name = node.getAttribute('name').replace('/', '') + node_name_mixed = self.node_name_mixed = node_name.replace('_', '') + node_name_lc = self.node_name_lc = node_name.lower() + node_name_uc = self.node_name_uc = node_name.upper() + + interfaces = node.getElementsByTagName('interface') + assert len(interfaces) == 1, interfaces + interface = interfaces[0] + self.iface_name = interface.getAttribute('name') + + tmp = interface.getAttribute('tp:implement-service') + if tmp == "no": + return + + tmp = interface.getAttribute('tp:causes-havoc') + if tmp and not self.allow_havoc: + raise AssertionError('%s is %s' % (self.iface_name, tmp)) + + self.b('static const DBusGObjectInfo _%s%s_object_info;' + % (self.prefix_, node_name_lc)) + self.b('') + + methods = interface.getElementsByTagName('method') + signals = interface.getElementsByTagName('signal') + properties = interface.getElementsByTagName('property') + # Don't put properties in dbus-glib glue + glue_properties = [] + + self.b('struct _%s%sClass {' % (self.Prefix, node_name_mixed)) + self.b(' GTypeInterface parent_class;') + for method in methods: + self.b(' %s %s;' % self.get_method_impl_names(method)) + self.b('};') + self.b('') + + if signals: + self.b('enum {') + for signal in signals: + self.b(' %s,' % self.get_signal_const_entry(signal)) + self.b(' N_%s_SIGNALS' % node_name_uc) + self.b('};') + self.b('static guint %s_signals[N_%s_SIGNALS] = {0};' + % (node_name_lc, node_name_uc)) + self.b('') + + self.b('static void %s%s_base_init (gpointer klass);' + % (self.prefix_, node_name_lc)) + self.b('') + + self.b('GType') + self.b('%s%s_get_type (void)' + % (self.prefix_, node_name_lc)) + self.b('{') + self.b(' static GType type = 0;') + self.b('') + self.b(' if (G_UNLIKELY (type == 0))') + self.b(' {') + self.b(' static const GTypeInfo info = {') + self.b(' sizeof (%s%sClass),' % (self.Prefix, node_name_mixed)) + self.b(' %s%s_base_init, /* base_init */' + % (self.prefix_, node_name_lc)) + self.b(' NULL, /* base_finalize */') + self.b(' NULL, /* class_init */') + self.b(' NULL, /* class_finalize */') + self.b(' NULL, /* class_data */') + self.b(' 0,') + self.b(' 0, /* n_preallocs */') + self.b(' NULL /* instance_init */') + self.b(' };') + self.b('') + self.b(' type = g_type_register_static (G_TYPE_INTERFACE,') + self.b(' "%s%s", &info, 0);' % (self.Prefix, node_name_mixed)) + self.b(' }') + self.b('') + self.b(' return type;') + self.b('}') + self.b('') + + self.h('/**') + self.h(' * %s%s:' % (self.Prefix, node_name_mixed)) + self.h(' *') + self.h(' * Dummy typedef representing any implementation of this ' + 'interface.') + self.h(' */') + self.h('typedef struct _%s%s %s%s;' + % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed)) + self.h('') + self.h('/**') + self.h(' * %s%sClass:' % (self.Prefix, node_name_mixed)) + self.h(' *') + self.h(' * The class of %s%s.' % (self.Prefix, node_name_mixed)) + self.h(' */') + self.h('typedef struct _%s%sClass %s%sClass;' + % (self.Prefix, node_name_mixed, self.Prefix, node_name_mixed)) + self.h('') + self.h('GType %s%s_get_type (void);' + % (self.prefix_, node_name_lc)) + + gtype = self.current_gtype = \ + self.MAIN_PREFIX_ + 'TYPE' + self._SUB_PREFIX_ + node_name_uc + classname = self.Prefix + node_name_mixed + + self.h('#define %s \\\n (%s%s_get_type ())' + % (gtype, self.prefix_, node_name_lc)) + self.h('#define %s%s(obj) \\\n' + ' (G_TYPE_CHECK_INSTANCE_CAST((obj), %s, %s))' + % (self.PREFIX_, node_name_uc, gtype, classname)) + self.h('#define %sIS%s%s(obj) \\\n' + ' (G_TYPE_CHECK_INSTANCE_TYPE((obj), %s))' + % (self.MAIN_PREFIX_, self._SUB_PREFIX_, node_name_uc, gtype)) + self.h('#define %s%s_GET_CLASS(obj) \\\n' + ' (G_TYPE_INSTANCE_GET_INTERFACE((obj), %s, %sClass))' + % (self.PREFIX_, node_name_uc, gtype, classname)) + self.h('') + self.h('') + + base_init_code = [] + + for method in methods: + self.do_method(method) + + for signal in signals: + base_init_code.extend(self.do_signal(signal)) + + self.b('static inline void') + self.b('%s%s_base_init_once (gpointer klass G_GNUC_UNUSED)' + % (self.prefix_, node_name_lc)) + self.b('{') + self.b(' static TpDBusPropertiesMixinPropInfo properties[%d] = {' + % (len(properties) + 1)) + + for m in properties: + access = m.getAttribute('access') + assert access in ('read', 'write', 'readwrite') + + if access == 'read': + flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_READ' + elif access == 'write': + flags = 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE' + else: + flags = ('TP_DBUS_PROPERTIES_MIXIN_FLAG_READ | ' + 'TP_DBUS_PROPERTIES_MIXIN_FLAG_WRITE') + + self.b(' { 0, %s, "%s", 0, NULL, NULL }, /* %s */' + % (flags, m.getAttribute('type'), m.getAttribute('name'))) + + self.b(' { 0, 0, NULL, 0, NULL, NULL }') + self.b(' };') + self.b(' static TpDBusPropertiesMixinIfaceInfo interface =') + self.b(' { 0, properties, NULL, NULL };') + self.b('') + self.b(' interface.dbus_interface = g_quark_from_static_string ' + '("%s");' % self.iface_name) + + for i, m in enumerate(properties): + self.b(' properties[%d].name = g_quark_from_static_string ("%s");' + % (i, m.getAttribute('name'))) + self.b(' properties[%d].type = %s;' + % (i, type_to_gtype(m.getAttribute('type'))[1])) + + self.b(' tp_svc_interface_set_dbus_properties_info (%s, &interface);' + % self.current_gtype) + + self.b('') + for s in base_init_code: + self.b(s) + self.b(' dbus_g_object_type_install_info (%s%s_get_type (),' + % (self.prefix_, node_name_lc)) + self.b(' &_%s%s_object_info);' + % (self.prefix_, node_name_lc)) + self.b('}') + + self.b('static void') + self.b('%s%s_base_init (gpointer klass)' + % (self.prefix_, node_name_lc)) + self.b('{') + self.b(' static gboolean initialized = FALSE;') + self.b('') + self.b(' if (!initialized)') + self.b(' {') + self.b(' initialized = TRUE;') + self.b(' %s%s_base_init_once (klass);' + % (self.prefix_, node_name_lc)) + self.b(' }') + # insert anything we need to do per implementation here + self.b('}') + + self.h('') + + self.b('static const DBusGMethodInfo _%s%s_methods[] = {' + % (self.prefix_, node_name_lc)) + + method_blob, offsets = self.get_method_glue(methods) + + for method, offset in zip(methods, offsets): + self.do_method_glue(method, offset) + + self.b('};') + self.b('') + + self.b('static const DBusGObjectInfo _%s%s_object_info = {' + % (self.prefix_, node_name_lc)) + self.b(' 0,') # version + self.b(' _%s%s_methods,' % (self.prefix_, node_name_lc)) + self.b(' %d,' % len(methods)) + self.b('"' + method_blob.replace('\0', '\\0') + '",') + self.b('"' + self.get_signal_glue(signals).replace('\0', '\\0') + '",') + self.b('"' + + self.get_property_glue(glue_properties).replace('\0', '\\0') + + '",') + self.b('};') + self.b('') + + self.node_name_mixed = None + self.node_name_lc = None + self.node_name_uc = None + + def get_method_glue(self, methods): + info = [] + offsets = [] + + for method in methods: + offsets.append(len(''.join(info))) + + info.append(self.iface_name + '\0') + info.append(method.getAttribute('name') + '\0') + + info.append('A\0') # async + + counter = 0 + for arg in method.getElementsByTagName('arg'): + out = arg.getAttribute('direction') == 'out' + + name = arg.getAttribute('name') + if not name: + assert out + name = 'arg%u' % counter + counter += 1 + + info.append(name + '\0') + + if out: + info.append('O\0') + else: + info.append('I\0') + + if out: + info.append('F\0') # not const + info.append('N\0') # not error or return + info.append(arg.getAttribute('type') + '\0') + + info.append('\0') + + return ''.join(info) + '\0', offsets + + def do_method_glue(self, method, offset): + lc_name = camelcase_to_lower(method.getAttribute('name')) + + marshaller = method_to_glue_marshal_name(method, + self.signal_marshal_prefix) + wrapper = self.prefix_ + self.node_name_lc + '_' + lc_name + + self.b(" { (GCallback) %s, %s, %d }," % (wrapper, marshaller, offset)) + + def get_signal_glue(self, signals): + info = [] + + for signal in signals: + info.append(self.iface_name) + info.append(signal.getAttribute('name')) + + return '\0'.join(info) + '\0\0' + + # the implementation can be the same + get_property_glue = get_signal_glue + + def get_method_impl_names(self, method): + dbus_method_name = method.getAttribute('name') + class_member_name = camelcase_to_lower(dbus_method_name) + stub_name = (self.prefix_ + self.node_name_lc + '_' + + class_member_name) + return (stub_name + '_impl', class_member_name) + + def do_method(self, method): + assert self.node_name_mixed is not None + + in_class = [] + + # Examples refer to Thing.DoStuff (su) -> ii + + # DoStuff + dbus_method_name = method.getAttribute('name') + # do_stuff + class_member_name = camelcase_to_lower(dbus_method_name) + # void tp_svc_thing_do_stuff (TpSvcThing *, const char *, guint, + # DBusGMethodInvocation *); + stub_name = (self.prefix_ + self.node_name_lc + '_' + + class_member_name) + # typedef void (*tp_svc_thing_do_stuff_impl) (TpSvcThing *, + # const char *, guint, DBusGMethodInvocation); + impl_name = stub_name + '_impl' + # void tp_svc_thing_return_from_do_stuff (DBusGMethodInvocation *, + # gint, gint); + ret_name = (self.prefix_ + self.node_name_lc + '_return_from_' + + class_member_name) + + # Gather arguments + in_args = [] + out_args = [] + for i in method.getElementsByTagName('arg'): + name = i.getAttribute('name') + direction = i.getAttribute('direction') or 'in' + dtype = i.getAttribute('type') + + assert direction in ('in', 'out') + + if name: + name = direction + '_' + name + elif direction == 'in': + name = direction + str(len(in_args)) + else: + name = direction + str(len(out_args)) + + ctype, gtype, marshaller, pointer = type_to_gtype(dtype) + + if pointer: + ctype = 'const ' + ctype + + struct = (ctype, name) + + if direction == 'in': + in_args.append(struct) + else: + out_args.append(struct) + + # Implementation type declaration (in header, docs in body) + self.b('/**') + self.b(' * %s:' % impl_name) + self.b(' * @self: The object implementing this interface') + for (ctype, name) in in_args: + self.b(' * @%s: %s (FIXME, generate documentation)' + % (name, ctype)) + self.b(' * @context: Used to return values or throw an error') + self.b(' *') + self.b(' * The signature of an implementation of the D-Bus method') + self.b(' * %s on interface %s.' % (dbus_method_name, self.iface_name)) + self.b(' */') + self.h('typedef void (*%s) (%s%s *self,' + % (impl_name, self.Prefix, self.node_name_mixed)) + for (ctype, name) in in_args: + self.h(' %s%s,' % (ctype, name)) + self.h(' DBusGMethodInvocation *context);') + + # Class member (in class definition) + in_class.append(' %s %s;' % (impl_name, class_member_name)) + + # Stub definition (in body only - it's static) + self.b('static void') + self.b('%s (%s%s *self,' + % (stub_name, self.Prefix, self.node_name_mixed)) + for (ctype, name) in in_args: + self.b(' %s%s,' % (ctype, name)) + self.b(' DBusGMethodInvocation *context)') + self.b('{') + self.b(' %s impl = (%s%s_GET_CLASS (self)->%s);' + % (impl_name, self.PREFIX_, self.node_name_uc, class_member_name)) + self.b('') + self.b(' if (impl != NULL)') + tmp = ['self'] + [name for (ctype, name) in in_args] + ['context'] + self.b(' {') + self.b(' (impl) (%s);' % ',\n '.join(tmp)) + self.b(' }') + self.b(' else') + self.b(' {') + if self.not_implemented_func: + self.b(' %s (context);' % self.not_implemented_func) + else: + self.b(' GError e = { DBUS_GERROR, ') + self.b(' DBUS_GERROR_UNKNOWN_METHOD,') + self.b(' "Method not implemented" };') + self.b('') + self.b(' dbus_g_method_return_error (context, &e);') + self.b(' }') + self.b('}') + self.b('') + + # Implementation registration (in both header and body) + self.h('void %s%s_implement_%s (%s%sClass *klass, %s impl);' + % (self.prefix_, self.node_name_lc, class_member_name, + self.Prefix, self.node_name_mixed, impl_name)) + + self.b('/**') + self.b(' * %s%s_implement_%s:' + % (self.prefix_, self.node_name_lc, class_member_name)) + self.b(' * @klass: A class whose instances implement this interface') + self.b(' * @impl: A callback used to implement the %s D-Bus method' + % dbus_method_name) + self.b(' *') + self.b(' * Register an implementation for the %s method in the vtable' + % dbus_method_name) + self.b(' * of an implementation of this interface. To be called from') + self.b(' * the interface init function.') + self.b(' */') + self.b('void') + self.b('%s%s_implement_%s (%s%sClass *klass, %s impl)' + % (self.prefix_, self.node_name_lc, class_member_name, + self.Prefix, self.node_name_mixed, impl_name)) + self.b('{') + self.b(' klass->%s = impl;' % class_member_name) + self.b('}') + self.b('') + + # Return convenience function (static inline, in header) + self.h('/**') + self.h(' * %s:' % ret_name) + self.h(' * @context: The D-Bus method invocation context') + for (ctype, name) in out_args: + self.h(' * @%s: %s (FIXME, generate documentation)' + % (name, ctype)) + self.h(' *') + self.h(' * Return successfully by calling dbus_g_method_return().') + self.h(' * This inline function exists only to provide type-safety.') + self.h(' */') + tmp = (['DBusGMethodInvocation *context'] + + [ctype + name for (ctype, name) in out_args]) + self.h('static inline') + self.h('/* this comment is to stop gtkdoc realising this is static */') + self.h(('void %s (' % ret_name) + (',\n '.join(tmp)) + ');') + self.h('static inline void') + self.h(('%s (' % ret_name) + (',\n '.join(tmp)) + ')') + self.h('{') + tmp = ['context'] + [name for (ctype, name) in out_args] + self.h(' dbus_g_method_return (' + ',\n '.join(tmp) + ');') + self.h('}') + self.h('') + + return in_class + + def get_signal_const_entry(self, signal): + assert self.node_name_uc is not None + return ('SIGNAL_%s_%s' + % (self.node_name_uc, signal.getAttribute('name'))) + + def do_signal(self, signal): + assert self.node_name_mixed is not None + + in_base_init = [] + + # for signal: Thing::StuffHappened (s, u) + # we want to emit: + # void tp_svc_thing_emit_stuff_happened (gpointer instance, + # const char *arg0, guint arg1); + + dbus_name = signal.getAttribute('name') + stub_name = (self.prefix_ + self.node_name_lc + '_emit_' + + camelcase_to_lower(dbus_name)) + const_name = self.get_signal_const_entry(signal) + + # Gather arguments + args = [] + for i in signal.getElementsByTagName('arg'): + name = i.getAttribute('name') + dtype = i.getAttribute('type') + tp_type = i.getAttribute('tp:type') + + if name: + name = 'arg_' + name + else: + name = 'arg' + str(len(args)) + + ctype, gtype, marshaller, pointer = type_to_gtype(dtype) + + if pointer: + ctype = 'const ' + ctype + + struct = (ctype, name, gtype) + args.append(struct) + + tmp = (['gpointer instance'] + + [ctype + name for (ctype, name, gtype) in args]) + + self.h(('void %s (' % stub_name) + (',\n '.join(tmp)) + ');') + + # FIXME: emit docs + + self.b('/**') + self.b(' * %s:' % stub_name) + self.b(' * @instance: The object implementing this interface') + for (ctype, name, gtype) in args: + self.b(' * @%s: %s (FIXME, generate documentation)' + % (name, ctype)) + self.b(' *') + self.b(' * Type-safe wrapper around g_signal_emit to emit the') + self.b(' * %s signal on interface %s.' + % (dbus_name, self.iface_name)) + self.b(' */') + + self.b('void') + self.b(('%s (' % stub_name) + (',\n '.join(tmp)) + ')') + self.b('{') + self.b(' g_assert (instance != NULL);') + self.b(' g_assert (G_TYPE_CHECK_INSTANCE_TYPE (instance, %s));' + % (self.current_gtype)) + tmp = (['instance', '%s_signals[%s]' % (self.node_name_lc, const_name), + '0'] + [name for (ctype, name, gtype) in args]) + self.b(' g_signal_emit (' + ',\n '.join(tmp) + ');') + self.b('}') + self.b('') + + signal_name = dbus_gutils_wincaps_to_uscore(dbus_name).replace('_', + '-') + in_base_init.append(' /**') + in_base_init.append(' * %s%s::%s:' + % (self.Prefix, self.node_name_mixed, signal_name)) + for (ctype, name, gtype) in args: + in_base_init.append(' * @%s: %s (FIXME, generate documentation)' + % (name, ctype)) + in_base_init.append(' *') + in_base_init.append(' * The %s D-Bus signal is emitted whenever ' + 'this GObject signal is.' % dbus_name) + in_base_init.append(' */') + in_base_init.append(' %s_signals[%s] =' + % (self.node_name_lc, const_name)) + in_base_init.append(' g_signal_new ("%s",' % signal_name) + in_base_init.append(' G_OBJECT_CLASS_TYPE (klass),') + in_base_init.append(' G_SIGNAL_RUN_LAST|G_SIGNAL_DETAILED,') + in_base_init.append(' 0,') + in_base_init.append(' NULL, NULL,') + in_base_init.append(' %s,' + % signal_to_marshal_name(signal, self.signal_marshal_prefix)) + in_base_init.append(' G_TYPE_NONE,') + tmp = ['%d' % len(args)] + [gtype for (ctype, name, gtype) in args] + in_base_init.append(' %s);' % ',\n '.join(tmp)) + in_base_init.append('') + + return in_base_init + + def __call__(self): + self.h('#include <glib-object.h>') + self.h('#include <dbus/dbus-glib.h>') + self.h('#include <telepathy-glib/dbus-properties-mixin.h>') + self.h('') + self.h('G_BEGIN_DECLS') + self.h('') + + self.b('#include "%s.h"' % basename) + self.b('') + for header in self.headers: + self.b('#include %s' % header) + self.b('') + + nodes = self.dom.getElementsByTagName('node') + nodes.sort(cmp_by_name) + + for node in nodes: + self.do_node(node) + + self.h('') + self.h('G_END_DECLS') + + self.b('') + for header in self.end_headers: + self.b('#include %s' % header) + + self.h('') + self.b('') + open(basename + '.h', 'w').write('\n'.join(self.__header)) + open(basename + '.c', 'w').write('\n'.join(self.__body)) + + +def cmdline_error(): + print """\ +usage: + gen-ginterface [OPTIONS] xmlfile Prefix_ +options: + --include='<header.h>' (may be repeated) + --include='"header.h"' (ditto) + --include-end='"header.h"' (ditto) + Include extra headers in the generated .c file + --signal-marshal-prefix='prefix' + Use the given prefix on generated signal marshallers (default is + prefix.lower()). + --filename='BASENAME' + Set the basename for the output files (default is prefix.lower() + + 'ginterfaces') + --not-implemented-func='symbol' + Set action when methods not implemented in the interface vtable are + called. symbol must have signature + void symbol (DBusGMethodInvocation *context) + and return some sort of "not implemented" error via + dbus_g_method_return_error (context, ...) +""" + sys.exit(1) + + +if __name__ == '__main__': + from getopt import gnu_getopt + + options, argv = gnu_getopt(sys.argv[1:], '', + ['filename=', 'signal-marshal-prefix=', + 'include=', 'include-end=', + 'allow-unstable', + 'not-implemented-func=']) + + try: + prefix = argv[1] + except IndexError: + cmdline_error() + + basename = prefix.lower() + 'ginterfaces' + signal_marshal_prefix = prefix.lower().rstrip('_') + headers = [] + end_headers = [] + not_implemented_func = '' + allow_havoc = False + + for option, value in options: + if option == '--filename': + basename = value + elif option == '--signal-marshal-prefix': + signal_marshal_prefix = value + elif option == '--include': + if value[0] not in '<"': + value = '"%s"' % value + headers.append(value) + elif option == '--include-end': + if value[0] not in '<"': + value = '"%s"' % value + end_headers.append(value) + elif option == '--not-implemented-func': + not_implemented_func = value + elif option == '--allow-unstable': + allow_havoc = True + + try: + dom = xml.dom.minidom.parse(argv[0]) + except IndexError: + cmdline_error() + + Generator(dom, prefix, basename, signal_marshal_prefix, headers, + end_headers, not_implemented_func, allow_havoc)() diff --git a/tools/glib-gtypes-generator.py b/tools/glib-gtypes-generator.py new file mode 100644 index 000000000..fcb46e841 --- /dev/null +++ b/tools/glib-gtypes-generator.py @@ -0,0 +1,230 @@ +#!/usr/bin/python + +# Generate GLib GInterfaces from the Telepathy specification. +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2006, 2007 Collabora Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +import sys +import xml.dom.minidom + +from libglibcodegen import escape_as_identifier, \ + get_docstring, \ + NS_TP, \ + Signature, \ + type_to_gtype, \ + xml_escape + + +def types_to_gtypes(types): + return [type_to_gtype(t)[1] for t in types] + + +class GTypesGenerator(object): + def __init__(self, dom, output, mixed_case_prefix): + self.dom = dom + self.Prefix = mixed_case_prefix + self.PREFIX_ = self.Prefix.upper() + '_' + self.prefix_ = self.Prefix.lower() + '_' + + self.header = open(output + '.h', 'w') + self.body = open(output + '-body.h', 'w') + + for f in (self.header, self.body): + f.write('/* Auto-generated, do not edit.\n *\n' + ' * This file may be distributed under the same terms\n' + ' * as the specification from which it was generated.\n' + ' */\n\n') + + self.need_mappings = {} + self.need_structs = {} + self.need_arrays = {} + + def do_mapping_header(self, mapping): + members = mapping.getElementsByTagNameNS(NS_TP, 'member') + assert len(members) == 2 + + impl_sig = ''.join([elt.getAttribute('type') + for elt in members]) + + esc_impl_sig = escape_as_identifier(impl_sig) + + name = (self.PREFIX_ + 'HASH_TYPE_' + + mapping.getAttribute('name').upper()) + impl = self.prefix_ + 'type_dbus_hash_' + esc_impl_sig + + docstring = get_docstring(mapping) or '(Undocumented)' + + self.header.write('/**\n * %s:\n *\n' % name) + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + self.header.write(' * This macro expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GHashTable\n') + self.header.write(' * appropriate for representing a D-Bus\n') + self.header.write(' * dictionary of signature\n') + self.header.write(' * <literal>a{%s}</literal>.\n' % impl_sig) + self.header.write(' *\n') + + key, value = members + + self.header.write(' * Keys (D-Bus type <literal>%s</literal>,\n' + % key.getAttribute('type')) + tp_type = key.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % key.getAttribute('name')) + docstring = get_docstring(key) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' * Values (D-Bus type <literal>%s</literal>,\n' + % value.getAttribute('type')) + tp_type = value.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % value.getAttribute('name')) + docstring = get_docstring(value) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' */\n') + + self.header.write('#define %s (%s ())\n\n' % (name, impl)) + self.need_mappings[impl_sig] = esc_impl_sig + + def do_struct_header(self, struct): + members = struct.getElementsByTagNameNS(NS_TP, 'member') + impl_sig = ''.join([elt.getAttribute('type') for elt in members]) + esc_impl_sig = escape_as_identifier(impl_sig) + + name = (self.PREFIX_ + 'STRUCT_TYPE_' + + struct.getAttribute('name').upper()) + impl = self.prefix_ + 'type_dbus_struct_' + esc_impl_sig + docstring = struct.getElementsByTagNameNS(NS_TP, 'docstring') + if docstring: + docstring = docstring[0].toprettyxml() + if docstring.startswith('<tp:docstring>'): + docstring = docstring[14:] + if docstring.endswith('</tp:docstring>\n'): + docstring = docstring[:-16] + if docstring.strip() in ('<tp:docstring/>', ''): + docstring = '(Undocumented)' + else: + docstring = '(Undocumented)' + self.header.write('/**\n * %s:\n\n' % name) + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + self.header.write(' * This macro expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GValueArray\n') + self.header.write(' * appropriate for representing a D-Bus struct\n') + self.header.write(' * with signature <literal>(%s)</literal>.\n' + % impl_sig) + self.header.write(' *\n') + + for i, member in enumerate(members): + self.header.write(' * Member %d (D-Bus type ' + '<literal>%s</literal>,\n' + % (i, member.getAttribute('type'))) + tp_type = member.getAttributeNS(NS_TP, 'type') + if tp_type: + self.header.write(' * type <literal>%s</literal>,\n' % tp_type) + self.header.write(' * named <literal>%s</literal>):\n' + % member.getAttribute('name')) + docstring = get_docstring(member) or '(Undocumented)' + self.header.write(' * %s\n' % xml_escape(docstring)) + self.header.write(' *\n') + + self.header.write(' */\n') + self.header.write('#define %s (%s ())\n\n' % (name, impl)) + + array_name = struct.getAttribute('array-name') + if array_name != '': + array_name = (self.PREFIX_ + 'ARRAY_TYPE_' + array_name.upper()) + impl = self.prefix_ + 'type_dbus_array_' + esc_impl_sig + self.header.write('/**\n * %s:\n\n' % array_name) + self.header.write(' * Expands to a call to a function\n') + self.header.write(' * that returns the #GType of a #GPtrArray\n') + self.header.write(' * of #%s.\n' % name) + self.header.write(' */\n') + self.header.write('#define %s (%s ())\n\n' % (array_name, impl)) + self.need_arrays[impl_sig] = esc_impl_sig + + self.need_structs[impl_sig] = esc_impl_sig + + def __call__(self): + mappings = self.dom.getElementsByTagNameNS(NS_TP, 'mapping') + structs = self.dom.getElementsByTagNameNS(NS_TP, 'struct') + + for mapping in mappings: + self.do_mapping_header(mapping) + + for sig in self.need_mappings: + self.header.write('GType %stype_dbus_hash_%s (void);\n\n' % + (self.prefix_, self.need_mappings[sig])) + self.body.write('GType\n%stype_dbus_hash_%s (void)\n{\n' % + (self.prefix_, self.need_mappings[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + # FIXME: translate sig into two GTypes + items = tuple(Signature(sig)) + gtypes = types_to_gtypes(items) + self.body.write(' t = dbus_g_type_get_map ("GHashTable", ' + '%s, %s);\n' % (gtypes[0], gtypes[1])) + self.body.write(' return t;\n') + self.body.write('}\n\n') + + for struct in structs: + self.do_struct_header(struct) + + for sig in self.need_structs: + self.header.write('GType %stype_dbus_struct_%s (void);\n\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write('GType\n%stype_dbus_struct_%s (void)\n{\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + self.body.write(' t = dbus_g_type_get_struct ("GValueArray",\n') + items = tuple(Signature(sig)) + gtypes = types_to_gtypes(items) + for gtype in gtypes: + self.body.write(' %s,\n' % gtype) + self.body.write(' G_TYPE_INVALID);\n') + self.body.write(' return t;\n') + self.body.write('}\n\n') + + for sig in self.need_arrays: + self.header.write('GType %stype_dbus_array_%s (void);\n\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write('GType\n%stype_dbus_array_%s (void)\n{\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' static GType t = 0;\n\n') + self.body.write(' if (G_UNLIKELY (t == 0))\n') + self.body.write(' t = dbus_g_type_get_collection ("GPtrArray", ' + '%stype_dbus_struct_%s ());\n' % + (self.prefix_, self.need_structs[sig])) + self.body.write(' return t;\n') + self.body.write('}\n\n') + +if __name__ == '__main__': + argv = sys.argv[1:] + + dom = xml.dom.minidom.parse(argv[0]) + + GTypesGenerator(dom, argv[1], argv[2])() diff --git a/tools/glib-interfaces-gen.py b/tools/glib-interfaces-gen.py new file mode 100644 index 000000000..741626ceb --- /dev/null +++ b/tools/glib-interfaces-gen.py @@ -0,0 +1,97 @@ +#!/usr/bin/python + +from sys import argv, stdout, stderr +import xml.dom.minidom + +from libglibcodegen import NS_TP, camelcase_to_upper, get_docstring, \ + get_descendant_text, get_by_path + +class Generator(object): + def __init__(self, prefix, implfile, declfile, dom): + self.prefix = prefix + '_' + self.impls = open(implfile, 'w') + self.decls = open(declfile, 'w') + self.spec = get_by_path(dom, "spec")[0] + + def __call__(self): + for file in self.decls, self.impls: + self.do_header(file) + self.do_body() + + # Header + def do_header(self, file): + file.write('/* Generated from: ') + file.write(get_descendant_text(get_by_path(self.spec, 'title'))) + version = get_by_path(self.spec, "version") + if version: + file.write(' version ' + get_descendant_text(version)) + file.write('\n\n') + for copyright in get_by_path(self.spec, 'copyright'): + stdout.write(get_descendant_text(copyright)) + stdout.write('\n') + file.write('\n') + file.write(get_descendant_text(get_by_path(self.spec, 'license'))) + file.write(get_descendant_text(get_by_path(self.spec, 'docstring'))) + file.write(""" + */ + +""") + + # Body + def do_body(self): + for iface in self.spec.getElementsByTagName('interface'): + self.do_iface(iface) + + def do_iface(self, iface): + parent_name = get_by_path(iface, '../@name') + self.decls.write("""\ +/** + * %(IFACE_DEFINE)s: + * + * The interface name "%(name)s" + */ +#define %(IFACE_DEFINE)s \\ +"%(name)s" +""" % {'IFACE_DEFINE' : (self.prefix + 'IFACE_' + \ + parent_name).upper().replace('/', ''), + 'name' : iface.getAttribute('name')}) + + self.decls.write(""" +/** + * %(IFACE_QUARK_DEFINE)s: + * + * Expands to a call to a function that returns a quark for the interface \ +name "%(name)s" + */ +#define %(IFACE_QUARK_DEFINE)s \\ + (%(iface_quark_func)s ()) + +GQuark %(iface_quark_func)s (void); + +""" % {'IFACE_QUARK_DEFINE' : (self.prefix + 'IFACE_QUARK_' + \ + parent_name).upper().replace('/', ''), + 'iface_quark_func' : (self.prefix + 'iface_quark_' + \ + parent_name).lower().replace('/', ''), + 'name' : iface.getAttribute('name')}) + + self.impls.write("""\ +GQuark +%(iface_quark_func)s (void) +{ + static GQuark quark = 0; + + if (G_UNLIKELY (quark == 0)) + { + quark = g_quark_from_static_string ("%(name)s"); + } + + return quark; +} + +""" % {'iface_quark_func' : (self.prefix + 'iface_quark_' + \ + parent_name).lower().replace('/', ''), + 'name' : iface.getAttribute('name')}) + +if __name__ == '__main__': + argv = argv[1:] + Generator(argv[0], argv[1], argv[2], xml.dom.minidom.parse(argv[3]))() diff --git a/tools/glib-signals-marshal-gen.py b/tools/glib-signals-marshal-gen.py new file mode 100644 index 000000000..0d02c1341 --- /dev/null +++ b/tools/glib-signals-marshal-gen.py @@ -0,0 +1,55 @@ +#!/usr/bin/python + +import sys +import xml.dom.minidom +from string import ascii_letters, digits + + +from libglibcodegen import signal_to_marshal_name, method_to_glue_marshal_name + + +class Generator(object): + + def __init__(self, dom): + self.dom = dom + self.marshallers = {} + + def do_method(self, method): + marshaller = method_to_glue_marshal_name(method, 'PREFIX') + + assert '__' in marshaller + rhs = marshaller.split('__', 1)[1].split('_') + + self.marshallers[marshaller] = rhs + + def do_signal(self, signal): + marshaller = signal_to_marshal_name(signal, 'PREFIX') + + assert '__' in marshaller + rhs = marshaller.split('__', 1)[1].split('_') + + self.marshallers[marshaller] = rhs + + def __call__(self): + methods = self.dom.getElementsByTagName('method') + + for method in methods: + self.do_method(method) + + signals = self.dom.getElementsByTagName('signal') + + for signal in signals: + self.do_signal(signal) + + all = self.marshallers.keys() + all.sort() + for marshaller in all: + rhs = self.marshallers[marshaller] + if not marshaller.startswith('g_cclosure'): + print 'VOID:' + ','.join(rhs) + +if __name__ == '__main__': + argv = sys.argv[1:] + dom = xml.dom.minidom.parse(argv[0]) + + Generator(dom)() diff --git a/tools/gobject-foo.py b/tools/gobject-foo.py new file mode 100644 index 000000000..5921cab8a --- /dev/null +++ b/tools/gobject-foo.py @@ -0,0 +1,81 @@ +#!/usr/bin/python + +# gobject-foo.py: generate standard GObject type macros etc. +# +# The master copy of this program is in the telepathy-glib repository - +# please make any changes there. +# +# Copyright (C) 2007 Collabora Ltd. <http://www.collabora.co.uk/> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +def gobject_header(head, tail, as_interface=False): + out = [] + o = out.append + + name = head + '_' + tail + MixedCase = name.replace('_', '') + lower_case = name.lower() + UPPER_CASE = name.upper() + + gtype = head.upper() + '_TYPE_' + tail.upper() + + o("typedef struct _%s %s;" % (MixedCase, MixedCase)) + o("typedef struct _%sClass %sClass;" % (MixedCase, MixedCase)) + o("typedef struct _%sPrivate %sPrivate;" % (MixedCase, MixedCase)) + o("") + o("GType %s_get_type (void);" % lower_case) + o("") + + o("#define %s \\" % gtype) + o(" (%s_get_type ())" % lower_case) + + o("#define %s(obj) \\" % UPPER_CASE) + o(" (G_TYPE_CHECK_INSTANCE_CAST ((obj), %s, \\" % gtype) + o(" %s))" % MixedCase) + + if not as_interface: + o("#define %s_CLASS(klass) \\" % UPPER_CASE) + o(" (G_TYPE_CHECK_CLASS_CAST ((klass), %s, \\" % gtype) + o(" %sClass))" % MixedCase) + + o("#define %s_IS_%s(obj) \\" % (head.upper(), tail.upper())) + o(" (G_TYPE_CHECK_INSTANCE_TYPE ((obj), %s))" % gtype) + + if not as_interface: + o("#define %s_IS_%s_CLASS(klass) \\" % (head.upper(), tail.upper())) + o(" (G_TYPE_CHECK_CLASS_TYPE ((klass), %s))" % gtype) + + o("#define %s_GET_CLASS(obj) \\" % UPPER_CASE) + o(" (G_TYPE_INSTANCE_GET_CLASS ((obj), %s, \\" % gtype) + o(" %sClass))" % MixedCase) + + return out + +if __name__ == '__main__': + import sys + from getopt import gnu_getopt + + options, argv = gnu_getopt(sys.argv[1:], '', ['interface']) + + as_interface = False + + for opt, val in options: + if opt == '--interface': + as_interface = True + + head, tail = argv + + print '\n'.join(gobject_header(head, tail, as_interface=as_interface)) diff --git a/tools/identity.xsl b/tools/identity.xsl new file mode 100644 index 000000000..6630f84de --- /dev/null +++ b/tools/identity.xsl @@ -0,0 +1,7 @@ +<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> + <xsl:template match="@*|node()"> + <xsl:copy> + <xsl:apply-templates select="@*|node()"/> + </xsl:copy> + </xsl:template> +</xsl:stylesheet> diff --git a/tools/lcov.am b/tools/lcov.am new file mode 100644 index 000000000..97eed8f41 --- /dev/null +++ b/tools/lcov.am @@ -0,0 +1,23 @@ +lcov-reset: + lcov --directory @top_srcdir@ --zerocounters + +lcov-report: + lcov --directory @top_srcdir@ --capture \ + --output-file @top_builddir@/lcov.info.tmp + lcov --directory @top_srcdir@ --output-file @top_builddir@/lcov.info \ + --remove @top_builddir@/lcov.info.tmp telepathy-glib-scan.c + rm @top_builddir@/lcov.info.tmp + $(mkdir_p) @top_builddir@/lcov.html + genhtml --title telepathy-glib \ + --output-directory @top_builddir@/lcov.html lcov.info + @echo + @echo 'lcov report can be found in:' + @echo 'file://@abs_top_builddir@/lcov.html/index.html' + @echo + +lcov-check: + $(MAKE) lcov-reset + $(MAKE) check + $(MAKE) lcov-report + +## vim:set ft=automake: diff --git a/tools/libglibcodegen.py b/tools/libglibcodegen.py new file mode 100644 index 000000000..129c179e7 --- /dev/null +++ b/tools/libglibcodegen.py @@ -0,0 +1,173 @@ +"""Library code for GLib/D-Bus-related code generation. + +The master copy of this library is in the telepathy-glib repository - +please make any changes there. +""" + +# Copyright (C) 2006-2008 Collabora Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +from libtpcodegen import NS_TP, \ + Signature, \ + camelcase_to_lower, \ + camelcase_to_upper, \ + cmp_by_name, \ + escape_as_identifier, \ + get_by_path, \ + get_descendant_text, \ + get_docstring, \ + xml_escape + +def dbus_gutils_wincaps_to_uscore(s): + """Bug-for-bug compatible Python port of _dbus_gutils_wincaps_to_uscore + which gets sequences of capital letters wrong in the same way. + (e.g. in Telepathy, SendDTMF -> send_dt_mf) + """ + ret = '' + for c in s: + if c >= 'A' and c <= 'Z': + length = len(ret) + if length > 0 and (length < 2 or ret[length-2] != '_'): + ret += '_' + ret += c.lower() + else: + ret += c + return ret + + +def signal_to_marshal_type(signal): + """ + return a list of strings indicating the marshalling type for this signal. + """ + + mtype=[] + for i in signal.getElementsByTagName("arg"): + name =i.getAttribute("name") + type = i.getAttribute("type") + mtype.append(type_to_gtype(type)[2]) + + return mtype + + +_glib_marshallers = ['VOID', 'BOOLEAN', 'CHAR', 'UCHAR', 'INT', + 'STRING', 'UINT', 'LONG', 'ULONG', 'ENUM', 'FLAGS', 'FLOAT', + 'DOUBLE', 'STRING', 'PARAM', 'BOXED', 'POINTER', 'OBJECT', + 'UINT_POINTER'] + + +def signal_to_marshal_name(signal, prefix): + + mtype = signal_to_marshal_type(signal) + if len(mtype): + name = '_'.join(mtype) + else: + name = 'VOID' + + if name in _glib_marshallers: + return 'g_cclosure_marshal_VOID__' + name + else: + return prefix + '_marshal_VOID__' + name + + +def method_to_glue_marshal_name(method, prefix): + + mtype = [] + for i in method.getElementsByTagName("arg"): + if i.getAttribute("direction") != "out": + type = i.getAttribute("type") + mtype.append(type_to_gtype(type)[2]) + + mtype.append('POINTER') + + name = '_'.join(mtype) + + if name in _glib_marshallers: + return 'g_cclosure_marshal_VOID__' + name + else: + return prefix + '_marshal_VOID__' + name + + +def type_to_gtype(s): + if s == 'y': #byte + return ("guchar ", "G_TYPE_UCHAR","UCHAR", False) + elif s == 'b': #boolean + return ("gboolean ", "G_TYPE_BOOLEAN","BOOLEAN", False) + elif s == 'n': #int16 + return ("gint ", "G_TYPE_INT","INT", False) + elif s == 'q': #uint16 + return ("guint ", "G_TYPE_UINT","UINT", False) + elif s == 'i': #int32 + return ("gint ", "G_TYPE_INT","INT", False) + elif s == 'u': #uint32 + return ("guint ", "G_TYPE_UINT","UINT", False) + elif s == 'x': #int64 + return ("gint64 ", "G_TYPE_INT64","INT64", False) + elif s == 't': #uint64 + return ("guint64 ", "G_TYPE_UINT64","UINT64", False) + elif s == 'd': #double + return ("gdouble ", "G_TYPE_DOUBLE","DOUBLE", False) + elif s == 's': #string + return ("gchar *", "G_TYPE_STRING", "STRING", True) + elif s == 'g': #signature - FIXME + return ("gchar *", "DBUS_TYPE_G_SIGNATURE", "STRING", True) + elif s == 'o': #object path + return ("gchar *", "DBUS_TYPE_G_OBJECT_PATH", "BOXED", True) + elif s == 'v': #variant + return ("GValue *", "G_TYPE_VALUE", "BOXED", True) + elif s == 'as': #array of strings + return ("gchar **", "G_TYPE_STRV", "BOXED", True) + elif s == 'ay': #byte array + return ("GArray *", + "dbus_g_type_get_collection (\"GArray\", G_TYPE_UCHAR)", "BOXED", + True) + elif s == 'au': #uint array + return ("GArray *", "DBUS_TYPE_G_UINT_ARRAY", "BOXED", True) + elif s == 'ai': #int array + return ("GArray *", "DBUS_TYPE_G_INT_ARRAY", "BOXED", True) + elif s == 'ax': #int64 array + return ("GArray *", "DBUS_TYPE_G_INT64_ARRAY", "BOXED", True) + elif s == 'at': #uint64 array + return ("GArray *", "DBUS_TYPE_G_UINT64_ARRAY", "BOXED", True) + elif s == 'ad': #double array + return ("GArray *", "DBUS_TYPE_G_DOUBLE_ARRAY", "BOXED", True) + elif s == 'ab': #boolean array + return ("GArray *", "DBUS_TYPE_G_BOOLEAN_ARRAY", "BOXED", True) + elif s == 'ao': #object path array + return ("GPtrArray *", + 'dbus_g_type_get_collection ("GPtrArray",' + ' DBUS_TYPE_G_OBJECT_PATH)', + "BOXED", True) + elif s == 'a{ss}': #hash table of string to string + return ("GHashTable *", "DBUS_TYPE_G_STRING_STRING_HASHTABLE", "BOXED", False) + elif s[:2] == 'a{': #some arbitrary hash tables + if s[2] not in ('y', 'b', 'n', 'q', 'i', 'u', 's', 'o', 'g'): + raise Exception, "can't index a hashtable off non-basic type " + s + first = type_to_gtype(s[2]) + second = type_to_gtype(s[3:-1]) + return ("GHashTable *", "(dbus_g_type_get_map (\"GHashTable\", " + first[1] + ", " + second[1] + "))", "BOXED", False) + elif s[:2] in ('a(', 'aa'): # array of structs or arrays, recurse + gtype = type_to_gtype(s[1:])[1] + return ("GPtrArray *", "(dbus_g_type_get_collection (\"GPtrArray\", "+gtype+"))", "BOXED", True) + elif s[:1] == '(': #struct + gtype = "(dbus_g_type_get_struct (\"GValueArray\", " + for subsig in Signature(s[1:-1]): + gtype = gtype + type_to_gtype(subsig)[1] + ", " + gtype = gtype + "G_TYPE_INVALID))" + return ("GValueArray *", gtype, "BOXED", True) + + # we just don't know .. + raise Exception, "don't know the GType for " + s diff --git a/tools/libtpcodegen.py b/tools/libtpcodegen.py new file mode 100644 index 000000000..6391f1a48 --- /dev/null +++ b/tools/libtpcodegen.py @@ -0,0 +1,231 @@ +"""Library code for language-independent D-Bus-related code generation. + +The master copy of this library is in the telepathy-glib repository - +please make any changes there. +""" + +# Copyright (C) 2006-2008 Collabora Limited +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + + +from string import ascii_letters, digits + + +NS_TP = "http://telepathy.freedesktop.org/wiki/DbusSpec#extensions-v0" + +_ASCII_ALNUM = ascii_letters + digits + + +def camelcase_to_lower(s): + out =""; + out += s[0].lower() + last_upper=False + if s[0].isupper(): + last_upper=True + for i in range(1,len(s)): + if s[i].isupper(): + if last_upper: + if (i+1) < len(s) and s[i+1].islower(): + out += "_" + s[i].lower() + else: + out += s[i].lower() + else: + out += "_" + s[i].lower() + last_upper=True + else: + out += s[i] + last_upper=False + return out + + +def camelcase_to_upper(s): + return camelcase_to_lower(s).upper() + + +def cmp_by_name(node1, node2): + return cmp(node1.getAttributeNode("name").nodeValue, + node2.getAttributeNode("name").nodeValue) + + +def escape_as_identifier(identifier): + """Escape the given string to be a valid D-Bus object path or service + name component, using a reversible encoding to ensure uniqueness. + + The reversible encoding is as follows: + + * The empty string becomes '_' + * Otherwise, each non-alphanumeric character is replaced by '_' plus + two lower-case hex digits; the same replacement is carried out on + the first character, if it's a digit + """ + # '' -> '_' + if not identifier: + return '_' + + # A bit of a fast path for strings which are already OK. + # We deliberately omit '_' because, for reversibility, that must also + # be escaped. + if (identifier.strip(_ASCII_ALNUM) == '' and + identifier[0] in ascii_letters): + return identifier + + # The first character may not be a digit + if identifier[0] not in ascii_letters: + ret = ['_%02x' % ord(identifier[0])] + else: + ret = [identifier[0]] + + # Subsequent characters may be digits or ASCII letters + for c in identifier[1:]: + if c in _ASCII_ALNUM: + ret.append(c) + else: + ret.append('_%02x' % ord(c)) + + return ''.join(ret) + + +def get_by_path(element, path): + branches = path.split('/') + branch = branches[0] + + # Is the current branch an attribute, if so, return the attribute value + if branch[0] == '@': + return element.getAttribute(branch[1:]) + + # Find matching children for the branch + children = [] + if branch == '..': + children.append(element.parentNode) + else: + for x in element.childNodes: + if x.localName == branch: + children.append(x) + + ret = [] + # If this is not the last path element, recursively gather results from + # children + if len(branches) > 1: + for x in children: + add = get_by_path(x, '/'.join(branches[1:])) + if isinstance(add, list): + ret += add + else: + return add + else: + ret = children + + return ret + + +def get_docstring(element): + docstring = None + for x in element.childNodes: + if x.namespaceURI == NS_TP and x.localName == 'docstring': + docstring = x + if docstring is not None: + docstring = docstring.toxml().replace('\n', ' ').strip() + if docstring.startswith('<tp:docstring>'): + docstring = docstring[14:].lstrip() + if docstring.endswith('</tp:docstring>'): + docstring = docstring[:-15].rstrip() + if docstring in ('<tp:docstring/>', ''): + docstring = '' + return docstring + + +def get_descendant_text(element_or_elements): + if not element_or_elements: + return '' + if isinstance(element_or_elements, list): + return ''.join(map(get_descendant_text, element_or_elements)) + parts = [] + for x in element_or_elements.childNodes: + if x.nodeType == x.TEXT_NODE: + parts.append(x.nodeValue) + elif x.nodeType == x.ELEMENT_NODE: + parts.append(get_descendant_text(x)) + else: + pass + return ''.join(parts) + + +class _SignatureIter: + """Iterator over a D-Bus signature. Copied from dbus-python 0.71 so we + can run genginterface in a limited environment with only Python + (like Scratchbox). + """ + def __init__(self, string): + self.remaining = string + + def next(self): + if self.remaining == '': + raise StopIteration + + signature = self.remaining + block_depth = 0 + block_type = None + end = len(signature) + + for marker in range(0, end): + cur_sig = signature[marker] + + if cur_sig == 'a': + pass + elif cur_sig == '{' or cur_sig == '(': + if block_type == None: + block_type = cur_sig + + if block_type == cur_sig: + block_depth = block_depth + 1 + + elif cur_sig == '}': + if block_type == '{': + block_depth = block_depth - 1 + + if block_depth == 0: + end = marker + break + + elif cur_sig == ')': + if block_type == '(': + block_depth = block_depth - 1 + + if block_depth == 0: + end = marker + break + + else: + if block_depth == 0: + end = marker + break + + end = end + 1 + self.remaining = signature[end:] + return Signature(signature[0:end]) + + +class Signature(str): + """A string, iteration over which is by D-Bus single complete types + rather than characters. + """ + def __iter__(self): + return _SignatureIter(self) + + +def xml_escape(s): + s = s.replace('&', '&').replace("'", ''').replace('"', '"') + return s.replace('<', '<').replace('>', '>') diff --git a/tools/make-version-script.py b/tools/make-version-script.py new file mode 100644 index 000000000..91306a014 --- /dev/null +++ b/tools/make-version-script.py @@ -0,0 +1,205 @@ +#!/usr/bin/python + +"""Construct a GNU ld or Debian dpkg version-script from a set of +RFC822-style symbol lists. + +Usage: + make-version-script.py [--symbols SYMBOLS] [--unreleased-version VER] + [--dpkg "LIBRARY.so.0 LIBRARY0 #MINVER#"] + [--dpkg-build-depends-package LIBRARY-dev] + [FILES...] + +Each FILE starts with RFC822-style headers "Version:" (the name of the +symbol version, e.g. FOO_1.2.3) and "Extends:" (either the previous +version, or "-" if this is the first version). Next there is a blank +line, then a list of C symbols one per line. + +Comments (lines starting with whitespace + "#") are allowed and ignored. + +If --symbols is given, SYMBOLS lists the symbols actually exported by +the library (one per line). If --unreleased-version is given, any symbols +in SYMBOLS but not in FILES are assigned to that version; otherwise, any +such symbols cause an error. + +If --dpkg is given, produce a Debian dpkg-gensymbols file instead of a +GNU ld version-script. The argument to --dpkg is the first line of the +resulting symbols file, and --dpkg-build-depends-package can optionally +be used to set the Build-Depends-Package field. + +This script originates in telepathy-glib <http://telepathy.freedesktop.org/> - +please send us any changes that are needed. +""" + +# Copyright (C) 2008 Collabora Ltd. <http://www.collabora.co.uk/> +# Copyright (C) 2008 Nokia Corporation +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +import sys +from getopt import gnu_getopt +from sets import Set as set + + +def e(format, *args): + sys.stderr.write((format + '\n') % args) + + +def main(abifiles, symbols=None, unreleased_version=None, + dpkg=False, dpkg_first_line=None, dpkg_build_depends_package=None): + + gnuld = not dpkg + symbol_set = None + + if symbols is not None: + symbol_set = open(symbols, 'r').readlines() + symbol_set = map(str.strip, symbol_set) + symbol_set = set(symbol_set) + + versioned_symbols = set() + + dpkg_symbols = [] + dpkg_versions = [] + + if dpkg: + assert dpkg_first_line is not None + print dpkg_first_line + if dpkg_build_depends_package is not None: + print "* Build-Depends-Package: %s" % dpkg_build_depends_package + + for filename in abifiles: + lines = open(filename, 'r').readlines() + + version = None + extends = None + release = None + + for i, line in enumerate(lines): + line = line.strip() + + if line.startswith('#'): + continue + elif not line: + # the transition betwen headers and symbols + cut = i + 1 + break + elif line.lower().startswith('version:'): + line = line[8:].strip() + version = line + continue + elif line.lower().startswith('extends:'): + line = line[8:].strip() + extends = line + continue + elif line.lower().startswith('release:'): + release = line[8:].strip() + continue + else: + e('Could not understand line in %s header: %s', filename, line) + raise SystemExit(1) + + else: + e('No symbols in %s', filename) + raise SystemExit(1) + + if version is None: + e('No Versions: header in %s', filename) + raise SystemExit(1) + + if extends is None: + e('No Extends: header in %s', filename) + raise SystemExit(1) + + if release is None and dpkg: + e('No Release: header in %s', filename) + raise SystemExit(1) + + if dpkg: + dpkg_versions.append('%s@%s %s' % (version, version, release)) + + lines = lines[cut:] + + if gnuld: + print "%s {" % version + print " global:" + + for symbol in lines: + symbol = symbol.strip() + + if symbol.startswith('#'): + continue + + if gnuld: + print " %s;" % symbol + elif dpkg: + dpkg_symbols.append('%s@%s %s' % (symbol, version, release)) + + versioned_symbols.add(symbol) + + if gnuld: + if extends == '-': + print " local:" + print " *;" + print "};" + else: + print "} %s;" % extends + print + + if dpkg: + dpkg_symbols.sort() + dpkg_versions.sort() + + for x in dpkg_versions: + print " %s" % x + + for x in dpkg_symbols: + print " %s" % x + + if symbol_set is not None: + missing = versioned_symbols - symbol_set + + if missing: + e('These symbols have disappeared:') + + for symbol in missing: + e(' %s', symbol) + + raise SystemExit(1) + + unreleased = symbol_set - versioned_symbols + + if unreleased: + if unreleased_version is None: + e('Unversioned symbols are not allowed in releases:') + + for symbol in unreleased: + e(' %s', symbol) + + raise SystemExit(1) + + if gnuld: + print "%s {" % unreleased_version + print " global:" + + for symbol in unreleased: + print " %s;" % symbol + + print "} %s;" % version + + +if __name__ == '__main__': + options, argv = gnu_getopt (sys.argv[1:], '', + ['symbols=', 'unreleased-version=', + 'dpkg=', 'dpkg-build-depends-package=']) + + opts = {'dpkg': False} + + for option, value in options: + if option == '--dpkg': + opts['dpkg'] = True + opts['dpkg_first_line'] = value + else: + opts[option.lstrip('-').replace('-', '_')] = value + + main(argv, **opts) diff --git a/tools/shave.mk b/tools/shave.mk new file mode 100644 index 000000000..53cb3bf5e --- /dev/null +++ b/tools/shave.mk @@ -0,0 +1 @@ +QUIET_GEN = $(Q:@=@echo ' GEN '$@;) diff --git a/tools/telepathy-glib-env.in b/tools/telepathy-glib-env.in new file mode 100644 index 000000000..ddc47bfd8 --- /dev/null +++ b/tools/telepathy-glib-env.in @@ -0,0 +1,9 @@ +#!/bin/sh +abs_top_builddir="@abs_top_builddir@" +export abs_top_builddir +LD_LIBRARY_PATH="${abs_top_builddir}/telepathy-glib/.libs${LD_LIBRARY_PATH:+":${LD_LIBRARY_PATH}"}" +export LD_LIBRARY_PATH +G_DEBUG="fatal_criticals,fatal_warnings${G_DEBUG:+",${G_DEBUG}"}" +export G_DEBUG + +exec "$@" diff --git a/tools/telepathy.am b/tools/telepathy.am new file mode 100644 index 000000000..d061b8918 --- /dev/null +++ b/tools/telepathy.am @@ -0,0 +1,27 @@ +## Useful top-level Makefile.am snippets for Telepathy projects. + +dist-hook: + chmod u+w ${distdir}/ChangeLog + if test -d ${top_srcdir}/.git; then \ + git log --stat > ${distdir}/ChangeLog || \ + git log > ${distdir}/ChangeLog; \ + fi + +maintainer-upload-release: _maintainer-upload-release + +_maintainer-upload-release-check: + @case @VERSION@ in \ + (*.*.*.*) \ + echo "@VERSION@ is not a release" >&2; \ + exit 2; \ + ;; \ + esac + test -f @PACKAGE@-@VERSION@.tar.gz + test -f @PACKAGE@-@VERSION@.tar.gz.asc + gpg --verify @PACKAGE@-@VERSION@.tar.gz.asc + +_maintainer-upload-release: _maintainer-upload-release-check + rsync -vzP @PACKAGE@-@VERSION@.tar.gz telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz + rsync -vzP @PACKAGE@-@VERSION@.tar.gz.asc telepathy.freedesktop.org:/srv/telepathy.freedesktop.org/www/releases/@PACKAGE@/@PACKAGE@-@VERSION@.tar.gz.asc + +## vim:set ft=automake: diff --git a/tools/with-session-bus.sh b/tools/with-session-bus.sh new file mode 100644 index 000000000..519b9b1c8 --- /dev/null +++ b/tools/with-session-bus.sh @@ -0,0 +1,84 @@ +#!/bin/sh +# with-session-bus.sh - run a program with a temporary D-Bus session daemon +# +# The canonical location of this program is the telepathy-glib tools/ +# directory, please synchronize any changes with that copy. +# +# Copyright (C) 2007-2008 Collabora Ltd. <http://www.collabora.co.uk/> +# +# Copying and distribution of this file, with or without modification, +# are permitted in any medium without royalty provided the copyright +# notice and this notice are preserved. + +set -e + +me=with-session-bus + +dbus_daemon_args="--print-address=5 --print-pid=6 --fork" + +usage () +{ + echo "usage: $me [options] -- program [program_options]" >&2 + echo "Requires write access to the current directory." >&2 + echo "" >&2 + echo "If \$WITH_SESSION_BUS_FORK_DBUS_MONITOR is set, fork dbus-monitor" >&2 + echo "with the arguments in \$WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT." >&2 + echo "The output of dbus-monitor is saved in $me-<pid>.dbus-monitor-logs" >&2 + exit 2 +} + +while test "z$1" != "z--"; do + case "$1" in + --session) + dbus_daemon_args="$dbus_daemon_args --session" + shift + ;; + --config-file=*) + # FIXME: assumes config file doesn't contain any special characters + dbus_daemon_args="$dbus_daemon_args $1" + shift + ;; + *) + usage + ;; + esac +done +shift +if test "z$1" = "z"; then usage; fi + +exec 5> $me-$$.address +exec 6> $me-$$.pid + +cleanup () +{ + pid=`head -n1 $me-$$.pid` + if test -n "$pid" ; then + echo "Killing temporary bus daemon: $pid" >&2 + kill -INT "$pid" + fi + rm -f $me-$$.address + rm -f $me-$$.pid +} + +trap cleanup INT HUP TERM +dbus-daemon $dbus_daemon_args + +{ echo -n "Temporary bus daemon is "; cat $me-$$.address; } >&2 +{ echo -n "Temporary bus daemon PID is "; head -n1 $me-$$.pid; } >&2 + +e=0 +DBUS_SESSION_BUS_ADDRESS="`cat $me-$$.address`" +export DBUS_SESSION_BUS_ADDRESS + +if [ -n "$WITH_SESSION_BUS_FORK_DBUS_MONITOR" ] ; then + echo -n "Forking dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT" >&2 + dbus-monitor $WITH_SESSION_BUS_FORK_DBUS_MONITOR_OPT \ + &> $me-$$.dbus-monitor-logs & +fi + +"$@" || e=$? + +trap - INT HUP TERM +cleanup + +exit $e |