diff --git a/NOTES_TO_PACKAGE_MAINTAINERS b/NOTES_TO_PACKAGE_MAINTAINERS index fd931f4b..b6396260 100644 --- a/NOTES_TO_PACKAGE_MAINTAINERS +++ b/NOTES_TO_PACKAGE_MAINTAINERS @@ -1,29 +1,35 @@ +# Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+ + To: distribution package maintainers Those are a few things about this project that you should know. I surely welcome patches to support both in a better way. libnozzle is a simple commodity library currently used by corosync, to manage tun/tap devices. libknet is the core of this project. It is considered stable and supported in the stable* branches and still under heavy development in master branch. Upstream does guarantee onwire and update compatibility between releases in the same major versions (aka 1.x will always be able to talk to 1.x+n). There is NO guarantee of onwire compatibility between major versions of knet (aka: 1.x might not be able to talk to 2.x). libknet has a lot of build dependencies due to its modular implementation. It does not, however, link with all those libraries but uses a dlopen model to save runtime resources and provide flexibility to users to install only the libraries they are planning to use. Make sure that you do build with all feature enabled (compatible with your distribution licencing/patent policy of course) and tune your packaging to Recommend/Suggest the external libraries. Thanks Your upstream maintainers diff --git a/build-aux/knet_valgrind_helgrind.supp b/build-aux/knet_valgrind_helgrind.supp index 116ee4cf..d3976c29 100644 --- a/build-aux/knet_valgrind_helgrind.supp +++ b/build-aux/knet_valgrind_helgrind.supp @@ -1,43 +1,49 @@ +# Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+ + { link enable/disable known race (safe to ignore) Helgrind:Race fun:_link_updown fun:knet_link_set_enable fun:test fun:main } { link enable/disable known race (safe to ignore) Helgrind:Race fun:_handle_heartbt_thread obj:/usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so fun:start_thread fun:clone } { helgrind glitch in parsing the heartbeat code Helgrind:Race fun:_handle_check_each fun:_handle_heartbt_thread obj:/usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so fun:start_thread fun:clone } { helgrind glitch in parsing the recv from links code Helgrind:Race fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread obj:/usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so fun:start_thread fun:clone } { helgrind glitch in parsing the PMTUd code Helgrind:Race fun:_handle_pmtud_link_thread obj:/usr/lib64/valgrind/vgpreload_helgrind-amd64-linux.so fun:start_thread fun:clone } diff --git a/build-aux/knet_valgrind_memcheck.supp b/build-aux/knet_valgrind_memcheck.supp index cd09f695..76b666cf 100644 --- a/build-aux/knet_valgrind_memcheck.supp +++ b/build-aux/knet_valgrind_memcheck.supp @@ -1,616 +1,622 @@ +# Copyright (C) 2016-2021 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+ + { lzma internals (spotted on Debian 9 and Ubuntu 18.04 LTS x86-64) Memcheck:Cond obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 obj:/lib/x86_64-linux-gnu/liblzma.so.5.2.2 fun:lzma_block_buffer_encode fun:lzma_stream_buffer_encode fun:lzma_easy_buffer_encode fun:lzma_compress fun:compress_lib_test fun:compress_cfg fun:knet_handle_compress fun:test } { lzma internals (spotted on Ubuntu 18.04 LTS i386) Memcheck:Cond obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 obj:/lib/i386-linux-gnu/liblzma.so.5.2.2 fun:lzma_stream_buffer_encode fun:lzma_easy_buffer_encode fun:lzma_compress fun:compress_lib_test fun:compress_cfg fun:knet_handle_compress } { openssl internals (spotted on OpenSUSE 15) Memcheck:Cond fun:__memcmp_sse4_1 obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_selftest obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_mode_set obj:/usr/lib64/libcrypto.so.1.1 fun:call_init.part.0 fun:_dl_init fun:dl_open_worker fun:_dl_catch_error fun:_dl_open fun:dlopen_doit } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib64/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib64/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on OpenSUSE Tumbleweed) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on OpenSUSE 15) Memcheck:Cond obj:/usr/lib64/libcrypto.so.1.1 fun:FIPS_mode_set obj:/usr/lib64/libcrypto.so.1.1 fun:call_init.part.0 fun:_dl_init fun:dl_open_worker fun:_dl_catch_error fun:_dl_open fun:dlopen_doit fun:_dl_catch_error fun:_dlerror_run fun:dlopen@@GLIBC_2.2.5 } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed and Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:_handle_check_link_pmtud fun:_handle_check_pmtud fun:_handle_pmtud_link_thread fun:start_thread fun:clone } { openssl uninitialised byte(s) (spotted on OpenSUSE Tumbleweed) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2019-10-30) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__libc_sendmsg fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread } { openssl internals (spotted on Ubuntu Devel x86-64 - 2020-07-10) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:_handle_check_each fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { nss internal leak (3.41) non recurring (spotted on f29) Memcheck:Leak match-leak-kinds: definite fun:malloc obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:/usr/lib64/libnss3.so } { nss internal leak (3.41) non recurring Memcheck:Leak match-leak-kinds: definite fun:calloc obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init fun:crypto_init fun:knet_handle_crypto_set_config fun:test fun:main } { nss internal leak (3.41) non recurring Memcheck:Leak match-leak-kinds: definite fun:malloc obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init fun:crypto_init fun:knet_handle_crypto_set_config fun:test fun:main } { nss internal leak (3.55) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:/usr/lib64/libnss3.so fun:SECMOD_LoadModule fun:SECMOD_LoadModule obj:/usr/lib64/libnss3.so fun:NSS_NoDB_Init fun:init_nss fun:nsscrypto_init fun:crypto_init fun:_knet_handle_crypto_set_config } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uncoditional jump (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl.isra.0 fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_pong fun:process_ping fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param socketcall.sendto(msg) fun:sendto fun:send_pmtud_reply fun:process_pmtud fun:_parse_recv_from_links fun:_handle_recv_from_links fun:_handle_recv_from_links_thread fun:start_thread fun:clone } { ubuntu-devel new toolchain is not stable yet (spotted on Ubuntu devel 10092020) Memcheck:Param sendmsg(msg.msg_iov[0]) fun:__libc_sendmsg fun:sendmsg fun:_sendmmsg fun:_dispatch_to_links fun:_prep_and_send_msgs fun:_parse_recv_from_sock fun:_handle_send_to_links fun:_handle_send_to_links_thread fun:start_thread fun:clone } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_instantiate obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_get0_public obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { openssl uncoditional jump (clang) (spotted on Ubuntu devel 10092020) Memcheck:Cond obj:/usr/lib/x86_64-linux-gnu/libcrypto.so.1.1 fun:RAND_DRBG_generate fun:RAND_DRBG_bytes fun:encrypt_openssl fun:opensslcrypto_encrypt_and_signv fun:opensslcrypto_encrypt_and_sign fun:send_ping fun:_send_pings fun:_handle_heartbt_thread fun:start_thread fun:clone } { nss internal leak (3.59) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:* obj:/usr/lib64/libnss3.so fun:SECMOD_LoadModule fun:SECMOD_LoadModule obj:/usr/lib64/libnss3.so fun:NSS_NoDB_Init fun:init_nss fun:nsscrypto_init } { nss internal leak (3.59) non recurring (spotted on f34) Memcheck:Leak match-leak-kinds: definite fun:malloc fun:realpath@@GLIBC_2.3 obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* obj:* fun:init_nss fun:nsscrypto_init } diff --git a/build-aux/update-copyright.sh b/build-aux/update-copyright.sh index 62c449c8..9bb9ff14 100755 --- a/build-aux/update-copyright.sh +++ b/build-aux/update-copyright.sh @@ -1,29 +1,29 @@ #!/bin/sh # -# Copyright (C) 2017-2019 Red Hat, Inc. All rights reserved. +# Copyright (C) 2017-2021 Red Hat, Inc. All rights reserved. # # Author: Fabio M. Di Nitto # # This software licensed under GPL-2.0+ # # script to update copyright dates across the tree enddate=$(date +%Y) -input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp |grep -v update-copyright |grep -v doxyxml.c) +input=$(grep -ril -e "Copyright.*Red Hat" |grep -v .swp |grep -v update-copyright) for i in $input; do startdate=$(git log --follow "$i" | grep ^Date: | tail -n 1 | awk '{print $6}') if [ "$startdate" != "$enddate" ]; then sed -i -e 's#Copyright (C).*Red Hat#Copyright (C) '$startdate'-'$enddate' Red Hat#g' $i else sed -i -e 's#Copyright (C).*Red Hat#Copyright (C) '$startdate' Red Hat#g' $i fi done input=$(find . -type f |grep -v ".git") for i in $input; do if [ -z "$(grep -i "Copyright" $i)" ]; then echo "WARNING: $i appears to be missing Copyright information" fi done diff --git a/m4/pkg_check_var.m4 b/m4/pkg_check_var.m4 index ae1bf222..fa3f5df3 100644 --- a/m4/pkg_check_var.m4 +++ b/m4/pkg_check_var.m4 @@ -1,14 +1,20 @@ +# Copyright (C) 2020-2021 Red Hat, Inc. All rights reserved. +# +# Author: Fabio M. Di Nitto +# +# This software licensed under GPL-2.0+ + # PKG_CHECK_VAR(VARIABLE, MODULE, CONFIG-VARIABLE, # [ACTION-IF-FOUND], [ACTION-IF-NOT-FOUND]) # ------------------------------------------- # Retrieves the value of the pkg-config variable for the given module. m4_ifndef([PKG_CHECK_VAR], [AC_DEFUN([PKG_CHECK_VAR], [AC_REQUIRE([PKG_PROG_PKG_CONFIG])dnl AC_ARG_VAR([$1], [value of $3 for $2, overriding pkg-config])dnl _PKG_CONFIG([$1], [variable="][$3]["], [$2]) AS_VAR_COPY([$1], [pkg_cv_][$1]) AS_VAR_IF([$1], [""], [$5], [$4])dnl ])# PKG_CHECK_VAR ]) diff --git a/man/doxyxml.c b/man/doxyxml.c index 880734a1..72fda764 100644 --- a/man/doxyxml.c +++ b/man/doxyxml.c @@ -1,1155 +1,1155 @@ /* - * Copyright (C) 2018-2020 Red Hat, Inc. All rights reserved. + * Copyright (C) 2018-2021 Red Hat, Inc. All rights reserved. * * Author: Christine Caulfield * * This software licensed under GPL-2.0+ */ /* * NOTE: this code is very rough, it does the bare minimum to parse the * XML out from doxygen and is probably very fragile to changes in that XML * schema. It probably leaks memory all over the place too. * * In its favour, it *does* generate nice man pages and should only be run very ocasionally */ #define _DEFAULT_SOURCE #define _BSD_SOURCE #define _XOPEN_SOURCE #define _XOPEN_SOURCE_EXTENDED #include #include #include #include #include #include #include #include #include #include #include #include #include /* * This isn't a maximum size, it just defines how long a parameter * type can get before we decide it's not worth lining everything up. * It's mainly to stop function pointer types (which can get VERY long because * of all *their* parameters) making everything else 'line-up' over separate lines */ #define LINE_LENGTH 80 static int print_ascii = 1; static int print_man = 0; static int print_params = 0; static int print_general = 0; static int num_functions = 0; static int quiet=0; static const char *man_section="3"; static const char *package_name="Package"; static const char *header="Programmer's Manual"; static const char *company="Red Hat"; static const char *output_dir="./"; static const char *xml_dir = "./xml/"; static const char *xml_file; static const char *manpage_date = NULL; static const char *headerfile = NULL; static const char *header_prefix = ""; static long manpage_year = LONG_MIN; static long start_year = 2010; static struct qb_list_head params_list; static struct qb_list_head retval_list; static qb_map_t *function_map; static qb_map_t *structures_map; static qb_map_t *used_structures_map; struct param_info { char *paramname; char *paramtype; char *paramdesc; struct param_info *next; struct qb_list_head list; }; struct struct_info { enum {STRUCTINFO_STRUCT, STRUCTINFO_ENUM} kind; char *structname; char *description; char *brief_description; struct qb_list_head params_list; /* our params */ struct qb_list_head list; }; static char *get_texttree(int *type, xmlNode *cur_node, char **returntext, char **notetext); static void traverse_node(xmlNode *parentnode, const char *leafname, void (do_members(xmlNode*, void*)), void *arg); static void free_paraminfo(struct param_info *pi) { free(pi->paramname); free(pi->paramtype); free(pi->paramdesc); free(pi); } static char *get_attr(xmlNode *node, const char *tag) { xmlAttr *this_attr; for (this_attr = node->properties; this_attr; this_attr = this_attr->next) { if (this_attr->type == XML_ATTRIBUTE_NODE && strcmp((char *)this_attr->name, tag) == 0) { return strdup((char *)this_attr->children->content); } } return NULL; } static char *get_child(xmlNode *node, const char *tag) { xmlNode *this_node; xmlNode *child; char buffer[1024] = {'\0'}; char *refid = NULL; char *declname = NULL; for (this_node = node->children; this_node; this_node = this_node->next) { if ((strcmp( (char*)this_node->name, "declname") == 0)) { declname = strdup((char*)this_node->children->content); } if ((this_node->type == XML_ELEMENT_NODE && this_node->children) && ((strcmp((char *)this_node->name, tag) == 0))) { refid = NULL; for (child = this_node->children; child; child = child->next) { if (child->content) { strncat(buffer, (char *)child->content, sizeof(buffer)-1); } if ((strcmp( (char*)child->name, "ref") == 0)) { if (child->children->content) { strncat(buffer,(char *)child->children->content, sizeof(buffer)-1); } refid = get_attr(child, "refid"); } } } if (declname && refid) { qb_map_put(used_structures_map, refid, declname); } } return strdup(buffer); } static struct param_info *find_param_by_name(struct qb_list_head *list, const char *name) { struct qb_list_head *iter; struct param_info *pi; qb_list_for_each(iter, list) { pi = qb_list_entry(iter, struct param_info, list); if (strcmp(pi->paramname, name) == 0) { return pi; } } return NULL; } static int not_all_whitespace(char *string) { unsigned int i; for (i=0; ichildren; this_tag; this_tag = this_tag->next) { for (sub_tag = this_tag->children; sub_tag; sub_tag = sub_tag->next) { if (sub_tag->type == XML_ELEMENT_NODE && strcmp((char *)sub_tag->name, "parameternamelist") == 0 && sub_tag->children->next->children) { paramname = (char*)sub_tag->children->next->children->content; } if (sub_tag->type == XML_ELEMENT_NODE && strcmp((char *)sub_tag->name, "parameterdescription") == 0 && paramname && sub_tag->children->next->children) { paramdesc = (char*)sub_tag->children->next->children->content; /* Add text to the param_map */ pi = find_param_by_name(list, paramname); if (pi) { pi->paramdesc = paramdesc; } else { pi = malloc(sizeof(struct param_info)); if (pi) { pi->paramname = paramname; pi->paramdesc = paramdesc; pi->paramtype = NULL; /* retval */ qb_list_add_tail(&pi->list, list); } } } } } } static char *get_text(xmlNode *cur_node, char **returntext, char **notetext) { xmlNode *this_tag; xmlNode *sub_tag; char *kind; char buffer[4096] = {'\0'}; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (this_tag->type == XML_TEXT_NODE && strcmp((char *)this_tag->name, "text") == 0) { if (not_all_whitespace((char*)this_tag->content)) { strncat(buffer, (char*)this_tag->content, sizeof(buffer)-1); } } if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "emphasis") == 0) { if (print_man) { strncat(buffer, "\\fB", sizeof(buffer)-1); } strncat(buffer, (char*)this_tag->children->content, sizeof(buffer)-1); if (print_man) { strncat(buffer, "\\fR", sizeof(buffer)-1); } } if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "ref") == 0) { if (print_man) { strncat(buffer, "\\fI", sizeof(buffer)-1); } strncat(buffer, (char*)this_tag->children->content, sizeof(buffer)-1); if (print_man) { strncat(buffer, "\\fR", sizeof(buffer)-1); } } if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "itemizedlist") == 0) { for (sub_tag = this_tag->children; sub_tag; sub_tag = sub_tag->next) { if (sub_tag->type == XML_ELEMENT_NODE && strcmp((char *)sub_tag->name, "listitem") == 0) { strncat(buffer, (char*)sub_tag->children->children->content, sizeof(buffer)-1); strncat(buffer, "\n", sizeof(buffer)-1); } } } /* Look for subsections - return value & params */ if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "simplesect") == 0) { char *tmp; kind = get_attr(this_tag, "kind"); tmp = get_text(this_tag->children, NULL, NULL); if (returntext && strcmp(kind, "return") == 0) { *returntext = tmp; } if (notetext && strcmp(kind, "note") == 0) { *notetext = tmp; } } if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "parameterlist") == 0) { kind = get_attr(this_tag, "kind"); if (strcmp(kind, "param") == 0) { get_param_info(this_tag, ¶ms_list); } if (strcmp(kind, "retval") == 0) { get_param_info(this_tag, &retval_list); } } } return strdup(buffer); } static void read_structname(xmlNode *cur_node, void *arg) { struct struct_info *si=arg; xmlNode *this_tag; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (strcmp((char*)this_tag->name, "compoundname") == 0) { si->structname = strdup((char*)this_tag->children->content); } } } static void read_structdesc(xmlNode *cur_node, void *arg) { struct struct_info *si=arg; xmlNode *this_tag; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (strcmp((char*)this_tag->name, "detaileddescription") == 0) { char *desc = get_texttree(NULL, this_tag, NULL, NULL); if (desc) { si->description = strdup((char*)desc); } } if (strcmp((char*)this_tag->name, "briefdescription") == 0) { char *brief = get_texttree(NULL, this_tag, NULL, NULL); if (brief) { si->brief_description = brief; } } } } static void read_headername(xmlNode *cur_node, void *arg) { char **h_file = arg; xmlNode *this_tag; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (strcmp((char*)this_tag->name, "compoundname") == 0) { *h_file = strdup((char*)this_tag->children->content); } } } /* Called from traverse_node() */ static void read_struct(xmlNode *cur_node, void *arg) { xmlNode *this_tag; struct struct_info *si=arg; struct param_info *pi; char fullname[1024]; char *type = NULL; char *name = NULL; const char *args=""; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (strcmp((char*)this_tag->name, "type") == 0) { type = (char*)this_tag->children->content; /* If type is NULL then look for a ref - it's probably an external struct or typedef */ if (type == NULL) { type = get_child(this_tag, "ref"); } } if (strcmp((char*)this_tag->name, "name") == 0) { name = (char*)this_tag->children->content; } if (this_tag->children && strcmp((char*)this_tag->name, "argsstring") == 0) { args = (char*)this_tag->children->content; } } if (name) { pi = malloc(sizeof(struct param_info)); if (pi) { snprintf(fullname, sizeof(fullname), "%s%s", name, args); pi->paramtype = type?strdup(type):strdup(""); pi->paramname = strdup(fullname); pi->paramdesc = NULL; qb_list_add_tail(&pi->list, &si->params_list); } } } static int read_structure_from_xml(const char *refid, const char *name) { char fname[PATH_MAX]; xmlNode *rootdoc; xmlDocPtr doc; struct struct_info *si; struct stat st; int ret = -1; snprintf(fname, sizeof(fname), "%s/%s.xml", xml_dir, refid); /* Don't call into libxml if the file does not exist - saves unwanted error messages */ if (stat(fname, &st) == -1) { return -1; } doc = xmlParseFile(fname); if (doc == NULL) { fprintf(stderr, "Error: unable to open xml file for %s\n", refid); return -1; } rootdoc = xmlDocGetRootElement(doc); if (!rootdoc) { fprintf(stderr, "Can't find \"document root\"\n"); return -1; } si = malloc(sizeof(struct struct_info)); if (si) { memset(si, 0, sizeof(*si)); si->kind = STRUCTINFO_STRUCT; qb_list_init(&si->params_list); traverse_node(rootdoc, "memberdef", read_struct, si); traverse_node(rootdoc, "compounddef", read_structdesc, si); traverse_node(rootdoc, "compounddef", read_structname, si); ret = 0; qb_map_put(structures_map, refid, si); } xmlFreeDoc(doc); return ret; } static char *allcaps(const char *name) { static char buffer[1024] = {'\0'}; size_t i; for (i=0; i< strlen(name); i++) { buffer[i] = toupper(name[i]); } buffer[strlen(name)] = '\0'; return buffer; } static void print_param(FILE *manfile, struct param_info *pi, int field_width, int bold, const char *delimiter) { const char *asterisks = " "; char *type = pi->paramtype; int typelength = strlen(type); /* Reformat pointer params so they look nicer */ if (typelength > 0 && pi->paramtype[typelength-1] == '*') { asterisks=" *"; type = strdup(pi->paramtype); type[typelength-1] = '\0'; /* Cope with double pointers */ if (typelength > 1 && pi->paramtype[typelength-2] == '*') { asterisks="**"; type[typelength-2] = '\0'; } /* Tidy function pointers */ if (typelength > 1 && pi->paramtype[typelength-2] == '(') { asterisks="(*"; type[typelength-2] = '\0'; } } fprintf(manfile, " %s%-*s%s%s\\fI%s\\fP%s\n", bold?"\\fB":"", field_width, type, asterisks, bold?"\\fP":"", pi->paramname, delimiter); if (type != pi->paramtype) { free(type); } } static void print_structure(FILE *manfile, struct struct_info *si) { struct param_info *pi; struct qb_list_head *iter; unsigned int max_param_length=0; fprintf(manfile, ".nf\n"); fprintf(manfile, "\\fB\n"); if (si->brief_description) { fprintf(manfile, "%s\n", si->brief_description); } if (si->description) { fprintf(manfile, "%s\n", si->description); } qb_list_for_each(iter, &si->params_list) { pi = qb_list_entry(iter, struct param_info, list); if (strlen(pi->paramtype) > max_param_length) { max_param_length = strlen(pi->paramtype); } } if (si->kind == STRUCTINFO_STRUCT) { fprintf(manfile, "struct %s {\n", si->structname); } else if (si->kind == STRUCTINFO_ENUM) { fprintf(manfile, "enum %s {\n", si->structname); } else { fprintf(manfile, "%s {\n", si->structname); } qb_list_for_each(iter, &si->params_list) { pi = qb_list_entry(iter, struct param_info, list); print_param(manfile, pi, max_param_length, 0,";"); } fprintf(manfile, "};\n"); fprintf(manfile, "\\fP\n"); fprintf(manfile, ".fi\n"); } char *get_texttree(int *type, xmlNode *cur_node, char **returntext, char **notetext) { xmlNode *this_tag; char *tmp = NULL; char buffer[4096] = {'\0'}; for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "para") == 0) { tmp = get_text(this_tag, returntext, notetext); strncat(buffer, tmp, sizeof(buffer)-1); strncat(buffer, "\n", sizeof(buffer)-1); free(tmp); } } if (buffer[0]) { return strdup(buffer); } else { return NULL; } } /* The text output is VERY basic and just a check that it's working really */ static void print_text(char *name, char *def, char *brief, char *args, char *detailed, struct qb_list_head *param_list, char *returntext, char *notetext) { printf(" ------------------ %s --------------------\n", name); printf("NAME\n"); if (brief) { printf(" %s - %s\n", name, brief); } else { printf(" %s\n", name); } printf("SYNOPSIS\n"); printf(" #include <%s%s>\n", header_prefix, headerfile); if (args) { printf(" %s %s\n\n", name, args); } if (detailed) { printf("DESCRIPTION\n"); printf(" %s\n", detailed); } if (returntext) { printf("RETURN VALUE\n"); printf(" %s\n", returntext); } if (notetext) { printf("NOTE\n"); printf(" %s\n", notetext); } } /* Print a long string with para marks in it. */ static void man_print_long_string(FILE *manfile, char *text) { char *next_nl; char *current = text; next_nl = strchr(text, '\n'); while (next_nl && *next_nl != '\0') { *next_nl = '\0'; if (strlen(current)) { fprintf(manfile, ".PP\n%s\n", current); } *next_nl = '\n'; current = next_nl+1; next_nl = strchr(current, '\n'); } /* The bit at the end */ if (strlen(current)) { fprintf(manfile, ".PP\n%s\n", current); } } static void print_manpage(char *name, char *def, char *brief, char *args, char *detailed, struct qb_list_head *param_map, char *returntext, char *notetext) { char manfilename[PATH_MAX]; char gendate[64]; const char *dateptr = gendate; FILE *manfile; time_t t; struct tm *tm; qb_map_iter_t *map_iter; struct qb_list_head *iter; struct qb_list_head *tmp; const char *p; void *data; unsigned int max_param_type_len; unsigned int max_param_name_len; unsigned int num_param_descs; int param_count = 0; int param_num = 0; struct param_info *pi; t = time(NULL); tm = localtime(&t); if (!tm) { perror("unable to get localtime"); exit(1); } strftime(gendate, sizeof(gendate), "%Y-%m-%d", tm); if (manpage_date) { dateptr = manpage_date; } if (manpage_year == LONG_MIN) { manpage_year = tm->tm_year+1900; } snprintf(manfilename, sizeof(manfilename), "%s/%s.%s", output_dir, name, man_section); manfile = fopen(manfilename, "w+"); if (!manfile) { perror("unable to open output file"); printf("%s", manfilename); exit(1); } /* Work out the length of the parameters, so we can line them up */ max_param_type_len = 0; max_param_name_len = 0; num_param_descs = 0; qb_list_for_each(iter, ¶ms_list) { pi = qb_list_entry(iter, struct param_info, list); /* It's mainly macros that break this, * macros need more work */ if (!pi->paramtype) { pi->paramtype = strdup(""); } if ((strlen(pi->paramtype) < LINE_LENGTH) && (strlen(pi->paramtype) > max_param_type_len)) { max_param_type_len = strlen(pi->paramtype); } if (strlen(pi->paramname) > max_param_name_len) { max_param_name_len = strlen(pi->paramname); } if (pi->paramdesc) { num_param_descs++; } param_count++; } /* Off we go */ fprintf(manfile, ".\\\" Automatically generated man page, do not edit\n"); fprintf(manfile, ".TH %s %s %s \"%s\" \"%s\"\n", allcaps(name), man_section, dateptr, package_name, header); fprintf(manfile, ".SH NAME\n"); if (brief) { fprintf(manfile, "%s \\- %s\n", name, brief); } else { fprintf(manfile, "%s\n", name); } fprintf(manfile, ".SH SYNOPSIS\n"); fprintf(manfile, ".nf\n"); fprintf(manfile, ".B #include <%s%s>\n", header_prefix, headerfile); if (def) { fprintf(manfile, ".sp\n"); fprintf(manfile, "\\fB%s\\fP(\n", def); qb_list_for_each(iter, ¶ms_list) { pi = qb_list_entry(iter, struct param_info, list); print_param(manfile, pi, max_param_type_len, 1, ++param_num < param_count?",":""); } fprintf(manfile, ");\n"); fprintf(manfile, ".fi\n"); } if (print_params && num_param_descs) { fprintf(manfile, ".SH PARAMS\n"); qb_list_for_each(iter, ¶ms_list) { pi = qb_list_entry(iter, struct param_info, list); fprintf(manfile, "\\fB%-*s \\fP\\fI%s\\fP\n", (int)max_param_name_len, pi->paramname, pi->paramdesc); fprintf(manfile, ".PP\n"); } } if (detailed) { fprintf(manfile, ".SH DESCRIPTION\n"); man_print_long_string(manfile, detailed); } if (qb_map_count_get(used_structures_map)) { int first_struct = 1; map_iter = qb_map_iter_create(used_structures_map); for (p = qb_map_iter_next(map_iter, &data); p; p = qb_map_iter_next(map_iter, &data)) { struct struct_info *si; const char *refid = p; char *refname = data; /* If it's not been read in - go and look for it */ si = qb_map_get(structures_map, refid); if (!si) { if (!read_structure_from_xml(refid, refname)) { si = qb_map_get(structures_map, refid); } } /* Only print header if the struct files exist - sometimes they don't */ if (si && first_struct) { fprintf(manfile, ".SH STRUCTURES\n"); first_struct = 0; } if (si) { print_structure(manfile, si); fprintf(manfile, ".PP\n"); } } qb_map_iter_free(map_iter); fprintf(manfile, ".RE\n"); } if (returntext) { fprintf(manfile, ".SH RETURN VALUE\n"); man_print_long_string(manfile, returntext); fprintf(manfile, ".PP\n"); } qb_list_for_each(iter, &retval_list) { pi = qb_list_entry(iter, struct param_info, list); fprintf(manfile, "\\fB%-*s \\fP%s\n", 10, pi->paramname, pi->paramdesc); fprintf(manfile, ".PP\n"); } if (notetext) { fprintf(manfile, ".SH NOTE\n"); man_print_long_string(manfile, notetext); } fprintf(manfile, ".SH SEE ALSO\n"); fprintf(manfile, ".PP\n"); fprintf(manfile, ".nh\n"); fprintf(manfile, ".ad l\n"); param_num = 0; map_iter = qb_map_iter_create(function_map); for (p = qb_map_iter_next(map_iter, &data); p; p = qb_map_iter_next(map_iter, &data)) { /* Exclude us! */ if (strcmp(data, name)) { fprintf(manfile, "\\fI%s\\fR(%s)%s", (char *)data, man_section, param_num < (num_functions - 1)?", ":""); } param_num++; } qb_map_iter_free(map_iter); fprintf(manfile, "\n"); fprintf(manfile, ".ad\n"); fprintf(manfile, ".hy\n"); fprintf(manfile, ".SH \"COPYRIGHT\"\n"); fprintf(manfile, ".PP\n"); fprintf(manfile, "Copyright (C) %4ld-%4ld %s, Inc. All rights reserved.\n", start_year, manpage_year, company); fclose(manfile); /* Free the params & retval info */ qb_list_for_each_safe(iter, tmp, ¶ms_list) { pi = qb_list_entry(iter, struct param_info, list); qb_list_del(&pi->list); free_paraminfo(pi); } qb_list_for_each_safe(iter, tmp, &retval_list) { pi = qb_list_entry(iter, struct param_info, list); qb_list_del(&pi->list); free_paraminfo(pi); } /* Free used-structures map */ map_iter = qb_map_iter_create(used_structures_map); for (p = qb_map_iter_next(map_iter, &data); p; p = qb_map_iter_next(map_iter, &data)) { qb_map_rm(used_structures_map, p); free(data); } } /* Same as traverse_members, but to collect function names */ static void collect_functions(xmlNode *cur_node, void *arg) { xmlNode *this_tag; char *kind; char *name = NULL; if (cur_node->name && strcmp((char *)cur_node->name, "memberdef") == 0) { kind = get_attr(cur_node, "kind"); if (kind && strcmp(kind, "function") == 0) { for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "name") == 0) { name = strdup((char *)this_tag->children->content); } } if (name) { qb_map_put(function_map, name, name); num_functions++; } } } } /* Same as traverse_members, but to collect enums. The behave like structures for, but, for some reason, are in the main XML file rather than their own */ static void collect_enums(xmlNode *cur_node, void *arg) { xmlNode *this_tag; struct struct_info *si; char *kind; char *refid = NULL; char *name = NULL; if (cur_node->name && strcmp((char *)cur_node->name, "memberdef") == 0) { kind = get_attr(cur_node, "kind"); if (kind && strcmp(kind, "enum") == 0) { refid = get_attr(cur_node, "id"); for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "name") == 0) { name = strdup((char *)this_tag->children->content); } } if (name) { si = malloc(sizeof(struct struct_info)); if (si) { memset(si, 0, sizeof(*si)); si->kind = STRUCTINFO_ENUM; qb_list_init(&si->params_list); si->structname = strdup(name); traverse_node(cur_node, "enumvalue", read_struct, si); qb_map_put(structures_map, refid, si); } } } } } static void traverse_members(xmlNode *cur_node, void *arg) { xmlNode *this_tag; /* if arg == NULL then we're generating a page for the whole header file */ if ((cur_node->name && (strcmp((char *)cur_node->name, "memberdef") == 0)) || ((arg == NULL) && cur_node->name && strcmp((char *)cur_node->name, "compounddef")) == 0) { char *kind = NULL; char *def = NULL; char *args = NULL; char *name = NULL; char *brief = NULL; char *detailed = NULL; char *returntext = NULL; char *notetext = NULL; int type; kind=def=args=name=NULL; kind = get_attr(cur_node, "kind"); for (this_tag = cur_node->children; this_tag; this_tag = this_tag->next) { if (!this_tag->children || !this_tag->children->content) continue; if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "definition") == 0) def = strdup((char *)this_tag->children->content); if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "argsstring") == 0) args = strdup((char *)this_tag->children->content); if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "name") == 0) name = strdup((char *)this_tag->children->content); if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "briefdescription") == 0) { brief = get_texttree(&type, this_tag, &returntext, ¬etext); if (brief) { /* * apparently brief text contains extra trailing space and a \n. * remove them. */ brief[strlen(brief) - 2] = '\0'; } } if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "detaileddescription") == 0) { detailed = get_texttree(&type, this_tag, &returntext, ¬etext); } /* Get all the params */ if (this_tag->type == XML_ELEMENT_NODE && strcmp((char *)this_tag->name, "param") == 0) { char *param_type = get_child(this_tag, "type"); char *param_name = get_child(this_tag, "declname"); struct param_info *pi = malloc(sizeof(struct param_info)); if (pi) { pi->paramname = param_name; pi->paramtype = param_type; pi->paramdesc = NULL; qb_list_add_tail(&pi->list, ¶ms_list); } } } if (arg == headerfile) { /* Print header page */ name = (char*)headerfile; if (print_man) { if (!quiet) { printf("Printing header manpage for %s\n", name); } print_manpage(name, def, brief, args, detailed, ¶ms_list, returntext, notetext); } else { print_text(name, def, brief, args, detailed, ¶ms_list, returntext, notetext); } } if (kind && strcmp(kind, "function") == 0) { /* Make sure function has a doxygen description */ if (!detailed) { fprintf(stderr, "No detailed description for function '%s' - please fix this\n", name); } if (!name) { fprintf(stderr, "Internal error - no name found for function\n"); } else { if (print_man) { if (!quiet) { printf("Printing manpage for %s\n", name); } print_manpage(name, def, brief, args, detailed, ¶ms_list, returntext, notetext); } else { print_text(name, def, brief, args, detailed, ¶ms_list, returntext, notetext); } } } free(kind); free(def); free(args); free(name); } } static void traverse_node(xmlNode *parentnode, const char *leafname, void (do_members(xmlNode*, void*)), void *arg) { xmlNode *cur_node; for (cur_node = parentnode->children; cur_node; cur_node = cur_node->next) { if (cur_node->type == XML_ELEMENT_NODE && cur_node->name && strcmp((char*)cur_node->name, leafname)==0) { do_members(cur_node, arg); continue; } if (cur_node->type == XML_ELEMENT_NODE) { traverse_node(cur_node, leafname, do_members, arg); } } } static void usage(char *name) { printf("Usage:\n"); printf(" %s [OPTIONS] \n", name); printf("\n"); printf(" This is a tool to generate API manpages from a doxygen-annotated header file.\n"); printf(" First run doxygen on the file and then run this program against the main XML file\n"); printf(" it created and the directory containing the ancilliary files. It will then\n"); printf(" output a lot of *.3 man page files which you can then ship with your library.\n"); printf("\n"); printf(" You will need to invoke this program once for each .h file in your library,\n"); printf(" using the name of the generated .xml file. This file will usually be called\n"); printf(" something like _8h.xml, eg qbipcs_8h.xml\n"); printf("\n"); printf(" If you want HTML output then simpy use nroff on the generated files as you\n"); printf(" would do with any other man page.\n"); printf("\n"); printf(" -a Print ASCII dump of man pages to stdout\n"); printf(" -m Write man page files to \n"); printf(" -P Print PARAMS section\n"); printf(" -g Print general man page for the whole header file\n"); printf(" -s Write man pages into section Use name. default \n"); printf(" -H
Set header (default \"Programmer's Manual\"\n"); printf(" -I Set include filename (default taken from xml)\n"); printf(" -i Prefix for include files. eg qb/ (default \"\")\n"); printf(" -C Company name in copyright (defaults to Red Hat)\n"); printf(" -D Date to print at top of man pages (format not checked, default: today)\n"); printf(" -S Start year to print at end of copyright line (default: 2010)\n"); printf(" -Y Year to print at end of copyright line (default: today's year)\n"); printf(" -o Write all man pages to (default .)\n"); printf(" -d Directory for XML files (./xml/)\n"); printf(" -h Print this usage text\n"); } static long get_year(char *optionarg, char optionchar) { long year = strtol(optionarg, NULL, 10); /* * Don't make too many assumptions about the year. I was on call at the * 2000 rollover. #experience */ if (year == LONG_MIN || year == LONG_MAX || year < 1900) { fprintf(stderr, "Value passed to -%c is not a valid year number\n", optionchar); return 0; } return year; } int main(int argc, char *argv[]) { xmlNode *rootdoc; xmlDocPtr doc; int opt; char xml_filename[PATH_MAX]; while ( (opt = getopt_long(argc, argv, "H:amqgPD:Y:s:S:d:o:p:f:I:i:C:h?", NULL, NULL)) != EOF) { switch(opt) { case 'a': print_ascii = 1; print_man = 0; break; case 'm': print_man = 1; print_ascii = 0; break; case 'P': print_params = 1; break; case 'g': print_general = 1; break; case 'q': quiet = 1; break; case 'I': headerfile = optarg; break; case 'i': header_prefix = optarg; break; case 'C': company = optarg; break; case 's': man_section = optarg; break; case 'S': start_year = get_year(optarg, 'S'); if (start_year == 0) { return 1; } break; case 'd': xml_dir = optarg; break; case 'D': manpage_date = optarg; break; case 'Y': manpage_year = get_year(optarg, 'Y'); if (manpage_year == 0) { return 1; } break; case 'p': package_name = optarg; break; case 'H': header = optarg; break; case 'o': output_dir = optarg; break; case '?': case 'h': usage(argv[0]); return 0; } } if (argv[optind]) { xml_file = argv[optind]; } if (!xml_file) { usage(argv[0]); exit(1); } if (!quiet) { printf("reading %s ... ", xml_file); } snprintf(xml_filename, sizeof(xml_filename), "%s/%s", xml_dir, xml_file); doc = xmlParseFile(xml_filename); if (doc == NULL) { fprintf(stderr, "Error: unable to read xml file %s\n", xml_filename); exit(1); } rootdoc = xmlDocGetRootElement(doc); if (!rootdoc) { fprintf(stderr, "Can't find \"document root\"\n"); exit(1); } if (!quiet) printf("done.\n"); /* Get our header file name */ if (!headerfile) { traverse_node(rootdoc, "compounddef", read_headername, &headerfile); } /* Default to *something* if it all goes wrong */ if (!headerfile) { headerfile = "unknown.h"; } qb_list_init(¶ms_list); qb_list_init(&retval_list); structures_map = qb_hashtable_create(10); function_map = qb_hashtable_create(10); used_structures_map = qb_hashtable_create(10); /* Collect functions */ traverse_node(rootdoc, "memberdef", collect_functions, NULL); /* Collect enums */ traverse_node(rootdoc, "memberdef", collect_enums, NULL); /* print pages */ traverse_node(rootdoc, "memberdef", traverse_members, NULL); if (print_general) { /* Generate and print a page for the headerfile itself */ traverse_node(rootdoc, "compounddef", traverse_members, (char *)headerfile); } return 0; }