From patchwork Thu Jul 5 14:42:41 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Reisner X-Patchwork-Id: 670 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id 38751545967E for ; Thu, 5 Jul 2018 14:42:55 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on apollo X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_MED=-2.3,T_DKIMWL_WL_HIGH=-0.01 autolearn=ham autolearn_force=no version=3.4.1 X-Spam-BL-Results: [127.0.9.2] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:42:55 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 458A4BAD18E0B; Thu, 5 Jul 2018 14:42:54 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [5.9.250.164]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS; Thu, 5 Jul 2018 14:42:54 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 0A29D2C560; Thu, 5 Jul 2018 14:42:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=luna2; t=1530801774; bh=eYUkvpmWvPD+frnvNwby3YMBpfVjALoVwkvY0na33V8=; h=From:To:Date:Subject:List-Id:List-Unsubscribe:List-Archive: List-Post:List-Help:List-Subscribe:Reply-To:Cc; b=Yyym9+OS8B9HazcAUSKV8n4dOFaTzK6OVkY+6xijU6K/VD4mzBr805eq5QOvyh47q +CMcEUGSSSfN9PYo3pFYsDlnX7p7dxw3RJlZybk9JIItzZX2yfafUkGCZxnpA5T5Dw TK1N3Lyre/NgJp0fxAUWRBbsW6lUNITlbSQ2rAUDAkvLr1LrnwIYn4KtFs+spXWGCr pNTJ3KtqTs2yCU1T7rA6t5dX7BcSoGIGoWtmq7J9fb7khNaD387bMPMgw1Ss79w4i0 HZSEQtssZtzHHg/sEJ/7IfVcMMOZgxDJmcvz6UBYFWgb4f2wP0eKvMPP7OCyZZ1VW5 HPpUcCgdegiharIh3dk5EE1rjArZEhUE4aOvBB/6GWuzv73BMCUh4/KIdD9Utg5myw yPWCq+o/cA9QvvA4wO8OW4z/u5x2lCZvXElBfj7tFvoIW+9H92Bf+k9/Jzb/LI90yt OwQ4pZDpvyMFJ0oBJVeesWsN7M/TfEOXucQxZ7pQB3zFI10f2Hx7C6hw9x0NJqdX+0 fkHCcCnsl2D9vnNRcN3MPImHyJrTV3tCafnTFb2/YewVhxVVcwVIe7IMZKzVQMUEN3 o+9cMNOQG5OOYYUIn1xiPH/A8W3CZbVurOJC7BwfKd4ectKyKtGNyasX8V/wKt4g3X H6mLc9YEWaGhE8BH4y1pg3HM= Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id AD4AB2C3F0 for ; Thu, 5 Jul 2018 14:42:50 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by luna.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:42:50 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 8CC1DBAD18E05; Thu, 5 Jul 2018 14:42:49 +0000 (UTC) Received: from localhost (unknown [IPv6:2604:2000:1406:11:309a:eca6:7ba1:ff59]) (using TLSv1.2 with cipher DHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) (Authenticated sender: dreisner) by orion.archlinux.org (Postfix) with ESMTPSA id 1E3D4BAD18E04; Thu, 5 Jul 2018 14:42:49 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=orion; t=1530801769; bh=eYUkvpmWvPD+frnvNwby3YMBpfVjALoVwkvY0na33V8=; h=From:To:Cc:Subject:Date; b=SjI1LCfwf12IJ0eZ5LvisTEooIfdDtr+4P5i4NgOVUUnTLqsWulEA0N6x3yxgm5bT qXXjNHYCuzRiEJuCKnNhBGN+unJQKDFTFo6XkwfcWs0LWhUfidmf6Iow3/RSWRtLeC u+K9Hoc4L5hlX2b7xr0gCYs0hxoKUGudFTPhJp7HZRnOHa8T7JoW2+yLi6Tjevc7Ew SNtg222rLncDbTZuugRrn6TWu91iRMNN7SsqJ1thl8xuq6fW2Q441bero0ZTvIeXvJ Y7f8tzEsNVA+WXwUcp3MNvbwaTjifaCQ7/67AszMVTWkHBmMckMsF5XGiXLEzOL6tK uL8qhMhOI3H1vAy8w/l77RqO2eyLirKY1DLUxHxkVk8J7SUsTuwmXfJh3U2xPq6e+r Ec6NVKzOJNhJxYtJQxNrqkm+QTk9d9h5Kcq3YzU/GAEk++/Fa1KIaBkEy2iEu8If/M dkFmgAr1N1CJVChbE2j/PZRrFGXGd4KZQe6jDHbW1LnyQ+IY9JCpiZlRk+fXej8M2c XzzDJmdPQACn59c2BUfflZH43/kIvmHbF8MCIDfkUgMsw5C/DLR2i5XKhODhNpok34 2cm5H6iBZdHGOkIGh5oRlKDQ0RmGD09BUMhJ7v6j++uv8GSKW4d7HTSoUgUrs+owdZ IKkwHRTsullMOE0teoxcjozI= From: Dave Reisner To: pacman-dev@archlinux.org Date: Thu, 5 Jul 2018 10:42:41 -0400 Message-Id: <20180705144244.15619-1-dreisner@archlinux.org> X-Mailer: git-send-email 2.18.0 Subject: [pacman-dev] [PATCH 1/4] pacman/conf: Remove unused include X-BeenThere: pacman-dev@archlinux.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Discussion list for pacman development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Discussion list for pacman development Cc: Dave Reisner Errors-To: pacman-dev-bounces@archlinux.org Sender: "pacman-dev" --- src/pacman/conf.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/pacman/conf.c b/src/pacman/conf.c index 9a37dcea..29f69052 100644 --- a/src/pacman/conf.c +++ b/src/pacman/conf.c @@ -35,7 +35,6 @@ #include "conf.h" #include "ini.h" #include "util.h" -#include "pacman.h" #include "callback.h" /* global config variable */ From patchwork Thu Jul 5 14:42:42 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Reisner X-Patchwork-Id: 671 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id 3E35254596F5 for ; Thu, 5 Jul 2018 14:43:09 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on apollo X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_MED=-2.3,T_DKIMWL_WL_HIGH=-0.01 autolearn=ham autolearn_force=no version=3.4.1 X-Spam-BL-Results: [127.0.9.2] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:09 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 5A57FBAD18E24; Thu, 5 Jul 2018 14:43:02 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [IPv6:2a01:4f8:160:3033::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS; Thu, 5 Jul 2018 14:43:02 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 3A3A72BDF5; Thu, 5 Jul 2018 14:43:02 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=luna2; t=1530801782; bh=5AryoVbWN1BidCBbfc/WehNFO+B/+hPf5l1qxQaMAb4=; h=From:To:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: Reply-To:Cc; b=vL68WlpkMgf1booCWjwFp0G6BKEcgtCdN4hoVT0YztMGgeCN1FkNatlK9jhHlwyEG yVXSeCTEqiIGNBwLoV81ZSYIk28fFZRlLc8r5IZCMNE5Q46RHrrpdxfgIaIB1AkXui vcDx/8BeNjrQ9rARhE7vdojebRMgctTRCfxHj8mhazml0HhbjLBdaioqZ5dQuAxCPc RTMHh36yfgbYrW1XyVrDy9rvmvDdwg/EzlD6AsG77ftEEexIE0BTdmP1QT9bPzKc25 +ZcRmuxy/H0x1V9NPGb5sdnlLtISzaQBgfxF8AXDr4LVLuaWynCdFrkywnic7aK5Jo QFqFLtHUwKIxlOCyi6Z0CeW890l1Y6ZZQGw0JL/ky3QcPnicNP1meinloZMLOwhpxm 2BC/CqyRTwbTqP701RX64BA7LwEIwjFmdYPOjZs2ZvSdR+Oqa17Juu4MbHZfhRtYVl i1qJNGB1mzlLXU3AzdaB22jNSDD+03sHkSy+yQFWweyTX1aUq4wNXu2rFGllY6iaeZ Rc5JrboziBOZrBjmSa9FNlffnpM0T7zWah31hjNxyJUBlNBvzU1sfULl2qnK1Jq2l4 KPQcdWFaHYw1S5GbAR8EeraKnlRUFEh1KfFKkGk8fUk5CupwQgYnbVWc/2mmXggDDs NxQLcTbvK+u6QYKtSQFWBpNE= Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 72BF82B34C for ; Thu, 5 Jul 2018 14:43:00 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [IPv6:2a01:4f8:160:6087::1]) by luna.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:00 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id D5223BAD18E0A; Thu, 5 Jul 2018 14:42:51 +0000 (UTC) Received: from localhost (unknown [IPv6:2604:2000:1406:11:309a:eca6:7ba1:ff59]) (using TLSv1.2 with cipher DHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) (Authenticated sender: dreisner) by orion.archlinux.org (Postfix) with ESMTPSA id 6FF9ABAD18E09; Thu, 5 Jul 2018 14:42:51 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=orion; t=1530801771; bh=5AryoVbWN1BidCBbfc/WehNFO+B/+hPf5l1qxQaMAb4=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=b3rF7v7XOTeMXkRPnoa5jIlJvw6luCmJWLkXPcQuspK0qwIqxCOmZ7ea1FKr+67GR 0eXnhb2AMvmJvCGYpK/QbnqdMeO6VN+Xq1K7+kVMqgDVHdXE7TC7s247+aJi7b5J+w V0lzM1+Ubsv9iAIHv6VDIy2nRRKclQB4UdgHzSN3mKfMkWVlcfHFenh4dPWIBknANW buYBu4Fq0T19xB7X6RnGyTngCX9cKpFe0FmkErrPZdCyV7ViVi1lTXPPi7ocnvL1QM DddthpgDa/UOZ8yXm4ObAtPYgzQTjoou9NqBfs+uDux9DAFGJkeLeqP+8cq6a1Ny7C POlPzrfyXatqOVf4PEoQ1j2ExNd0UcZ0WB+w9M6wO9onx7SrhhoRsVPBLtHY24SKwC YdHHi6qH1GS9bKvaTnBIQNMawgZWbFmp3WNxjm+t6g/hm/lWiK18fbLgsJHWUGJKv0 Sl5YCYpE0grp/zEqUNKWHbGxpKR+qL+Q2XOW4pV0AZhl2ZtB+dOHnh1HbUyBvbSKZy 5CHTYvCL7SLgiDEASWS14fY6ggtSuWDAqXQ1i/XwsxiLqCsbECdAhTU7ydNczl5HTb xqLwv2Qld9SHZCBCQ1p+6HX6jIC9lbndQ0snjnPsLlRckozqc5+bg1Nc4VKvil5DKM GNwcSlYh39uz68cAiu/aafwo= From: Dave Reisner To: pacman-dev@archlinux.org Date: Thu, 5 Jul 2018 10:42:42 -0400 Message-Id: <20180705144244.15619-2-dreisner@archlinux.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180705144244.15619-1-dreisner@archlinux.org> References: <20180705144244.15619-1-dreisner@archlinux.org> Subject: [pacman-dev] [PATCH 2/4] Create a convenience library for reused functionality X-BeenThere: pacman-dev@archlinux.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Discussion list for pacman development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Discussion list for pacman development Cc: Dave Reisner Errors-To: pacman-dev-bounces@archlinux.org Sender: "pacman-dev" This is shared between pacman and pacman-conf (and might be used by other binaries in the future) -- no need to compile it once for each consumer. --- src/pacman/.gitignore | 3 ++- src/pacman/Makefile.am | 37 +++++++++++++++++++------------------ 2 files changed, 21 insertions(+), 19 deletions(-) diff --git a/src/pacman/.gitignore b/src/pacman/.gitignore index 24e11ed3..9889c35e 100644 --- a/src/pacman/.gitignore +++ b/src/pacman/.gitignore @@ -1,6 +1,7 @@ .deps .libs +*.l[ao] pacman pacman.exe pacman-conf -pacman-conf.exe \ No newline at end of file +pacman-conf.exe diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 2344daff..15cf20ce 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -8,6 +8,19 @@ hookdir = ${sysconfdir}/pacman.d/hooks/ cachedir = ${localstatedir}/cache/pacman/pkg/ logfile = ${localstatedir}/log/pacman.log +noinst_LTLIBRARIES = \ + libbasic.la + +libbasic_la_SOURCES = \ + conf.h conf.c \ + ini.h ini.c \ + callback.h callback.c \ + util.h util.c \ + util-common.h util-common.c + +libbasic_la_LIBADD = \ + $(top_builddir)/lib/libalpm/.libs/libalpm.la + bin_PROGRAMS = pacman pacman-conf AM_CPPFLAGS = \ @@ -31,37 +44,25 @@ endif pacman_SOURCES = \ check.h check.c \ - conf.h conf.c \ database.c \ deptest.c \ files.c \ - ini.h ini.c \ package.h package.c \ pacman.h pacman.c \ query.c \ remove.c \ sighandler.h sighandler.c \ sync.c \ - callback.h callback.c \ - upgrade.c \ - util.h util.c \ - util-common.h util-common.c + upgrade.c pacman_LDADD = \ $(LTLIBINTL) \ + libbasic.la \ $(top_builddir)/lib/libalpm/.libs/libalpm.la \ $(LIBARCHIVE_LIBS) -pacman_conf_SOURCES = pacman-conf.c \ - util.h \ - util.c \ - ini.h \ - ini.c \ - util-common.h \ - util-common.c \ - callback.h \ - callback.c \ - conf.h \ - conf.c +pacman_conf_SOURCES = pacman-conf.c -pacman_conf_LDADD = $(top_builddir)/lib/libalpm/.libs/libalpm.la +pacman_conf_LDADD = \ + libbasic.la \ + $(top_builddir)/lib/libalpm/.libs/libalpm.la From patchwork Thu Jul 5 14:42:43 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Reisner X-Patchwork-Id: 672 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id B56E85459701 for ; Thu, 5 Jul 2018 14:43:15 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on apollo X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_MED=-2.3,T_DKIMWL_WL_HIGH=-0.01 autolearn=ham autolearn_force=no version=3.4.1 X-Spam-BL-Results: [127.0.9.2] Received: from orion.archlinux.org (orion.archlinux.org [IPv6:2a01:4f8:160:6087::1]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:15 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 85640BAD18F25; Thu, 5 Jul 2018 14:43:08 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [IPv6:2a01:4f8:160:3033::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS; Thu, 5 Jul 2018 14:43:08 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 690D92C794; Thu, 5 Jul 2018 14:43:08 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=luna2; t=1530801788; bh=oX6efO0C17EHJvHqpTHAGAPhvObYO34EHLUfnQWNUS0=; h=From:To:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: Reply-To:Cc; b=DTbHNqntg/O26FABb1dXvzUL68m1+XE/L1axVcyUM4J0Vcte18IVGwgs4zs1LaWff hkMn35jycTYtnz9qaKry7ePr5SnbunFSEHNVQwbmNo32VB2988zkRpMGX3I62TdvGf 9zRr5yqMvShsOMZn4Th3yfn/tTq/vOKGcI0ZPB5DMlgnc48x5nGxfE1nj6ZVRsizTQ iFMczGgR7XBzKGjB5vXnq6S9EQim3bnx0FkGc+V34m8u+WPOiFr0AvnP9guAxz9rK8 gu/R4Wg4YmoTCdZDS4OhtoNUlcHFoleXMrEdcfpudtSs5DMBIgDQi6z1LRHJHb6QY7 tfjF0u/gqnViwC2ACfwGZgSlsswsNsnwd+efq7FWU4aoXyofWy1B41O5ijEjSRv9Ew 1ZfadDEo9Sz4v5cuky5tLpEZGzwFvn2ePw5D7FoxqNU8++MSYGWJi09IARTIe6Cv6B VoHbWUOlzBlcdys2jjXiYurFRKcAruc2fP7pj/WazA1bAyHrFzmV3yRpg5pk8fl+a4 GXNpEMrsJlQZIyeKI0bIDzY1W/AzXfM+n1tPXRk5SaC0J+HAPjjVEu+GxwVJUoCVcO RdcU4O5Kya8EmkqkqgWqq0aiwY2pNIiLkMY8Sd6kF/j4y1YIgn8G7l13aveIYCiO4L qq713bo4PTJDZSgFn2keo8v4= Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id C79872C12B for ; Thu, 5 Jul 2018 14:43:06 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by luna.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:06 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 3DA36BAD18E12; Thu, 5 Jul 2018 14:42:55 +0000 (UTC) Received: from localhost (unknown [IPv6:2604:2000:1406:11:309a:eca6:7ba1:ff59]) (using TLSv1.2 with cipher DHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) (Authenticated sender: dreisner) by orion.archlinux.org (Postfix) with ESMTPSA id 64BA5BAD18E0C; Thu, 5 Jul 2018 14:42:54 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=orion; t=1530801775; bh=oX6efO0C17EHJvHqpTHAGAPhvObYO34EHLUfnQWNUS0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=gW1gZEX/oGIUUZItTkH1MyNov/JdTCWtVDSR/9qXVc7vGIwYK/3DT8XwBTouXVdFv d0vbpIEDScC+e6wYWmpT0S+Ud1zLAqbtBjg5zyIBkd4WPAiQDMVmX5fUgUNYJnwgeA mobFj6A4I5O9XWW5aLNhUTnRiDvgH6cELEDvlC+ZSuI92tM1TfNpPsBL9hTraC6y7Q 1JY1nvhyJRMFYPuY+AaUp3GP4JkujNE8kcyQ6kHW2P3fJsKl9UB6gEElHbDpuT3M6a 8jHYoMm86NDLUzMh6ZcfaxLd4mo2uxyHpq/He9Q+t8qHi0GxkshlpbX8jZUxMx2JIk dtlifvZkscKq0NAZJ7rlAlscZs+J/1ZX1n9hgfdhhh38dHyh/8ozRXzVgg5RivOfXQ xFI+WpqoTSQkxUHIoCFOBUceSbBFYeT3xpYJ4BSoflYQdy0DZ6OunZdfhyrOuPLeMn C0kCzBfHvRwOTBBE0GjpJkSXxOax4dlE06E89IN10gXm0ZLCoG1CGenor8K1pG+W9e oQ2eAeEP79cUBsswzot5cfNb4XU1FvdzztOr/eTSAMqsM0cyRPowLQU1GwXJoOhEh2 IemVcku7mCx1Xk3CA6XRpq6XenNCWvEajqE6o5pNLBD1CzFIeN58fDYHduaD0uTivg vZQ3LAri4aAg+cEzB3MFr/5A= From: Dave Reisner To: pacman-dev@archlinux.org Date: Thu, 5 Jul 2018 10:42:43 -0400 Message-Id: <20180705144244.15619-3-dreisner@archlinux.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180705144244.15619-1-dreisner@archlinux.org> References: <20180705144244.15619-1-dreisner@archlinux.org> Subject: [pacman-dev] [PATCH 3/4] doc: use implicit rules to build manpages X-BeenThere: pacman-dev@archlinux.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Discussion list for pacman development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Discussion list for pacman development Cc: Dave Reisner Errors-To: pacman-dev-bounces@archlinux.org Sender: "pacman-dev" Use implicit dependency rules to translate asciidoc inputs to HTML and manpage outputs. We should only have to declare explicit dependencies for odd cases, e.g. the PKGBUILD documentation has an additional include file and isn't a 1:1 conversion. --- doc/Makefile.am | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/doc/Makefile.am b/doc/Makefile.am index 8dec4ab1..2ac38cba 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -3,7 +3,7 @@ # files listed in EXTRA_DIST no matter what. However, we only add them to # man_MANS if --enable-asciidoc and/or --enable-doxygen are used. -ASCIIDOC_MANS = \ +MANPAGES = \ alpm-hooks.5 \ pacman.8 \ makepkg.8 \ @@ -66,11 +66,11 @@ EXTRA_DIST = \ submitting-patches.asciidoc \ translation-help.asciidoc \ Doxyfile \ - $(ASCIIDOC_MANS) \ + $(MANPAGES) \ $(DOXYGEN_MANS) # Files that should be removed, but which Automake does not know. -MOSTLYCLEANFILES = *.xml $(ASCIIDOC_MANS) $(HTML_DOCS) repo-remove.8 website.tar.gz +MOSTLYCLEANFILES = *.xml $(MANPAGES) $(HTML_DOCS) repo-remove.8 website.tar.gz # Ensure manpages are fresh when building a dist tarball dist-hook: @@ -85,7 +85,7 @@ REAL_PACKAGE_VERSION = $(PACKAGE_VERSION) endif man_MANS = -dist_man_MANS = $(ASCIIDOC_MANS) +dist_man_MANS = $(MANPAGES) if USE_DOXYGEN man_MANS += $(DOXYGEN_MANS) @@ -96,6 +96,7 @@ doxygen.in: $(DOXYGEN) $(srcdir)/Doxyfile endif +man: $(MANPAGES) html: $(HTML_DOCS) website: website.tar.gz @@ -129,11 +130,12 @@ A2X_OPTS = \ -f manpage \ --xsltproc-opts='-param man.endnotes.list.enabled 0 -param man.endnotes.are.numbered 0' -# These rules are due to the includes and files of the asciidoc text -$(ASCIIDOC_MANS): asciidoc.conf footer.asciidoc Makefile.am +# Generate manpages +%: %.asciidoc asciidoc.conf footer.asciidoc Makefile.am $(AM_V_GEN)a2x $(A2X_OPTS) --asciidoc-opts="$(ASCIIDOC_OPTS) --out-file=./$@.xml" $(srcdir)/$@.asciidoc -%.html: %.asciidoc +# Generate HTML pages +%.html: %.asciidoc asciidoc.conf footer.asciidoc Makefile.am $(AM_V_GEN)asciidoc $(ASCIIDOC_OPTS) -o - $*.asciidoc | \ sed -e 's/\r$$//' > $@ @@ -142,27 +144,15 @@ HACKING.html: ../HACKING sed -e 's/\r$$//' > $@ # Customizations for certain HTML docs -$(HTML_MANPAGES): asciidoc.conf footer.asciidoc Makefile.am -$(HTML_OTHER): asciidoc.conf Makefile.am %.html: ASCIIDOC_OPTS += -a linkcss -a toc -a icons -a max-width=960px -a stylesheet=asciidoc-override.css %.8.html: ASCIIDOC_OPTS += -d manpage %.5.html: ASCIIDOC_OPTS += -d manpage %.3.html: ASCIIDOC_OPTS += -d manpage -# Dependency rules -alpm-hooks.5 alpm-hooks.5.html: alpm-hooks.5.asciidoc -pacman.8 pacman.8.html: pacman.8.asciidoc -makepkg.8 makepkg.8.html: makepkg.8.asciidoc -makepkg-template.1 makepkg-template.1.html: makepkg-template.1.asciidoc -repo-add.8 repo-add.8.html: repo-add.8.asciidoc -vercmp.8 vercmp.8.html: vercmp.8.asciidoc -pkgdelta.8 pkgdelta.8.html: pkgdelta.8.asciidoc -pacman-key.8 pacman-key.8.html: pacman-key.8.asciidoc +# Custom dependency rules PKGBUILD.5 PKGBUILD.5.html: PKGBUILD.5.asciidoc PKGBUILD-example.txt -makepkg.conf.5 makepkg.conf.5.html: makepkg.conf.5.asciidoc -pacman.conf.5 pacman.conf.5.html: pacman.conf.5.asciidoc -libalpm.3 libalpm.3.html: libalpm.3.asciidoc -# this one is just a symlink + +# Manpages as symlinks repo-remove.8: repo-add.8 $(RM) repo-remove.8 $(LN_S) repo-add.8 repo-remove.8 From patchwork Thu Jul 5 14:42:44 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Dave Reisner X-Patchwork-Id: 673 Return-Path: Delivered-To: patchwork@archlinux.org Received: from apollo.archlinux.org (localhost [127.0.0.1]) by apollo.archlinux.org (Postfix) with ESMTP id AD97E5459710 for ; Thu, 5 Jul 2018 14:43:18 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.4.1 (2015-04-28) on apollo X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=DKIM_SIGNED=0.1, DKIM_VALID=-0.1,DKIM_VALID_AU=-0.1,MAILING_LIST_MULTI=-1, RCVD_IN_DNSWL_MED=-2.3,T_DKIMWL_WL_HIGH=-0.01 autolearn=ham autolearn_force=no version=3.4.1 X-Spam-BL-Results: [127.0.9.2] Received: from orion.archlinux.org (orion.archlinux.org [88.198.91.70]) by apollo.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:18 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id B2472BAD18FBE; Thu, 5 Jul 2018 14:43:11 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [IPv6:2a01:4f8:160:3033::2]) (using TLSv1.2 with cipher ADH-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by orion.archlinux.org (Postfix) with ESMTPS; Thu, 5 Jul 2018 14:43:11 +0000 (UTC) Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 9494D2C56E; Thu, 5 Jul 2018 14:43:11 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=luna2; t=1530801791; bh=od3hbRQ0QKmE/6+9ng7m5KvGcauFHFdqpZUFBzp9Bts=; h=From:To:Date:In-Reply-To:References:Subject:List-Id: List-Unsubscribe:List-Archive:List-Post:List-Help:List-Subscribe: Reply-To:Cc; b=MyQ0FFs9gM8QI1X1jaX+Fg/JaoBdb1Dhxik3WcOG+0eHYpzT6YAm0F/kW9BrV2+PF IYGJY1w9DaGhhWnRmbEzh1Czls4sjOz7EOsKalaIpfYjapdAgFgAVKS/+fYtHfqB9S LB7pL6LHg661cWVKDi0NcPbZPCN29NfTHm4sM5VmTi7+EDTygpCHJDwAbQ9RzrEOR7 VgrWUYHym6NzAB0XM9NbpxgoONzIYH73Oo1XMXzhXAq9Lw5IijAYO9sO6peCnEKGOb /KFVpWe+1de8wiNFg0NwInfDnofiWMfsqiOjHf7fOR6WLdiDdefmc0SYGnqiaG/s5B nGptYMYzgRKQM+hQyVRduuYu+YaU9Wz7Nt8ClASKe9XIlmSne+Ba4W4wKV2LaDRWRh MeadK55q3xHhhqe93YSBkQfB8DAOJu1uZcWYC5UqPUt5TYNWU9jwycMrOYwhGIGruD czQxtu9+MOjOZTIo+XAkpaw6zZyE1jqh8rE8O9asbX4+pYto+zGwhACVGixyNQDGmL sIjC29gkhmOhJTDuyZ+Der0ARKp0tVZ4hkpi8nV6rB+lo8UKfZH2oGtfW/4Y0sUZaq PFmxtBnkgJMkAlnPpiD/ZFe8ced/JwRb3a5/vw0nkMitV6shN4dYp7Ls9TYz4jVyxD Vuk7H64aRq2BtKgsQu7+kFrM= Received: from luna.archlinux.org (luna.archlinux.org [127.0.0.1]) by luna.archlinux.org (Postfix) with ESMTP id 4D2082C12B for ; Thu, 5 Jul 2018 14:43:08 +0000 (UTC) Received: from orion.archlinux.org (orion.archlinux.org [IPv6:2a01:4f8:160:6087::1]) by luna.archlinux.org (Postfix) with ESMTPS for ; Thu, 5 Jul 2018 14:43:08 +0000 (UTC) Received: from orion.archlinux.org (localhost [127.0.0.1]) by orion.archlinux.org (Postfix) with ESMTP id 9998FBAD18E1B; Thu, 5 Jul 2018 14:42:57 +0000 (UTC) Received: from localhost (unknown [IPv6:2604:2000:1406:11:309a:eca6:7ba1:ff59]) (using TLSv1.2 with cipher DHE-RSA-CHACHA20-POLY1305 (256/256 bits)) (No client certificate requested) (Authenticated sender: dreisner) by orion.archlinux.org (Postfix) with ESMTPSA id DC785BAD18E1A; Thu, 5 Jul 2018 14:42:56 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=archlinux.org; s=orion; t=1530801777; bh=od3hbRQ0QKmE/6+9ng7m5KvGcauFHFdqpZUFBzp9Bts=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=vGRfbC5DFlCeG/tyxpnx4Es6sYO/2357dbOEiogAbv5eAQ9PQ92Q6dbcDDrENKymU pxuG69earNlzGrXbgJIpyIMgJzKmPHo5Sz2pePMIZtWGZLQOgCtxCRFxrBvYH1PTEP 6nTlcF6JkrA6h/5VDzP8m8RRRuyutJdN2RR0NMFt7HmQMad+KnuOxOHfShoFZgINPE HZM3RyEaX6YNq6l/Jm9fBTFOVkNaa2SeHfwTyez2B27rvHnx3+Qx5euBEAEH6efRfo BUfVVMs3IbhpvrHmhAcTLUQOiQJ02hcp6GD7RQ9W0ZCrlJPYC5cCquDuMsOtAounP3 GeYllM9kS5gCplBWH1ma4XVaRJh2XTHfjS+AiplMFHwvBgmCapEIPDA5U3uHeeBbGh 0JXCRalifhQGtvfLFNSmfGqL7hd8rPIIGoVxzRmXIfRrOWq7cIjnGjiuLUcQuN56um S6XZrAubrR/t/yyA+mcTKqxZudHBd/lRBADQTQonhfAMC3+DVJ1OOGUfJmXH+uG2aO //7NZu6E5WBWbFDe+aPTV0kUX9BbUhGxQLMHeifjTZmps88g1QECvATyne9OQ5edaS 0icneSpK6NoFn7vubg9JmrVEgCT31xTs9TsILfvokGaFcWd0oLtQ/TCFv3FLF6D6xl 2ZpXy98jp0CbsU59yDVFUDco= From: Dave Reisner To: pacman-dev@archlinux.org Date: Thu, 5 Jul 2018 10:42:44 -0400 Message-Id: <20180705144244.15619-4-dreisner@archlinux.org> X-Mailer: git-send-email 2.18.0 In-Reply-To: <20180705144244.15619-1-dreisner@archlinux.org> References: <20180705144244.15619-1-dreisner@archlinux.org> Subject: [pacman-dev] [PATCH 4/4] Merge expac into src/pacman X-BeenThere: pacman-dev@archlinux.org X-Mailman-Version: 2.1.26 Precedence: list List-Id: Discussion list for pacman development List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Reply-To: Discussion list for pacman development Cc: Dave Reisner Errors-To: pacman-dev-bounces@archlinux.org Sender: "pacman-dev" This introduces code which has long been maintained at: https://github.com/falconindy/expac From the README: expac is a data extraction tool for alpm databases. It features printf-like flexibility and aims to be used as a simple tool for other pacman based utilities which don't link against the library. It uses pacman.conf as a config file for locating and loading your local and sync databases. --- I expect that I'll get some pushback on the use of #pragma here. I don't really know how portable it is to other compilers. Open to suggestions on how to better avoid this (though I'd prefer not to disable the warnings entirely for the file). doc/Makefile.am | 7 +- doc/expac.1.asciidoc | 179 +++++++++ src/pacman/.gitignore | 2 + src/pacman/Makefile.am | 8 +- src/pacman/expac.c | 864 +++++++++++++++++++++++++++++++++++++++++ 5 files changed, 1057 insertions(+), 3 deletions(-) create mode 100644 doc/expac.1.asciidoc create mode 100644 src/pacman/expac.c diff --git a/doc/Makefile.am b/doc/Makefile.am index 2ac38cba..38f7077b 100644 --- a/doc/Makefile.am +++ b/doc/Makefile.am @@ -16,7 +16,8 @@ MANPAGES = \ makepkg.conf.5 \ pacman.conf.5 \ libalpm.3 \ - BUILDINFO.5 + BUILDINFO.5 \ + expac.1 DOXYGEN_MANS = $(wildcard man3/*.3) @@ -32,7 +33,8 @@ HTML_MANPAGES = \ PKGBUILD.5.html \ makepkg.conf.5.html \ pacman.conf.5.html \ - libalpm.3.html + libalpm.3.html \ + expac.1.html HTML_OTHER = \ index.html \ @@ -61,6 +63,7 @@ EXTRA_DIST = \ pacman.conf.5.asciidoc \ BUILDINFO.5.asciidoc \ libalpm.3.asciidoc \ + expac.1.asciidoc \ footer.asciidoc \ index.asciidoc \ submitting-patches.asciidoc \ diff --git a/doc/expac.1.asciidoc b/doc/expac.1.asciidoc new file mode 100644 index 00000000..1c7052b5 --- /dev/null +++ b/doc/expac.1.asciidoc @@ -0,0 +1,179 @@ +expac(1) +========= + +Name +---- +expac - alpm data extraction utility + +Synopsis +-------- +'expac' [options] + +Description +----------- +expac is a data extraction tool for alpm databases. It features printf-like +flexibility and aims to be used as a simple tool for other pacman based +utilities which don't link against the library. It uses pacman.conf as a config +file for locating and loading your local and sync databases. + +Invoking expac consists of supplying a format string, which is generally +described by one to many of the formatting tokens (see the 'FORMATTING' +section), any relevant options and zero to many targets. The format string +'must' be the first non-option argument. Targets can be a simple package name, +a query string (in the case of a search), or in repo/package syntax when the +-sync option is supplied. + + +Options +------- +*-Q, \--query*:: + Search the local database for provided targets. This is the default behavior. + +*-S, \--sync*:: + Search the sync databases for provided targets. + +*-s, --search*:: + Search for packages matching the strings specified by targets. This is a + boolean AND query and regex is allowed. + +*-g, --group*:: + Return packages matching the specified targets as package groups. + +*\--config* :: + Read from for alpm initialization instead of . + +*-H, \--humansize* :: + Format package sizes in SI units according to . Valid options are: ++ +B, K, M, G, T, P, E, Z, Y + +*-1, \--readone*:: + Stop searching after the first result. This only has an effect on -S operations + without -s. + +*-d, \--delim *:: + Separate each package with the specified . The default value is a + newline character. + +*-l, \--listdelim* :: + Separate each list item with the specified . Lists are any interpreted + sequence specified with a capital letter. The default value is two spaces. + +*-p, \--file*:: + Interpret targets as paths to local files. + +*-t, \--timefmt* :: + Output time described by the specified . This string is passed directly + to linkman:strftime[3]. The default format is %c. + +*-v, \--verbose*:: + Output more. `Package not found' errors will be shown, and empty field values + will display as 'None'. + +*-h, \--help*:: + +Display the help message. + +*-V, \--version*:: + +Display version information. + +Formatting +---------- + +The format argument allows the following interpreted sequences: + + %B backup files + + %C conflicts with (no version strings) + + %D depends on + + %E depends on (no version strings) + + %F files (only with -Q) + + %G groups + + %H conflicts with + + %L licenses + + %N required by + + %O optional deps + + %o optional deps (no descriptions) + + %P provides + + %R replaces (no version strings) + + %T replaces + + %S provides (no version strings) + + %a architecture + + %b build date + + %d description + + %e package base + + %f filename (only with -S) + + %g base64 encoded PGP signature (only with -S) + + %h sha256sum + + %V package validation method + + %i has install scriptlet (only with -Q) + + %k download size (only with -S) + + %l install date (only with -Q) + + %m install size + + %M modified backup files (only with -Q) + + %n package name + + %p packager name + + %r repo + + %s md5sum + + %u project URL + + %v version + + %w install reason (only with -Q) + + %! result number (auto-incremented counter, starts at 0) + + %% literal % + +Note that for any lowercase tokens aside from %m and %k, full printf support is +allowed, e.g. %-20n. This does not apply to any list based, date, or numerical +output. + +Standard backslash escape sequences are supported, as per printf(1). + +Examples +-------- + +expac -Ss \'%r/%n %v\n %d\' :: + Emulate pacman\'s search function. + +expac --timefmt=%s \'%b\t%n\' | sort -n | head -10:: + List the oldest 10 installed packages (by build date). + +See Also +-------- +linkman:libalpm[3], linkman:pacman.conf[5] + +include::footer.asciidoc[] diff --git a/src/pacman/.gitignore b/src/pacman/.gitignore index 9889c35e..78b78159 100644 --- a/src/pacman/.gitignore +++ b/src/pacman/.gitignore @@ -5,3 +5,5 @@ pacman pacman.exe pacman-conf pacman-conf.exe +expac +expac.exe diff --git a/src/pacman/Makefile.am b/src/pacman/Makefile.am index 15cf20ce..deb386ab 100644 --- a/src/pacman/Makefile.am +++ b/src/pacman/Makefile.am @@ -21,7 +21,7 @@ libbasic_la_SOURCES = \ libbasic_la_LIBADD = \ $(top_builddir)/lib/libalpm/.libs/libalpm.la -bin_PROGRAMS = pacman pacman-conf +bin_PROGRAMS = pacman pacman-conf expac AM_CPPFLAGS = \ -imacros $(top_builddir)/config.h \ @@ -66,3 +66,9 @@ pacman_conf_SOURCES = pacman-conf.c pacman_conf_LDADD = \ libbasic.la \ $(top_builddir)/lib/libalpm/.libs/libalpm.la + +expac_SOURCES = expac.c + +expac_LDADD = \ + libbasic.la \ + $(top_builddir)/lib/libalpm/.libs/libalpm.la diff --git a/src/pacman/expac.c b/src/pacman/expac.c new file mode 100644 index 00000000..332414a0 --- /dev/null +++ b/src/pacman/expac.c @@ -0,0 +1,864 @@ +/* + * expac.c + * + * Copyright (c) 2018 Pacman Development Team + * Copyright (c) 2010-2018 by Dave Reisner + * + * 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, see . + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "conf.h" +#include "util.h" + +#define DEFAULT_DELIM "\n" +#define DEFAULT_LISTDELIM " " +#define DEFAULT_TIMEFMT "%c" +#define SIZE_TOKENS "BKMGTPEZY\0" + +static char const digits[] = "0123456789"; +static char const printf_flags[] = "'-+ #0I"; + +typedef enum package_corpus_t { + CORPUS_LOCAL, + CORPUS_SYNC, + CORPUS_FILE, +} package_corpus_t; + +typedef enum search_what_t { + SEARCH_EXACT, + SEARCH_GROUPS, + SEARCH_REGEX, +} search_what_t; + +typedef struct expac_t { + config_t *config; +} expac_t; + +bool opt_readone = false; +bool opt_verbose = false; +char opt_humansize = 'B'; +package_corpus_t opt_corpus = CORPUS_LOCAL; +search_what_t opt_what = SEARCH_EXACT; +const char *opt_format = NULL; +const char *opt_timefmt = DEFAULT_TIMEFMT; +const char *opt_listdelim = DEFAULT_LISTDELIM; +const char *opt_delim = DEFAULT_DELIM; +const char *opt_config_file = "/etc/pacman.conf"; +int opt_pkgcounter = 0; + +typedef const char *(*extractfn)(void*); + +static int is_valid_size_unit(char *u) +{ + return u[0] != '\0' && u[1] == '\0' && + memchr(SIZE_TOKENS, *u, strlen(SIZE_TOKENS)) != NULL; +} + +static const char *alpm_backup_get_name(alpm_backup_t *bkup) +{ + return bkup->name; +} + +static char *size_to_string(off_t pkgsize) +{ + static char out[64]; + + if(opt_humansize == 'B') { + snprintf(out, sizeof(out), "%jd", (intmax_t)pkgsize); + } else { + snprintf(out, sizeof(out), "%.2f %ciB", humanize_size(pkgsize, opt_humansize, 0, NULL), opt_humansize); + } + + return out; +} + +static char *format_optdep(alpm_depend_t *optdep) +{ + char *out = NULL; + + if(asprintf(&out, "%s: %s", optdep->name, optdep->desc) < 0) { + return NULL; + } + + return out; +} + +static const char *alpm_dep_get_name(alpm_depend_t *dep) +{ + return dep->name; +} + +static void usage(void) +{ + fprintf(stderr, "expac %s\n" + "Usage: expac [options] target...\n\n", VERSION); + fprintf(stderr, + " Options:\n" + " -Q, --query search local DB (default)\n" + " -S, --sync search sync DBs\n" + " -s, --search search for matching regex\n" + " -g, --group return packages matching targets as groups\n" + " -H, --humansize format package sizes in SI units (default: bytes)\n" + " -1, --readone return only the first result of a sync search\n\n" + " -d, --delim separator used between packages (default: \"\\n\")\n" + " -l, --listdelim separator used between list elements (default: \" \")\n" + " -p, --file query local files instead of the DB\n" + " -t, --timefmt date format passed to strftime (default: \"%%c\")\n" + " --config read from for alpm initialization (default: /etc/pacman.conf)\n\n" + " -v, --verbose be more verbose\n\n" + " -V, --version display version information\n" + " -h, --help display this help information\n\n" + "For more details see expac(1).\n"); +} + +static int parse_options(int *argc, char **argv[]) +{ + static struct option opts[] = { + {"readone", no_argument, 0, '1'}, + {"delim", required_argument, 0, 'd'}, + {"listdelim", required_argument, 0, 'l'}, + {"group", required_argument, 0, 'g'}, + {"help", no_argument, 0, 'h'}, + {"file", no_argument, 0, 'p'}, + {"humansize", required_argument, 0, 'H'}, + {"query", no_argument, 0, 'Q'}, + {"sync", no_argument, 0, 'S'}, + {"search", no_argument, 0, 's'}, + {"timefmt", required_argument, 0, 't'}, + {"verbose", no_argument, 0, 'v'}, + {"version", no_argument, 0, 'V'}, + {"config", required_argument, 0, 128}, + {0, 0, 0, 0} + }; + + for(;;) { + int opt; + + opt = getopt_long(*argc, *argv, "1l:d:gH:hf:pQSst:Vv", opts, NULL); + if(opt < 0) { + break; + } + + switch (opt) { + case 'S': + opt_corpus = CORPUS_SYNC; + break; + case 'Q': + opt_corpus = CORPUS_LOCAL; + break; + case '1': + opt_readone = true; + break; + case 'd': + opt_delim = optarg; + break; + case 'g': + opt_what = SEARCH_GROUPS; + break; + case 'l': + opt_listdelim = optarg; + break; + case 'H': + if(!is_valid_size_unit(optarg)) { + fprintf(stderr, "error: invalid SI size formatter: %s\n", optarg); + return -1; + } + opt_humansize = *optarg; + break; + case 'h': + usage(); + exit(0); + case 'p': + opt_corpus = CORPUS_FILE; + break; + case 's': + opt_what = SEARCH_REGEX; + break; + case 't': + opt_timefmt = optarg; + break; + case 'v': + opt_verbose = true; + break; + case 128: + opt_config_file = optarg; + break; + case 'V': + printf("expac v%s\n", VERSION); + break; + + case '?': + return -EINVAL; + default: + return -EINVAL; + } + } + + if(optind < *argc) { + opt_format = (*argv)[optind++]; + } else { + fprintf(stderr, "error: missing format string (use -h for help)\n"); + return -EINVAL; + } + + *argc -= optind; + *argv += optind; + + return 0; +} + +static int print_escaped(const char *delim) +{ + const char *f; + int out = 0; + + for(f = delim; *f != '\0'; f++) { + if(*f == '\\') { + switch (*++f) { + case '\\': + fputc('\\', stdout); + break; + case '"': + fputc('\"', stdout); + break; + case 'a': + fputc('\a', stdout); + break; + case 'b': + fputc('\b', stdout); + break; + case 'e': /* \e is nonstandard */ + fputc('\033', stdout); + break; + case 'n': + fputc('\n', stdout); + break; + case 'r': + fputc('\r', stdout); + break; + case 't': + fputc('\t', stdout); + break; + case 'v': + fputc('\v', stdout); + break; + case '0': + fputc('\0', stdout); + break; + default: + fputc(*f, stdout); + break; + } + ++out; + } else { + fputc(*f, stdout); + ++out; + } + } + + return out; +} + +static int print_list(alpm_list_t *list, extractfn fn) +{ + alpm_list_t *i; + int out = 0; + + if(!list) { + if(opt_verbose) { + out += printf("None"); + } + return out; + } + + i = list; + for(;;) { + const char *item = fn ? fn(i->data) : i->data; + if(item == NULL) { + continue; + } + + out += printf("%s", item); + + if((i = i->next)) { + out += print_escaped(opt_listdelim); + } else { + break; + } + } + + return out; +} + +static int print_allocated_list(alpm_list_t *list, extractfn fn) +{ + int out = print_list(list, fn); + alpm_list_free(list); + return out; +} + +static int print_time(time_t timestamp) { + char buffer[64]; + int out = 0; + + if(!timestamp) { + if(opt_verbose) { + out += printf("None"); + } + return out; + } + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + /* no overflow here, strftime prints a max of 64 including null */ + strftime(&buffer[0], 64, opt_timefmt, localtime(×tamp)); +#pragma GCC diagnostic pop + + out += printf("%s", buffer); + + return out; +} + +static int print_filelist(alpm_filelist_t *filelist) +{ + int out = 0; + size_t i; + + for(i = 0; i < filelist->count; i++) { + out += printf("%s", (filelist->files + i)->name); + if(i < filelist->count - 1) { + out += print_escaped(opt_listdelim); + } + } + + return out; +} + +static bool backup_file_is_modified(const alpm_backup_t *backup_file) +{ + char fullpath[PATH_MAX]; + char *md5sum = NULL; + bool modified; + + snprintf(fullpath, sizeof(fullpath), "%s%s", config->rootdir, backup_file->name); + + md5sum = alpm_compute_md5sum(fullpath); + if(md5sum == NULL) { + return false; + } + + modified = strcmp(md5sum, backup_file->hash) != 0; + free(md5sum); + + return modified; +} + +static alpm_list_t *get_modified_files(alpm_pkg_t *pkg) +{ + alpm_list_t *i, *modified_files = NULL; + + for(i = alpm_pkg_get_backup(pkg); i; i = i->next) { + const alpm_backup_t *backup = i->data; + if(backup->hash && backup_file_is_modified(backup)) { + modified_files = alpm_list_add(modified_files, backup->name); + } + } + + return modified_files; +} + +static alpm_list_t *get_validation_method(alpm_pkg_t *pkg) +{ + alpm_list_t *validation = NULL; + + alpm_pkgvalidation_t v = alpm_pkg_get_validation(pkg); + + if(v == ALPM_PKG_VALIDATION_UNKNOWN) { + return alpm_list_add(validation, (void*)"Unknown"); + } + + if(v & ALPM_PKG_VALIDATION_NONE) { + return alpm_list_add(validation, (void*)"None"); + } + + if(v & ALPM_PKG_VALIDATION_MD5SUM) { + validation = alpm_list_add(validation, (void*)"MD5 Sum"); + } + if(v & ALPM_PKG_VALIDATION_SHA256SUM) { + validation = alpm_list_add(validation, (void*)"SHA256 Sum"); + } + if(v & ALPM_PKG_VALIDATION_SIGNATURE) { + validation = alpm_list_add(validation, (void*)"Signature"); + } + + return validation; +} + +static void print_pkg(alpm_pkg_t *pkg, const char *format) +{ + const char *f, *end; + int out = 0; + + end = format + strlen(format); + + for(f = format; f < end; f++) { + if(*f == '%') { + char fmt[64] = {0}; + int l = 1; + + l += strspn(f + l, printf_flags); + l += strspn(f + l, digits); + memcpy(fmt, f, l); + fmt[l] = 's'; + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wformat-nonliteral" + f += l; + switch (*f) { + /* simple attributes */ + case 'f': /* filename */ + out += printf(fmt, alpm_pkg_get_filename(pkg)); + break; + case 'e': /* package base */ + out += printf(fmt, alpm_pkg_get_base(pkg)); + break; + case 'n': /* package name */ + out += printf(fmt, alpm_pkg_get_name(pkg)); + break; + case 'v': /* version */ + out += printf(fmt, alpm_pkg_get_version(pkg)); + break; + case 'd': /* description */ + out += printf(fmt, alpm_pkg_get_desc(pkg)); + break; + case 'u': /* project url */ + out += printf(fmt, alpm_pkg_get_url(pkg)); + break; + case 'p': /* packager name */ + out += printf(fmt, alpm_pkg_get_packager(pkg)); + break; + case 's': /* md5sum */ + out += printf(fmt, alpm_pkg_get_md5sum(pkg)); + break; + case 'a': /* architecture */ + out += printf(fmt, alpm_pkg_get_arch(pkg)); + break; + case 'i': /* has install scriptlet? */ + out += printf(fmt, alpm_pkg_has_scriptlet(pkg) ? "yes" : "no"); + break; + case 'r': /* repo */ + out += printf(fmt, alpm_db_get_name(alpm_pkg_get_db(pkg))); + break; + case 'w': /* install reason */ + out += printf(fmt, alpm_pkg_get_reason(pkg) ? "dependency" : "explicit"); + break; + case '!': /* result number */ + fmt[strlen(fmt)-1] = 'd'; + out += printf(fmt, opt_pkgcounter++); + break; + case 'g': /* base64 gpg sig */ + out += printf(fmt, alpm_pkg_get_base64_sig(pkg)); + break; + case 'h': /* sha256sum */ + out += printf(fmt, alpm_pkg_get_sha256sum(pkg)); + break; + + /* times */ + case 'b': /* build date */ + out += print_time(alpm_pkg_get_builddate(pkg)); + break; + case 'l': /* install date */ + out += print_time(alpm_pkg_get_installdate(pkg)); + break; + + /* sizes */ + case 'k': /* download size */ + out += printf(fmt, size_to_string(alpm_pkg_get_size(pkg))); + break; + case 'm': /* install size */ + out += printf(fmt, size_to_string(alpm_pkg_get_isize(pkg))); + break; + + /* lists */ + case 'F': /* files */ + out += print_filelist(alpm_pkg_get_files(pkg)); + break; + case 'N': /* requiredby */ + out += print_list(alpm_pkg_compute_requiredby(pkg), NULL); + break; + case 'L': /* licenses */ + out += print_list(alpm_pkg_get_licenses(pkg), NULL); + break; + case 'G': /* groups */ + out += print_list(alpm_pkg_get_groups(pkg), NULL); + break; + case 'E': /* depends (shortdeps) */ + out += print_list(alpm_pkg_get_depends(pkg), (extractfn)alpm_dep_get_name); + break; + case 'D': /* depends */ + out += print_list(alpm_pkg_get_depends(pkg), (extractfn)alpm_dep_compute_string); + break; + case 'O': /* optdepends */ + out += print_list(alpm_pkg_get_optdepends(pkg), (extractfn)format_optdep); + break; + case 'o': /* optdepends (shortdeps) */ + out += print_list(alpm_pkg_get_optdepends(pkg), (extractfn)alpm_dep_get_name); + break; + case 'H': /* conflicts */ + out += print_list(alpm_pkg_get_conflicts(pkg), (extractfn)alpm_dep_compute_string); + break; + case 'C': /* conflicts (shortdeps) */ + out += print_list(alpm_pkg_get_conflicts(pkg), (extractfn)alpm_dep_get_name); + break; + case 'S': /* provides (shortdeps) */ + out += print_list(alpm_pkg_get_provides(pkg), (extractfn)alpm_dep_get_name); + break; + case 'P': /* provides */ + out += print_list(alpm_pkg_get_provides(pkg), (extractfn)alpm_dep_compute_string); + break; + case 'R': /* replaces (shortdeps) */ + out += print_list(alpm_pkg_get_replaces(pkg), (extractfn)alpm_dep_get_name); + break; + case 'T': /* replaces */ + out += print_list(alpm_pkg_get_replaces(pkg), (extractfn)alpm_dep_compute_string); + break; + case 'B': /* backup */ + out += print_list(alpm_pkg_get_backup(pkg), (extractfn)alpm_backup_get_name); + break; + case 'V': /* package validation */ + out += print_allocated_list(get_validation_method(pkg), NULL); + break; + case 'M': /* modified */ + out += print_allocated_list(get_modified_files(pkg), NULL); + break; + case '%': + fputc('%', stdout); + out++; + break; + default: + fputc('?', stdout); + out++; + break; + } + } else if(*f == '\\') { + char esc[3] = { f[0], f[1], '\0' }; + out += print_escaped(esc); + ++f; + } else { + fputc(*f, stdout); + out++; + } + } +#pragma GCC diagnostic pop + + /* only print a delimeter if any package data was outputted */ + if(out > 0) { + print_escaped(opt_delim); + } +} + +static alpm_list_t *all_packages(alpm_list_t *dbs) +{ + alpm_list_t *i, *packages = NULL; + + for(i = dbs; i; i = i->next) { + packages = alpm_list_join(packages, alpm_list_copy(alpm_db_get_pkgcache(i->data))); + } + + return packages; +} + +static alpm_list_t *search_packages(alpm_list_t *dbs, alpm_list_t *targets) +{ + alpm_list_t *i, *packages = NULL; + + for(i = dbs; i; i = i->next) { + packages = alpm_list_join(packages, alpm_db_search(i->data, targets)); + } + + return packages; +} + +static alpm_list_t *search_groups(alpm_list_t *dbs, alpm_list_t *groupnames) +{ + alpm_list_t *i, *j, *packages = NULL; + + for(i = groupnames; i; i = i->next) { + for(j = dbs; j; j = j->next) { + alpm_group_t *grp = alpm_db_get_group(j->data, i->data); + if(grp != NULL) { + packages = alpm_list_join(packages, alpm_list_copy(grp->packages)); + } + } + } + + return packages; +} + +static alpm_list_t *search_exact(alpm_list_t *dblist, alpm_list_t *targets) +{ + alpm_list_t *results = NULL; + + /* resolve each target individually from the repo pool */ + for(alpm_list_t *t = targets; t; t = t->next) { + char *pkgname, *reponame; + alpm_list_t *r; + int found = 0; + + pkgname = reponame = t->data; + if(strchr(pkgname, '/')) { + strsep(&pkgname, "/"); + } else { + reponame = NULL; + } + + for(r = dblist; r; r = r->next) { + alpm_db_t *repo = r->data; + alpm_pkg_t *pkg; + + if(reponame && strcmp(reponame, alpm_db_get_name(repo)) != 0) { + continue; + } + + pkg = alpm_db_get_pkg(repo, pkgname); + if(pkg == NULL) { + continue; + } + + found = 1; + results = alpm_list_add(results, pkg); + if(opt_readone) { + break; + } + } + + if(!found && opt_verbose) { + fprintf(stderr, "error: package `%s' not found\n", pkgname); + } + } + + return results; +} + +static alpm_list_t *resolve_targets(alpm_list_t *dblist, alpm_list_t *targets) +{ + if(targets == NULL) { + return all_packages(dblist); + } + + if(opt_what == SEARCH_REGEX) { + return search_packages(dblist, targets); + } + + if(opt_what == SEARCH_GROUPS) { + return search_groups(dblist, targets); + } + + return search_exact(dblist, targets); +} + +static void expac_free(expac_t *expac) +{ + free(expac); + config_free(config); +} + +static int expac_new(expac_t **expac, const char *config_file) +{ + expac_t *e; + + config = config_new(); + + e = calloc(1, sizeof(*e)); + if(e == NULL) { + return -ENOMEM; + } + + if(parseconfig(config_file) != 0) { + fprintf(stderr, "error parsing '%s'\n", config_file); + return 1; + } + + e->config = config; + *expac = e; + + return 0; +} + +static alpm_list_t *expac_search_files(expac_t *expac, alpm_list_t *targets) +{ + alpm_list_t *i, *r = NULL; + + for(i = targets; i; i = i->next) { + const char *path = i->data; + alpm_pkg_t *pkg; + + if(alpm_pkg_load(expac->config->handle, path, 0, 0, &pkg) != 0) { + fprintf(stderr, "error: %s: %s\n", path, + alpm_strerror(alpm_errno(expac->config->handle))); + continue; + } + + r = alpm_list_add(r, pkg); + } + + return r; +} + +static alpm_list_t *expac_search_local(expac_t *expac, alpm_list_t *targets) +{ + alpm_list_t *dblist, *r; + + dblist = alpm_list_add(NULL, alpm_get_localdb(expac->config->handle)); + r = resolve_targets(dblist, targets); + alpm_list_free(dblist); + + return r; +} + +static alpm_list_t *expac_search_sync(expac_t *expac, alpm_list_t *targets) +{ + return resolve_targets(alpm_get_syncdbs(expac->config->handle), targets); +} + +static alpm_list_t *expac_search( + expac_t *expac, package_corpus_t corpus, alpm_list_t *targets) +{ + switch (corpus) { + case CORPUS_LOCAL: + return expac_search_local(expac, targets); + case CORPUS_SYNC: + return expac_search_sync(expac, targets); + case CORPUS_FILE: + return expac_search_files(expac, targets); + } + + /* should be unreachable */ + return NULL; +} + +static int read_targets_from_file(FILE *in, alpm_list_t **targets) +{ + char line[BUFSIZ]; + int i = 0, end = 0, targets_added = 0; + + while(!end) { + line[i] = fgetc(in); + + if(feof(in)) + end = 1; + + if(isspace(line[i]) || end) { + line[i] = '\0'; + /* avoid adding zero length arg, if multiple spaces separate args */ + if(i > 0) { + if(!alpm_list_find_str(*targets, line)) { + *targets = alpm_list_add(*targets, strdup(line)); + } + i = 0; + ++targets_added; + } + } else { + ++i; + if(i >= BUFSIZ) { + fprintf(stderr, "error: buffer overflow on stdin\n"); + return -1; + } + } + } + + return targets_added; +} + +static int process_targets(int argc, char **argv, alpm_list_t **targets) +{ + int allow_stdin; + + allow_stdin = !isatty(STDIN_FILENO); + + for(int i = 0; i < argc; ++i) { + if(allow_stdin && strcmp(argv[i], "-") == 0) { + int k; + + k = read_targets_from_file(stdin, targets); + if(k < 0) { + return k; + } + + if(k == 0) { + fputs("error: argument '-' specified with empty stdin\n", stderr); + return -1; + } + + allow_stdin = 0; + } else { + *targets = alpm_list_add(*targets, strdup(argv[i])); + } + } + + return 0; +} + +int main(int argc, char *argv[]) +{ + alpm_list_t *results = NULL, *targets = NULL; + expac_t *expac = NULL; + int r; + + r = parse_options(&argc, &argv); + if(r < 0) { + return 1; + } + + r = process_targets(argc, argv, &targets); + if(r < 0) { + return 1; + } + + r = expac_new(&expac, opt_config_file); + if(r < 0) { + return 1; + } + + results = expac_search(expac, opt_corpus, targets); + if(results == NULL) { + return 1; + } + + for(alpm_list_t *i = results; i; i = i->next) { + print_pkg(i->data, opt_format); + } + + alpm_list_free_inner(targets, free); + alpm_list_free(targets); + alpm_list_free(results); + expac_free(expac); + + return 0; +} + +/* vim: set ts=2 sw=2 noet: */