summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntti-Juhani Kaijanaho <ajk@debian.org>2006-01-28 21:10:55 +0100
committerAntti-Juhani Kaijanaho <ajk@debian.org>2006-01-28 21:10:55 +0100
commit4c90b78306e1334e1bd6dcb105d9bb4d5f53a845 (patch)
tree65b3c9e54508bd4f800ae6caed260c85a29248ce
downloaddctrl-tools-4c90b78306e1334e1bd6dcb105d9bb4d5f53a845.tar.gz
Import 1.100
-rw-r--r--AUTHORS2
-rw-r--r--COPYING340
-rw-r--r--Compatibility18
-rw-r--r--License-Blurb13
-rw-r--r--Makefile31
-rw-r--r--NEWS23
-rw-r--r--PROJECT1
-rw-r--r--README5
-rw-r--r--TODO8
-rw-r--r--debian/README.build-system6
-rw-r--r--debian/changelog282
-rw-r--r--debian/conffiles1
-rw-r--r--debian/control26
-rw-r--r--debian/copyright36
-rw-r--r--debian/librules-manual.txt131
-rw-r--r--debian/librules.mk180
-rw-r--r--debian/rules54
-rw-r--r--fieldtrie.c75
-rw-r--r--fieldtrie.h52
-rw-r--r--fsaf.c230
-rw-r--r--fsaf.h80
-rw-r--r--grep-dctrl.1.cp388
-rw-r--r--grep-dctrl.c548
-rw-r--r--grep-dctrl.rc15
-rw-r--r--i18n.h32
-rw-r--r--msg.c93
-rw-r--r--msg.h133
-rw-r--r--paragraph.c135
-rw-r--r--paragraph.h54
-rw-r--r--predicate.c173
-rw-r--r--predicate.h88
-rw-r--r--rc.c130
-rw-r--r--rc.h30
-rw-r--r--strutil.c110
-rw-r--r--strutil.h43
-rw-r--r--util.c48
-rw-r--r--util.h29
37 files changed, 3643 insertions, 0 deletions
diff --git a/AUTHORS b/AUTHORS
new file mode 100644
index 0000000..9946a9d
--- /dev/null
+++ b/AUTHORS
@@ -0,0 +1,2 @@
+Antti-Juhani Kaijanaho
+
diff --git a/COPYING b/COPYING
new file mode 100644
index 0000000..60549be
--- /dev/null
+++ b/COPYING
@@ -0,0 +1,340 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) 19yy <name of author>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) 19yy name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
diff --git a/Compatibility b/Compatibility
new file mode 100644
index 0000000..07898d4
--- /dev/null
+++ b/Compatibility
@@ -0,0 +1,18 @@
+If you use grep-dctrl in a Debian package, you should depend on the
+grep-dctrl package and heed the following compatibility notes:
+
+ * Always call only the "grep-dctrl" executable.
+ Although the "grep-status" and "grep-available" symlinks
+ are installed by default, this may change in the future.
+ Those symlinks are meant for manual - not scripted - use.
+
+ * Always specify an explicit file name
+ Don't rely on the implicit file name feature. The system
+ administrator may have changed the default file name.
+
+ * Not all features have been with us in every version
+ Check if any of the features you use is mentioned in the
+ changelog. Use a versioned dependency on grep-dctrl, if it
+ is necessary.
+
+ - ajk
diff --git a/License-Blurb b/License-Blurb
new file mode 100644
index 0000000..1379f1c
--- /dev/null
+++ b/License-Blurb
@@ -0,0 +1,13 @@
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..4ea9c7d
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,31 @@
+
+sysconf = /etc
+
+CC = gcc -std=gnu99
+CFLAGS = -O2 -g -Wall -DENABLE_L_DEBUG -D_GNU_SOURCE -DSYSCONF=\"$(sysconf)\"
+
+CFLAGS += -DVERSION=\"$(shell dpkg-parsechangelog | grep '^Version' | cut -b10-)\"
+CFLAGS += -DMAINTAINER='"$(shell grep ^Maintainer: debian/control | cut -b13-)"'
+
+#CFLAGS += -pg
+#LDFLAGS += -pg
+
+LDLIBS = -lpub
+
+all : grep-dctrl grep-dctrl.1
+
+grep-dctrl : grep-dctrl.o msg.o predicate.o util.o fsaf.o paragraph.o \
+ fieldtrie.o rc.o strutil.o
+
+%.test : %.test.o
+
+%.test.o : %.c
+ $(CC) -c $(CFLAGS) -DTESTMAIN $< -o $@
+
+%.1 : %.1.cp
+ sed 's*SYSCONF*$(sysconf)*' $< > $@
+
+fsaf.test : fsaf.test.o msg.o
+
+clean :
+ $(RM) core grep-dctrl grep-dctrl.1 *.o
diff --git a/NEWS b/NEWS
new file mode 100644
index 0000000..5bbb88e
--- /dev/null
+++ b/NEWS
@@ -0,0 +1,23 @@
+1.100 - a total rewrite
+ new feature: boolean queries
+ known regressions:
+ + unacceptably slow search in full paragraph
+ + no -Ffoo,bar,baz (equivalent boolean q available)
+ + no internationalization
+
+1.11 - added the -s option
+
+1.10 - made -c synonymous with --count
+
+1.7 - allowed several -F options and comma-separated list of
+ fields as -F's argument
+
+1.6 - disabled the -c option
+
+1.3 - fixed a segfault related to the -c option
+ deprecated the short -c option (use the long option instead)
+
+1.2 - added the -v option (see manpage for details)
+ New documentation file Compatibility.
+
+1.0 - no news is good news
diff --git a/PROJECT b/PROJECT
new file mode 100644
index 0000000..35c62bb
--- /dev/null
+++ b/PROJECT
@@ -0,0 +1 @@
+dctrl-tools - Debian control file inspection tools
diff --git a/README b/README
new file mode 100644
index 0000000..27e7926
--- /dev/null
+++ b/README
@@ -0,0 +1,5 @@
+grep-dctrl is a command-line tool for searching and manipulating
+certain Debian-specific files. It's not much use on other systems,
+but it should still compile on a non-Debian system. You need Lars
+Wirzenius' publib library to compile it (you should be able to find it
+from the Debian distribution or at http://www.iki.fi/liw/programs/).
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..3391d90
--- /dev/null
+++ b/TODO
@@ -0,0 +1,8 @@
+Things left to be done on grep-dctrl:
+ * Write a good Texinfo manual.
+ * Do translations of the messages to other languages
+ (we now have English).
+ * Fix any bugs.
+
+If you want to help with one of these (or you have some other ideas
+for grep-dctrl), contact <ajk@debian.org>.
diff --git a/debian/README.build-system b/debian/README.build-system
new file mode 100644
index 0000000..3dd5cb9
--- /dev/null
+++ b/debian/README.build-system
@@ -0,0 +1,6 @@
+
+$Id: README.build-system,v 1.4 2003/08/10 16:43:16 ajk Exp $
+
+This package uses a new experimental debian/rules helper, librules.mk,
+written by Antti-Juhani Kaijanaho <ajk@debian.org>. Documentation for
+it is available in the file librules-manual.txt.
diff --git a/debian/changelog b/debian/changelog
new file mode 100644
index 0000000..c0f19d1
--- /dev/null
+++ b/debian/changelog
@@ -0,0 +1,282 @@
+grep-dctrl (1.100) unstable; urgency=low
+
+ * A (nearly) full rewrite (bumped minor version number to match)
+ * Includes an annoying one-time-per-user banner asking for testing (will
+ be removed in the future).
+ * debian/control [Standards-Version]: Upgrade to 3.6.0.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 10 Aug 2003 18:33:05 +0300
+
+grep-dctrl (1.12) unstable; urgency=low
+
+ * matcher.c (find_field): Simplify code (this seems
+ to be a bit faster, too).
+ * This version was never uploaded.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Tue, 22 Apr 2003 19:33:09 +0300
+
+grep-dctrl (1.11) unstable; urgency=low
+
+ * The four-year near-anniversary overhaul.
+ * debian/copyright: Add copyright years.
+ * debian/copyright: Fix my snailmail address.
+ * debian/{prerm,postinst}: Remove (they handled only the FHS transition).
+ * debian/rules: Rewrote using my modernish rules helper. Closes: #164652.
+ * grep-dctrl.c: Don't use perror to report errors; instead use fprintf
+ and strerror so that the file name is reported. Closes: #162072.
+ * grep-dctrl.1.cp: Fix manpage syntax error, thanks to Bill Allombert.
+ Closes: #160521.
+ * grep-dctrl.c, matcher.h, matcher.c, buffer.h, buffer.c:
+ Implement -d switch, suggested by Chris Waters. Closes: #106175.
+ * po/fi.po: Updated
+ * matcher.c: Don't display a blank field when fields are selected, as
+ suggested by Horms. Closes: #167365.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 16 Feb 2003 18:48:11 +0200
+
+grep-dctrl (1.10) unstable; urgency=low
+
+ * grep-dctrl.c, grep-dctrl.1.cp: Make -c synonymous with --count.
+ * grep-dctrl.1.cp: Add Bill Allombert's example. Closes: #145301.
+ * debian/control [Standards-Version]: Upgrade to 3.5.6
+ + debian/rules: Implement debug & nostrip
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Thu, 25 Jul 2002 21:44:28 +0300
+
+grep-dctrl (1.9) unstable; urgency=low
+
+ * intl/Makefile.in: We don't have a ../config.h. Closes: #106001
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 30 Jul 2001 20:09:18 +0300
+
+grep-dctrl (1.8) unstable; urgency=low
+
+ * Fix manpage, closes: #102021
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Thu, 19 Jul 2001 19:40:55 +0300
+
+grep-dctrl (1.7) unstable; urgency=low
+
+ * Added copyright blurb to some source files that missed it.
+ * grep-dctrl.c, matcher.[ch]: Implement multiple -F options,
+ allows search in several fields at once.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sat, 20 May 2000 18:32:00 +0300
+
+grep-dctrl (1.6) unstable; urgency=low
+
+ * Disable the -c switch to allow its meaning to be changed
+ in woody+1.
+ * grep-dctrl.1.cp: Added COMPATIBILITY section, based on
+ the file Compatibility.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Wed, 10 May 2000 15:29:02 +0300
+
+grep-dctrl (1.5) unstable; urgency=low
+
+ * Incorporate bugfix release 1.3a into the development branch.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 5 Mar 2000 14:23:07 +0200
+
+grep-dctrl (1.4) unstable; urgency=low
+
+ * debian/control [Standards-Version]: 3.1.1
+ + debian/control [Build-Depends]: Added
+ * debian/control [Description]: Improved.
+ * debian/check-sourcedeps: Removed.
+ * debian/rules [debian/build-depends.stamp]: Removed.
+ * buffer.c, buffer.h: Make buffer_clear() an inline function.
+ * grep-dctrl.c (main), matcher.h (struct matcher_t),
+ matcher.c (grep_control): Implement the --count option
+ suggested by Dirk Eddelbuettel.
+ * configure.in, msg.h: Added a --enable-debug-level switch
+ * matcher.c (slurp_paragraph): Rewrote for speed.
+ * Versions 1.3 and 1.4 together closes: #57144.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 6 Feb 2000 21:42:30 +0200
+
+grep-dctrl (1.3a) frozen; urgency=low
+
+ * matcher.c (find_field): Unroll the first iteration of the first loop
+ and then remove the special-case p==s if in the loop body.
+ Closes: bug#59455.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 5 Mar 2000 14:21:41 +0200
+
+grep-dctrl (1.3) frozen; urgency=low
+
+ * grep-dctrl.c (main): Add a colon after c in getopt's
+ argument, fixing the segfault in bug#57144. This fix is meant
+ for frozen and is minimal; I will upload a more complicated fix
+ (but more correct in the long run) separately to unstable, since
+ the better fix requires feature changes.
+ * grep-dctrl.c (print_usage, main), grep-dctrl.1.cp, po/fi.po:
+ Deprecated short option "-c" to allow its meaning to be changed later
+ in woody. Functionality is not changed in this version; only
+ messages about the deprecation have been added. This must go to
+ potato to allow a smooth transition to the better fix for bug#57144.
+ * debian/copyright: Updated copyright years (added 2000).
+ * debian/NEWS: documented this release's changes
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 6 Feb 2000 14:50:06 +0200
+
+grep-dctrl (1.2) unstable; urgency=low
+
+ * grep-dctrl.c (main), matcher.h (struct matcher_t), matcher.c
+ (grep_control): Implement the -v option suggested by David Coe.
+ Closes: #45115.
+ * debian/rules: Modernize.
+ + Factor install into a variable.
+ + Don't use install_gzip.
+ + Use stamp files.
+ + Split clean into {build,binary}-clean
+ + Use a separate target for the configure call.
+ + Don't test for rootness.
+ + Remove $(rootdir) at start of binary targets.
+ * grep-dctrl.1.cp: Documented the -v option.
+ * debian/{prerm,postinst,rules}: Implement the /usr/doc transition method.
+ * po/fi.po: Updated.
+ * Compatibility: New file.
+ * debian/rules: Install Compatibility.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Wed, 15 Sep 1999 20:06:20 +0300
+
+grep-dctrl (1.1) unstable; urgency=low
+
+ * matcher.c (grep_control): Only return on feof if the para is empty.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 2 Aug 1999 21:42:53 +0300
+
+grep-dctrl (1.0) unstable; urgency=low
+
+ * New major version. No major changes, just polishing - we have
+ been converging to 1.0 for some time now.
+ * grep-dctrl.c (main): Don't allow -s to be used many times,
+ as it does not work in the obvious way.
+ * Updated the Finnish translation.
+ * grep-dctrl.1.cp: Updated the DIAGNOSTICS section.
+ * Added files TODO, NEWS and README to the source distribution.
+ Only README is not relevant to Debian users, so not installing it.
+ * configure.in: Check whether we have dpkg-parsechangelog, and
+ use a default dummy version number if we don't. This allows
+ the package to build more easily on a non-Debian system.
+ * Unsymlink things that had symlinks outside the source.
+ * Added getopt source for the benefit of broken systems.
+ * configure.in: Use /usr/share/common-licenses/GPL as a default for
+ the copying file location.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sat, 10 Jul 1999 20:58:46 +0300
+
+grep-dctrl (0.16) unstable; urgency=low
+
+ * Upgraded Standards-Version to 3.0.0.0, with necessary
+ changes to debian/rules and debian/copyright.
+ * configure.in: Added an anchor to the grep in the version number,
+ finder, and reran autoconf
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Fri, 2 Jul 1999 10:42:24 +0300
+
+grep-dctrl (0.15) unstable; urgency=low
+
+ * Removed the file called "1" from the source package.
+ Closes: bug#40358.
+ * debian/dpkg-sourcedeps: New file.
+ * debian/rules: Converted the source dependency check to use
+ debian/dpkg-sourcedeps
+ * grep-dctrl.1.cp: Wrote an EXAMPLES section.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 28 Jun 1999 18:02:36 +0300
+
+grep-dctrl (0.14) unstable; urgency=low
+
+ * matcher.c (grep_control): Test for EOF before a paragraph
+ is processed, not after. This fixes an unreported bug
+ that caused grep-dctrl -sPackage '' output a spurious
+ empty Package: line.
+ * debian/rules: Added a simple source dependency check.
+ * debian/rules: Use -isp with dpkg-gencontrol.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Sat, 26 Jun 1999 03:21:20 +0300
+
+grep-dctrl (0.13) unstable; urgency=low
+
+ * buffer.c (buffer_trim): I had ">=" in the loop
+ condition, should be "<". Corrected that; this
+ fixes bug #38047.
+ * Added debug_messages and asserts all over buffer.c
+ while hunting bug #38047.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Thu, 20 May 1999 21:47:31 +0300
+
+grep-dctrl (0.12) unstable; urgency=low
+
+ * Removed old-Makefile.in from the tarball.
+ * Updated Finnish translation.
+ * Made field name matching ignore case.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Tue, 18 May 1999 08:53:42 +0300
+
+grep-dctrl (0.11) unstable; urgency=low
+
+ * Added shorthand option -P.
+ * Fixed a typo in config file name in the manual page.
+ * grep_dctrl (set_match_field): New function.
+ * Fixed some -Wall warnings in matcher.c.
+ * rc.c, line 107: Had forgotten the `++' in front of lineno.
+ Corrected that.
+ * Added the option -n for suppressing the field names on output.
+ * Added a some informational messages to rcfile parsing.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Fri, 9 Apr 1999 20:24:30 +0300
+
+grep-dctrl (0.10) unstable; urgency=low
+
+ * Got rid of version.h. The defines are now done on the
+ compiler command line. This will avoid the harmful rebuild of
+ grep-dctrl.o in Makefile's install target. Fixes bug#35527.
+ * Added the generated manual page to CLEANFILES, so that the
+ manpage gets rebuilt.
+ * Clean off backup files on debian/rules clean.
+ * rc.c: Search user's rcfile first.
+ * rc.c: Upgrade the "reading config file" message from debug message
+ to informational.
+ * Updated the Finnish translation.
+ * Prettified the long description in debian/control.
+ * matcher.c: Downgraded several messages to the debug level `debug' so that
+ the level `informational' becomes much less verbose.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 5 Apr 1999 23:35:39 +0300
+
+grep-dctrl (0.9) unstable; urgency=low
+
+ * Introduced a config file system for specifying default
+ input file names based on the base name of argv[0].
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Wed, 24 Mar 1999 22:02:49 +0200
+
+grep-dctrl (0.8) unstable; urgency=low
+
+ * Rewrote build system to use autoconf & automake.
+ * Internationalized. Finnish translation is included.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Fri, 19 Mar 1999 11:07:15 +0200
+
+grep-dctrl (0.7) unstable; urgency=low
+
+ * Added an option for exact matches.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Tue, 9 Mar 1999 02:58:30 +0200
+
+grep-dctrl (0.6) unstable; urgency=low
+
+ * Strip whitespace at the start of a field body before searching in it.
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 8 Mar 1999 22:28:23 +0200
+
+grep-dctrl (0.5) unstable; urgency=low
+
+ * First released version.
+ * This time the uploaded changes and .dsc are signed :-(
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Mon, 1 Mar 1999 22:10:01 +0200
+
diff --git a/debian/conffiles b/debian/conffiles
new file mode 100644
index 0000000..d5c1f12
--- /dev/null
+++ b/debian/conffiles
@@ -0,0 +1 @@
+/etc/grep-dctrl.rc
diff --git a/debian/control b/debian/control
new file mode 100644
index 0000000..2b2684d
--- /dev/null
+++ b/debian/control
@@ -0,0 +1,26 @@
+Source: grep-dctrl
+Section: utils
+Priority: optional
+Maintainer: Antti-Juhani Kaijanaho <ajk@debian.org>
+Standards-Version: 3.6.0
+Build-Depends: publib-dev
+
+Package: grep-dctrl
+Architecture: any
+Depends: ${shlibs:Depends}
+Description: Grep Debian package information
+ The grep-dctrl program can answer such questions as
+ * "What is the Debian package foo?"
+ * "Which version of the Debian package bar is now current?"
+ * "Which Debian packages does John Doe maintain?"
+ * "Which Debian packages are somehow related to the Scheme
+ programming language?"
+ and with some help
+ * "Who maintain the essential packages of a Debian system?"
+ given a useful input file.
+ .
+ It is a specialised grep program that is meant for processing any
+ file which has the general format of a Debian package control file.
+ These include the dpkg available file, the dpkg status file, and the
+ Packages files on a distribution medium (such as a Debian CD-ROM or
+ an FTP site carrying Debian).
diff --git a/debian/copyright b/debian/copyright
new file mode 100644
index 0000000..e193d9c
--- /dev/null
+++ b/debian/copyright
@@ -0,0 +1,36 @@
+This package and the program in it were written and debianized by
+Antti-Juhani Kaijanaho <ajk@debian.org>.
+
+Copyright:
+
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Antti-Juhani Kaijanaho
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ The author can be reached via mail at (ISO 8859-1 charset for the city)
+ Antti-Juhani Kaijanaho
+ Helokantie 1 A 16
+ FIN-40640 JYVÄSKYLÄ
+ FINLAND
+ EUROPE
+ and via electronic mail from
+ gaia@iki.fi
+ If you have a choice, use the email address; it is more likely to
+ stay current.
+
+
+In Debian systems, the GNU GPL version 2 is available at
+/usr/share/common-licenses/GPL .
diff --git a/debian/librules-manual.txt b/debian/librules-manual.txt
new file mode 100644
index 0000000..f577112
--- /dev/null
+++ b/debian/librules-manual.txt
@@ -0,0 +1,131 @@
+Manual for the librules helper -*- Text -*-
+------------------------------
+Last modified: 2002-10-16
+
+This file documents an experimental new debian/rules helper, a
+makefile called "librules.mk", which does all the boring work of
+building a package.
+
+Usage:
+
+The very first non-comment thing in your debian/rules should be the
+following line:
+librules_interface = 2
+This helps to spot incompatibilities with debian/rules and the
+librules.mk file currently in use.
+(See the section "Incompatible changes" for what to look for when
+upgrading from an old version.)
+
+Include "debian/librules.mk" just after that line. Precede it with a
+variable definition "librules_native_pkg=yes" if the package you are building
+is a Debian native package.
+
+Define a target debian/stamp/build that builds the package (like the
+build target does in conventional debian/rules files). Put "touch $@"
+as the last action in that rule.
+
+For every binary package <package> you want to build:
+
+ - If the package is "arch: all", make debian/stamp/binary/indep depend
+ on debian/stamp/binary/<package>; otherwise make debian/stamp/binary/arch
+ depend on that target
+
+ - Write a target debian/stamp/binary/<package> using the following template:
+
+debian/stamp/binary/<package>: package=<package>
+debian/stamp/binary/<package>: debian/stamp/build
+ $(prebinary)
+ # Add here your own commands
+ $(postbinary)
+ touch $@
+
+ The $(prebinary) macro will create a skeletal build tree for the
+ package. It also install the copyright file (debian/copyright)
+ and the Debian changelog file (debian/changelog).
+
+ See below for instructions about how to write your own install commands.
+
+ The $(postbinary) macro fixes directory permissions, generates the binary
+ control file and builds the package.
+
+ - You may want to define targets "clean", "clean-binary" and "clean-build"
+ to reverse the effects of your own commands in the build and binary targets.
+ The librules.mk file cleans up for itself, you don't need to worry about that.
+
+
+How to write your own commands for binary targets:
+
+Use the following macros to install files:
+
+ $(install_exec) SOURCE TARGET
+ $(install_exec) SOURCE SOURCE ... DIRECTORY
+ installs one or more binary executables
+ (TARGET need not be a directory name)
+
+ $(install_nonex) SOURCE TARGET
+ $(install_nonex) SOURCE SOURCE ... DIRECTORY
+ install one or more non-executable files
+ (TARGET need not be a directory name)
+
+ $(install_dir) DIRECTORY
+ create the directory
+
+ $(install_script) SOURCE TARGET
+ $(install_script) SOURCE SOURCE ... DIRECTORY
+ install one or more executable scripts
+ (TARGET need not be a directory name)
+
+ $(install_prerm)
+ $(install_postrm)
+ $(install_preinst)
+ $(install_postinst)
+ install debian/prerm.$(package) etc.
+ to DEBIAN using the appropriate name
+
+The macros above are wrappers around the "install" utility.
+
+ $(install_symlink) SOURCE [TARGET]
+ Install a symlink from SOURCE to TARGET
+ (This macro is a wrapper around ln -s)
+
+ $(gzip) FILE ...
+ Compress the given files
+ (This is a wrapper around gzip)
+
+ $(strip_lib) FILE ...
+ Strip the given files the way shared libraries are stripped
+ (This is a wrapper around strip)
+
+
+*Never* refer to a file in the install target tree by their real name.
+Use the following macros instead:
+
+ $(rootdir) - the directory that masquerades as / in the target tree
+ (usually a subdirectory under debian/tmp)
+ $(ctldir) - the directory where control files are installed
+ (usually $(rootdir)/DEBIAN)
+ $(bindir) - the main binary directory
+ (usually $(rootdir)/usr/bin)
+ $(docdir) - the main doc directory
+ (usually $(rootdir)/usr/share/doc/<package>)
+ ...
+(see librules.mk for what's available)
+
+
+If your debian/rules needs the dpkg-architecture variables, add the
+definition "librules_need_archvars=yes" before the include at the top
+of the file. If you use this feature, you need to Build-Depend on
+"dpkg-dev (>= 1.4.1.5)".
+
+If you want to patch/unpatch the package, add the definitions
+"librules_patch_support=yes" and "librules_patches=file1.diff
+file2.diff ... filen.diff" before the include at the top of the file.
+If you use this, you need to Build-Depend on "patch".
+
+
+Incompatible changes
+--------------------
+
+From 1 to 2:
+ - {pre,post}{rm,inst} scripts are not installed by default
+ (previously prerm and postinst were unconditionally installed)
diff --git a/debian/librules.mk b/debian/librules.mk
new file mode 100644
index 0000000..c5fa631
--- /dev/null
+++ b/debian/librules.mk
@@ -0,0 +1,180 @@
+# librules.mk - a library of convenient rules and macros for debian/rules files
+#
+# Copyright © 1999, 2000, 2002, 2003 Antti-Juhani Kaijanaho.
+#
+# Permission is hereby granted, free of charge, to any person
+# obtaining a copy of this file, to deal in this file without
+# restriction, including without limitation the rights to use, copy,
+# modify, merge, publish, distribute, sublicense, and/or sell copies
+# of this file, and to permit persons to whom this file is furnished
+# to do so, subject to the following condition: The above copyright
+# notice and this permission notice shall be included in all copies or
+# substantial portions of this file.
+#
+# THIS FILE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FIT- NESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL SOFTWARE IN THE PUBLIC INTEREST,
+# INC. BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
+# IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
+# IN CONNECTION WITH THIS FILE OR THE USE OR OTHER DEALINGS IN THIS
+# FILE.
+#
+# Except as contained in this notice, the name of the author(s) of
+# this file shall not be used in advertising or otherwise to promote
+# the sale, use or other dealings in this file without prior written
+# authorization from the author(s).
+
+# This file is set up to be compliant with Debian Standards Version
+# 3.6.0.
+
+# Changes:
+# 2003-08-10 ajk Add $(etcdir)
+# 2002-10-16 ajk Don't force installing the prerm/postinst scripts
+# Instead, install them if present.
+# INCOMPATIBLE CHANGE; updated interface to 2
+
+default:
+ @echo You need to specify a target.
+ @exit 1
+
+librules_a_variable_just_to_run_the_commands1 := $(shell mkdir debian/stamp)
+librules_a_variable_just_to_run_the_commands2 := $(shell mkdir debian/stamp/binary)
+
+# Make sure we don't get used by an incompatible debian/rules
+# WHEN YOU MAKE INCOMPATIBLE CHANGES, EDIT THIS!
+ifneq ($(librules_interface),2)
+$(error incompatible debian/rules)
+endif
+
+# Standard interface targets
+build: debian/stamp/build
+binary: binary-indep binary-arch
+binary-arch: debian/stamp/binary/arch
+binary-indep: debian/stamp/binary/indep
+clean: clean-build clean-binary clean-std
+
+
+# Nonstandard interface targets
+clean-build: clean-build-std
+clean-binary: clean-binary-std
+
+# Stamp targets for the standard binary targets
+debian/stamp/binary/arch: debian/stamp/build
+ touch $@
+
+debian/stamp/binary/indep: debian/stamp/build
+ touch $@
+
+.PHONY: default build binary binary-arch binary-indep \
+ clean clean-build clean-binary
+
+ifeq ($(librules_need_archvars),yes)
+DEB_BUILD_ARCH = $(shell dpkg-architecture -qDEB_BUILD_ARCH)
+DEB_BUILD_GNU_TYPE = $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+DEB_BUILD_GNU_CPU = $(shell dpkg-architecture -qDEB_BUILD_GNU_CPU)
+DEB_BUILD_GNU_SYSTEM = $(shell dpkg-architecture -qDEB_BUILD_GNU_SYSTEM)
+DEB_HOST_ARCH = $(shell dpkg-architecture -qDEB_HOST_ARCH)
+DEB_HOST_GNU_TYPE = $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_HOST_GNU_CPU = $(shell dpkg-architecture -qDEB_HOST_GNU_CPU)
+DEB_HOST_GNU_SYSTEM = $(shell dpkg-architecture -qDEB_HOST_GNU_SYSTEM)
+endif
+
+CFLAGS = -O2 -Wall
+STRIP =
+ifneq (,$(findstring debug,$(DEB_BUILD_OPTIONS)))
+CFLAGS += -g
+endif
+ifeq (,$(findstring nostrip,$(DEB_BUILD_OPTIONS)))
+STRIP = -s
+endif
+
+export CFLAGS
+
+install := install -o root -g root
+install_exec := $(install) -m 0755 $(STRIP)
+install_nonex := $(install) -m 0644
+install_dir := $(install) -m 0755 -d
+install_script := $(install) -m 0755
+install_symlink := ln -s
+gzip := gzip -9
+strip_lib := strip --strip-unneeded
+
+tmpdir := $(shell pwd)/debian/tmp
+
+# These must not be :='s!
+rootdir = $(tmpdir)/$(package)
+ctldir = $(rootdir)/DEBIAN
+etcdir = $(rootdir)/etc
+bindir = $(rootdir)/usr/bin
+sbindir = $(rootdir)/usr/sbin
+docdir = $(rootdir)/usr/share/doc/$(package)
+exampledir = $(docdir)/examples
+mandir = $(rootdir)/usr/share/man
+elispdir = $(rootdir)/usr/share/emacs/site-lisp
+emacs_d_dir = $(etcdir)/emacs/site-start.d
+man1dir = $(mandir)/man1
+man2dir = $(mandir)/man2
+man3dir = $(mandir)/man3
+man4dir = $(mandir)/man4
+man5dir = $(mandir)/man5
+man6dir = $(mandir)/man6
+man7dir = $(mandir)/man7
+man8dir = $(mandir)/man8
+sharedir = $(rootdir)/usr/share/$(package)
+libdir = $(rootdir)/usr/lib/$(package)
+docbasedir = $(rootdir)/usr/share/doc-base
+usrlib = $(rootdir)/usr/lib
+includedir = $(rootdir)/usr/include
+
+ifeq ($(librules_native_pkg),yes)
+librules_changelog=changelog
+else
+librules_changelog=changelog.Debian
+endif
+
+install_prerm = $(install_script) debian/prerm.$(package) $(ctldir)/prerm
+install_postrm = $(install_script) debian/postrm.$(package) $(ctldir)/postrm
+install_preinst = $(install_script) debian/preinst.$(package) $(ctldir)/preinst
+install_postinst = $(install_script) debian/postinst.$(package) $(ctldir)/postinst
+
+
+define prebinary
+ $(RM) -r $(rootdir)
+ $(install_dir) $(ctldir)
+ $(install_dir) $(docdir)
+ $(install_nonex) debian/copyright $(docdir)
+ $(install_nonex) debian/changelog $(docdir)/$(librules_changelog)
+ $(gzip) $(docdir)/$(librules_changelog)
+endef
+
+define postbinary
+ chmod -R g-s $(rootdir)
+ dpkg-gencontrol -isp -p$(package) -P$(rootdir) $(gencontrol_options)
+ dpkg --build $(rootdir) ..
+endef
+
+clean-build-std:
+ rm -f debian/stamp/build
+
+clean-binary-std:
+ rm -f debian/stamp/binary/*
+ rm -f debian/files debian/substvars
+ rm -rf $(tmpdir)
+
+clean-std:
+ rm -rf debian/stamp/
+
+# Patching support
+ifeq ($(librules_patch_support),yes)
+debian/stamp/build: debian/stamp/patch
+clean-build: unpatch
+
+debian/stamp/patch:
+ $(foreach patch, $(librules_patches), patch -fs < $(patch) && )true
+ touch $@
+
+unpatch: debian/stamp/patch
+ $(foreach patch, $(librules_patches), patch -fsR < $(patch) && )true
+ rm -f debian/stamp/patch
+endif
diff --git a/debian/rules b/debian/rules
new file mode 100644
index 0000000..71ed474
--- /dev/null
+++ b/debian/rules
@@ -0,0 +1,54 @@
+#!/usr/bin/make -f
+# Written by Antti-Juhani Kaijanaho <ajk@debian.org>.
+# You may treat this file as if it were in the public domain.
+
+librules_interface = 2
+librules_native_pkg=yes
+include debian/librules.mk
+
+debian/stamp/build: #debian/stamp/build-configure
+ $(MAKE)
+ touch $@
+
+#debian/stamp/build-configure:
+# ./configure --prefix=/usr --sysconfdir=/etc --mandir=/usr/share
+# touch $@
+
+clean-build:
+ -$(MAKE) clean
+
+debian/stamp/binary/arch: debian/stamp/binary/grep-dctrl
+
+debian/stamp/binary/grep-dctrl: package=grep-dctrl
+debian/stamp/binary/grep-dctrl: debian/stamp/build
+ $(prebinary)
+# Install by the master makefile
+# $(MAKE) prefix=$(rootdir)/usr sysconfdir=$(rootdir)/etc \
+# mandir=$(mandir) install
+# Install configuration file
+ $(install_dir) $(etcdir)
+ $(install_nonex) grep-dctrl.rc $(etcdir)
+# Install the binary.
+ $(install_dir) $(bindir)
+ $(install_exec) grep-dctrl $(bindir)
+ set -e ; for dest in grep-status grep-available ; do \
+ $(install_symlink) grep-dctrl $(bindir)/$$dest ; \
+ done
+# Zip the manual page.
+ $(install_dir) $(man1dir)
+ $(install_nonex) grep-dctrl.1 $(man1dir)/
+ $(gzip) $(man1dir)/grep-dctrl.1
+ set -e ; for dest in grep-status grep-available ; do \
+ $(install_symlink) grep-dctrl.1.gz $(man1dir)/$$dest.1.gz ; \
+ done
+# Install the supporting documentation.
+ $(install_nonex) TODO NEWS Compatibility $(docdir)
+# Install config file information
+ $(install_nonex) debian/conffiles $(rootdir)/DEBIAN
+# Get the shared library deps
+ dpkg-shlibdeps $(bindir)/grep-dctrl
+ $(postbinary)
+ touch $@
+
+clean-binary:
+ $(RM) *~
diff --git a/fieldtrie.c b/fieldtrie.c
new file mode 100644
index 0000000..3d6019a
--- /dev/null
+++ b/fieldtrie.c
@@ -0,0 +1,75 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <string.h>
+#include "fieldtrie.h"
+#include "msg.h"
+
+void fieldtrie_init(fieldtrie_t * trie)
+{
+ assert(trie != 0);
+ for (size_t i = 0; i < UCHAR_MAX; i++) {
+ trie->fields[i] = 0;
+ }
+ trie->nextfree = 0;
+}
+
+size_t fieldtrie_insert(fieldtrie_t * trie, char const * s)
+{
+ size_t slen = strlen(s);
+ size_t r = fieldtrie_lookup(trie, s, slen);
+ if (r != -1) return r;
+ struct field_bucket * b = malloc(sizeof *b);
+ if (b == 0) fatal_enomem(0);
+ b->name = malloc(slen+1);
+ if (b->name == 0) fatal_enomem(0);
+ strcpy((char*)b->name, s);
+ b->namelen = slen;
+ b->inx = trie->nextfree++;
+ unsigned char c = tolower((unsigned char)(b->name[0]));
+ b->next = trie->fields[c];
+ trie->fields[c] = b;
+ return b->inx;
+}
+
+size_t fieldtrie_lookup(fieldtrie_t * trie, char const * s, size_t n)
+{
+ for (struct field_bucket * b = trie->fields[tolower((unsigned char)s[0])];
+ b != 0;
+ b = b->next) {
+ if (n == b->namelen &&
+ strncasecmp(s, b->name, n) == 0) return b->inx;
+ }
+ return (size_t)(-1);
+}
+
+void fieldtrie_clear(fieldtrie_t * trie)
+{
+ for (size_t i = 0; i < UCHAR_MAX; i++) {
+ struct field_bucket * b = trie->fields[i];
+ while (b != 0) {
+ struct field_bucket * bn = b->next;
+ free(b);
+ b = bn;
+ }
+ trie->fields[i] = 0;
+ }
+ trie->nextfree = 0;
+}
diff --git a/fieldtrie.h b/fieldtrie.h
new file mode 100644
index 0000000..7ae7d8c
--- /dev/null
+++ b/fieldtrie.h
@@ -0,0 +1,52 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef FIELDTRIE_H
+#define FIELDTRIE_H
+
+#include <limits.h>
+#include <stddef.h>
+
+struct field_bucket {
+ char const * name;
+ size_t namelen;
+ size_t inx;
+ struct field_bucket * next;
+};
+
+struct fieldtrie_private {
+ size_t nextfree;
+ /* A one-level trie listing all field names occurring in the
+ * atomic predicates. */
+ struct field_bucket * fields[UCHAR_MAX];
+};
+
+typedef struct fieldtrie_private fieldtrie_t;
+
+void fieldtrie_init(fieldtrie_t *);
+
+// case-insensitive
+size_t fieldtrie_insert(fieldtrie_t *, char const *);
+
+// case-insensitive
+// (size_t)(-1) if failed
+size_t fieldtrie_lookup(fieldtrie_t *, char const *, size_t n);
+
+void fieldtrie_clear(fieldtrie_t *);
+
+#endif /* FIELDTRIE_H */
diff --git a/fsaf.c b/fsaf.c
new file mode 100644
index 0000000..5077b3a
--- /dev/null
+++ b/fsaf.c
@@ -0,0 +1,230 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <assert.h>
+#include <errno.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "fsaf.h"
+#include "msg.h"
+
+#if !defined(_POSIX_MAPPED_FILES) || _POSIX_MAPPED_FILES == -1
+# warning "No mmap support detected."
+#endif
+
+#define READAHEAD 1
+
+static size_t pagesize;
+
+static inline
+size_t align(size_t offset, bool ceil)
+{
+ return (offset / pagesize + (ceil && offset % pagesize != 0)) * pagesize;
+}
+
+FSAF * fsaf_fdopen(int fd)
+{
+ pagesize = (size_t) sysconf (_SC_PAGESIZE);
+ FSAF * rv = malloc(sizeof *rv);
+ if (rv == 0) { errno = ENOMEM; return 0; }
+
+ rv->fd = fd;
+ rv->eof_mark = (size_t)(-1);
+ rv->buf = 0;
+ rv->buf_capacity = 0;
+ rv->buf_offset = 0;
+ rv->buf_size = 0;
+ rv->invalid_mark = 0;
+#ifdef _POSIX_MAPPED_FILES
+ rv->mapped = false;
+ rv->topread = 0;
+#endif
+
+ struct stat stat;
+ int res = fstat(fd, &stat);
+ if (res == -1) goto fail;
+
+ if (S_ISREG(stat.st_mode)) {
+ rv->eof_mark = stat.st_size;
+#ifdef _POSIX_MAPPED_FILES
+ /* try mmapping, it is a regular file */
+ size_t eof_pagebound = align(rv->eof_mark, true);
+ char * buf = mmap(0, eof_pagebound, PROT_READ, MAP_SHARED, fd, 0);
+ if (buf != MAP_FAILED) {
+ debug_message("mmapping", 0);
+ rv->mapped = 1;
+ rv->buf = buf;
+ rv->buf_capacity = eof_pagebound;
+ rv->buf_offset = 0;
+ rv->buf_size = rv->eof_mark;
+ //madvise(rv->buf, rv->buf_capacity, MADV_SEQUENTIAL);
+ return rv;
+ }
+#endif
+ }
+
+ return rv;
+fail:
+ free(rv);
+ return 0;
+}
+
+void fsaf_close(FSAF * fp)
+{
+ assert(fp != 0);
+#if _POSIX_MAPPED_FILES
+ if (fp->mapped) {
+ munmap(fp->buf, fp->buf_capacity);
+ free(fp);
+ return;
+ }
+#endif
+ free(fp->buf);
+ free(fp);
+}
+
+static void slurp(FSAF * fp, size_t len)
+{
+ assert(fp != 0);
+ assert(len > 0);
+ if (fp->buf_size + len > fp->buf_capacity) {
+ size_t nc = fp->buf_capacity;
+ if (nc == 0) nc = 256;
+ while (nc < fp->buf_size + len) nc *= 2;
+ char * nb = realloc(fp->buf, nc);
+ if (nb != 0) {
+ fp->buf = nb;
+ fp->buf_capacity = nc;
+ } else {
+ assert(fp->invalid_mark >= fp->buf_offset);
+ size_t delta = fp->invalid_mark - fp->buf_offset;
+ if (delta == 0) {
+ /* Cannot move needed stuff... */
+ fatal_enomem(0);
+ }
+ memmove(fp->buf, fp->buf + delta, fp->buf_size - delta);
+ fp->buf_offset += delta;
+ fp->buf_size -= delta;
+ if (fp->buf_size + len > fp->buf_capacity) {
+ len = fp->buf_capacity - fp->buf_size;
+ }
+ }
+ }
+ assert(len > 0);
+ assert(fp->buf_size + len <= fp->buf_capacity);
+
+ ssize_t res;
+ do {
+// res = read(fp->fd, fp->buf + fp->buf_size, len);
+ res = read(fp->fd, fp->buf + fp->buf_size, fp->buf_capacity - fp->buf_size);
+ } while (res == -1 && errno == EINTR);
+ if (res == 0) {
+ fp->eof_mark = fp->buf_offset + fp->buf_size;
+ }
+ fp->buf_size += res;
+}
+
+//static inline
+struct fsaf_read_rv fsaf_read(FSAF * fp, size_t offset, size_t len)
+{
+ struct fsaf_read_rv rv;
+
+ /* Make sure we don't read past the EOF mark. */
+ if (offset + len > fp->eof_mark) len = fp->eof_mark - offset;
+
+#if _POSIX_MAPPED_FILES
+ if (fp->mapped) {
+#if 0 /* madvise seems not to give a noteworthy efficiency boost */
+ /* Notify the kernel that we will soon want more of
+ * the data, but do this only once for each page! */
+ if (offset + len >= fp->topread) {
+ size_t base = align(offset - fp->buf_offset, 1);
+ size_t rl = READAHEAD * pagesize;
+ madvise(fp->buf + base, rl, MADV_WILLNEED);
+ fp->topread += rl;
+ }
+#endif
+ } else
+#endif
+ {
+ /* Ensure that we have enough data in the buffer.
+ * This is only executed if we are not dealing with a
+ * mapped file. */
+ assert(offset >= fp->buf_offset);
+ if (offset - fp->buf_offset + len > fp->buf_size) {
+ slurp(fp, offset - fp->buf_offset + len - fp->buf_size);
+ if (offset - fp->buf_offset + len > fp->buf_size) {
+ len = fp->buf_size - (offset - fp->buf_offset);
+ }
+ }
+
+ }
+
+ assert(offset - fp->buf_offset + len <= fp->buf_size);
+ assert(offset + len <= fp->eof_mark);
+ rv.b = fp->buf + (offset - fp->buf_offset);
+ rv.len = len;
+ return rv;
+}
+
+void fsaf_invalidate(FSAF * fp, size_t offset)
+{
+ if (fp->eof_mark >= offset) return;
+
+#ifdef _POSIX_MAPPED_FILES
+ if (fp->mapped) {
+ size_t old = align(fp->eof_mark - fp->buf_offset, 0);
+ size_t new = align(offset - fp->buf_offset, 0);
+ madvise(fp->buf + old, new - old, MADV_DONTNEED);
+ }
+#endif
+
+ fp->eof_mark = offset;
+}
+
+#ifdef TESTMAIN
+#include <stdio.h>
+volatile char c;
+int main(int argc, char * argv[])
+{
+ if (argc == 1) {
+ set_loglevel(L_DEBUG);
+ FSAF * fp = fsaf_fdopen(STDIN_FILENO);
+ assert(fp != 0);
+ size_t i = 0;
+ while (i < fsaf_eof(fp)) {
+ struct fsaf_read_rv rr = fsaf_read(fp, i, 1);
+ //fwrite(rr.b, 1, rr.len, stdout);
+ c = rr.b[0];
+ i += rr.len;
+ }
+ fsaf_close(fp);
+ } else {
+ int ch;
+ while ((ch = getchar()) != EOF) {
+ c = ch;
+ }
+ }
+ return 0;
+}
+#endif
diff --git a/fsaf.h b/fsaf.h
new file mode 100644
index 0000000..a9a562c
--- /dev/null
+++ b/fsaf.h
@@ -0,0 +1,80 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef FSAF_H
+#define FSAF_H
+
+#include <assert.h>
+#include <stdbool.h>
+
+/* FAST (MOSTLY) SEQUENTIAL-ACCESS FILE LAYER */
+
+struct fsaf_private {
+ int fd;
+ char * buf;
+ size_t buf_capacity;
+ size_t buf_offset;
+ size_t buf_size;
+ size_t invalid_mark;
+ size_t eof_mark; /* can be (size_t)(-1) if not reached yet */
+#ifdef _POSIX_MAPPED_FILES
+ bool mapped;
+ size_t topread; /* marks the top of what has been read ahead */
+#endif
+};
+
+typedef struct fsaf_private FSAF;
+
+/* Open a FSAF for the given fd. Only read access is supported for
+ * now. The whole file is initially valid. */
+FSAF * fsaf_fdopen(int fd);
+
+/* Close the given FSAF. This DOES NOT close the underlying fd. */
+void fsaf_close(FSAF *);
+
+/* Return a pointer to a buffer containing len bytes from the FSAF
+ * starting at offset. Note that if offset is below the invalid mark,
+ * we return b = NULL. This is a CHEAP operation, if the full range
+ * has already been accessed. The buffer may be invalidated by any
+ * subsequent call to this function. */
+struct fsaf_read_rv {
+ char const * b;
+ size_t len;
+} fsaf_read(FSAF *, size_t offset, size_t len);
+
+static inline
+int fsaf_getc(FSAF * fp, size_t offset)
+{
+ if (offset >= fp->eof_mark) return -1;
+ struct fsaf_read_rv r = fsaf_read(fp, offset, 1);
+ if (offset >= fp->eof_mark) return -1;
+ assert(r.len == 1);
+ return (unsigned char)r.b[0];
+}
+
+
+/* Invalidate all bytes in FSAF up to and excluding offset. */
+void fsaf_invalidate(FSAF *, size_t offset);
+
+/* Return an upper bound for the end of file, either the smallest
+ * offset beyond eof or (size_t)(-1). */
+static inline
+size_t fsaf_eof(FSAF * fp) { return fp->eof_mark; }
+
+
+#endif /* FSAF_H */
diff --git a/grep-dctrl.1.cp b/grep-dctrl.1.cp
new file mode 100644
index 0000000..ac4fbee
--- /dev/null
+++ b/grep-dctrl.1.cp
@@ -0,0 +1,388 @@
+.TH GREP-DCTRL 1 2003-08-10 "Debian Project" "Debian user's manual"
+\" Copyright (C) 1999, 2000, 2001, 2002, 2003 Antti-Juhani Kaijanaho
+\" <gaia@iki.fi>
+\" Permission is granted to make and distribute verbatim copies of
+\" this manual provided the copyright notice and this permission notice
+\" are preserved on all copies.
+\"
+\" Permission is granted to copy and distribute modified versions of this
+\" manual under the conditions for verbatim copying, provided that the
+\" entire resulting derived work is distributed under the terms of a
+\" permission notice identical to this one.
+\"
+\" Permission is granted to copy and distribute translations of this
+\" manual into another language, under the above conditions for modified
+\" versions, except that this permission notice may be included in
+\" translations approved by the authors of this manual instead of in
+\" the original English.
+\"
+.SH NAME
+grep-dctrl \- grep Debian control files
+.SH SYNOPSIS
+.B grep-dctrl
+[options] predicate
+[
+.IR file " ..."
+]
+.sp
+.B grep-dctrl
+--copying | --help | --version | -ChV
+.SH DESCRIPTION
+The grep-dctrl program can answer such questions as
+.IR "What is the Debian package foo?" ,
+.IR "Which version of the Debian package bar is now current?" ,
+.IR "Which Debian packages does John Doe maintain?" ,
+.I "Which Debian packages are somehow related to the Scheme"
+.IR " programming language?" ,
+and with some help,
+.IR "Who maintain the essential packages of a Debian system?" ,
+given a useful input file.
+.PP
+It is a specialised grep program that is meant for processing any file
+which has the general format of a Debian package control file, as
+described in the Debian Packaging Manual. These include the dpkg
+available file, the dpkg status file, and the Packages files on a
+distribution medium (such as a Debian CD-ROM or an FTP site carrying
+Debian).
+.PP
+You must give a search predicate on the command line. The predicate
+defines which kind of paragraphs (aka package records) are output. An
+atomic predicate is a search pattern along with any options that
+modify it. Possible modifiers are --eregex, --field, --ignore-case,
+-P, --regex and --exact-match, along with their single-letter
+equivalents. An atomic predicate gives a pattern to search for. By
+default, the search is a case-sensitive fixed substring match on each
+paragraph (in other words, package record) in the input. With
+suitable modifiers, this can be changed: the search can be
+case-insensitive and the pattern can be seen as an extended POSIX
+regular expression. Predicates can be combined using the connectives
+--and, --or and --not. Predicates can be grouped using parentheses.
+.PP
+By default, the full matching paragraphs are printed on the standard
+output; specific fields can be selected for output with the -s option.
+.PP
+After the predicate comes zero or more file names. If no file names
+are specified, the file name is searched in configuration files. The
+input file from the first program name \- input file association with
+the correct program name is used. The program names are matched with
+the base form of the name of the current program (the 0'th command
+line argument, if you will). The file name "-" is taken to mean the
+standard input stream. The files are searched in order but
+separately; they are
+.B not
+concatenated together. In other words, the end of a file always
+implies the end of the current paragraph.
+.PP
+There is one exception to the above: if the program name is
+.BR grep-dctrl ,
+the default input source is always standard input; this cannot be
+overridden by the configuration file.
+.SH OPTIONS
+.SS Atomic predicate modifiers
+.IP "-F FIELD,FIELD,...; --field=FIELD,FIELD,..."
+Restrict pattern matching to the FIELDs given.
+.B Multiple fields in one -F is broken currently.
+Use the -o option in the mean time.
+.IP -P
+Shorthand for "-FPackage".
+.IP "-e, --eregex"
+Regard the pattern of the current atomic predicate as an extended
+POSIX regular expression
+.IP "-r, --regex"
+The pattern of the current atomic predicate is a standard POSIX regular expression.
+.IP "-i, --ignore-case"
+Ignore case when looking for a match in the current atomic predicate.
+.IP "-X, --exact-match"
+Do an exact match (as opposed to a substring match) in the current
+atomic predicate.
+.SS Predicate connectives
+.IP "-!, --not, !"
+Negate the following predicate.
+.IP "-o, --or"
+Disjunct the preceding and the following predicate.
+.IP "-a, --and"
+Conjunct the preceding and the following predicate.
+.IP "( ... )"
+Parentheses can be used for grouping. Note that they need to be
+escaped for most shells.
+.SS Output format modifiers
+.IP "-s FIELD,FIELD,...; --show-field=FIELD,FIELD,..."
+Show only the body of these fields from the matching paragraphs. The
+field names must not include any colons or commas. Commas are used to
+delimit field names in the argument to this option. The fields are
+shown in the order given here.
+.IP "-d"
+Show only the first line of the Description field from the matching
+paragraphs. If no "-s" option is specified, this option also effects
+"-s Description"; if there is a "-s" option but it does not include
+the Description field name, one is appended to the option. Thus the
+Description field's location in the output is determined by the "-s"
+option, if any, the last field being the default.
+.IP "-n, --no-field-names"
+Suppress field names when showing specified fields, only their bodies
+are shown. Each field is printed in its original form without the
+field name, the colon after it and any whitespace predecing the start
+of the body.
+.IP "-v, --invert-match"
+Instead of showing all the paragraphs that match, show those paragraphs
+that do
+.I not
+match.
+.IP "-c, --count"
+Instead of showing the paragraphs that match (or, with -v, that don't
+match), show the count of those paragraphs.
+.SS Miscellaneous
+.IP "--config-file=FNAME"
+Use FNAME as the config file instead of the defaults.
+.IP "-l LEVEL, --errorlevel=LEVEL"
+Set debugging level to LEVEL. LEVEL is one of "fatal", "important",
+"informational" and "debug", but the last may not be available,
+depending on the compile-time options. These categories are given
+here in order; every message that is emitted when "fatal" is in
+effect, will be emitted in the "important" error level, and so on.
+The default is "important".
+.IP "-V, --version"
+Print out version information.
+.IP "-C, --copying"
+Print out the copyright license. This produces much output; be sure
+to redirect or pipe it somewhere (such as your favourite pager).
+.IP "-h, --help"
+Print out a help summary.
+.SH EXAMPLES
+The following example queries assume that the default configuration is
+in effect.
+.PP
+The almost simplest use of this program is to print out the status or
+available record of a package. In this respect,
+.B grep-dctrl
+is like
+.B "dpkg -s"
+or
+.BR "dpkg --print-avail".
+To print out the status record of the package "mixal", do
+.nf
+% grep-status -PX mixal
+.fi
+and to get its available record, use
+.nf
+% grep-available -PX mixal
+.fi
+In fact, you can ask for the record of the "mixal" package
+from any Debian control file. Say, you have the Debian 2.2
+CD-ROM's Packages file in the current directory; now you
+can do a
+.nf
+% grep-dctrl -PX mixal Packages
+.fi
+.PP
+But
+.B grep-dctrl
+can do more than just emulate
+.BR dpkg .
+It can more-or-less emulate
+.BR apt-cache !
+That program has a search feature that searches package descriptions.
+But we can do that too:
+.nf
+% grep-available -F Description foo
+.fi
+searches for the string "foo" case-sensitively in the descriptions of
+all available packages. If you want case-insensitivity, use
+.nf
+% grep-available -F Description -i foo
+.fi
+Truth to be told,
+.B apt-cache
+searches package names, too. We can separately search in the names;
+to do so, do
+.nf
+% grep-available -F Package foo
+.fi
+or
+.nf
+% grep-available -P foo
+.fi
+which is pretty much the same thing. We can also search in both
+descriptions and names; if match is found in either, the package
+record is printed:
+.nf
+% grep-available -P -F Description foo
+.fi
+or
+.nf
+% grep-available -F Package -F Description foo
+.fi
+This kind of search is the exactly same that
+.B apt-cache
+does.
+.PP
+Here's one thing neither
+.B dpkg
+nor
+.B apt-cache
+do. Search for a string in the whole status or available file (or
+any Debian control file, for that matter) and print out all package
+records where we have a match. Try
+.nf
+% grep-available dpkg
+.fi
+sometime and watch how thoroughly
+.B dpkg
+has infiltrated Debian.
+.PP
+All the above queries were based on simple substring searches.
+But
+.B grep-dctrl
+can handle regular expressions in the search pattern. For example,
+to see the status records of all packages with either "apt" or
+"dpkg" in their names, use
+.nf
+% grep-status -P -e 'apt|dpkg'
+.fi
+.PP
+Now that we have seen all these fine and dandy queries, you might
+begin to wonder whether it is necessary to always see the whole
+paragraph. You may be, for example, interest only in the dependency
+information of the packages involved. Fine. To show the depends
+lines of all packages maintained by me, do a
+.nf
+% grep-available -F Maintainer -s Depends 'ajk@debian.org'
+.fi
+If you want to see the packages' names, too, use
+.nf
+% grep-available -F Maintainer -s Package,Depends \\
+ 'ajk@debian.org'
+.fi
+Note that there must be no spaces in the argument to the -s switch.
+.PP
+More complex queries are also possible. For example, to see the list of packages
+maintained by me and depending on libc6, do
+.nf
+% grep-available -F Maintainer 'ajk@debian.org' \\
+ -a -F Depends libc6 -s Package,Depends
+.fi
+Remember that you can use other Unix filters to help you, too. Ever
+wondered, who's the most active Debian developer based on the number
+of source packages being maintained? Easy. You just need to have a
+copy of the most recent Sources file from any Debian mirror.
+.nf
+% grep-dctrl -n -s Maintainer '' Sources | sort |
+ uniq -c | sort -nr
+.fi
+This example shows a neat trick: if you want to selectively
+show only some field of
+.I all
+packages, just supply an empty pattern.
+.PP
+The term "bogopackage" means the count of the packages that a Debian
+developer maintains. To get the bogopackage count for the maintainer
+of
+.BR grep-dctrl ,
+say
+.nf
+% grep-available -c -FMaintainer \\
+ "`grep-available -sMaintainer -n -PX grep-dctrl`"
+.fi
+.PP
+Sometimes it is useful to output the data of several fields on the
+same line. For example, the following command outputs the list of
+installed packages, sorted by their Installed-Size.
+.nf
+% grep-status -FStatus -sInstalled-Size,Package -n \\
+ "install ok installed" | paste -sd " \\n" | sort -n
+.fi
+Note that there should be exactly 2 spaces in the " \n" string.
+.PP
+These examples cover a lot of typical uses of this utility, but not
+all possible uses. Use your imagination! The building blocks are
+there, and if something's missing, let me know.
+.SH DIAGNOSTICS
+These messages are emitted in log levels "fatal" and "important".
+.B This list is out of date.
+.IP "you can only use -s once"
+You must give all fields to show in one -s command. Usually many -s's
+are typos anyway, so heed this message: remove one of the -s's or
+merge all of them into one -s.
+.IP "no such log level"
+The argument to -l was invalid.
+.IP "cumulative field name exceeds maximum length"
+The combined length of the argument to all -F options given may not
+exceed 512 bytes. Longer arguments cannot be used.
+.IP "too many fields to search in"
+Too many fields were specified for searchin in. This number is
+limited to 256.
+.IP "output field spec exceeds maximum length"
+The argument to -s was too long; it is restricted to 512 bytes.
+Longer arguments cannot be used.
+.IP "too many output fields"
+The argument to -s had too many field names in it. This number is
+limited to 256.
+.IP "do not use both -e and -r options"
+The pattern cannot be both a standard POSIX regular expression and an
+extended POSIX regular expression at the same time. You must use at
+most one of the options -e and -r; using both does not make sense.
+.IP "I'm broken - please report this to <gaia@iki.fi>"
+An internal consistency check failed. Please, report this bug.
+.IP "a pattern is mandatory"
+You must specify a pattern to be searched.
+.IP "cannot find enough memory"
+More memory was needed than was available. This error may be
+transient, that is, if you try again, all may go well.
+.IP "don't know how to do an exact regex match"
+Currently you cannot do exact match searches with regular expressions.
+.IP "cannot suppress field names when showing whole paragraphs"
+When you do not use the -s switch,
+.B grep-dctrl
+just passes the matching paragraphs through, not touching them any
+way. This means, for example, that you can only use -n when you use
+-s.
+.IP "need a file name to grep"
+For some reason no file name is available. This means that the configuration
+file did not list a default file name for this name of the program, and no
+file name was given on the command line.
+.IP "syntax error: need a executable name"
+There is a problem in the configuration file. Look, and you shall find it.
+.IP "syntax error: need an input file name"
+There is a problem in the configuration file. Look, and you shall find it.
+.SH COMPATIBILITY
+If you use grep-dctrl in a Debian package, you should depend on the
+grep-dctrl package and heed the following compatibility notes:
+.PP
+.IP "Always call only the \fBgrep-dctrl\fR executable."
+Although the \fBgrep-status\fR and \fBgrep-available\fR symlinks are installed
+by default, this may change in the future. Those symlinks are meant
+for manual and not scripted use.
+.IP "Always specify an explicit file name"
+Don't rely on the implicit file name feature. The system
+administrator may have changed the default file name. You should
+always specify the "-" file, too.
+.IP "Not all features have been with us in every version"
+Check if any of the features you use is mentioned in the changelog.
+Use a versioned dependency on grep-dctrl, if it is necessary.
+.SH FILES
+.IP SYSCONF/grep-dctrl.rc
+See the next file.
+.IP ~/.grep-dctrlrc
+These files are the default configuration files for
+.BR grep-dctrl .
+The format is line-based, with `#' introducing a comment that lasts to
+the end of the line. Each line defines one association between a
+program name and a default input file. These two things are listed in
+the line in order, separated by whitespace. Empty lines are ignored.
+.SH AUTHOR
+The program and this manual page were written by Antti-Juhani
+Kaijanaho <gaia@iki.fi>. Bill Allombert <ballombe@debian.org>
+provided one of the examples in the manual page.
+.SH "SEE ALSO"
+Ian Jackson et al.: Debian Packaging Manual. Published as the Debian
+package packaging-manual. Also available in the Debian website. The
+Debian project, 2003.
+.PP
+.BR apt-cache (1),
+.BR dpkg (1),
+.BR dpkg-awk (1),
+.BR sgrep (1)
+\" Local variables:
+\" mode: nroff
+\" End:
+
diff --git a/grep-dctrl.c b/grep-dctrl.c
new file mode 100644
index 0000000..e2b7e53
--- /dev/null
+++ b/grep-dctrl.c
@@ -0,0 +1,548 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999, 2000, 2001, 2002, 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <argp.h>
+#include <assert.h>
+#include <fcntl.h>
+#include <publib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <unistd.h>
+#include "fsaf.h"
+#include "msg.h"
+#include "paragraph.h"
+#include "predicate.h"
+#include "rc.h"
+#include "util.h"
+
+const char * argp_program_version = "grep-dctrl (dctrl-tools) " VERSION;
+const char * argp_program_bug_address = MAINTAINER;
+
+const char description [] = "Description";
+size_t description_inx;
+
+static char progdoc [] = "grep-dctrl -- grep Debian control files";
+
+#define OPT_CONFIG 256
+#define OPT_OPTPARSE 257
+
+void banner(bool automatic)
+{
+ char * fname = fnqualify_xalloc("~/.grep-dctrl-banner-shown");
+ struct stat st;
+ if (automatic) {
+ int r = stat(fname, &st);
+ if (r == 0) goto end;
+ }
+ FILE * fp = fopen("/dev/tty", "w");
+ if (fp == 0) {
+ perror("/dev/tty");
+ goto end;
+ }
+ fprintf(fp,
+ "==========================================================================\n"
+ " NOTE \n"
+ " grep-dctrl has been rewritten from scratch. Although this does add new \n"
+ " features, regressions are certainly possible. Please watch for them and \n"
+ " report them to the BTS. \n"
+ "==========================================================================\n"
+ "(The above annoying banner will not be shown to you again, unless you\n"
+ "request it with the -B switch. It will also be removed entirely soon.)\n");
+
+ int r = creat(fname, 0644);
+ if (r == -1) perror(fname);
+
+ if (!automatic) exit(EXIT_SUCCESS);
+
+ for (int i = 15; i > 0; i--) {
+ fprintf(fp, "%2d seconds until program is resumed...\r", i);
+ fflush(fp);
+ sleep(1);
+ }
+ fprintf(fp, " \r");
+ fflush(fp);
+end:
+ free(fname);
+}
+
+static struct argp_option options[] = {
+ { "banner", 'B', 0, 0, "Show the testing banner." },
+ { "errorlevel", 'l', "LEVEL", 0, "Set debugging level to LEVEL." },
+ { "field", 'F', "FIELD,FIELD,...", 0, "Restrict pattern matching to the FIELDs given." },
+ { 0, 'P', 0, 0, "Shorthand for -FPackage" },
+ { "show-field", 's', "FIELD,FIELD,...", 0, "Show only the body of these fields from the matching paragraphs." },
+ { 0, 'd', 0, 0, "Show only the first line of the Description field from the matching paragraphs." },
+ { "no-field-names", 'n', 0, 0, "Suppress field names when showing specified fields." },
+ { "eregex", 'e', 0, 0, "Regard the pattern as an extended POSIX regular expression." },
+ { "regex", 'r', 0, 0, "The pattern is a standard POSIX regular expression." },
+ { "ignore-case", 'i', 0, 0, "Ignore case when looking for a match." },
+ { "invert-match", 'v', 0, 0, "Show only paragraphs that do not match." },
+ { "count", 'c', 0, 0, "Show only the count of matching paragraphs." },
+ { "config-file", OPT_CONFIG, "FNAME", 0, "Use FNAME as the config file." },
+ { "exact-match", 'X', 0, 0, "Do an exact match." },
+ { "copying", 'C', 0, 0, "Print out the copyright license." },
+ { "and", 'a', 0, 0, "Conjunct predicates." },
+ { "or", 'o', 0, 0, "Disjunct predicates." },
+ { "not", '!', 0, 0, "Negate the following predicate." },
+ { "debug-optparse", OPT_OPTPARSE, 0, 0, "Debug option parsing." },
+ { 0 }
+};
+
+
+enum state { STATE_ATOM, STATE_NEG, STATE_CONJ, STATE_DISJ, STATE_PAREN,
+ STATE_START, STATE_FINISHED };
+
+#define MAX_FNAMES 4096
+
+static int debug_optparse = 0;
+
+struct arguments {
+ /* Parser state, used when parsing the predicate. */
+ enum state state;
+ /* Top of the parser stack. */
+ size_t top;
+ /* Number of file names seen. */
+ size_t num_fnames;
+ /**/
+ size_t num_show_fields;
+ /* A machine-readable representation of the predicate. */
+ struct predicate p;
+ /* Configuration file name */
+ char const * rcname;
+ /* Do show field names? */
+ bool show_field_name;
+ /* Do show (only) first line of Description? */
+ bool short_descr;
+ /* Does show_fields contain Description? */
+ bool description_selected;
+ /* Count matching paragraphs? */
+ bool count;
+ /* Invert match? */
+ bool invert_match;
+ /* Parser stack. */
+ struct {
+ enum state state;
+ int insn;
+ } stack[MAX_OPS];
+ /* File names seen on the command line. */
+ char const * fname[MAX_FNAMES];
+ /**/
+ struct show_fields {
+ char const * name;
+ size_t inx;
+ } show_fields[MAX_FIELDS];
+};
+
+static void finish_atom(struct arguments * args)
+{
+ struct atom * atom = get_current_atom(&args->p);
+ if (atom->pat == 0) {
+ message(L_FATAL, "A pattern is mandatory.", 0);
+ exit(EXIT_FAILURE);
+ }
+ predicate_finish_atom(&args->p);
+}
+
+/* Pop off one stack state, inserting the associated instruction to
+ * the predicate program. If paren is true, current state must be
+ * STATE_PAREN, and if paren is false, it must not be STATE_PAREN. */
+static void leave(struct arguments * args, int paren)
+{
+ debug_message("leaving...", 0);
+ assert(paren == (args->state == STATE_PAREN));
+ if (args->state == STATE_ATOM) finish_atom(args);
+ assert(args->top > 0);
+ --args->top;
+ addinsn(&args->p, args->stack[args->top].insn);
+ args->state = args->stack[args->top].state;
+}
+
+#define ENTER(state,insn) do { enter(args, (state), (insn)); } while (0)
+
+static void prim_enter(struct arguments * args, const enum state state, const int insn)
+{
+ if (args->top >= MAX_OPS) {
+ message(L_FATAL, "predicate is too complex", 0);
+ exit(EXIT_FAILURE);
+ }
+ args->stack[args->top].insn = insn;
+ args->stack[args->top].state = args->state;
+ ++args->top;
+ args->state = state;
+}
+
+/* Push current state along with the given instruction to stack and
+ * enter the given state.
+ */
+static void enter(struct arguments * args, const enum state state, const int insn)
+{
+ if (args->state == STATE_FINISHED) {
+ message(L_FATAL, "syntax error in command line", 0);
+ exit(EXIT_FAILURE);
+ }
+ while (args->state < state || (state != STATE_NEG && args->state == state)) {
+ leave(args, 0);
+ }
+ prim_enter(args, state, insn);
+ debug_message("entering...", 0);
+}
+
+#define FINISH do { finish(args); } while (0)
+
+/* Flush the state stack. */
+static void finish(struct arguments * args)
+{
+ while (args->top > 0) {
+ if (args->state == STATE_PAREN) {
+ message(L_FATAL, "missing ')' in command line", 0);
+ exit(EXIT_FAILURE);
+ }
+ leave(args, 0);
+ }
+ assert(args->state == STATE_START);
+ args->state = STATE_FINISHED;
+}
+
+#define ENTER_ATOM (enter_atom((args)))
+
+/* If necessary, enter STATE_ATOM and allocate a new atom, pushing
+ * along with the old state a PUSH instruction for the new atom to the
+ * parser stack. If we are already in STATE_ATOM, reuse the current
+ * atom. */
+static struct atom * enter_atom(struct arguments * args)
+{
+ struct atom * rv;
+ if (args->state == STATE_ATOM || args->state == STATE_FINISHED) {
+ assert(args->p.num_atoms > 0);
+ return &args->p.atoms[args->p.num_atoms-1];
+ }
+ if (args->p.num_atoms >= MAX_ATOMS) {
+ message(L_FATAL, "predicate is too complex", 0);
+ exit(EXIT_FAILURE);
+ }
+ ENTER(STATE_ATOM, I_PUSH(args->p.num_atoms));
+ rv = &args->p.atoms[args->p.num_atoms++];
+ rv->field_name = 0;
+ rv->field_inx = -1;
+ rv->mode = M_SUBSTR;
+ rv->ignore_case = 0;
+ rv->pat = 0;
+ rv->patlen = 0;
+ return rv;
+}
+
+static error_t parse_opt (int key, char * arg, struct argp_state * state)
+{
+ struct arguments * args = state->input;
+ struct atom * atom;
+ debug_message("parse_opt", 0);
+ switch (key) {
+ case 'B':
+ banner(false);
+ case 'v':
+ args->invert_match = true;
+ break;
+ case 'c':
+ args->count = true;
+ break;
+ case 'n':
+ debug_message("parse_opt: n", 0);
+ args->show_field_name = false;
+ break;
+ case 'd':
+ args->short_descr = true;
+ break;
+ case 's': {
+ char * carg = strdup(arg);
+ if (carg == 0) fatal_enomem(0);
+ for (char * s = strtok(carg, ","); s != 0; s = strtok(0, ",")) {
+ struct show_fields * sf = &args->show_fields[args->num_show_fields];
+ sf->name = strdup(s);
+ if (sf->name == 0) fatal_enomem(0);
+ sf->inx = fieldtrie_insert(&args->p.trie, s);
+ if (sf->inx == description_inx) {
+ args->description_selected = true;
+ }
+ ++args->num_show_fields;
+ }
+ }
+ break;
+ case 'l': {
+ int ll = str2loglevel(optarg);
+ if (ll < 0)
+ {
+ message(L_FATAL, _("no such log level"), optarg);
+ exit(EXIT_FAILURE);
+ }
+ set_loglevel(ll);
+ debug_message("parse_opt: l", 0);
+ }
+ break;
+ case '!':
+ debug_message("parse_opt: !", 0);
+ ENTER(STATE_NEG, I_NEG);
+ break;
+ case 'a':
+ debug_message("parse_opt: a", 0);
+ ENTER(STATE_CONJ, I_AND);
+ break;
+ case 'o':
+ debug_message("parse_opt: o", 0);
+ ENTER(STATE_DISJ, I_OR);
+ break;
+ case 'P':
+ debug_message("parse_opt: P", 0);
+ arg = "Package";
+ /* pass through */
+ case 'F':
+ debug_message("parse_opt: F", 0);
+ atom = ENTER_ATOM;
+ assert(atom->field_name == 0); /* FIXME */
+ atom->field_name = strdup(arg);
+ if (atom->field_name == 0) fatal_enomem(0);
+ break;
+ case 'X':
+ debug_message("parse_opt: X", 0);
+ atom = ENTER_ATOM;
+ assert(atom->mode == M_SUBSTR); /* FIXME */
+ atom->mode = M_EXACT;
+ break;
+ case 'r':
+ debug_message("parse_opt: r", 0);
+ atom = ENTER_ATOM;
+ assert(atom->mode == M_SUBSTR); /* FIXME */
+ atom->mode = M_REGEX;
+ break;
+ case 'e':
+ debug_message("parse_opt: e", 0);
+ atom = ENTER_ATOM;
+ assert(atom->mode == M_SUBSTR); /* FIXME */
+ atom->mode = M_EREGEX;
+ break;
+ case 'i':
+ debug_message("parse_opt: i", 0);
+ atom = ENTER_ATOM;
+ atom->ignore_case = 1;
+ break;
+ case OPT_OPTPARSE:
+ debug_message("parse_opt: optparse", 0);
+ debug_optparse = 1;
+ break;
+ case ARGP_KEY_ARG:
+ debug_message("parse_opt: argument", 0);
+ redo:
+ debug_message("!!!", 0);
+ if (strcmp(arg, "!") == 0) {
+ debug_message("parse_opt: !", 0);
+ ENTER(STATE_NEG, I_NEG);
+ break;
+ }
+ if (strcmp(arg, "(") == 0) {
+ debug_message("parse_opt: (", 0);
+ prim_enter(args, STATE_PAREN, I_NOP);
+ break;
+ }
+ if (strcmp(arg, ")") == 0) {
+ debug_message("parse_opt: )", 0);
+ while (args->state != STATE_PAREN) {
+ if (args->top == 0) {
+ message(L_FATAL, "unexpected ')' in command line", 0);
+ exit(EXIT_FAILURE);
+ }
+ leave(args, 0);
+ }
+ leave(args, 1);
+ break;
+ }
+ if (args->state == STATE_FINISHED) {
+ char const * s;
+ if (args->num_fnames >= MAX_FNAMES) {
+ message(L_FATAL, "too many file names", 0);
+ exit(EXIT_FAILURE);
+ }
+ s = strdup(arg);
+ if (s == 0) fatal_enomem(0);
+ args->fname[args->num_fnames++] = s;
+ break;
+ }
+ if (strcmp(arg, "--") == 0) { FINISH; break; }
+ atom = ENTER_ATOM;
+ if (atom->pat != 0) { FINISH; goto redo; }
+ atom->patlen = strlen(arg);
+ atom->pat = malloc(atom->patlen+1);
+ if (atom->pat == 0) fatal_enomem(0);
+ strcpy((char*)atom->pat, arg);
+ break;
+ case ARGP_KEY_END:
+ debug_message("parse_opt: end", 0);
+ if (args->state != STATE_FINISHED) FINISH;
+ break;
+ case ARGP_KEY_ARGS: case ARGP_KEY_INIT: case ARGP_KEY_SUCCESS:
+ case ARGP_KEY_ERROR: case ARGP_KEY_FINI: case ARGP_KEY_NO_ARGS:
+ debug_message("parse_opt: ignored", 0);
+ break;
+ case OPT_CONFIG:
+ debug_message("parse_opt: --config-file", 0);
+ args->rcname = strdup(arg);
+ break;
+ default:
+ return ARGP_ERR_UNKNOWN;
+ }
+ return 0;
+}
+
+static void dump_args(struct arguments * args)
+{
+ size_t i;
+ assert(args->state == STATE_FINISHED);
+ assert(args->top == 0);
+ printf("num_atoms = %i\n", args->p.num_atoms);
+ for (i = 0; i < args->p.num_atoms; i++) {
+ printf("atoms[%i].field_name = %s\n", i, args->p.atoms[i].field_name);
+ printf("atoms[%i].mode = %i\n", i, args->p.atoms[i].mode);
+ printf("atoms[%i].ignore_case = %i\n", i, args->p.atoms[i].ignore_case);
+ printf("atoms[%i].pat = %s\n", i, args->p.atoms[i].pat);
+ }
+ printf("proglen = %i\n", args->p.proglen);
+ for (i = 0; i < args->p.proglen; i++) {
+ int op = args->p.program[i];
+ printf("program[%i] = ", i);
+ switch (op) {
+ case I_NOP: puts("NOP"); break;
+ case I_NEG: puts("NEG"); break;
+ case I_AND: puts("AND"); break;
+ case I_OR: puts("OR"); break;
+ default:
+ printf("PUSH(%i)\n", op - I_PUSH(0));
+ }
+ }
+ printf("num_fnames = %i\n", args->num_fnames);
+ for (i = 0; i < args->num_fnames; i++) {
+ printf("fname[%i] = %s\n", i, args->fname[i]);
+ }
+}
+
+static struct argp argp = { options, parse_opt, 0, progdoc };
+
+int main (int argc, char * argv[])
+{
+ static struct arguments args;
+ args.state = STATE_START;
+ args.show_field_name = true;
+ msg_set_progname(argv[0]);
+ init_predicate(&args.p);
+ description_inx = fieldtrie_insert(&args.p.trie, description);
+ argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &args);
+ banner(true);
+
+ if (debug_optparse) { dump_args(&args); return 0; }
+
+ if (args.short_descr && !args.description_selected) {
+ if (args.num_show_fields >= MAX_FIELDS) {
+ message(L_FATAL, _("too many output fields"), 0);
+ exit(EXIT_FAILURE);
+ }
+ message(L_INFORMATIONAL,
+ _("Adding Description to selected output fields because of -d"),
+ 0);
+ args.show_fields[args.num_show_fields].name = description;
+ args.show_fields[args.num_show_fields].inx = description_inx;
+ ++args.num_show_fields;
+ }
+
+ if (!args.show_field_name && args.num_show_fields == 0) {
+ message(L_FATAL,
+ _("cannot suppress field names when showing whole paragraphs"),
+ 0);
+ exit(EXIT_FAILURE);
+ }
+
+ size_t count = 0;
+ for (size_t i = 0; i < args.num_fnames || (i == 0 && args.num_fnames == 0); ++i) {
+ int fd;
+ const char * fname;
+ if (args.num_fnames == 0) {
+ // Hardcode grep-dctrl <-> "-" mapping so that
+ // Debian packages can genuinely depend on it.
+ char * argv0 = fnbase(argv[0]);
+ if (strcmp(argv0, "grep-dctrl") == 0) {
+ fname = "-";
+ } else {
+ fname = find_ifile_by_exename(argv0, args.rcname);
+ }
+ } else {
+ fname = args.fname[i];
+ }
+
+ if (strcmp(fname, "-") == 0) {
+ fd = STDIN_FILENO;
+ fname = "stdin";
+ } else {
+ fd = open(fname, O_RDONLY);
+ if (fd == -1) {
+ fprintf(stderr, "%s: %s: %s\n", argv[0], fname, strerror(errno));
+ break;
+ }
+ }
+
+ FSAF * fp = fsaf_fdopen(fd);
+ para_t para;
+ for (para_init(&para, fp, &args.p.trie);
+ !para_eof(&para);
+ para_parse_next(&para)) {
+ if ((args.invert_match || !does_para_satisfy(&args.p, &para))
+ && (!args.invert_match || does_para_satisfy(&args.p, &para))) {
+ continue;
+ }
+ if (args.count) {
+ ++count;
+ continue;
+ }
+ if (args.num_show_fields == 0) {
+ struct fsaf_read_rv r = fsaf_read(fp, para.start, para.end - para.start);
+ fwrite(r.b, 1, r.len, stdout);
+ putchar('\n');
+ continue;
+ }
+ for (size_t j = 0; j < args.num_show_fields; j++) {
+ if (args.show_field_name) {
+ printf("%s: ", args.show_fields[j].name);
+ }
+ struct field_data * fd = &para.fields[args.show_fields[j].inx];
+ struct fsaf_read_rv r = fsaf_read(fp, fd->start, fd->end - fd->start);
+ if (args.short_descr &&
+ args.show_fields[j].inx == description_inx) {
+ char * nl = memchr(r.b, '\n', r.len);
+ if (nl != 0) r.len = nl - r.b;
+ }
+ fwrite(r.b, 1, r.len, stdout);
+ puts("");
+ continue;
+ }
+ if (args.num_show_fields > 1) puts("");
+
+ }
+
+ if (fd != STDIN_FILENO) close(fd);
+ }
+ if (count) printf("%d\n", count);
+ return 0;
+}
+
diff --git a/grep-dctrl.rc b/grep-dctrl.rc
new file mode 100644
index 0000000..f73f5e3
--- /dev/null
+++ b/grep-dctrl.rc
@@ -0,0 +1,15 @@
+# Configuration for grep-dctrl. The config line format is
+# line-oriented. Each line defines one executable name - default
+# input file pair; the elements of the pair are in order and separated
+# by whitespace. The hash '#' begins a comment that lasts to the end
+# of line. Empty lines are ignored.
+
+# Template:
+# <executable name> <default input file name>
+
+# The following line used to be required, but it is now hardcoded.
+# grep-dctrl -
+
+# The following two pairs define common aliases for grep-dctrl.
+grep-status /var/lib/dpkg/status
+grep-available /var/lib/dpkg/available
diff --git a/i18n.h b/i18n.h
new file mode 100644
index 0000000..6942c51
--- /dev/null
+++ b/i18n.h
@@ -0,0 +1,32 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999, 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef I18N_H__
+#define I18N_H__
+
+#ifdef HAVE_GETTEXT
+#include <libintl.h>
+#define _(String) gettext(String)
+#else
+#define _(String) (String)
+#define textdomain(Domain)
+#define bindtextdomain(Package, Directory)
+#endif
+
+#endif /* I18N_H__ */
diff --git a/msg.c b/msg.c
new file mode 100644
index 0000000..82b8796
--- /dev/null
+++ b/msg.c
@@ -0,0 +1,93 @@
+/* grep-dctrl - grep Debian control files
+ Copyright (C) 1999 Antti-Juhani Kaijanaho
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ The author can be reached via mail at (ISO 8859-1 charset for the city)
+ Antti-Juhani Kaijanaho
+ Helvintie 2 e as 9
+ FIN-40500 JYVÄSKYLÄ
+ FINLAND
+ EUROPE
+ and via electronic mail from
+ gaia@iki.fi
+ If you have a choice, use the email address; it is more likely to
+ stay current.
+
+*/
+
+
+#define MSG_C__
+
+#include <assert.h>
+#include <string.h>
+#include "msg.h"
+
+struct str2int_avec_t {
+ const char * str;
+ int integer;
+};
+
+int
+within_interval (int n, int a, int b)
+{
+ if (a > b)
+ {
+ int tmp;
+ tmp = b;
+ b = a;
+ a = tmp;
+ }
+
+ assert (a <= b);
+
+ return (a <= n && n <= b);
+}
+
+void
+msg_set_progname (const char * pn)
+{
+ strncpy (progname, pn, PROGNAME_MAXLEN);
+ progname [PROGNAME_MAXLEN - 1] = 0;
+}
+
+void
+set_loglevel (int ll)
+{
+ assert (within_interval (loglevel, L_FATAL, L_DEBUG));
+
+ loglevel = ll;
+}
+
+int
+str2loglevel (const char * s)
+{
+ static struct str2int_avec_t avec [] = {
+ { "fatal", L_FATAL },
+ { "important", L_IMPORTANT },
+ { "informational", L_INFORMATIONAL },
+#if !defined(NDEBUG) && defined(ENABLE_L_DEBUG)
+ { "debug", L_DEBUG },
+#endif
+ { 0, 0 } };
+
+ int i;
+
+ for (i = 0; avec [i].str != 0; i++)
+ if (strcasecmp (avec [i].str, s) == 0)
+ return avec[i].integer;
+ return -1;
+}
diff --git a/msg.h b/msg.h
new file mode 100644
index 0000000..ecd61e7
--- /dev/null
+++ b/msg.h
@@ -0,0 +1,133 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef MSG_H__
+#define MSG_H__
+
+#include <stdio.h>
+#include <stdlib.h>
+#include "i18n.h"
+
+/* log levels */
+#define L_FATAL 3
+#define L_IMPORTANT 2
+#define L_INFORMATIONAL 1
+#define L_DEBUG 0
+
+#define PROGNAME_MAXLEN 64
+
+#if !defined(NDEBUG) && !defined(TEST_NODEBUG) && defined(ENABLE_L_DEBUG)
+# define INCLUDE_DEBUG_MSGS
+#endif
+
+#ifdef MSG_C__
+int loglevel = L_IMPORTANT;
+char progname [PROGNAME_MAXLEN];
+#endif
+
+inline static int
+do_msg(int severity)
+{
+#ifndef MSG_C__
+ extern int loglevel;
+#endif
+
+#if defined(TEST_NODEBUG)
+ if (severity == L_DEBUG)
+ {
+ line_message (L_INFORMATIONAL, _("Got a L_DEBUG while TEST_NODEBUG "
+ "is defined"), 0, 0);
+ message (L_FATAL, _("I'm broken - please report this "
+ "to <gaia@iki.fi>"), 0, 0);
+ abort ();
+ }
+#endif
+
+ return severity >= loglevel;
+}
+
+inline static void
+line_message (int severity, const char * s, const char * fname, int line)
+{
+ if (do_msg(severity)) {
+#ifndef MSG_C__
+ extern const char progname [PROGNAME_MAXLEN];
+#endif
+
+ if (fname == 0) {
+ fprintf (stderr, "%s: %s.\n", progname, s);
+ } else {
+ if (line > 0) {
+ fprintf (stderr, "%s: %s: %i: %s.\n", progname, fname, line, s);
+ } else {
+ fprintf (stderr, "%s: %s: %s.\n", progname, fname, s);
+ }
+ }
+ }
+}
+
+inline static void
+message (int severity, const char * s, const char * fname)
+{
+ line_message (severity, s, fname, 0);
+}
+
+#ifndef MSG_C__
+#undef PROGNAME_MAXLEN
+#endif
+
+inline static void
+debug_message (const char * s, const char * fname)
+{
+#ifdef INCLUDE_DEBUG_MSGS
+ message (L_DEBUG, s, fname);
+#endif
+}
+
+#define enomem_msg _("cannot find enough memory")
+
+inline static void
+enomem (const char * fname)
+{
+ message (L_IMPORTANT, enomem_msg, fname);
+}
+
+inline static void
+fatal_enomem (const char * fname)
+{
+ message (L_FATAL, enomem_msg, fname);
+ exit (EXIT_FAILURE);
+}
+
+#undef enomem_msg
+
+/* Given a string that represents a log level, return the number that
+ repsesents that loglevel. A negative return value means that the
+ string is not a valid log level. */
+int
+str2loglevel (const char * s);
+
+/* Set current log level to ll. */
+void
+set_loglevel (int ll);
+
+/* Set program name to pn. */
+void
+msg_set_progname (const char * pn);
+
+#endif /* MSG_H__ */
diff --git a/paragraph.c b/paragraph.c
new file mode 100644
index 0000000..a6d1145
--- /dev/null
+++ b/paragraph.c
@@ -0,0 +1,135 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include "msg.h"
+#include "paragraph.h"
+
+void para_init(para_t * para, FSAF * fp, fieldtrie_t * trie)
+{
+ para->fp = fp;
+ para->trie = trie;
+ para->start = 0;
+ para->end = 0;
+ para->eof = false;
+ para_parse_next(para);
+}
+
+void para_parse_next(para_t * para)
+{
+ debug_message("para_parse_next", 0);
+ para->start = para->end;
+ fsaf_invalidate(para->fp, para->start);
+ register enum { START, FIELD_NAME, BODY, BODY_NEWLINE,
+ BODY_SKIPBLANKS, END } state = START;
+ register size_t pos = para->start;
+ register FSAF * fp = para->fp;
+ size_t field_start = 0;
+ struct field_data * field_data = 0;
+ while (state != END) {
+ int c = fsaf_getc(fp, pos++);
+ switch (state) {
+ case START:
+ switch (c) {
+ case -1:
+ para->eof = true;
+ state = END;
+ break;
+ case '\n':
+ para->start++;
+ break;
+ default:
+ field_start = --pos;
+ state = FIELD_NAME;
+ }
+ break;
+ case FIELD_NAME:
+ switch (c) {
+ case -1:
+ message(L_FATAL, "unexpected end of file", 0);
+ exit(EXIT_FAILURE);
+ case ':': {
+ size_t len = (pos-1) - field_start;
+ struct fsaf_read_rv r = fsaf_read(fp, field_start, len);
+ assert(r.len == len);
+ size_t inx = fieldtrie_lookup(para->trie, r.b, len);
+ if (inx == -1) {
+ field_data = 0;
+ } else {
+ assert(inx < MAX_FIELDS);
+ field_data = &para->fields[inx];
+ field_data->start = pos;
+ }
+ state = BODY;
+ }
+ break;
+ case '\n':
+ message(L_FATAL, "unexpected end of line", 0);
+ exit(EXIT_FAILURE);
+ }
+ break;
+ case BODY:
+ switch (c) {
+ case -1:
+ message(L_FATAL, "unexpected end of file", 0);
+ exit(EXIT_FAILURE);
+ case '\n':
+ if (field_data != 0) {
+ field_data->end = pos-1;
+ while (field_data->start < field_data->end
+ && fsaf_getc(fp, field_data->start) == ' ') {
+ ++field_data->start;
+ }
+ }
+ state = BODY_NEWLINE;
+ break;
+ }
+ break;
+ case BODY_NEWLINE:
+ switch (c) {
+ case -1:
+ para->eof = true;
+ /* pass through */
+ case '\n':
+ state = END;
+ break;
+ case ' ': case '\t':
+ state = BODY_SKIPBLANKS;
+ break;
+ default:
+ field_start = --pos;
+ state = FIELD_NAME;
+ }
+ break;
+ case BODY_SKIPBLANKS:
+ switch (c) {
+ case -1:
+ /* pass through */
+ case '\n':
+ state = END;
+ break;
+ case ' ': case '\t':
+ break;
+ default:
+ state = BODY;
+ }
+ break;
+ case END: assert(0);
+ }
+ }
+ para->end = pos-1;
+}
diff --git a/paragraph.h b/paragraph.h
new file mode 100644
index 0000000..a4e15fc
--- /dev/null
+++ b/paragraph.h
@@ -0,0 +1,54 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PARAGRAPH_H
+#define PARAGRAPH_H
+
+#define MAX_FIELDS 100
+
+#include <stddef.h>
+#include "fsaf.h"
+#include "fieldtrie.h"
+
+struct field_data {
+ size_t start, end; /* offsets to the file; [start,end) is the body */
+};
+
+struct paragraph_private {
+ FSAF * fp;
+ fieldtrie_t * trie;
+ bool eof;
+
+ // CURRENT PARAGRAPH PARSED
+
+ size_t start, end; /* offsets to the file; [start,end) is the paragraph */
+ struct field_data fields[MAX_FIELDS];
+};
+
+typedef struct paragraph_private para_t;
+
+/* Initialize the given para_t, associating with it the given
+ * FSAF and the field trie. */
+void para_init(para_t *, FSAF *, fieldtrie_t *);
+
+void para_parse_next(para_t *);
+
+static inline
+bool para_eof(para_t * para) { return para->eof; }
+
+#endif /* PARAGRAPH_H */
diff --git a/predicate.c b/predicate.c
new file mode 100644
index 0000000..e0a5dec
--- /dev/null
+++ b/predicate.c
@@ -0,0 +1,173 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctype.h>
+#include <stdlib.h>
+#include <regex.h>
+#include <string.h>
+#include "fsaf.h"
+#include "msg.h"
+#include "util.h"
+#include "predicate.h"
+
+void init_predicate(struct predicate * p)
+{
+ p->num_atoms = 0;
+ p->proglen = 0;
+ fieldtrie_init(&p->trie);
+}
+
+void addinsn(struct predicate * p, int insn)
+{
+ if (insn == I_NOP) return;
+ if (p->proglen >= MAX_OPS) {
+ message(L_FATAL, "predicate is too complex", 0);
+ exit(EXIT_FAILURE);
+ }
+ p->program[p->proglen++] = insn;
+}
+
+void predicate_finish_atom(struct predicate * p)
+{
+ struct atom * atom = get_current_atom(p);
+ if (atom->field_name == 0) return;
+ atom->field_inx = fieldtrie_insert(&p->trie, atom->field_name);
+
+ if (atom->mode == M_REGEX || atom->mode == M_EREGEX) {
+ int rerr = regcomp(&atom->regex, atom->pat,
+ (atom->mode == M_EREGEX ? REG_EXTENDED : 0)
+ | REG_NOSUB
+ | (atom->ignore_case ? REG_ICASE : 0));
+ if (rerr != 0) {
+ char * s;
+ s = get_regerror(rerr, &atom->regex);
+ if (s == 0) fatal_enomem(0);
+ message(L_FATAL, s, 0);
+ free(s);
+ exit(EXIT_FAILURE);
+ }
+ }
+}
+
+static bool verify_atom(struct atom * atom, para_t * para)
+{
+ size_t start, end;
+ if (atom->field_inx == -1) {
+ /* Take the full paragraph */
+ start = para->start;
+ end = para->end;
+ } else {
+ /* Take the field */
+ struct field_data * fd = &para->fields[atom->field_inx];
+ start = fd->start;
+ end = fd->end;
+ }
+ size_t len = end - start;
+ struct fsaf_read_rv r = fsaf_read(para->fp, start, len);
+ assert(r.len == len);
+ switch (atom->mode) {
+ case M_EXACT:
+ if (len != atom->patlen) return false;
+ if (atom->ignore_case) {
+ return strncasecmp(atom->pat, r.b, len) == 0;
+ } else {
+ return strncmp(atom->pat, r.b, len) == 0;
+ }
+ case M_SUBSTR: {
+#if 0
+ if (atom->ignore_case) {
+ return strncasestr(r.b, atom->pat, len);
+ } else {
+ return strnstr(r.b, atom->pat, len);
+ }
+#else
+ bool rv;
+ char * s = strndup(r.b, len);
+ if (s == 0) fatal_enomem(0);
+ if (atom->ignore_case) {
+ rv = strcasestr(s, atom->pat) != 0;
+ } else {
+ rv = strstr(s, atom->pat) != 0;
+ }
+ free(s);
+ return rv;
+#endif
+ }
+ case M_REGEX: case M_EREGEX: {
+ char * s = strndup(r.b, len);
+ if (s == 0) fatal_enomem(0);
+ int regex_errcode = regexec(&atom->regex, s, 0, 0, 0);
+ free(s);
+ if (regex_errcode == 0 || regex_errcode == REG_NOMATCH) {
+ return (regex_errcode == 0);
+ }
+ /* Error handling be here. */
+ assert(regex_errcode != 0 && regex_errcode != REG_NOMATCH);
+ s = get_regerror (regex_errcode, &atom->regex);
+ if (s == 0) { enomem (0); return false; }
+ message(L_IMPORTANT, s, 0);
+ free(s);
+ return false;
+ }
+ }
+ assert(0);
+}
+
+bool does_para_satisfy(struct predicate * p, para_t * para)
+{
+ assert(para->trie == & p->trie);
+
+ bool sat_atom[MAX_ATOMS];
+ bool stack[MAX_OPS];
+ size_t sp = 0;
+
+ /* Verify atoms. */
+ for (size_t i = 0; i < p->num_atoms; i++) {
+ sat_atom[i] = verify_atom(&p->atoms[i], para);
+ }
+
+ /* Run the program. */
+ for (size_t i = 0; i < p->proglen; i++) {
+ switch (p->program[i]) {
+ case I_NOP: break;
+ case I_NEG:
+ assert(sp >= 1);
+ stack[sp-1] = !stack[sp-1];
+ break;
+ case I_AND:
+ assert(sp >= 2);
+ stack[sp-2] = stack[sp-2] && stack[sp-1];
+ --sp;
+ break;
+ case I_OR:
+ assert(sp >= 2);
+ stack[sp-2] = stack[sp-2] || stack[sp-1];
+ --sp;
+ break;
+ default:
+ {
+ int atom = p->program[i] - I_PUSH(0);
+ assert(atom <= p->num_atoms);
+ stack[sp] = sat_atom[atom];
+ ++sp;
+ }
+ }
+ }
+ assert(sp == 1);
+ return stack[0];
+}
diff --git a/predicate.h b/predicate.h
new file mode 100644
index 0000000..f60a6ea
--- /dev/null
+++ b/predicate.h
@@ -0,0 +1,88 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef PREDICATE_H
+#define PREDICATE_H
+
+#include <assert.h>
+#include <regex.h>
+#include "fieldtrie.h"
+#include "paragraph.h"
+
+#define MAX_OPS 4096
+#define MAX_ATOMS 4096
+
+#define I_NOP 0
+#define I_NEG 1 /* --not; 1-1 */
+#define I_AND 2 /* --and; 2-1 */
+#define I_OR 3 /* --or; 2-1 */
+#define I_PUSH(n) (4+(n)) /* push result of nth atomic proposition */
+
+/* An atomic predicate. */
+struct atom {
+ /* The name of field to which matching is limited. Empty
+ * field_name specifies the whole paragraph (in which case
+ * field_inx is -1. */
+ char const * field_name; size_t field_inx;
+ /* Matching mode */
+ enum { M_SUBSTR, /* substring matching */
+ M_REGEX, /* POSIX regular expression match */
+ M_EREGEX, /* POSIX extended regular expression matching */
+ M_EXACT /* exact match */
+ } mode;
+ /* Flag: should matching ignore case */
+ unsigned ignore_case;
+ /* The pattern as given on the command line; interpretation
+ * depends on matching mode. */
+ char const * pat; size_t patlen;
+ /* A compiled version of pat; valid only when mode is M_REGEX
+ * or M_EREGEX. */
+ regex_t regex;
+};
+
+/* A predicate is represented as a set of atomic predicates and a
+ * program - a sequence of stack-based "bytecode" instructions - that
+ * specifies the structure of the combined predicate. */
+struct predicate {
+ /* Number of atomic predicates. */
+ size_t num_atoms;
+ /* Length of the program */
+ size_t proglen;
+ /* The program */
+ int program[MAX_OPS];
+ /* The atomic predicates */
+ struct atom atoms[MAX_ATOMS];
+ fieldtrie_t trie;
+};
+
+void init_predicate(struct predicate * p);
+
+static inline
+struct atom * get_current_atom(struct predicate * p)
+{
+ assert(p->num_atoms > 0);
+ return &p->atoms[p->num_atoms-1];
+}
+
+void predicate_finish_atom(struct predicate *);
+
+void addinsn(struct predicate * p, int insn);
+
+bool does_para_satisfy(struct predicate * p, para_t *);
+
+#endif /* PREDICATE_H */
diff --git a/rc.c b/rc.c
new file mode 100644
index 0000000..4d5f308
--- /dev/null
+++ b/rc.c
@@ -0,0 +1,130 @@
+/* grep-dctrl - grep Debian control files
+ Copyright (C) 1999, 2003 Antti-Juhani Kaijanaho
+
+ 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; see the file COPYING. If not, write to
+ the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ Boston, MA 02111-1307, USA.
+
+ The author can be reached via mail at (ISO 8859-1 charset for the city)
+ Antti-Juhani Kaijanaho
+ Helokantie 1 A 16
+ FIN-40640 JYVÄSKYLÄ
+ FINLAND
+ EUROPE
+ and via electronic mail from
+ gaia@iki.fi
+ If you have a choice, use the email address; it is more likely to
+ stay current.
+
+*/
+
+#include <assert.h>
+#include <errno.h>
+#include <publib.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "msg.h"
+#include "rc.h"
+#include "strutil.h"
+
+
+const char * find_ifile_by_exename(const char * exename, const char * rcfname)
+{
+ static const char * default_rcfiles [] = {
+ /* Order is significant: earlier files override later ones. */
+ "~/.grep-dctrlrc",
+ SYSCONF "/grep-dctrl.rc",
+ 0 };
+ int i;
+ const char * rv = 0;
+ char * fname;
+ int lineno;
+ FILE * f;
+
+ assert(exename != 0);
+
+ if (rcfname == 0) {
+ for (i = 0; rv == 0 && default_rcfiles [i] != 0; i++) {
+ rv = find_ifile_by_exename(exename, default_rcfiles [i]);
+ }
+ return rv;
+ }
+
+ assert(rcfname != 0);
+
+ fname = fnqualify_xalloc(rcfname);
+
+ message(L_INFORMATIONAL, _("reading config file"), fname);
+
+ f = fopen(fname, "r");
+ if (f == 0) {
+ message(L_INFORMATIONAL, strerror(errno), fname);
+ return 0;
+ }
+
+ lineno = 0;
+ while (1) {
+ static char * line = 0;
+ char * line_exe;
+ char * line_ifile;
+
+ /* If this is not the first call, line may be non-null
+ and must be freed. It must be freed on all
+ non-first iterations, too. */
+ free(line);
+
+ line = xgetaline (f);
+ ++lineno;
+ if (line == 0) {
+ rv = 0;
+ break;
+ }
+
+ chop_comment(line, '#');
+
+ if (left_trimmed(line) [0] == 0) {
+ continue;
+ }
+
+ line_exe = strtok(line, " \t");
+ if (line_exe == 0) {
+ line_message(L_IMPORTANT,
+ _("syntax error: need a executable name"),
+ fname, lineno);
+ continue;
+ }
+
+ line_ifile = strtok(0, " \t");
+ if (line_ifile == 0) {
+ line_message(L_IMPORTANT,
+ _("syntax error: need an input file name"),
+ fname, lineno);
+ continue;
+ }
+
+ message(L_INFORMATIONAL, _("considering executable name"), line_exe);
+ if (strcmp (exename, line_exe) == 0) {
+ message(L_INFORMATIONAL, _("yes, will use executable name"), line_exe);
+ rv = line_ifile;
+ message(L_INFORMATIONAL, _("default input file"), rv);
+ break;
+ }
+ }
+
+ fclose(f);
+ free(fname);
+ return rv;
+}
+
diff --git a/rc.h b/rc.h
new file mode 100644
index 0000000..c080f6f
--- /dev/null
+++ b/rc.h
@@ -0,0 +1,30 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999, 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef RC_H__
+#define RC_H__
+
+/* Search for exename (only basename, though) in rcfname (or if it is
+ null, in default rc files) and return the found corresponding
+ default input file name, or null, if not found or other error
+ occurred. The returned pointer will be invalidated by the next
+ call to this function. */
+const char *
+find_ifile_by_exename (const char * exename, const char * rcfname);
+
+#endif
diff --git a/strutil.c b/strutil.c
new file mode 100644
index 0000000..2160993
--- /dev/null
+++ b/strutil.c
@@ -0,0 +1,110 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999, 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <ctype.h>
+#include "strutil.h"
+
+const char * left_trimmed(const char * s)
+{
+ const char * p;
+
+ for (p = s; *p != 0 && isspace (*p); p++);
+
+ return p;
+}
+
+void trim_right (char * s)
+{
+ char * p;
+ char * herep;
+ enum { BLANKS, NONBLANKS } state = NONBLANKS;
+
+ for (herep = 0, p = s; *p != 0; p++) {
+ switch (state) {
+ case BLANKS:
+ if (!isspace (*p)) {
+ state = NONBLANKS;
+ }
+ break;
+ case NONBLANKS:
+ if (isspace (*p)) {
+ herep = p;
+ state = BLANKS;
+ }
+ }
+ }
+ if (state == BLANKS) *herep = 0;
+}
+
+#ifdef TESTMAIN
+
+#define _GNU_SOURCE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+void
+printout (const char * s)
+{
+ printf("\"%s\"\n", s);
+}
+
+int
+main (void)
+{
+ static const char * teststrings [] = {
+ "autoksiko",
+ " autoksiko",
+ "autoksiko ",
+ " autoksiko ",
+ "autoksiko teen",
+ " autoksiko teen",
+ "autoksiko teen ",
+ " autoksiko teen ",
+ " miljoona miljoona ruusua ",
+ 0 };
+ int i;
+
+ for (i = 0; teststrings [i] != 0; i++)
+ {
+ char * ts;
+ char * orig_ts;
+
+ orig_ts = ts = strdup (teststrings [i]);
+ if (ts == 0)
+ exit (EXIT_FAILURE);
+
+ printf ("Plain: ");
+ printout (ts);
+
+ printf ("Left-trimmed: ");
+ printout (left_trimmed (ts));
+
+ printf ("Right-trimmed: ");
+ trim_right (ts);
+ printout (ts);
+
+ printf ("Completely trimmed: ");
+ printout (left_trimmed (ts));
+
+ puts ("");
+ free (orig_ts);
+ }
+ return 0;
+}
+#endif /* TESTMAIN */
diff --git a/strutil.h b/strutil.h
new file mode 100644
index 0000000..862e721
--- /dev/null
+++ b/strutil.h
@@ -0,0 +1,43 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 1999, 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+
+#ifndef STRUTIL_H__
+#define STRUTIL_H__
+
+#include <string.h>
+
+/* Return a pointer to first nonblank character in s. */
+const char * left_trimmed(const char * s);
+
+/* Mutate s and trim whitespace off its right end. */
+void trim_right(char * s);
+
+/* Chop off everything after and including the first comchar in line.
+ This mutates line! */
+static inline void chop_comment(char * line, char comchar)
+{
+ char * comstart;
+
+ comstart = strchr (line, comchar);
+
+ if (comstart != 0)
+ *comstart = 0;
+}
+
+#endif /* STRUTIL_H__ */
diff --git a/util.c b/util.c
new file mode 100644
index 0000000..99b181b
--- /dev/null
+++ b/util.c
@@ -0,0 +1,48 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <publib.h>
+#include <stdlib.h>
+#include <regex.h>
+#include "util.h"
+
+char * get_regerror (int errcode, regex_t *compiled)
+{
+ size_t length = regerror (errcode, compiled, NULL, 0);
+ char * buffer = malloc (length);
+
+ if (buffer == 0)
+ return 0;
+
+ (void) regerror (errcode, compiled, buffer, length);
+ return buffer;
+}
+
+char * fnqualify_xalloc(const char * fname)
+{
+ char * rv = 0;
+ size_t rv_len = 0;
+ int actual_len = 0;
+
+ while (actual_len >= rv_len) {
+ rv = xrealloc(rv, rv_len += 64);
+ actual_len = fnqualify(rv, fname, rv_len);
+ }
+
+ return rv;
+}
diff --git a/util.h b/util.h
new file mode 100644
index 0000000..25d0562
--- /dev/null
+++ b/util.h
@@ -0,0 +1,29 @@
+/* dctrl-tools - Debian control file inspection tools
+ Copyright (C) 2003 Antti-Juhani Kaijanaho
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef UTIL_H
+#define UTIL_H
+
+#include <regex.h>
+
+char * get_regerror (int errcode, regex_t *compiled);
+
+
+char * fnqualify_xalloc(const char * fname);
+
+#endif /* UTIL_H */