Browse Source

dpkg (1.1.4); priority=MEDIUM

  * Allow overwriting of conflicting packages being removed.  (Bug#2614.)

  * a.out control file says Pre-Depends: libc4 | libc.  (Bug#2640.)
  * ELF control file and libc dependencies changed to use finalised scheme.
  * ELF control file and libc dependencies for i386 only.  (Bug#2617.)

  * Guidelines say use only released libraries and compilers.
  * Install wishlist as /usr/doc/dpkg/WISHLIST.
  * Remove spurious entries for Guidelines in info dir file.

  * dpkg-deb --build checks permissions on control (DEBIAN) directory.

  * Spaces in control file fields not copied by dpkg-split.  (Bug#2633.)
  * Spaces in split file part control data ignore.  (Bug#2633.)

  * Portability fixes, including patch from Richard Kettlewell.
  * Fixed minor configure.in bug causing mangled GCC -W options.

 -- Ian Jackson <ian@chiark.chu.cam.ac.uk>  Thu, 4 Apr 1996 01:58:40 +0100
Ian Jackson 28 years ago
commit
1b80fb16c2
100 changed files with 20364 additions and 0 deletions
  1. 339 0
      COPYING
  2. 146 0
      INSTALL
  3. 131 0
      Makefile.in
  4. 72 0
      NEWS
  5. 23 0
      README
  6. 57 0
      TODO
  7. 31 0
      acconfig.h
  8. 21 0
      archtable
  9. 129 0
      config.h.bot
  10. 212 0
      config.h.in
  11. 2374 0
      configure
  12. 242 0
      configure.in
  13. 1253 0
      debian.Changelog
  14. 36 0
      debian.README
  15. 15 0
      debian.control
  16. 15 0
      debian.controlaout
  17. 193 0
      debian.postinst
  18. 86 0
      debian.preinst
  19. 12 0
      debian.prerm
  20. 85 0
      debian.rules
  21. 81 0
      doc/Makefile.in
  22. 62 0
      doc/auto-deconfiguration.txt
  23. 487 0
      doc/database-structure.fig
  24. 104 0
      doc/deb-control.5
  25. 69 0
      doc/deb.5
  26. 97 0
      doc/dependency-ordering.txt
  27. 112 0
      doc/descriptions.txt
  28. 44 0
      doc/disappear-replace.txt
  29. 131 0
      doc/diversions.text
  30. 101 0
      doc/dpkg.texi
  31. 43 0
      doc/essential-flag.txt
  32. 1039 0
      doc/guidelines.info-1
  33. 744 0
      doc/guidelines.info-2
  34. 1936 0
      doc/guidelines.texi
  35. 1056 0
      doc/guidelines.texi.beforeeric
  36. 33 0
      doc/guidelines.texi.rej
  37. 29 0
      doc/junk
  38. 173 0
      doc/maintainer-script-args.txt
  39. 220 0
      doc/upgrades+errors.txt
  40. 59 0
      doc/version-ordering.txt
  41. 105 0
      doc/virtual-dependencies.txt
  42. 66 0
      dpkg-deb/Makefile.in
  43. 267 0
      dpkg-deb/build.c
  44. 3 0
      dpkg-deb/debugmake
  45. 130 0
      dpkg-deb/dpkg-deb.8
  46. 133 0
      dpkg-deb/dpkg-deb.8-vuori
  47. 40 0
      dpkg-deb/dpkg-deb.h
  48. 316 0
      dpkg-deb/extract.c
  49. 240 0
      dpkg-deb/info.c
  50. 151 0
      dpkg-deb/main.c
  51. 67 0
      dpkg-deb/mkdeb.sh
  52. 119 0
      dselect/Makefile.in
  53. 264 0
      dselect/basecmds.cc
  54. 351 0
      dselect/baselist.cc
  55. 61 0
      dselect/basetop.cc
  56. 166 0
      dselect/bindings.cc
  57. 94 0
      dselect/bindings.h
  58. 17 0
      dselect/checkunimp.pl
  59. 33 0
      dselect/curkeys.cc
  60. 3 0
      dselect/debugmake
  61. 89 0
      dselect/dselect.8
  62. 149 0
      dselect/dselect.h
  63. 179 0
      dselect/helpmsgs.src
  64. 162 0
      dselect/junk
  65. 59 0
      dselect/keyoverride
  66. 91 0
      dselect/keys.c
  67. 30 0
      dselect/kt.c
  68. 30 0
      dselect/kt.cc
  69. 308 0
      dselect/main.cc
  70. 112 0
      dselect/methkeys.cc
  71. 213 0
      dselect/methlist.cc
  72. 272 0
      dselect/method.cc
  73. 79 0
      dselect/method.h
  74. 289 0
      dselect/methparse.cc
  75. 121 0
      dselect/mkcurkeys.pl
  76. 74 0
      dselect/mkhelpmsgs.pl
  77. 217 0
      dselect/pkgcmds.cc
  78. 303 0
      dselect/pkgdepcon.cc
  79. 142 0
      dselect/pkgdisplay.cc
  80. 163 0
      dselect/pkginfo.cc
  81. 139 0
      dselect/pkgkeys.cc
  82. 378 0
      dselect/pkglist.cc
  83. 183 0
      dselect/pkglist.h
  84. 206 0
      dselect/pkgsublist.cc
  85. 249 0
      dselect/pkgtop.cc
  86. 2 0
      dselect/rp
  87. 1 0
      dselect/t.c
  88. 26 0
      include/Makefile.in
  89. 272 0
      include/dpkg-db.h
  90. 179 0
      include/dpkg.h
  91. 38 0
      include/myopt.h
  92. 57 0
      include/tarfn.h
  93. 14 0
      insert-version.pl
  94. 119 0
      install.sh
  95. 91 0
      lib/Makefile.in
  96. 102 0
      lib/compat.c
  97. 249 0
      lib/database.c
  98. 256 0
      lib/dbmodify.c
  99. 3 0
      lib/debugmake
  100. 0 0
      lib/dump.c

+ 339 - 0
COPYING

@@ -0,0 +1,339 @@
+		    GNU GENERAL PUBLIC LICENSE
+		       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+                          675 Mass Ave, Cambridge, MA 02139, 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., 675 Mass Ave, Cambridge, MA 02139, 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.

+ 146 - 0
INSTALL

@@ -0,0 +1,146 @@
+   This is a generic INSTALL file for utilities distributions.
+If this package does not come with, e.g., installable documentation or
+data files, please ignore the references to them below.
+
+   The `configure' shell script attempts to guess correct values for
+various system-dependent variables used during compilation, and
+creates the Makefile(s) (one in each subdirectory of the source
+directory).  In some packages it creates a C header file containing
+system-dependent definitions.  It also creates a file `config.status'
+that you can run in the future to recreate the current configuration.
+
+To compile this package:
+
+1.  Configure the package for your system.
+
+   Normally, you just `cd' to the directory containing the package's
+source code and type `./configure'.  If you're using `csh' on an old
+version of System V, you might need to type `sh configure' instead to
+prevent `csh' from trying to execute `configure' itself.
+
+   Running `configure' takes awhile.  While it is running, it
+prints some messages that tell what it is doing.  If you don't want to
+see any messages, run `configure' with its standard output redirected
+to `/dev/null'; for example, `./configure >/dev/null'.
+
+   To compile the package in a different directory from the one
+containing the source code, you must use a version of `make' that
+supports the `VPATH' variable, such as GNU `make'.  `cd' to the
+directory where you want the object files and executables to go and run
+the `configure' script.  `configure' automatically checks for the
+source code in the directory that `configure' is in and in `..'.  If
+for some reason `configure' is not in the source code directory that
+you are configuring, then it will report that it can't find the source
+code.  In that case, run `configure' with the option `--srcdir=DIR',
+where DIR is the directory that contains the source code.
+
+   By default, `make install' will install the package's files in
+`/usr/local/bin', `/usr/local/man', etc.  You can specify an
+installation prefix other than `/usr/local' by giving `configure' the
+option `--prefix=PATH'.  Alternately, you can do so by consistently
+giving a value for the `prefix' variable when you run `make', e.g.,
+     make prefix=/usr/gnu
+     make prefix=/usr/gnu install
+
+   You can specify separate installation prefixes for
+architecture-specific files and architecture-independent files.  If you
+give `configure' the option `--exec-prefix=PATH' or set the `make'
+variable `exec_prefix' to PATH, the package will use PATH as the prefix
+for installing programs and libraries.  Data files and documentation
+will still use the regular prefix.  Normally, all files are installed
+using the same prefix.
+
+   Some packages pay attention to `--with-PACKAGE' options to
+`configure', where PACKAGE is something like `gnu-as' or `x' (for the
+X Window System).  They may also pay attention to `--enable-FEATURE'
+options, where FEATURE indicates an optional part of the package.  The
+README should mention any `--with-' and `--enable-' options that the
+package recognizes.
+
+   `configure' also recognizes the following options:
+
+`--help'
+     Print a summary of the options to `configure', and exit.
+
+`--quiet'
+`--silent'
+     Do not print messages saying which checks are being made.
+
+`--verbose'
+     Print the results of the checks.
+
+`--version'
+     Print the version of Autoconf used to generate the `configure'
+     script, and exit.
+
+`--x-includes=DIR'
+     X include files are in DIR.
+
+`--x-libraries=DIR'
+     X library files are in DIR.
+
+   `configure' also accepts and ignores some other options.
+
+   On systems that require unusual options for compilation or linking
+that the package's `configure' script does not know about, you can give
+`configure' initial values for variables by setting them in the
+environment.  In Bourne-compatible shells, you can do that on the
+command line like this:
+
+     CC='gcc -traditional' LIBS=-lposix ./configure
+
+On systems that have the `env' program, you can do it like this:
+
+     env CC='gcc -traditional' LIBS=-lposix ./configure
+
+   Here are the `make' variables that you might want to override with
+environment variables when running `configure'.
+
+   For these variables, any value given in the environment overrides the
+value that `configure' would choose:
+
+ - Variable: CC
+     C compiler program.  The default is `cc'.
+
+ - Variable: INSTALL
+     Program to use to install files.  The default is `install' if you
+     have it, `cp' otherwise.
+
+   For these variables, any value given in the environment is added to
+the value that `configure' chooses:
+
+ - Variable: DEFS
+     Configuration options, in the form `-Dfoo -Dbar...'.  Do not use
+     this variable in packages that create a configuration header file.
+
+ - Variable: LIBS
+     Libraries to link with, in the form `-lfoo -lbar...'.
+
+   If you need to do unusual things to compile the package, we encourage
+you to figure out how `configure' could check whether to do them, and
+mail diffs or instructions to the address given in the README so we
+can include them in the next release.
+
+2.  Type `make' to compile the package.  If you want, you can override
+the `make' variables CFLAGS and LDFLAGS like this:
+
+	make CFLAGS=-O2 LDFLAGS=-s
+
+3.  If the package comes with self-tests and you want to run them,
+type `make check'.  If you're not sure whether there are any, try it;
+if `make' responds with something like
+	make: *** No way to make target `check'.  Stop.
+then the package does not come with self-tests.
+
+4.  Type `make install' to install programs, data files, and
+documentation.
+
+5.  You can remove the program binaries and object files from the
+source directory by typing `make clean'.  To also remove the
+Makefile(s), the header file containing system-dependent definitions
+(if the package uses one), and `config.status' (all the files that
+`configure' created), type `make distclean'.
+
+   The file `configure.in' is used to create `configure' by a program
+called `autoconf'.  You only need it if you want to regenerate
+`configure' using a newer version of `autoconf'.

+ 131 - 0
Makefile.in

@@ -0,0 +1,131 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+docdir = $(prefix)/doc
+devdocdir = $(docdir)/dpkg
+copyingfile = $(docdir)/copyright/dpkg
+infodir = $(prefix)/info
+bindir = $(exec_prefix)/bin
+sbindir = $(exec_prefix)/sbin
+libdir = $(prefix)/lib
+dpkglibdir = $(libdir)/dpkg
+methodsdir = $(dpkglibdir)/methods
+datadir = /var/lib/dpkg
+methodsdatadir = $(datadir)/methods
+methodsmnt = $(datadir)/methods/mnt
+pinfodir = $(datadir)/info
+pupdatesdir = $(datadir)/updates
+altsdatadir = $(datadir)/alternatives
+partsdir = $(datadir)/parts
+mandir = $(prefix)/man
+man1dir = $(mandir)/man1
+man5dir = $(mandir)/man5
+man8dir = $(mandir)/man8
+man1 = 1
+man5 = 5
+man8 = 8
+etcdir= /etc
+altsetcdir = $(etcdir)/alternatives
+
+BOURNESHELL = /bin/sh
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+
+SUBDIRS = lib main dpkg-deb split md5sum scripts doc include dselect methods
+PORTABLEDIRS = lib dpkg-deb split md5sum
+
+.SUFFIXES:	.c .o
+
+.c.o:
+		$(CC) $(ALL_CFLAGS) -c $<
+
+all:		version
+		set -e; for d in $(SUBDIRS) ; do \
+			cd $$d ; \
+			$(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)'; \
+			cd .. ; \
+		done
+
+install:	all
+		$(BOURNESHELL) $(srcdir)/mkinstalldirs $(bindir) $(sbindir) \
+			$(man1dir) $(man5dir) $(man8dir) $(devdocdir) \
+			$(libdir) $(datadir) $(pinfodir) $(pupdatesdir) \
+			$(dpkglibdir) $(methodsdir) $(methodsdatadir) $(methodsmnt) \
+			$(altsdatadir) $(altsetcdir) $(partsdir) $(infodir)
+		set -e; for d in $(SUBDIRS) ; do \
+			cd $$d ; \
+			$(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' \
+				install ; \
+			cd .. ; \
+		done
+		$(INSTALL_DATA) COPYING $(copyingfile)
+
+portable:	version
+		set -e; for d in lib dpkg-deb split md5sum ; do \
+			cd $$d ; \
+			$(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' ; \
+			cd .. ; \
+		done
+
+install-portable: portable
+		$(BOURNESHELL) $(srcdir)/mkinstalldirs $(bindir) \
+			$(man1dir) $(man8dir) $(libdir) $(dpkglibdir)
+		set -e; for d in $(PORTABLEDIRS) ; do \
+			cd $$d ; \
+			$(MAKE) 'CC=$(CC)' 'LDFLAGS=$(LDFLAGS)' 'XLIBS=$(XLIBS)' \
+				install ; \
+			cd .. ; \
+		done
+#		$(INSTALL_DATA) COPYING $(copyingfile)
+
+autoconf:
+		autoheader
+		autoconf
+
+clean:
+		set -e; for d in $(SUBDIRS) ; do \
+			cd $$d ; \
+			$(MAKE) clean ; \
+			cd .. ; \
+		done
+		rm -f core version.h.new
+
+distclean:	clean
+		set -e; for d in $(SUBDIRS) ; do \
+			cd $$d ; \
+			$(MAKE) distclean ; \
+			cd .. ; \
+		done
+		rm -f Makefile *.orig *~ *.~* ./#*#
+		rm -f config.h config.status install config.cache config.log
+
+version:
+		perl insert-version.pl <version.h >version.h.new
+		cmp -s version.h.new version.h || mv version.h.new version.h

+ 72 - 0
NEWS

@@ -0,0 +1,72 @@
+(-*- indented-text -*-)
+
+
+CHANGES SINCE dpkg 0.93.7:
+
+ * a Perl-based front-end with many new features has replaced dpkg.sh.
+   The new features are detailed below.  dpkg.pl is not finished,
+   however, as it does not yet support CONFLICTS, DEPENDS, OPTIONAL,
+   or RECOMMENDED.  All of the above will be supported in Debian 0.93.
+
+   In addition, it does not yet support PARTS, but that may wait until
+   Debian 0.94.  (In the meantime, we can create disk-sized packages by
+   hand.)
+
+   dpkg.pl has been constructed from code originally by Matt Welsh,
+   with additions by Carl Streeter, Ian Murdock, and Ian Jackson.
+
+New features in dpkg.pl:
+
+ * dpkg.pl can now manipulate many packages at a time; dpkg.sh could
+   only manipulate one package at a time.
+
+ * dpkg.pl supports pre-installation, post-installation, pre-removal,
+   and post-removal scripts.  During batch installation,
+   post-installation scripts are executed after all packages have
+   been installed.  (dpkg.sh supported all of the above except the
+   batch installation feature, because dpkg.sh did not itself support
+   batch installation.)
+
+ * dpkg.pl now supports the upgrading of packages.  A newer version of
+   a package, when released, can be obtained and installed normally on
+   the system to replace an older, previously installed version of it,
+   all with a minimum of manuals steps.
+
+   During the installation process, dpkg.pl determines whether or not
+   a version of the package is currently installed on the system.  If
+   it is, it determines whether it is an older version than the
+   package being installed (in which case we are ``upgrading'', and
+   the installation proceeds after saving the configuration files and
+   removing the older version), or whether it is the same or a newer
+   version than the package being installed (in which case we are, for
+   whatever reason, attempting to install a package twice or
+   ``downgrading'', and dpkg.pl asks for confirmation).
+
+ * dpkg.pl now supports automatic and intelligent configuration file
+   updates during the upgrade process.  During a package upgrade, it
+   determines when a configuration file has changed since the last
+   installation and, for those that have, prompts the user whether to
+   keep the older or newer configuration file, providing them with
+   default responses.
+
+New features in dpkg-deb:
+
+ * dpkg-util.deb has been renamed to dpkg-deb, for brevity.
+
+ * dpkg-deb is much less verbose, and in most cases it says nothing
+   unless an error has occurred.  The front-end is expected to provide
+   the necessary verbosity when appropriate.
+
+ * `dpkg-deb --describe' now outputs the description only, without the
+   ``Description:'' label.
+
+ * `dpkg-deb --list' output is now sorted by package name.
+
+ * `dpkg-deb --remove' bug fix: in dpkg 0.93.7 (or earlier), some
+   directories did not get properly removed.  This has been fixed.
+
+ * `dpkg-deb --version' now outputs the version information only,
+   without the `Version:'' label, and without maintainer information.
+
+ * `dpkg-deb --version' now provides the version of dpkg if no
+   argument is specified.

+ 23 - 0
README

@@ -0,0 +1,23 @@
+-*- text -*-
+
+Please see the file `Guidelines' for the guidelines for creating and
+maintaining Debian packages.  dpkg Texinfo documentation and a manual
+page will be available with the next release, but in the interest of
+time I am releasing dpkg 0.93.8 without them.
+
+Please send bug reports and comments to <debian-bugs@pixar.com>.
+Please be sure to put the following at the top of the message body:
+
+Package: dpkg
+
+This will enter your bug report in our tracking system, and will help
+us to investigate and respond to your problem as promptly as possible.
+
+Please read the file `COPYING' for copying conditions.
+
+Please read the file `INSTALL' for installation instructions.
+
+Please read the file `NEWS' for a description of new features, etc.
+
+[ Note for users of GCC 2.7.0: you must compile at least
+ `dselect/main.cc' with only -O2, due to a bug in GCC. ]

+ 57 - 0
TODO

@@ -0,0 +1,57 @@
+Here are some currently-known inadequacies:
+
+urgent
+ * Pre-Depends installation ordering
+
+done
+ * a.out version
+ * uncomment ELF preinst modification
+ * Replaces (auto-deselect for conflicts)
+ * Replaces (don't overwrite otherwise)
+ * compile with ELF GCC out of the box
+ * dpkg --print-architecture
+ * Architecture field check
+ * symlink rename change
+
+bugs that need to be fixed quickly
+ * version numbers not starting digit early.
+ * check description in dpkg-deb
+ * field overflow in dpkg --list
+ * _always_ show section in --yet-to-unpack
+ * automatically do --yet-to-unpack in installation methods
+ * check depending packages when installing new version.
+ * error handling from some dselect actions. 1399
+ * Several things ought to be configurable but aren't.
+ * Filenames containing newlines.  Conffile names containing spaces.
+ * dpkg --status for virtual packages
+ * dselect bottom window too large, and/or resize
+ * update-alternatives prompting.
+ * logging, both transcript logs (kept briefly)
+   and action logs (kept forever?)  957
+ * start-stop-daemon process status check. 1480
+ * remove old docs from /usr/doc/dpkg.
+
+other stuff unlikely to get done soon
+ * single maintainer script, and new package getting there first
+ * dpkg -s show something for virtual packages
+ * dpkg --listfiles should do better for multi-package files  (pkg, pkg: ...)
+ * settable defaults for update-rc.d
+ * local conffiles
+ * hooks
+ * gzip -0 option for dpkg-deb
+ * There is no documentation. 1526
+ * newbie interface to dselect. 1037
+ * FTP installation method
+ * `template' file giving default selections of dselect.
+ * update-rc.d in C
+ * start-stop-daemon in C. 1670
+ * dselect per-half focus and keybindings improvements. 1555
+ * floppy map (where are the files)
+ * highlight or pre-sort or something new or changed packages,
+   during upgrade selection.
+ * how to change case of package names
+ * support for adding files to dpkg's file lists
+ * side-by-side version display
+ * `fake' or `null' packages
+ * --purge remove empty directories which used too contain conffiles
+ * conffiles handling options, including `replace removed files'

+ 31 - 0
acconfig.h

@@ -0,0 +1,31 @@
+/* Additional tests: */
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_INLINE
+
+/* Define if sysinfo is available.  */
+#undef HAVE_SYSINFO
+
+/* Define if __NR_sysinfo is available.  */
+#undef HAVE_NRSYSINFO
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_ALPHASORT_DECLARATION
+
+/* Define if function attributes a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_ATTRIB
+
+/* Define if constant functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_CONST
+
+/* Define if nonreturning functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_NORETURN
+
+/* Define if printf-format argument lists a la GCC are available.  */
+#undef HAVE_GNUC25_PRINTFFORMAT
+
+/* Set this to the canonical Debian architecture string for this CPU type. */
+#undef ARCHITECTURE
+
+/* Set this to 1 to build new archives by default. */
+#define BUILDOLDPKGFORMAT 0

+ 21 - 0
archtable

@@ -0,0 +1,21 @@
+# This file contains a table of known architecture strings, with
+# things to map them to. `configure' will take the output of gcc
+# --print-libgcc-file-name, strip off leading directories up to and
+# including gcc-lib, strip off trailing /libgcc.a and trailing version
+# number directory, and then strip off everything after the first
+# hyphen.  The idea is that you're left with this bit:
+#   $ gcc --print-libgcc-file-name
+#   /usr/lib/gcc-lib/i486-linux/2.7.2/libgcc.a
+#                    ^^^^
+# This is then looked up in the table below, to find out what to map
+# it to.  If it isn't found then configure will print a warning and
+# continue.  You can override configure's ideas using --with-arch.
+
+i386	i386
+i486	i386
+i586	i386
+sparc	sparc
+alpha	alpha
+m68k	m68k
+arm	arm
+ppc	ppc

+ 129 - 0
config.h.bot

@@ -0,0 +1,129 @@
+
+/* These are from config.h.bot, pasted onto the end of config.h.in. */
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* Use the definitions: */
+
+/* Give us an unsigned 32-bit data type. */
+#if SIZEOF_UNSIGNED_LONG==4
+#define UWORD32 unsigned long
+#elif SIZEOF_UNSIGNED_INT==4
+#define UWORD32 unsigned int
+#else
+#error I do not know what to use for a UWORD32.
+#endif
+
+/* The maximum length of a #! interpreter displayed by dpkg-deb. */
+#ifdef PATH_MAX
+#define INTERPRETER_MAX PATH_MAX
+#else
+#define INTERPRETER_MAX 1024
+#endif
+
+/* GNU C attributes. */
+#ifndef FUNCATTR
+#ifdef HAVE_GNUC25_ATTRIB
+#define FUNCATTR(x) __attribute__(x)
+#else
+#define FUNCATTR(x)
+#endif
+#endif
+
+/* GNU C printf formats, or null. */
+#ifndef ATTRPRINTF
+#ifdef HAVE_GNUC25_PRINTFFORMAT
+#define ATTRPRINTF(si,tc) format(printf,si,tc)
+#else
+#define ATTRPRINTF(si,tc)
+#endif
+#endif
+#ifndef PRINTFFORMAT
+#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
+#endif
+
+/* GNU C nonreturning functions, or null. */
+#ifndef ATTRNORETURN
+#ifdef HAVE_GNUC25_NORETURN
+#define ATTRNORETURN noreturn
+#else
+#define ATTRNORETURN
+#endif
+#endif
+#ifndef NONRETURNING
+#define NONRETURNING FUNCATTR((ATTRNORETURN))
+#endif
+
+/* Combination of both the above. */
+#ifndef NONRETURNPRINTFFORMAT
+#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
+#endif
+
+/* GNU C constant functions, or null. */
+#ifndef ATTRCONST
+#ifdef HAVE_GNUC25_CONST
+#define ATTRCONST const
+#else
+#define ATTRCONST
+#endif
+#endif
+#ifndef CONSTANT
+#define CONSTANT FUNCATTR((ATTRCONST))
+#endif
+
+/* Declare strerror if we don't have it already. */
+#ifndef HAVE_STRERROR
+const char *strerror(int);
+#endif
+
+/* Declare strsignal if we don't have it already. */
+#ifndef HAVE_STRSIGNAL
+const char *strsignal(int);
+#endif
+
+/* Declare scandir if we don't have it already. */
+#ifndef HAVE_SCANDIR
+struct dirent;
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*));
+#endif
+
+/* Declare alphasort if we don't have it already. */
+#if !defined(HAVE_ALPHASORT) || !defined(HAVE_ALPHASORT_DECLARATION)
+struct dirent;
+int alphasort(const struct dirent *a, const struct dirent *b);
+#endif
+
+/* Declare unsetenv if we don't have it already. */
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *x);
+#endif
+
+/* Define strtoul if we don't have it already. */
+#ifndef HAVE_STRTOUL
+#define strtoul strtol
+#endif
+
+/* Sort out sysinfo */
+#if !defined(HAVE_SYSINFO) && defined(HAVE_NRSYSINFO)
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+static inline _syscall1(int,sysinfo,struct sysinfo*,info)
+#endif
+
+/* Define WCOREDUMP if we don't have it already - coredumps won't be
+ * detected, though.
+ */
+#ifndef WCOREDUMP
+#define WCOREDUMP(x) 0
+#endif
+
+/* Set BUILDOLDPKGFORMAT to 1 to build old-format archives by default.
+ */
+#ifndef BUILDOLDPKGFORMAT
+#define BUILDOLDPKGFORMAT 0
+#endif

+ 212 - 0
config.h.in

@@ -0,0 +1,212 @@
+/* config.h.in.  Generated automatically from configure.in by autoheader.  */
+
+/* Define to empty if the keyword does not work.  */
+#undef const
+
+/* Define if you don't have vprintf but do have _doprnt.  */
+#undef HAVE_DOPRNT
+
+/* Define if you have the vprintf function.  */
+#undef HAVE_VPRINTF
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef mode_t
+
+/* Define to `int' if <sys/types.h> doesn't define.  */
+#undef pid_t
+
+/* Define to `unsigned' if <sys/types.h> doesn't define.  */
+#undef size_t
+
+/* Define if you have the ANSI C header files.  */
+#undef STDC_HEADERS
+
+/* Define if your processor stores words with the most significant
+   byte first (like Motorola and SPARC, unlike Intel and VAX).  */
+#undef WORDS_BIGENDIAN
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_INLINE
+
+/* Define if sysinfo is available.  */
+#undef HAVE_SYSINFO
+
+/* Define if __NR_sysinfo is available.  */
+#undef HAVE_NRSYSINFO
+
+/* Define if inline functions a la GCC are available.  */
+#undef HAVE_ALPHASORT_DECLARATION
+
+/* Define if function attributes a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_ATTRIB
+
+/* Define if constant functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_CONST
+
+/* Define if nonreturning functions a la GCC 2.5 and higher are available.  */
+#undef HAVE_GNUC25_NORETURN
+
+/* Define if printf-format argument lists a la GCC are available.  */
+#undef HAVE_GNUC25_PRINTFFORMAT
+
+/* Set this to the canonical Debian architecture string for this CPU type. */
+#undef ARCHITECTURE
+
+/* Set this to 1 to build new archives by default. */
+#define BUILDOLDPKGFORMAT 0
+
+/* The number of bytes in a unsigned int.  */
+#undef SIZEOF_UNSIGNED_INT
+
+/* The number of bytes in a unsigned long.  */
+#undef SIZEOF_UNSIGNED_LONG
+
+/* Define if you have the alphasort function.  */
+#undef HAVE_ALPHASORT
+
+/* Define if you have the scandir function.  */
+#undef HAVE_SCANDIR
+
+/* Define if you have the strerror function.  */
+#undef HAVE_STRERROR
+
+/* Define if you have the strsignal function.  */
+#undef HAVE_STRSIGNAL
+
+/* Define if you have the strtoul function.  */
+#undef HAVE_STRTOUL
+
+/* Define if you have the unsetenv function.  */
+#undef HAVE_UNSETENV
+
+/* Define if you have the <sys/cdefs.h> header file.  */
+#undef HAVE_SYS_CDEFS_H
+
+/* These are from config.h.bot, pasted onto the end of config.h.in. */
+
+#ifdef HAVE_SYS_CDEFS_H
+#include <sys/cdefs.h>
+#endif
+
+/* Use the definitions: */
+
+/* Give us an unsigned 32-bit data type. */
+#if SIZEOF_UNSIGNED_LONG==4
+#define UWORD32 unsigned long
+#elif SIZEOF_UNSIGNED_INT==4
+#define UWORD32 unsigned int
+#else
+#error I do not know what to use for a UWORD32.
+#endif
+
+/* The maximum length of a #! interpreter displayed by dpkg-deb. */
+#ifdef PATH_MAX
+#define INTERPRETER_MAX PATH_MAX
+#else
+#define INTERPRETER_MAX 1024
+#endif
+
+/* GNU C attributes. */
+#ifndef FUNCATTR
+#ifdef HAVE_GNUC25_ATTRIB
+#define FUNCATTR(x) __attribute__(x)
+#else
+#define FUNCATTR(x)
+#endif
+#endif
+
+/* GNU C printf formats, or null. */
+#ifndef ATTRPRINTF
+#ifdef HAVE_GNUC25_PRINTFFORMAT
+#define ATTRPRINTF(si,tc) format(printf,si,tc)
+#else
+#define ATTRPRINTF(si,tc)
+#endif
+#endif
+#ifndef PRINTFFORMAT
+#define PRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc)))
+#endif
+
+/* GNU C nonreturning functions, or null. */
+#ifndef ATTRNORETURN
+#ifdef HAVE_GNUC25_NORETURN
+#define ATTRNORETURN noreturn
+#else
+#define ATTRNORETURN
+#endif
+#endif
+#ifndef NONRETURNING
+#define NONRETURNING FUNCATTR((ATTRNORETURN))
+#endif
+
+/* Combination of both the above. */
+#ifndef NONRETURNPRINTFFORMAT
+#define NONRETURNPRINTFFORMAT(si,tc) FUNCATTR((ATTRPRINTF(si,tc),ATTRNORETURN))
+#endif
+
+/* GNU C constant functions, or null. */
+#ifndef ATTRCONST
+#ifdef HAVE_GNUC25_CONST
+#define ATTRCONST const
+#else
+#define ATTRCONST
+#endif
+#endif
+#ifndef CONSTANT
+#define CONSTANT FUNCATTR((ATTRCONST))
+#endif
+
+/* Declare strerror if we don't have it already. */
+#ifndef HAVE_STRERROR
+const char *strerror(int);
+#endif
+
+/* Declare strsignal if we don't have it already. */
+#ifndef HAVE_STRSIGNAL
+const char *strsignal(int);
+#endif
+
+/* Declare scandir if we don't have it already. */
+#ifndef HAVE_SCANDIR
+struct dirent;
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*));
+#endif
+
+/* Declare alphasort if we don't have it already. */
+#if !defined(HAVE_ALPHASORT) || !defined(HAVE_ALPHASORT_DECLARATION)
+struct dirent;
+int alphasort(const struct dirent *a, const struct dirent *b);
+#endif
+
+/* Declare unsetenv if we don't have it already. */
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *x);
+#endif
+
+/* Define strtoul if we don't have it already. */
+#ifndef HAVE_STRTOUL
+#define strtoul strtol
+#endif
+
+/* Sort out sysinfo */
+#if !defined(HAVE_SYSINFO) && defined(HAVE_NRSYSINFO)
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+static inline _syscall1(int,sysinfo,struct sysinfo*,info)
+#endif
+
+/* Define WCOREDUMP if we don't have it already - coredumps won't be
+ * detected, though.
+ */
+#ifndef WCOREDUMP
+#define WCOREDUMP(x) 0
+#endif
+
+/* Set BUILDOLDPKGFORMAT to 1 to build old-format archives by default.
+ */
+#ifndef BUILDOLDPKGFORMAT
+#define BUILDOLDPKGFORMAT 0
+#endif

File diff suppressed because it is too large
+ 2374 - 0
configure


+ 242 - 0
configure.in

@@ -0,0 +1,242 @@
+dnl Process this file with autoconf to produce a configure script.
+
+AC_INIT(include/dpkg.h)
+AC_CONFIG_HEADER(config.h)
+
+AC_PREFIX_DEFAULT(/usr)
+
+AC_PROG_CC
+AC_PROG_CXX
+
+AC_ARG_WITH(arch,
+[  --with-arch=value       set/override (Debian) architecture value],
+[
+ if test "x$with_arch" = x; then
+  AC_MSG_ERROR(--with-arch requires an architecture name)
+ fi
+ AC_DEFINE_UNQUOTED(ARCHITECTURE, "${with_arch}")
+],[
+ AC_MSG_CHECKING(system architecture)
+ dpkg_archwhy=''
+ AC_CACHE_VAL(dpkg_cv_arch,[
+  dpkg_arch="`dpkg --print-architecture 2>/dev/null`"
+  if test "x$dpkg_arch" != x; then
+   dpkg_archwhy="  (obtained from dpkg)"
+  elif test "${GCC-no}" = yes; then
+changequote(, )dnl
+   dpkg_arch="`$(CC) --print-libgcc-file-name |
+	sed -e 's,^.*/gcc-lib/,,; s,/libgcc\.a$,,; s,/[0-9.][0-9.]*$,,; s/-.*$//'`"
+changequote([, ])dnl
+   if test "x`echo \"$dpkg_arch\" | tr -d a-z0-9-`" != x -o "x$dpkg_arch" = x
+   then
+    dpkg_arch=""
+    dpkg_archwhy=" (bad output from --print-libgcc-file-name)"
+   else
+changequote(, )dnl
+    dpkg_arch2="`sed -e '/^'$dpkg_arch'[ 	]/!d; s/^[-0-9a-z]*[	 ]*//' \
+		     $srcdir/archtable`"
+changequote([, ])dnl
+    if test "x$dpkg_arch2" = "x$dpkg_arch"; then
+     dpkg_archwhy=" (obtained from gcc)"
+    elif test "x$dpkg_arch2" != x; then
+     dpkg_archwhy=" (from gcc, canonical form of $dpkg_arch)"
+     dpkg_arch="$dpkg_arch2"
+    else
+     dpkg_archwhy=" (from gcc, but not in archtable)"
+    fi
+   fi
+  else
+   dpkg_archwhy=''
+  fi
+  dpkg_cv_arch="$dpkg_arch"
+ ])
+ if test "x$dpkg_cv_arch" != x; then
+  AC_MSG_RESULT("$dpkg_cv_arch$dpkg_archwhy")
+  AC_DEFINE_UNQUOTED(ARCHITECTURE, "${dpkg_cv_arch}")
+ else
+  AC_MSG_RESULT("failed$dpkg_archwhy")
+ fi
+])
+ 
+AC_ARG_WITH(newdeb,
+[  --with-newdeb           make dpkg-deb default to new archives],
+[
+ AC_DEFINE(BUILDOLDPKGFORMAT, 0)
+],[
+ AC_ARG_WITH(olddeb,
+[  --with-olddeb           make dpkg-deb default to old archives],
+[
+  AC_DEFINE(BUILDOLDPKGFORMAT, 1)
+],
+[
+  case "$CC" in
+  /*)
+   pathccompiler="$CC"
+   ;;
+  *)
+   AC_PATH_PROG(pathccompiler,"$CC")
+   ;;
+  esac
+  AC_MSG_CHECKING(.deb format to build by default)
+  if file "$pathccompiler" 2>/dev/null | grep ELF >/dev/null 2>&1; then
+   AC_MSG_RESULT([new (C compiler looks like ELF)])
+   AC_DEFINE(BUILDOLDPKGFORMAT, 0)
+  else
+   AC_MSG_RESULT([old (C compiler not ELF)])
+   AC_DEFINE(BUILDOLDPKGFORMAT, 1)
+  fi
+])])
+
+AC_ARG_WITH(newdeb,
+[  --with-newdeb           make dpkg-deb default to new archives],
+[AC_DEFINE(BUILDOLDPKGFORMAT, 0)])
+
+
+AC_MSG_CHECKING(for /usr/bin/perl)
+if test -f /usr/bin/perl
+then
+	AC_MSG_RESULT(yes)
+	perlpath=/usr/bin/perl
+	AC_SUBST(perlpath)
+else
+	AC_MSG_RESULT(no)
+	AC_PATH_PROG(perlpath,perl)
+fi
+
+AC_STDC_HEADERS
+AC_PROG_INSTALL
+dnl AC_PROGRAM_PATH(GZIP, gzip, )   use these from $PATH
+dnl AC_PROGRAM_PATH(TAR, tar, )     use these from $PATH
+AC_PROG_RANLIB
+AC_MODE_T
+AC_PID_T
+AC_SIZE_T
+AC_VPRINTF
+AC_C_CONST
+AC_C_BIGENDIAN
+AC_CHECK_SIZEOF(unsigned long)
+AC_CHECK_SIZEOF(unsigned int)
+AC_CHECK_FUNCS(unsetenv alphasort scandir strerror strsignal strtoul)
+AC_CHECK_HEADERS(sys/cdefs.h)
+
+AC_CHECK_FUNC(sysinfo,
+  AC_DEFINE(HAVE_SYSINFO),
+  AC_MSG_CHECKING(__NR_sysinfo)
+  AC_EGREP_CPP(yes, [
+#include <linux/sys.h>
+#include <linux/kernel.h>
+#include <linux/unistd.h>
+#ifdef __NR_sysinfo
+ yes
+#endif
+],
+    AC_MSG_RESULT([yes; tsk tsk - get your libc fixed.])
+    AC_DEFINE(HAVE_NRSYSINFO),
+    AC_MSG_RESULT(no)
+    AC_MSG_WARN([sysinfo missing; compilation of dpkg proper may fail.])))
+
+AC_SUBST(OPTCFLAGS)
+if test "${GCC-no}" = yes; then
+ CFLAGS=-O2; OPTCFLAGS=-O3
+else
+ CFLAGS=-O
+fi
+
+dnl DPKG_CACHED_TRY_COMPILE(<description>,<cachevar>,<include>,<program>,<ifyes>,<ifno>)
+define(DPKG_CACHED_TRY_COMPILE,[
+ AC_MSG_CHECKING($1)
+ AC_CACHE_VAL($2,[
+  AC_TRY_COMPILE([$3],[$4],[$2=yes],[$2=no])
+ ])
+ if test "x$$2" = xyes; then
+  true
+  $5
+ else
+  true
+  $6
+ fi
+])
+
+DPKG_CACHED_TRY_COMPILE(your C compiler,dpkg_cv_c_works,
+ [#include <string.h>], [strcmp("a","b")],
+ AC_MSG_RESULT(works),
+ AC_MSG_RESULT(broken)
+ AC_MSG_ERROR(C compiler is broken))
+
+DPKG_CACHED_TRY_COMPILE(alphasort declaration,dpkg_cv_header_alphasort,[
+#include <sys/types.h>
+#include <sys/dir.h>
+], alphasort,
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_ALPHASORT_DECLARATION),
+ AC_MSG_RESULT(no))
+
+DPKG_CACHED_TRY_COMPILE(inlines,dpkg_cv_c_inline,,
+ [} inline int foo (int x) {],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_INLINE),
+ AC_MSG_RESULT(no))
+
+DPKG_CACHED_TRY_COMPILE(__attribute__((,,)),dpkg_cv_c_attribute_supported,,
+ [extern int testfunction(int x) __attribute__((,,))],
+ AC_MSG_RESULT(yes)
+ AC_DEFINE(HAVE_GNUC25_ATTRIB)
+  DPKG_CACHED_TRY_COMPILE(__attribute__((noreturn)),dpkg_cv_c_attribute_noreturn,,
+   [extern int testfunction(int x) __attribute__((noreturn))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_NORETURN),
+   AC_MSG_RESULT(no))
+  DPKG_CACHED_TRY_COMPILE(__attribute__((const)),dpkg_cv_c_attribute_const,,
+   [extern int testfunction(int x) __attribute__((const))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_CONST),
+   AC_MSG_RESULT(no))
+  DPKG_CACHED_TRY_COMPILE(__attribute__((format...)),dpkg_cv_attribute_format,,
+   [extern int testfunction(char *y, ...) __attribute__((format(printf,1,2)))],
+   AC_MSG_RESULT(yes)
+   AC_DEFINE(HAVE_GNUC25_PRINTFFORMAT),
+   AC_MSG_RESULT(no)),
+ AC_MSG_RESULT(no))
+
+AC_SUBST(CWARNS)
+CWARNS=""
+
+dnl DPKG_C_GCC_TRY_WARNS(<warnings>,<cachevar>)
+define(DPKG_C_GCC_TRY_WARNS,[
+ AC_MSG_CHECKING([GCC warning flag(s) $1])
+ if test "${GCC-no}" = yes
+ then
+  AC_CACHE_VAL($2,[
+   oldcflags="${CFLAGS-}"
+   CFLAGS="${CFLAGS-} ${CWARNS} $1 -Werror"
+   AC_TRY_COMPILE([
+#include <string.h>
+#include <stdio.h>
+],[
+    strcmp("a","b"); fprintf(stdout,"test ok\n");
+], [$2=yes], [$2=no])
+   CFLAGS="${oldcflags}"])
+  if test "x$$2" = xyes; then
+   CWARNS="${CWARNS} $1"
+   AC_MSG_RESULT(ok)
+  else
+   $2=''
+   AC_MSG_RESULT(no)
+  fi
+ else
+  AC_MSG_RESULT(no, not using GCC)
+ fi
+])
+
+DPKG_C_GCC_TRY_WARNS(-Wall -Wno-implicit, dpkg_cv_c_gcc_warn_all)
+DPKG_C_GCC_TRY_WARNS(-Wwrite-strings, dpkg_cv_c_gcc_warn_writestrings)
+DPKG_C_GCC_TRY_WARNS(-Wpointer-arith, dpkg_cv_c_gcc_warn_pointerarith)
+DPKG_C_GCC_TRY_WARNS(-Wimplicit -Wnested-externs, dpkg_cv_c_gcc_warn_implicit)
+
+if test "${GCC-no}" = yes; then
+ CWARNS="${CWARNS} -Wmissing-prototypes -Wstrict-prototypes"
+fi
+
+AC_OUTPUT(Makefile dpkg-deb/Makefile lib/Makefile include/Makefile
+          dselect/Makefile split/Makefile methods/Makefile
+          md5sum/Makefile main/Makefile doc/Makefile scripts/Makefile)

File diff suppressed because it is too large
+ 1253 - 0
debian.Changelog


+ 36 - 0
debian.README

@@ -0,0 +1,36 @@
+This is Debian/GNU Linux's package maintenance system.
+
+For an example of how to construct packages see the `hello' package
+which is part of Debian.
+
+[ Note for users of GCC 2.7.0: you must compile at least
+ `dselect/main.cc' with only -O2, due to a bug in GCC. ]
+
+Copyright (C) 1994,1995,1996 Ian Jackson <iwj10@cus.cam.ac.uk>
+Copyright (C) 1995 Bruce Perens <bruce@pixar.com>
+Copyright (C) 1994 Carl Streeter <streeter@cae.wisc.edu>
+Copyright (C) 1994 Matt Welsh <mdw@sunsite.unc.edu>
+Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+Copyright (C) 1995,1996 Erick Branderhorst <branderhorst@heel.fgg.eur.nl>
+
+This 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, or (at your option) any later
+version.
+
+This 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 with
+your Debian GNU/Linux system, in /usr/doc/copyright/GPL, or with the
+dpkg source package as the file COPYING.  If not, write to the Free
+Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+
+/usr/bin/md5sum is compiled from md5.[ch] (written by Colin Plumb in
+1993 and modified by Ian Jackson in 1995) and md5sum.c (written by
+Branko Lankester in 1993 and modified by Colin Plumb in 1993 and Ian
+Jackson in 1995).  The sources and the binary are all in the public
+domain.

+ 15 - 0
debian.control

@@ -0,0 +1,15 @@
+Package: dpkg
+Version: =elf
+Architecture: =
+Essential: yes
+Pre-Depends: libc5=, ncurses3.0
+Conflicts: dpkgname
+Replaces: dpkgname
+Maintainer: Ian Jackson <ian@chiark.chu.cam.ac.uk>
+Description: Package maintenance system for Debian GNU/Linux
+ This package contains the programs which handle the installation and
+ removal of packages on your system.
+ .
+ The primary interface for the dpkg suite is the `dselect' program;
+ a more low-level and less user-friendly interface is available in
+ the form of the `dpkg' command.

+ 15 - 0
debian.controlaout

@@ -0,0 +1,15 @@
+Package: dpkg
+Version: =
+Architecture: =
+Essential: yes
+Conflicts: dpkgname
+Replaces: dpkgname
+Pre-Depends: libc4 | libc
+Maintainer: Ian Jackson <ian@chiark.chu.cam.ac.uk>
+Description: Package maintenance system for Debian GNU/Linux
+ This package contains the programs which handle the installation and
+ removal of packages on your system.
+ .
+ The primary interface for the dpkg suite is the `dselect' program;
+ a more low-level and less user-friendly interface is available in
+ the form of the `dpkg' command.

+ 193 - 0
debian.postinst

@@ -0,0 +1,193 @@
+#!/bin/sh -
+
+set -e
+
+install-info --section Development Development \
+	     --quiet /usr/info/guidelines.info.gz
+
+dupdaemonhelp () {
+	cat <<'END'
+
+Some daemons and similar services whose scripts have links in the
+/etc/rcN.d directories have both start (S) and stop (K) links in
+some runlevels.  Thus these services get stopped and immediately
+restarted at some runlevel changes, which is probably not what
+you want.  I can remove the probably-spurious K links if you like.
+
+Type Y to remove then, N to leave them, or L to list them.
+If you don't know what to do you can say N now and then delete
+them by hand later.
+
+END
+}
+
+if [ "x$1" = xconfigure ]; then case "$2" in 0.* | 1.0.* | 1.1.0 | 1.1.0[^0-9]* | '' )
+	for f in 0 1 2 3 4 5 6
+	do
+		cd /etc/rc$f.d
+		for g in K[0-9][0-9]*
+		do
+			if [ -n "`echo \"x$g\" | tr -d 0-9A-Za-z_-`" ]
+			then
+				continue
+			fi
+			h="`echo $g | sed -e 's/^K/S/'`"
+			if ! [ -L $h -a -L $g ] \
+			  || [ "`ls -Li $g 2>/dev/null | awk '{print $1}'`" != \
+			       "`ls -Li $h 2>/dev/null | awk '{print $1}'`" ]
+			then
+				continue
+			fi
+			removes="$removes rc$f.d/$g"
+		done
+	done
+	if [ -n "$removes" ]
+	then
+		cd /etc
+		dupdaemonhelp
+		while [ -n "$removes" ]
+		do
+			echo -n 'y=remove, n=leave, l=list, h=help ?  '
+			read response
+			case "$response" in
+			[Yy]*)
+				echo "Removing duplicate K links ..."
+				rm -v $removes
+				removes=""
+				;;
+			[Nn]*)
+				echo -e "OK, leaving them.\n"
+				removes=""
+				;;
+			[Ll]*)
+				echo
+				echo $removes
+				echo
+				;;
+			[Hh]*)
+				dupdaemonhelp
+				;;
+			esac
+		done
+	fi
+;; esac ; fi
+
+cd /var/lib/dpkg
+if ! test -f diversions
+then
+	touch diversions
+fi
+
+cd /usr/bin
+if test dpkg-deb.dist -ef dpkg-deb; then rm dpkg-deb.dist; fi
+if test -f dpkg-deb.dist; then mv dpkg-deb.dist dpkg-deb; fi
+
+if test -d /DEBIAN
+then
+	echo 'Removing /DEBIAN directory which was created by a dpkg bug ...'
+	rm -r /DEBIAN
+fi
+
+if test -d /usr/lib/dpkg/methods/hd -a ! -x /usr/lib/dpkg/methods/hd/install
+then
+	echo \
+'Warning - /usr/lib/dpkg/methods/hd/ exists, but .../hd/install does not.
+This is probably left over from some previous manual installation of
+now-obsolete dselect-related software.  I suggest you remove the whole
+/usr/lib/dpkg/methods/hd directory and all its contents; otherwise dselect
+is unlikely to function correctly.'
+fi
+
+if test -f /var/lib/dpkg/status; then exit 0; fi
+
+cd /var/adm/dpkg
+
+if [ ! -f status ]
+then
+	echo 'Adding "status" file to dpkg system database ...'
+
+	rm -f /tmp/dpp.$$ || true
+
+	ls -1 deb/*.control >/tmp/dpp.$$
+	sed -e 's:^deb/::; s:\.control$: Install OK Installed:;' \
+		</tmp/dpp.$$ >status.new
+
+	rm /tmp/dpp.$$
+	mv status.new status
+fi
+
+if grep '{' deb/*.control >/dev/null
+then
+	echo 'Fixing up curly brackets in control files ...'
+	perl -i~ -pe \
+		'y/{}//d if m/^(depends|recommended|optional|conflicts):/i' \
+		deb/*.control
+	rm deb/*.control~
+fi
+
+if grep 'Optional: idanish ifrench' deb/ispell.control >/dev/null 2>&1
+then
+	echo 'Fixing up broken ispell.control file ...'
+	perl -i~ -pe 's/ /, /g, s/,// if m/^Optional:/' deb/ispell.control
+fi
+
+newdb=/var/lib/dpkg
+echo "Moving datatabase /var/adm/dpkg to $newdb and changing format ..."
+
+exec 4>$newdb/status.new
+exec 5<status
+
+while read <&5 package status
+do
+	echo " processing $package ..."
+	if test -f deb/$package.control
+	then
+		egrep . deb/$package.control >&4
+	else
+		echo >&4 "Package: $package"
+	fi
+	echo >&4 "Status: $status"
+ 	if test -f deb/$package.conffiles -a -s deb/$package.conffiles
+ 	then
+ 		echo >&4 "Conffiles:"
+ 		exec 6<deb/$package.conffiles
+ 		while read <&6 cfile
+ 		do
+ 			expr match "$cfile" "[^ 	]" >/dev/null || continue
+ 			if test -f deb/$package.hash
+ 			then
+ 				hash="`grep \"^$cfile \" <deb/$package.hash || \
+ 					test $? = 1`"
+ 			else
+ 				hash=''
+ 			fi
+ 			test -n "$hash" || hash="$cfile -"
+ 			expr match "$hash" / >/dev/null || hash="/$hash"
+ 			echo >&4 " $hash"
+ 		done
+ 	elif test -f deb/$package.hash -a -s deb/$package.conffiles
+ 	then
+ 		echo >&4 "Conffiles:"
+ 		sed -ne '/^[^\/]/ s:^:/:; s/^/ /; / ./p' >&4 deb/$package.hash
+ 	fi
+ 	echo >&4
+	for s in {pre,post}{rm,inst} list
+	do
+		if test -f deb/$package.$s
+		then
+			mv deb/$package.$s $newdb/info/$package.$s
+		fi
+	done
+done
+
+if ! test -f $newdb/available
+then
+	if test -f database
+	then
+		cp database $newdb/available
+	else
+		touch $newdb/available
+	fi
+fi
+
+mv $newdb/status.new $newdb/status

+ 86 - 0
debian.preinst

@@ -0,0 +1,86 @@
+#!/bin/sh -
+
+if [ "$1" != "upgrade" ]; then exit 0; fi
+
+set -e
+# i386elf: dpkg --assert-support-predepends
+
+oldver="$2"
+
+case "$oldver" in
+	0.93.[01234]* | - )	;;
+	* )			exit 0 ;;
+esac
+
+echo '
+contemplating upgrade of dpkg from pre-0.93.50 version ...'
+
+trap 'es=$?; rm -f /tmp/bp.$$; exit $es' 0
+
+perl -000 -ne 'print $x if m/^Package:\s+(\S+\n)/im &&
+			  ($x=$1) ne "dpkg\n" &&
+			  m/^Status:.*(unpacked|postinst)/im' \
+	/var/lib/dpkg/status >/tmp/bp.$$
+
+if test -s /tmp/bp.$$
+then
+	echo '
+
+WARNING - have you read the release notes for this upgrade ?
+
+The following packages have been unpacked but not yet configured:'
+	echo '' `cat /tmp/bp.$$`
+	echo -n '
+If you proceed with the dpkg upgrade with these packages in this state
+you will LOSE ANY CONFIGURATION CHANGES that have been made to their
+configuration files.  I recommend that you back out of the upgrade
+now (see below) and then configure each of these packages using:
+ dpkg --configure --force-hold <package>
+
+If you do this and it fails for some packages they are broken anyway, in
+which case you probably don'"'"'t have that much to lose by going ahead
+with the upgrade.
+
+Type "yes" to confirm that you really want to do the upgrade in
+spite of my warning above; if you give any other response we'"'"'ll back
+off the upgrade to give you a chance to fix things.
+
+Continue with upgrade despite probable loss of config data ? '
+	read response
+	case "$response" in
+	[Yy][Ye][Ss] )	echo OK ... ;;
+	* )		echo 'Aborting dpkg upgrade.'; exit 1 ;;
+	esac
+fi
+
+echo -n '
+IMPORTANT - you must install this upgrade on its own, not together in
+the same dpkg run as any other packages.  Otherwise you risk losing
+configuration information.
+
+If you say "no" to the question below we'"'"'ll back off the upgrade now,
+and you can then do it later using:
+ dpkg --install dpkg-0.93.51.deb
+If you'"'"'re not sure what to do, say "no", and then run that command
+(with the appropriate dpkg-*.deb filename) from a root shell prompt.
+
+Are you installing only the dpkg upgrade in this dpkg run ? [y/n] '
+read response
+case "$response" in
+[yY]* | '' )
+	echo 'OK, going ahead.'
+	;;
+* )
+	echo '
+Aborting dpkg upgrade (you will see error messages from dpkg about this).'
+	exit 1
+	;;
+esac
+
+if [ -d /usr/lib/dpkg/methods/hd ]
+then
+	echo 'Removing obsolete /usr/lib/dpkg/methods/hd ...'
+	rm -r /usr/lib/dpkg/methods/hd
+fi
+
+exit 0

+ 12 - 0
debian.prerm

@@ -0,0 +1,12 @@
+#!/bin/sh -
+
+set -e
+
+cd /usr/bin
+test -f dpkg-deb.dist || ln dpkg-deb dpkg-deb.dist
+
+install-info --quiet --remove /usr/info/Guidelines
+install-info --quiet --remove /usr/info/debian-guidelines
+install-info --quiet --remove /usr/info/guidelines
+install-info --quiet --remove /usr/info/debian-guidelines.info.gz
+install-info --quiet --remove /usr/info/guidelines.info.gz

+ 85 - 0
debian.rules

@@ -0,0 +1,85 @@
+#!/usr/bin/make -f
+
+package=dpkg
+version=1.1.4
+
+archi=$(shell dpkg --print-architecture)
+DIR:=$(shell pwd)
+
+build:
+	$(checkdir)
+	./configure --prefix=/usr
+	$(MAKE)
+	touch build
+
+clean:
+	$(checkdir)
+	-rm -f build
+	-$(MAKE) -i distclean
+	-rm -rf debian-tmp* *~ *.orig ./#*# tmp.*
+	-rm -f config.cache config.status config.h install config.log
+	find -name '*~' -print0 | xargs -r0 rm --
+
+binary:
+#checkroot build
+	-rm -rf debian-tmp
+	mkdir debian-tmp debian-tmp/DEBIAN
+	install -d debian-tmp/usr/doc/{copyright,dpkg}
+	cp debian.preinst debian-tmp/DEBIAN/preinst
+	if file main/dpkg | grep -q ELF; then \
+		if [ $(archi) = i386 ]; then \
+			sed -e '5s/=/ (>= 5.2.18-2)/' <debian.control >tmp.control ; \
+			sed -e 's/^# i386elf: //' <debian.preinst \
+				>debian-tmp/DEBIAN/preinst ; \
+		else \
+			sed -e '5s/=//' <debian.control >tmp.control ; \
+		fi ; \
+	else \
+		cp debian.controlaout tmp.control ; \
+	fi
+	sed -e '2s/=/$(version)/; 3s/=/$(archi)/' tmp.control >debian-tmp/DEBIAN/control
+	cp debian.prerm debian-tmp/DEBIAN/prerm
+	cp debian.postinst debian-tmp/DEBIAN/postinst
+	chmod +x debian-tmp/DEBIAN/{postinst,prerm,preinst}
+	$(MAKE) prefix=$(DIR)/debian-tmp/usr \
+		datadir=$(DIR)/debian-tmp/var/lib/dpkg \
+		etcdir=$(DIR)/debian-tmp/etc \
+		install
+	gzip -9 debian-tmp/usr/info/guidelines.info*
+	cp debian.README debian-tmp/usr/doc/copyright/dpkg
+	cp TODO debian-tmp/usr/doc/dpkg/WISHLIST
+	touch debian-tmp/var/lib/dpkg/{status,available}
+	chown -R root.root debian-tmp
+	chmod -R g-ws debian-tmp
+	cd debian-tmp && \
+	tar cf ../../$(package)-$(version).nondebbin.tar usr var && \
+	gzip -9vf ../../$(package)-$(version).nondebbin.tar
+	mv debian-tmp/usr/bin/dpkg-deb{,.dist}
+	rm debian-tmp/var/lib/dpkg/{status,available}
+	dpkg --build debian-tmp
+	if file main/dpkg | grep -q ELF; then \
+		mv debian-tmp.deb ../dpkg-$(version)elf.deb ; \
+		mv ../dpkg-$(version).nondebbin.tar.gz \
+		   ../dpkg-$(version)elf.nondebbin.tar.gz ; \
+	else \
+		mv debian-tmp.deb ../dpkg-$(version).deb ; \
+	fi
+
+define checkdir
+	test -f include/dpkg.h
+endef
+
+source:		clean
+	chmod +x debian.rules
+	cd .. && \
+	tar cf $(package)-$(version).tar $(package)-$(version) && \
+	gzip -9vf $(package)-$(version).tar
+ 
+diff:
+	@echo '((( no diff - this package is a Debian special )))'
+
+checkroot:
+	$(checkdir)
+	test root = "`whoami`"
+
+.PHONY: binary source diff clean checkroot

+ 81 - 0
doc/Makefile.in

@@ -0,0 +1,81 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+infodir = $(prefix)/info
+mandir = $(prefix)/man
+man5dir = $(mandir)/man5
+man5 = 5
+docdir = $(prefix)/doc
+devdocdir = $(docdir)/dpkg
+
+DIST = Makefile.in $(SRC) $(MAN)
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+MAKEINFO = makeinfo
+TEXI2DVI = texi2dvi
+
+DEVDOCS= auto-deconfiguration.txt dependency-ordering.txt \
+ disappear-replace.txt diversions.text \
+ essential-flag.txt version-ordering.txt
+
+# Files folded into main guidelines document
+OBSOLETEDOCS= descriptions.txt upgrades+errors.txt \
+ maintainer-script-args.txt virtual-dependencies.txt
+
+all:		$(DEVDOCS) guidelines.info
+
+guidelines.info: guidelines.texi
+		$(MAKEINFO) $(srcdir)/guidelines.texi
+
+database-structure.ps:	database-structure.fig
+		fig2dev -L ps -c -l _ -P <database-structure.fig >ps
+		mv ps database-structure.ps
+
+database-structure.monops: database-structure.ps
+		perl -pe 's:^/(col[0-7]) \{[01 ]*1[01 ]* setrgbcolor\}\
+ bind def$$:/$$1 {} bind def:' database-structure.ps >ps
+		mv ps database-structure.monops
+
+#dpkg.dvi:
+#		$(TEXI2DVI) $(srcdir)/dpkg.texi
+#
+#dpkg.info:
+#		$(MAKEINFO) $(srcdir)/dpkg.texi
+
+clean:
+		rm -f database-structure.ps database-structure.monops ps
+		rm -f *.{aux,cp,dvi,fn,ky,log,pg,toc,tp,vr}
+		rm -f guidelines.info
+
+distclean:
+		rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:	all
+		$(INSTALL_DATA) deb.5 $(man5dir)/deb.$(man5)
+		$(INSTALL_DATA) deb-control.5 $(man5dir)/deb-control.$(man5)
+		$(INSTALL_DATA) guidelines.info guidelines.info-*[0-9] \
+			$(infodir)/.
+		set -e; for d in $(DEVDOCS) ; do \
+			$(INSTALL_DATA) $$d $(devdocdir)/$$d ; \
+		done

+ 62 - 0
doc/auto-deconfiguration.txt

@@ -0,0 +1,62 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Re: dpkg maintainer script calls and arguments
+In-Reply-To: <1506077@toto.iv>
+FCC: ~/mail/Outbound
+--text follows this line--
+In order to support easier upgrades where important packages get split
+into several pieces, I have implemented the following scheme, which I
+described on debian-private a while ago.  It is enabled by the use of
+`--auto-deconfigure', or `-B', and the dselect method scripts in
+0.93.76 have been changed to supply this option.
+
+] I plan to make it possible to `deconfigure' packages at installation
+] time, in order to keep dependency invariants satisfied.  In a sane
+] installation this will mean that everything will work right, even when
+] (for example) an important package is split into two pieces or
+] packages.
+] 
+] Basically, suppose that package A is being split into A1 and A2, and B
+] and C depend on A1 and A2 respectively.  If you try to install A1 dpkg
+] will consider removing A (because of the conflict between A and each
+] of A1 and A2), but then C's dependency is not satisifed, and if you
+] try to install A2 B's dependency wouldn't be satisfied.
+] 
+] At the moment dpkg will simply refuse to do it.  You have to say
+] --force-depends, or remove either B or C.
+] 
+] I'm going to arrange that dpkg will automatically deconfigure B or C,
+] as appropriate, and try to reconfigure it later.
+] 
+] So, if you do `dpkg -i A1.deb A2.deb' all will be well; if you do
+] `dpkg -i A1.deb' you'll get A1 installed and configured correctly, but
+] error messages about C being broken, and in order to fix C you'll have
+] to install A2 as well, or return to A (dpkg will remove A1).
+] 
+] All of this will appear very automatic to people who use dselect.
+] People who do things manually will have a slightly more complicated
+] task, as dpkg won't remove A (in the scenario above) unless it has
+] been selected for deinstallation using dselect or dpkg --remove (which
+] would fail because of the dependencies from B and C).
+
+This means that maintainer scripts can get called in two new ways:
+  <prerm(C)> deconfigure in-favour <A1> <version> removing <A> <v.>
+  <postinst(C)> abort-deconfigure in-favour <A1> <version> removing <A> <v.>
+using the example package names above.
+
+The first call happens before the prerm script of the package which is
+being removed (A) is called; the second happens if an error occurs and
+dpkg wants to back out of the installation.
+
+If the installation of both A1 and A2 is successful dpkg will then
+call both
+  <postinst(B)> configure
+  <postinst(C)> configure
+as usual.
+
+Some time ago I posted a message documenting all the maintainer script
+calls and their arguments.  Below is a revised version of that
+message.  I shall upload it as maintainer-script-args.txt, and it
+should go in project/standards.  The top half of this message will go
+in auto-deconfiguration.txt.
+
+Ian.

+ 487 - 0
doc/database-structure.fig

@@ -0,0 +1,487 @@
+#FIG 2.1
+80 2
+6 59 74 199 169
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 129 199 129 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 149 199 149 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 129 69 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 59 109 199 109 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 129 139 169 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 199 169 199 89 59 89 59 169 199 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 89 139 109 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 104 name
+4 0 12 10 0 -1 0 0.000 4 9 84 64 122 pkginfoperfile
+4 0 12 10 0 -1 0 0.000 4 9 42 74 144 depends
+4 0 12 10 0 -1 0 0.000 4 9 48 74 162 depended
+4 0 12 10 0 -1 0 0.000 4 9 42 59 84 pkginfo
+-6
+6 59 394 199 489
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 449 199 449 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 469 199 469 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 449 69 489 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 59 429 199 429 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 449 139 489 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 199 489 199 409 59 409 59 489 199 489 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 409 139 429 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 424 name
+4 0 12 10 0 -1 0 0.000 4 9 84 64 442 pkginfoperfile
+4 0 12 10 0 -1 0 0.000 4 9 42 74 464 depends
+4 0 12 10 0 -1 0 0.000 4 9 48 74 482 depended
+4 0 12 10 0 -1 0 0.000 4 9 42 59 404 pkginfo
+-6
+6 59 234 199 329
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 289 199 289 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 309 199 309 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 69 289 69 329 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 59 269 199 269 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 289 139 329 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 199 329 199 249 59 249 59 329 199 329 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 139 249 139 269 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 64 264 name
+4 0 12 10 0 -1 0 0.000 4 9 84 64 282 pkginfoperfile
+4 0 12 10 0 -1 0 0.000 4 9 42 74 304 depends
+4 0 12 10 0 -1 0 0.000 4 9 48 74 322 depended
+4 0 12 10 0 -1 0 0.000 4 9 42 59 244 pkginfo
+-6
+6 559 74 699 169
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 569 129 699 129 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 569 149 699 149 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 569 129 569 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 559 109 699 109 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 639 129 639 169 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 699 169 699 89 559 89 559 169 699 169 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 639 89 639 109 9999 9999
+4 0 12 10 0 -1 0 0.000 4 5 24 564 104 name
+4 0 12 10 0 -1 0 0.000 4 9 84 564 122 pkginfoperfile
+4 0 12 10 0 -1 0 0.000 4 9 42 574 144 depends
+4 0 12 10 0 -1 0 0.000 4 9 48 574 162 depended
+4 0 12 10 0 -1 0 0.000 4 9 42 559 84 pkginfo
+-6
+6 399 119 499 214
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 499 214 499 134 399 134 399 214 499 214 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 399 154 499 154 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 399 174 499 174 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 399 194 499 194 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 439 134 439 214 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 404 149 up
+4 0 12 10 0 -1 0 0.000 4 7 24 404 169 next
+4 0 12 10 0 -1 0 0.000 4 7 24 404 189 list
+4 0 12 10 0 -1 0 0.000 4 9 24 404 209 type
+4 0 12 10 0 -1 0 0.000 4 9 60 399 129 dependency
+-6
+6 654 224 754 319
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 754 319 754 239 654 239 654 319 754 319 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 654 259 754 259 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 654 279 754 279 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 654 299 754 299 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 694 239 694 319 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 659 254 up
+4 0 12 10 0 -1 0 0.000 4 7 24 659 274 next
+4 0 12 10 0 -1 0 0.000 4 7 24 659 294 list
+4 0 12 10 0 -1 0 0.000 4 9 24 659 314 type
+4 0 12 10 0 -1 0 0.000 4 9 60 654 234 dependency
+-6
+6 164 294 174 304
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 164 294 174 304 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 164 304 174 294 9999 9999
+-6
+6 164 454 174 464
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 164 454 174 464 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 164 464 174 454 9999 9999
+-6
+6 464 159 474 169
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 464 159 474 169 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 464 169 474 159 9999 9999
+-6
+6 719 264 729 274
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 719 264 729 274 9999 9999
+2 1 0 1 1 0 0 0 0.000 7 0 0
+	 719 274 729 264 9999 9999
+-6
+6 164 154 174 164
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 164 154 174 164 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 164 164 174 154 9999 9999
+-6
+6 354 339 364 349
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 354 339 364 349 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 354 349 364 339 9999 9999
+-6
+6 269 259 389 394
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 269 294 389 294 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 269 314 389 314 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 269 334 389 334 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 269 354 389 354 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 329 274 329 394 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 389 394 389 274 269 274 269 394 389 394 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 269 374 389 374 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 269 269 deppossi
+4 0 12 10 0 -1 0 0.000 4 7 12 274 289 up
+4 0 12 10 0 -1 0 0.000 4 7 24 274 309 next
+4 0 12 10 0 -1 0 0.000 4 7 12 274 329 ed
+4 0 12 10 0 -1 0 0.000 4 7 42 274 389 version
+4 0 12 10 0 -1 0 0.000 4 7 42 274 349 nextrev
+4 0 12 10 0 -1 0 0.000 4 7 42 274 369 backrev
+-6
+6 354 359 364 369
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 354 359 364 369 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 354 369 364 359 9999 9999
+-6
+6 74 564 194 599
+4 0 12 12 0 -1 0 0.000 4 12 84 74 579 Package: foo
+4 0 12 12 0 -1 0 0.000 4 12 119 74 595 Depends: a | b, c
+-6
+6 389 449 399 459
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 389 449 399 459 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 389 459 399 449 9999 9999
+-6
+6 389 509 399 519
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 389 509 399 519 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 389 519 399 509 9999 9999
+-6
+6 304 409 424 544
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 304 444 424 444 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 304 464 424 464 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 304 484 424 484 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 304 504 424 504 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 364 424 364 544 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 424 544 424 424 304 424 304 544 424 544 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 304 524 424 524 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 304 419 deppossi
+4 0 12 10 0 -1 0 0.000 4 7 12 309 439 up
+4 0 12 10 0 -1 0 0.000 4 7 24 309 459 next
+4 0 12 10 0 -1 0 0.000 4 7 12 309 479 ed
+4 0 12 10 0 -1 0 0.000 4 7 42 309 539 version
+4 0 12 10 0 -1 0 0.000 4 7 42 309 499 nextrev
+4 0 12 10 0 -1 0 0.000 4 7 42 309 519 backrev
+-6
+6 259 119 359 214
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 359 214 359 134 259 134 259 214 359 214 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 259 154 359 154 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 259 174 359 174 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 259 194 359 194 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 299 134 299 214 9999 9999
+4 0 12 10 0 -1 0 0.000 4 7 12 264 149 up
+4 0 12 10 0 -1 0 0.000 4 7 24 264 169 next
+4 0 12 10 0 -1 0 0.000 4 7 24 264 189 list
+4 0 12 10 0 -1 0 0.000 4 9 24 264 209 type
+4 0 12 10 0 -1 0 0.000 4 9 60 259 129 dependency
+-6
+6 479 279 599 414
+6 564 359 574 369
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 564 359 574 369 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 564 369 574 359 9999 9999
+-6
+6 564 319 574 329
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 564 319 574 329 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 564 329 574 319 9999 9999
+-6
+6 479 279 599 414
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 479 314 599 314 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 479 334 599 334 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 479 354 599 354 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 479 374 599 374 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 539 294 539 414 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 599 414 599 294 479 294 479 414 599 414 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 479 394 599 394 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 479 289 deppossi
+4 0 12 10 0 -1 0 0.000 4 7 12 484 309 up
+4 0 12 10 0 -1 0 0.000 4 7 24 484 329 next
+4 0 12 10 0 -1 0 0.000 4 7 12 484 349 ed
+4 0 12 10 0 -1 0 0.000 4 7 42 484 409 version
+4 0 12 10 0 -1 0 0.000 4 7 42 484 369 nextrev
+4 0 12 10 0 -1 0 0.000 4 7 42 484 389 backrev
+-6
+6 564 379 574 389
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 564 379 574 389 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 564 389 574 379 9999 9999
+-6
+1 3 0 1 4 0 0 0 0.000 1 0.000 569 304 5 5 569 304 574 309
+1 3 0 1 6 0 0 0 0.000 1 0.000 569 344 5 5 569 344 574 349
+4 0 0 12 0 -1 0 0.000 4 6 5 589 289 c
+-6
+6 644 409 764 544
+6 729 489 739 499
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 729 489 739 499 9999 9999
+2 1 0 1 5 0 0 0 0.000 7 0 0
+	 729 499 739 489 9999 9999
+-6
+6 729 449 739 459
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 729 449 739 459 9999 9999
+2 1 0 1 2 0 0 0 0.000 7 0 0
+	 729 459 739 449 9999 9999
+-6
+6 644 409 764 544
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 644 444 764 444 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 644 464 764 464 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 644 484 764 484 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 644 504 764 504 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 704 424 704 544 9999 9999
+2 2 0 1 -1 0 0 0 0.000 0 0 0
+	 764 544 764 424 644 424 644 544 764 544 9999 9999
+2 1 2 1 -1 0 0 0 3.000 -1 0 0
+	 644 524 764 524 9999 9999
+4 0 12 10 0 -1 0 0.000 4 9 48 644 419 deppossi
+4 0 12 10 0 -1 0 0.000 4 7 12 649 439 up
+4 0 12 10 0 -1 0 0.000 4 7 24 649 459 next
+4 0 12 10 0 -1 0 0.000 4 7 12 649 479 ed
+4 0 12 10 0 -1 0 0.000 4 7 42 649 539 version
+4 0 12 10 0 -1 0 0.000 4 7 42 649 499 nextrev
+4 0 12 10 0 -1 0 0.000 4 7 42 649 519 backrev
+-6
+1 3 0 1 4 0 0 0 0.000 1 0.000 734 434 5 5 734 434 739 439
+1 3 0 1 6 0 0 0 0.000 1 0.000 734 474 5 5 734 474 739 479
+1 3 0 1 5 0 0 0 0.000 1 0.000 734 514 5 5 734 514 739 519
+4 0 0 12 0 -1 0 0.000 4 9 6 744 419 b
+4 0 12 12 0 7 0 0.000 4 9 28 719 539 >1.0
+-6
+6 449 564 589 599
+4 0 12 12 0 -1 0 0.000 4 12 70 449 579 Package: c
+4 0 12 12 0 -1 0 0.000 4 11 140 449 595 Recommends: b (>1.0)
+-6
+1 3 0 1 1 0 0 0 0.000 1 0.000 169 139 5 5 169 139 174 144
+1 3 0 1 1 0 0 0 0.000 1 0.000 669 139 5 5 669 139 674 144
+1 3 0 1 1 0 0 0 0.000 1 0.000 329 164 5 5 329 164 334 169
+1 3 0 1 2 0 0 0 0.000 1 0.000 329 184 5 5 329 184 334 189
+1 3 0 1 2 0 0 0 0.000 1 0.000 469 184 5 5 469 184 474 189
+1 3 0 1 2 0 0 0 0.000 1 0.000 724 289 5 5 724 289 729 294
+1 3 0 1 5 0 0 0 0.000 1 0.000 169 479 5 5 169 479 174 484
+1 3 0 1 5 0 0 0 0.000 1 0.000 669 159 5 5 669 159 674 164
+1 3 0 1 4 0 0 0 0.000 1 0.000 724 249 5 5 724 249 729 254
+1 3 0 1 4 0 0 0 0.000 1 0.000 329 144 5 5 329 144 334 149
+1 3 0 1 4 0 0 0 0.000 1 0.000 469 144 5 5 469 144 474 149
+1 3 0 1 5 0 0 0 0.000 1 0.000 169 319 5 5 169 319 174 324
+1 3 0 1 2 0 0 0 0.000 1 0.000 359 304 5 5 359 304 364 309
+1 3 0 1 4 0 0 0 0.000 1 0.000 359 284 5 5 359 284 364 289
+1 3 0 1 6 0 0 0 0.000 1 0.000 359 324 5 5 359 324 364 329
+1 3 0 1 5 0 0 0 0.000 1 0.000 394 494 5 5 394 494 399 499
+1 3 0 1 4 0 0 0 0.000 1 0.000 394 434 5 5 394 434 399 439
+1 3 0 1 6 0 0 0 0.000 1 0.000 394 474 5 5 394 474 399 479
+2 1 0 1 5 0 0 0 0.000 7 1 0
+	0 0 1.000 4.000 8.000
+	 169 479 299 479 9999 9999
+2 1 0 1 1 0 0 0 0.000 -1 0 1
+	0 0 1.000 4.000 8.000
+	 394 164 329 164 9999 9999
+3 2 0 1 1 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 169 139 199 139 219 144 239 149 254 149 9999 9999
+	 0.000 -190.000 186.321 138.362 193.821 138.362 203.746 139.584
+	 214.444 142.861 223.556 145.139 234.254 148.416 241.590 149.319
+	 245.340 149.319 0.000 -190.000
+3 2 0 1 1 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 669 139 704 144 719 154 734 234 9999 9999
+	 0.000 -190.000 689.270 140.465 698.020 141.715 708.066 145.553
+	 716.306 149.925 728.121 167.798 731.871 187.798 0.000 -190.000
+3 2 0 1 2 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 329 184 319 184 314 184 304 194 304 199 304 259 9999 9999
+	 0.000 0.000 323.209 184.000 320.709 184.000 317.861 184.000
+	 315.246 183.484 310.477 185.460 305.459 190.476 303.484 195.246
+	 304.000 197.861 304.000 209.251 304.000 224.251 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 359 304 389 309 399 339 404 384 404 419 9999 9999
+	 0.000 0.000 376.183 303.206 383.683 304.456 396.372 315.299
+	 397.434 331.869 401.243 349.210 403.427 373.663 404.332 389.993
+	 404.332 398.743 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 469 184 504 189 534 229 549 289 9999 9999
+	 0.000 0.000 489.097 184.107 497.847 185.357 515.602 195.870
+	 528.871 218.224 538.758 238.997 542.508 253.997 0.000 0.000
+3 2 0 1 2 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 724 289 709 299 704 414 9999 9999
+	 0.000 0.000 714.657 293.115 710.907 295.615 696.821 320.614
+	 695.571 349.364 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 394 494 444 499 569 499 639 499 9999 9999
+	 0.000 0.000 422.899 497.321 435.399 498.571 472.526 500.423
+	 540.524 499.000 580.960 499.000 598.460 499.000 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 669 159 649 159 634 164 604 204 579 289 9999 9999
+	 0.000 0.000 657.478 158.436 652.478 158.436 645.334 159.595
+	 637.243 161.663 623.745 171.392 609.302 193.426 596.954 218.053
+	 590.704 239.303 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 394 434 414 429 419 424 414 279 364 219 9999 9999
+	 0.000 0.000 405.666 432.138 410.666 430.888 415.525 428.137
+	 418.291 425.798 433.545 387.100 427.322 313.905 408.621 264.907
+	 396.121 249.907 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 569 304 554 234 529 189 504 174 9999 9999
+	 0.000 0.000 562.162 263.254 558.412 245.754 549.770 222.731
+	 537.823 198.122 525.252 185.125 519.002 181.375 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 359 284 359 249 354 219 9999 9999
+	 0.000 0.000 359.497 263.759 359.497 255.009 358.568 243.779
+	 357.318 236.279 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 734 434 724 379 724 324 9999 9999
+	 0.000 0.000 727.366 402.355 724.866 388.605 723.148 369.549
+	 723.148 355.799 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 724 249 719 209 699 174 9999 9999
+	 0.000 -190.000 722.530 225.840 721.280 215.840 716.720 202.160
+	 711.720 193.410 0.000 -190.000
+3 2 0 1 4 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 329 144 304 144 269 139 219 124 204 124 9999 9999
+	 0.000 -190.000 314.537 144.305 308.287 144.305 295.917 143.426
+	 276.919 140.743 257.308 136.426 231.067 125.771 216.399 123.618
+	 212.649 123.618 0.000 -190.000
+3 2 0 1 5 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 169 319 189 319 229 324 254 329 264 329 9999 9999
+	 0.000 0.000 180.574 318.787 185.574 318.787 198.208 319.573
+	 219.921 322.527 234.742 324.932 248.152 328.421 255.720 329.170
+	 258.220 329.170 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 394 474 339 469 299 469 259 469 234 469 204 469 9999 9999
+	 0.000 0.000 362.200 470.679 348.450 469.429 329.874 468.586
+	 308.112 469.000 289.888 469.000 268.112 469.000 253.305 469.000
+	 239.695 469.000 228.874 469.000 221.374 469.000 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 734 474 659 469 434 484 299 489 204 489 9999 9999
+	 0.000 0.000 690.661 470.250 671.911 469.000 607.354 469.001
+	 485.316 481.339 403.258 485.594 329.783 488.430 282.765 489.301
+	 259.015 489.301 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 569 344 594 339 619 304 634 204 644 174 9999 9999
+	 0.000 0.000 583.473 343.015 589.723 341.765 603.620 332.780
+	 615.079 313.689 628.219 281.222 628.581 226.603 635.271 198.699
+	 637.771 191.199 0.000 0.000
+3 2 0 1 6 0 0 0 0.000 1 0
+	0 0 1.000 4.000 8.000
+	 359 324 294 319 204 309 9999 9999
+	 0.000 0.000 321.344 321.293 305.094 320.043 278.591 317.552
+	 256.091 315.052 0.000 0.000
+3 2 0 1 5 0 0 0 0.000 0 1
+	0 0 1.000 4.000 8.000
+	 429 514 564 519 714 519 734 514 9999 9999
+	 0.000 0.000 507.163 517.323 540.913 518.573 598.180 519.633
+	 679.471 523.251 717.559 518.562 722.559 517.312 0.000 0.000
+3 2 0 1 4 0 0 0 0.000 0 1
+	0 0 1.000 4.000 8.000
+	 204 99 364 109 414 139 469 144 9999 9999
+	 0.000 0.000 296.049 97.811 336.049 100.311 377.555 113.214
+	 400.605 134.627 423.515 142.106 437.265 143.356 0.000 0.000
+4 0 0 12 0 -1 0 0.000 4 9 15 159 104 foo
+4 0 0 12 0 -1 0 0.000 4 6 5 479 129 c
+4 0 0 12 0 -1 0 0.000 4 12 42 309 209 depends
+4 0 0 12 0 -1 0 0.000 4 12 42 449 209 depends
+4 0 0 12 0 -1 0 0.000 4 9 6 744 234 b
+4 0 0 12 0 -1 0 0.000 4 6 18 714 314 rec.
+4 0 0 12 0 -1 0 0.000 4 6 6 164 264 a
+4 0 0 12 0 -1 0 0.000 4 9 6 164 424 b
+4 0 0 12 0 -1 0 0.000 4 6 5 664 104 c
+4 0 0 18 0 -1 0 0.000 4 17 632 64 54 example of the structures (in the C code) which contain related packages information
+4 0 12 12 0 -1 0 0.000 4 12 70 284 589 Package: a
+4 0 0 12 0 -1 0 0.000 4 6 6 374 269 a
+4 0 0 12 0 -1 0 0.000 4 9 6 384 419 b
+4 0 0 12 0 -1 0 0.000 4 9 15 339 129 a|b
+4 0 12 12 0 -1 0 0.000 4 12 70 674 589 Package: b

+ 104 - 0
doc/deb-control.5

@@ -0,0 +1,104 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Author: Raul Miller
+.\" Includes text from the debian Guidelines by Ian Jackson, Ian Murdock
+.TH DEB-CONTROL 5 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+deb\-control \- Debian GNU/Linux packages' master control file format
+.SH SYNOPSIS
+control
+.SH DESCRIPTION
+Master control file format:
+.LP
+The `control' file contains a number of fields.  Each field begins
+with a tag, such as `PACKAGE' or `VERSION' (case insensitive),
+followed by a colon, and the body of the field. Fields are delimited
+only by field tags.  In other words, field text may be multiple lines
+in length, but the installation tools will generally join lines when
+processing the body of the field.
+.SH REQUIRED FIELDS
+.TP
+.BR PACKAGE: \ <Short\ name\ of\ package>
+The value of this field is used to generate file names by some
+installation tools.
+.TP
+.BR VERSION: \ <Original\ version\ number>
+typically, this is the original portable package's version
+number in whatever form the program's author uses.
+.TP
+.BR PACKAGE_REVISION: \ <Debian\ package\ revision\ number>
+this should usually be a plain number, or perhaps two numbers
+separated by a full stop.
+.TP
+.BR MAINTAINER: \ <Name\ and\ e-mail\ address\ of\ package\ maintainer>
+should be in the format  Joe Bloggs <jbloggs@foo.com>.
+.TP
+.BR DESCRIPTION: \ <Description\ of\ package> 
+.SH OPTIONAL FIELDS
+.TP
+.BR DEPENDS: \ <Short\ names\ of\ prerequisite\ packages>
+list of packages that are required for this package to provide a
+non-trivial amount of functionality.  The package maintenance software
+will not allow a package to be installed without also installing
+packages listed in its 
+.B DEPENDS
+field, and will rin the postinst scripts of packages listed in DEPENDS
+fields before those of the packages which depend on them, and run
+prerm scripts before.
+.TP
+.BR RECOMMENDED: \ <Short\ names\ of\ related,\ recommended\ packages>
+lists packages that would be found together with
+this one in all but unusual installations.  The package maintenance
+software will warn the user if they install a package without those
+listed in its
+.B RECOMMENDED
+field.
+.LP
+The syntax of
+.B DEPENDS
+and
+.B RECOMMENDED
+is a list of groups of alternative packages.  Each group is a list of
+packages separated by vertical bar (or `pipe') symbols, `|'.  The
+groups are separated by commas.  Each package is a package name
+optionally followed by a version number specification in parentheses.
+A version number may start with a `>', in which case any later version
+will match, and may specify or omit the Debian packaging revision
+(separated by a hyphen).  Commas are to be read as `AND', and pipes as
+`OR', with pipes binding more tightly.
+.TP
+.BR OPTIONAL: \ <Short\ names\ of\ related,\ optional\ packages>
+lists packages that are related to this one and can perhaps enhance
+its usefulness, but without which installing this package is perfectly
+reasonable.  The package maintenance software will not moan at the
+user for not selecting
+.B OPTIONAL
+related packages, but may use the information in the
+.B OPTIONAL
+field to assist the user during package selection.
+.TP
+.BR CONFLICTS: \ <Short\ names\ of\ packages\ which\ conflict\ with\ this\ one>
+lists packages that conflict with this one, for example by containing
+files with the same names (an example would be Smail vs. Sendmail).
+The package maintenance software will not allow conflicting packages
+to be installed.  Two conflicting packages should each include a
+.B CONFLICTS
+line mentioning the other.
+.LP
+The syntax of
+.B OPTIONAL
+and
+.B CONFLICTS
+is a list of package names, separated by commas (and optional
+whitespace).  In the
+.B CONFLICTS
+field, the comma should be read as `OR'.
+
+.SH BUGS
+This manpage is seriously out of date.
+
+.SH SEE ALSO
+.BR deb (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dpkg-dep (8),
+.BR dselect (8).

+ 69 - 0
doc/deb.5

@@ -0,0 +1,69 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Author: Raul Miller
+.TH DEB 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME 
+deb - Debian GNU/Linux package format
+.SH SYNOPSIS
+.IB <packagename>.deb
+.SH DESCRIPTION
+Debian archive file format.
+Version 0.93 is implemented as follows:
+.TP
+line 1:
+version number 
+.RB ( 0.93 ...),
+followed by
+.BR newline .
+.TP
+line 2:
+number of characters occupied by control area expressed in decimal,
+followed by 
+.BR newline .
+.TP 
+control area:
+compressed gzipped ustar formatted archive.  Must contain file named
+.BR control .
+May optionally contain files named:
+.BR conffiles ,
+.BR preinst ,
+.BR prerm ,
+.BR postint ,
+.BR postrm .
+.TP 
+files archive area:
+compressed gzipped ustar formatted archive.  [with file structures
+designed to be unpacked in the root directory].
+.SH FILES
+The files represented in the control area have special significance:
+.TP
+.B control
+see 
+.BR deb-control (5).
+.TP
+.B conffiles
+a line delimited list of "configuration files" which have special
+significance to 
+.BR dpkg (8).
+.TP
+.B preinst
+an executable to be run before unpacking the archived files.
+.TP
+.B prerm
+an executable to be run before removing files from a prior installation.
+.TP
+.B postinst
+an executable to be run after unpacking the archived files.
+.TP
+.B postrm
+an executable to be run after removing files from a prior
+installation.
+
+.BUGS
+There is a new package format, which is not documented here.
+
+.SH SEE ALSO
+.BR deb-control (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dpkg-dep (8),
+.BR dselect (8).

+ 97 - 0
doc/dependency-ordering.txt

@@ -0,0 +1,97 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Note about the default for virtal package dependencies
+
+As I wrote some time ago (see below), ordering is significant in the
+Depends and Recommended fields - in the absence of other information
+dselect will suggest to the user that they select the first named
+package in a list of options.
+
+However, there is no way to specify the `order' of several packages
+which all Provide the same thing, when that thing is listed as a
+Dependency.
+
+Eg, if we have:
+ Package: glibcdoc
+ Recommended: info-browser
+
+ Package: info
+ Provides: info-browser
+
+ Package: emacs
+ Provides: info-browser
+
+then (if emacs and info are both in the same Class) dselect's choice
+will be essentially random.
+
+It is important to think about this problem, and to consider whether
+to list one the the packages explicitly.
+
+For example,
+ Package: glibcdoc
+ Recommended: info | info-browser
+
+will do the same as the above, except that it will ensure that `info'
+is the package which dselect will suggest to the user they also select
+if the user has neither it nor Emacs and asks to select glibcdoc.
+
+This is not necessary if one of the packages has a more fundamental
+Class - see the details below.
+
+Ian.
+
+------- Start of forwarded message -------
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Ordering is significant in Depends: and Recommends:
+
+For dselect, the ordering of alternative packages in a Depends: or
+Recommended: line is significant.
+
+When an unsatisfied dependency (Depends or Recommended) or a conflict
+is detected dselect will go into a `recursive package list', where the
+user gets to choose how to resolve the problem.
+
+Usually dselect will suggest to the user that they select the package
+with the most `fundamental' class (eg, it will prefer Base packages to
+Optional ones), or the one that they `most wanted' to select in some
+sense.
+
+However, in the absence of other information dselect will prefer
+packages listed earlier in the unsatisfied entry in the Depends or
+Recommended field.
+
+NB: this doesn't apply to constructions of the form:
+ Package: auctex
+ Depends: emacs, tex
+which specifies that auctex depends on *both* emacs and tex.  In this
+case dselect will suggest to the user that they select both packages.
+
+It applies to constructions of the form:
+ Package: a2gs
+ Recommended: gs_x | gs_both | gs_svga
+Here, dselect will prefer gs_x because it is listed earlier.  (In the
+future I may make it more clever - it may be able to notice, to
+continue the example, that the dependencies of gs_x are not yet
+satisfied while those of gs_svga, are, and thus prefer the latter, or
+in a different situation to notice that gs_both has extra dependencies
+which are satisfied, and thus prefer it to gs_x and gs_svga.  More
+thought is needed in this area.)
+
+One final example.  In the more complicated construction:
+ Package: trn
+ Depends: smail | sendmail, inn | inewsinn
+dselect will prefer smail because it is a Standard package, and
+Sendmail is only Optional, and will prefer inewsinn because it is
+Recommended and inn is only Optional.  So, the default (if none of the
+other packages were selected) would be to select smail and inewsinn.
+
+However, if inewsinn were moved to Optional this would change, and inn
+would be preferred whenever the issue arose after the change.
+
+Optional fields have the same structure as Depends and Recommended
+fields, but they will not arrange for the packages they list to be
+suggested for selection, though they will be offered to the user.
+
+Ian M: can this go in an appendix to the Guidelines ?
+
+Ian.
+------- End of forwarded message -------

+ 112 - 0
doc/descriptions.txt

@@ -0,0 +1,112 @@
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Package maintainers please look at your Description fields.
+
+dselect will be much more useful when more packages are more
+informative in the Description they provide in their control file.
+
+So, when you next release a package, could you please check whether
+the `control' file has a good description of the package, formatted as
+described below ?
+
+A small amount of effort here on the part of package maintainers will
+improve the looks of things quite a bit, I think.
+
+BTW, a number of packages have been indenting continuation lines in
+their Description fields thus:
+  Description: gnomovision
+         Gnomovision is ....
+         further blurb ...
+Please don't do this.  According to the scheme described below (which
+I've now implemented), dselect interprets the extra indentation to
+mean `preformatted' text, and doesn't wordwrap it.
+
+Ian.
+
+
+The format of the Description field is as follows:
+
+Description: <single line synopsis>
+ <extended description over several lines>
+
+The extended description has several kinds of line:
+
+ - those starting with a single space are part of a paragraph.
+Successive lines of this form will be word-wrapped when displayed.
+The leading space will usually be stripped off.
+
+ - those starting with two or more spaces.  These will be displayed
+verbatim.  If the display cannot be panned horizontally the displaying
+program will linewrap them `hard' (ie, without taking account of word
+breaks).  If it can they will be allowed to trail off to the right.
+None, one or two initial spaces may be deleted, but the number of
+spaces deleted from each line will be the same (so that you can have
+indenting work right, for example).
+
+ - those containing a single space followed by a single full stop
+character.  These are rendered as blank lines.  This is the ONLY way
+to get a blank line - see below.
+
+ - those containing a space, a full stop and some more characters.
+These are for future expansion.  Don't use them.
+
+IMPORTANT and not so important TIPS:
+
+* ALWAYS START EXTENDED DESCRIPTION LINES WITH AT LEAST ONE WHITESPACE
+CHARACTER.  Fields in the control file and in the Packages file are
+separated by field names starting in the first column, just as in
+RFC822.  Forgetting the whitespace will cause dpkg-deb (>=0.93.23) to
+produce a syntax error when trying to build the package.  If you force
+it to build anyway dpkg will refuse to install the resulting mess.
+
+* DO NOT INCLUDE ANY COMPLETELY EMPTY LINES.  These separate different
+records in the Packages file, and are forbidden in control files.  See
+the previous paragraph for what happens if you get this wrong.
+
+* The single line synopsis should be kept brief - certainly under 80
+characters.  My current working half-dselect displays the first 49
+characters if you're using an 80-column terminal.
+
+* Don't include the package name in the synopsis line.  The display
+software knows how to display this already, and you don't need to
+state it.
+
+* The extended description should describe what the package does, and
+what component it forms of any larger subsystem of which it is a part.
+
+* Put important information first, both in the synopis and extended
+description.  Sometimes only the first part of the synopsis or of the
+description will be displayed.  You can assume that there will usually
+be a way to see the whole extended description.
+
+* You may include information about dependencies and so forth in the
+extended description, if you wish.
+
+* Don't use tab characters.  Their effect is not predictable.
+
+Example control file for Smail:
+
+Package: smail
+Version: 3.1.29.1
+Package_Revision: 8
+Maintainer: Ian Jackson <iwj10@cus.cam.ac.uk>
+Recommended: pine | elm | emacs | mh | mailx
+Optional: metamail
+Depends: cron
+Conflicts: sendmail
+Description: Electronic mail transport system.
+ Smail is the recommended mail transport agent (MTA) for Debian.
+ .
+ An MTA is the innards of the mail system - it takes messages from
+ user-friendly mailer programs and arranges for them to be delivered
+ locally or passed on to other systems as required.
+ .
+ In order to make use of it you must have one or more user level
+ mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+ and VM as mailreaders) installed.  If you wish to send messages other
+ than just to other users of your system you must also have appropriate
+ networking support, in the form of IP or UUCP.
+
+-- 
+Ian Jackson, at home.         ijackson@nyx.cs.du.edu or iwj10@cus.cam.ac.uk
++44 1223 575512    Escoerea on IRC.   http://www.cl.cam.ac.uk/users/iwj10/
+2 Lexington Close, Cambridge, CB4 3LS, England.   Urgent: iwj@cam-orl.co.uk

+ 44 - 0
doc/disappear-replace.txt

@@ -0,0 +1,44 @@
+From ian Tue Apr 18 23:30:04 1995 
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+	[nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+	nil)
+X-VM-Summary-Format: "%3n %a %2d %3m  %-19.19F  %s\n"
+X-VM-Labels: nil
+X-VM-VHeader: ("Resent-" "From:" "Sender:" "To:" "Apparently-To:" "Cc:" "Subject:" "Date:") nil
+X-VM-Bookmark: 5
+To: Debian developers list <debian-devel@pixar.com>
+Subject: Handling of base packages
+
+I propose to implement the following scheme to enable obsolete base
+packages to disappear, and to allow files in the base packages to move
+between one package and another.
+
+1. When a package is installed, and contains files that are already
+marked as belonging to some other package, the older package will have
+the files that have been overwritten removed from its file list.
+
+2. When a package ceases to contain any files due to the action of
+point 1 above, its postrm script is run with the argument `disappear'
+(in place of `remove', `purge' or whatever).  It will then be moved
+into the `purge ok not-installed' state, so that it will cease to
+appear in dpkg and dselect lists.  Its conffiles will be ignored,
+*not* purged.  The prerm will *not* be run as the packaging system
+doesn't know what files are in a package until it unpacks it.
+
+This will all happen during the `unpack' phase of the replacing
+package.
+
+3. If a base system package which is being installed conflicts with
+another base system package which is currently installed on the
+system, the currently installed one will be removed first (the prerm
+will be run with `replace <package> <version>' as arguments, then the
+package will be removed, then the postrm will be run, likewise with
+`replace').  If the replacement fails the removal will be aborted,
+involving running the old packages' scripts with `abort-replace'.
+
+4. Base system packages may not be removed except under 2. or 3.
+above.  (There will be a --force-remove-base flag to allow foolhardy
+users to go ahead anyway.)
+
+Ian.
+

+ 131 - 0
doc/diversions.text

@@ -0,0 +1,131 @@
+(These messages have been edited to conform to the terminology
+eventually decided on.)
+
+------- start of digest (2 messages) (RFC 934 encapsulation) -------
+Resent-Message-Id: <m0tcceI-0002c6C@chiark.chu.cam.ac.uk>
+Resent-From: ijackson (Ian Jackson)
+Resent-To: ian
+From: ian@chiark.chu.cam.ac.uk (Ian Jackson)
+To: Debian developers list <debian-devel@pixar.com>
+Subject: `diverting' dpkg for a particular file
+Date: Wed, 17 Jan 96 18:31 GMT
+
+I'm almost finished with the implementation of a feature for dpkg that
+will allow the sysadmin or package maintainer to prevent dpkg from
+overwriting a particular file.
+
+Instead, whenever dpkg finds a package containing that file it
+`redirects' the reference to an alternative name.
+
+Eg, if you were to `divert' /usr/sbin/smail to /usr/sbin/smail.real
+then any package containing /usr/sbin/smail would have the file placed
+as /usr/sbin/smail.real instead.  The feature will work during package
+removal, as well.
+
+There's provision for a single package to be named which is allowed to
+provide a version of the file which will installed under the original
+name.
+
+This feature shouldn't be mixed with the conffiles update mechanism,
+as this is unlikely to produce useful results and likely to produce
+confusion on the part of the user at the very least and possibly on
+the part of dpkg too :-).
+
+No package should contain a file whose name is the diverted name of
+another file; dpkg will spot this and balk if such a package is
+installed when the diversion is in place, or if a diversion is set up
+which involves overwriting an existing file whether managed by dpkg
+or not (this latter check only happens if dpkg-divert is given the
+--rename option which makes it actually rename any copy of the file
+found in the filesystem).
+
+Only one diversion for a particular file is allowed, and you can't
+divert A to B and then B to C.
+
+[...]
+
+This feature is intended to be used sparingly; a system administrator
+can use it to keep a locally-installed version of a piece of system
+software that has to live in a particular place.
+
+A package should preferably only use it if the package's main function
+is to replace the file in question (whether or not the diverted - ie,
+replaced, in this case - version of the file needs to be available);
+otherwise a sysadmin might find that the feature wasn't available to
+them when they wanted to install their own version of the file because
+a package had already done so.
+
+It's possible that I might introduce a facility that would allow
+*requests* for redirection of files to be redirected themselves, by
+using a special 2nd-level redirection option.
+
+Ian.
+------------------------------
+To: debian-devel@Pixar.com
+Subject: Re: `overriding' dpkg for a particular file
+
+[...]
+Forgive me for being perhaps rather baseic, but here are two examples,
+diagrammatically:
+
+1. Administrator wants to replace a Debian-provided program with
+   their own version, or wants to put a wrapper around it:
+                                            ____________________
+     smail.deb___________                  /                    \
+     |  ...              |                |\____________________/|
+     | /usr/sbin/smail --+----.           |                      |
+     |  ...              |     \          | /                    |
+     |___________________|      \         | /usr                 |
+                                 \        | /usr/sbin            |
+                                  `-------> /usr/sbin/smail.real |
+                                  .-------> /usr/sbin/smail      |
+      ~/stuff/smail/wrapper.c    /        |                      |
+      ~/stuff/smail/wrapper ----'          \____________________/
+
+     # dpkg-divert --divert /usr/sbin/smail.real /usr/sbin/smail
+     # cp ~fred/stuff/smail/wrapper /usr/sbin/smail
+
+2. Package maintainer wants to provide an `improved' version of a
+   file in another package.
+
+     fileutils.deb_______                   ____________________
+     |  ...              |                 /                    \
+     | /bin/ls ----------+----.           |\____________________/|
+     |  ...              |     \          |                      |
+     |___________________|      \         | /                    |
+                                 \        | /bin                 |
+     colour-ls.deb_______         `-------> /bin/ls.mono         |
+     |  ...              |       .--------> /bin/ls              |
+     | /bin/ls ----------+------'         |                      |
+     |  ...              |                 \____________________/
+     |...................|
+     |preinst:           |
+     | dpkg-divert --divert /bin/ls.mono \
+     |   --package colour-ls /bin/ls
+     |...................|
+     |postrm:            |
+     | dpkg-divert --remove --divert /bin/ls.mono \
+     |   --package colour-ls /bin/ls
+     |___________________|
+
+We need a name that applies to `/usr/sbin/smail.real' and
+`/bin/ls.mono', the filenames, in both situations, and another name
+to apply to `/usr/sbin/smail' and `/bin/ls'.
+
+Raul Miller writes ("Re: `overriding' dpkg for a particular file"):
+[...]
+> Also, it would be nice to see either some documentation or some sort
+> of warning about the case where the file is a directory.
+
+If the file is a directory there will be no good effect.  This is
+because the redirection would affect only the entry for the directory
+itself in the packages whose instances if it were being redirected,
+and would not affect any of the files in it.
+
+The most likely result is that dpkg will fail to install the package
+because one of the directories where it has files doesn't exist.  It
+would probably create the `diverted' name of the directory, fail, and
+then clean it up.
+
+Ian.
+------- end -------

+ 101 - 0
doc/dpkg.texi

@@ -0,0 +1,101 @@
+\input texinfo @c -*-texinfo-*-
+@c %**start of header
+@setfilename dpkg.info
+@settitle The @code{dpkg} Package Maintenance System
+@c %**end of header
+
+@ifinfo
+@format
+START-INFO-DIR-ENTRY
+* dpkg: (dpkg).          The @code{dpkg} package maintenance system.
+END-INFO-DIR-ENTRY
+@end format
+@end ifinfo
+
+@setchapternewpage off
+
+@ifinfo
+This file documents the @code{dpkg} package maintenance system.
+
+Copyright (C) 1994 Ian A. Murdock
+
+Permission is granted to make and distribute verbatim copies of this
+document provided the copyright notice and this permission notice are
+preserved on all copies.
+
+@ignore
+Permission is granted to process this file through TeX and print the
+results, provided the printed document carries a copying permission
+notice identical to this one, except for the removal of this paragraph
+(this paragraph not being relevant to the printed manual).
+@end ignore
+
+Permission is granted to copy and distribute modified versions of this
+document 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 document
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by The Debian Linux Association.
+@end ifinfo
+
+@titlepage
+@title The @code{dpkg} Package Maintenance System
+@author Ian A. Murdock
+@page
+
+@vskip 0pt plus 1filll
+Copyright @copyright{} 1994 Ian A. Murdock
+
+Permission is granted to make and distribute verbatim copies of this
+document provided the copyright notice and this permission notice are
+preserved on all copies.
+
+Permission is granted to copy and distribute modified versions of this
+document 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 document
+into another language, under the above conditions for modified versions,
+except that this permission notice may be stated in a translation approved
+by The Debian Linux Association.
+@end titlepage
+
+@node Top, Overview, (dir), (dir)
+
+@top Introduction
+@menu
+* Overview::            An overview of the @code{dpkg} package
+                        maintenance system.
+* Installation::        How to install a package with @code{dpkg}.
+* Removal::             How to remove a package with @code{dpkg}.
+* Information::         How to obtain information about both
+                        installed and not-yet-installed packages.
+* Extension::           How to extend @code{dpkg} to support new
+                        package formats.
+* Guidelines::          Guidelines for creating and maintaining
+                        packages for Debian GNU/Linux.
+@end menu
+
+@node Overview
+@chapter Overview
+
+@node Installation
+@chapter Package Installation
+
+@node Removal
+@chapter Package Removal
+
+@node Information
+@chapter Package Information
+
+@node Guidelines
+@chapter Debian GNU/Linux Guidelines
+
+@node Extension
+@chapter How to Extend @code{dpkg} to Support New Package Formats
+
+@bye

+ 43 - 0
doc/essential-flag.txt

@@ -0,0 +1,43 @@
+From ian Thu Jul  6 21:14:08 +0100 1995
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+	[nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+	nil)
+In-Reply-To: <m0sTw2a-00063aC@mongo.pixar.com>
+References: <m0sTw2a-00063aC@mongo.pixar.com>
+To: debian-devel@pixar.com
+Subject: Re: non-uninstallable packages
+
+Bruce Perens writes ("non-uninstallable packages"):
+> Assume that a package, such as one in the base, is supposed to be
+> non-uninstallable because it is a critical system component. We should
+> specify that in an unambiguous form, rather than indicating it by
+> specifying "Class: base" in the control file.
+> 
+> I suggest yet another control file field, called "Flags: ". This is
+> followed by a comma-delimited set of flags. An example might be:
+> 	Flags: no-uninstall
+> 
+> Another alternative would be to add control-file fields for each flag.
+> In this case, the field would appear as:
+> 	Allow-uninstall: no
+> ...and the default would be "yes".
+
+I think you're right.  Bill spotted that we were trying to overload
+the `Class' field.
+
+I don't think there's any need for a generic `Flags:' field; a simple
+extra field is fine, unless we're going to have an awful lot of
+boolean flags applying to packages (any attribute with a value is
+better handled using a field of its own anyway).
+
+I propose to call the new field `Essential', with allowable values
+`yes' and `no' and a default of `no'.
+
+This will be clearer all round, I think, than attempting to describe
+dpkg behaviour in the field name.
+
+If I don't have to make an emergency bugfix release of dpkg first this
+will be in the next version.  I'll modify dselect too.
+
+Ian.
+

File diff suppressed because it is too large
+ 1039 - 0
doc/guidelines.info-1


+ 744 - 0
doc/guidelines.info-2

@@ -0,0 +1,744 @@
+This is Info file guidelines.info, produced by Makeinfo-1.63 from the
+input file ./guidelines.texi.
+
+START-INFO-DIR-ENTRY
+* Guidelines: (guidelines).       How to make Debian packages.
+END-INFO-DIR-ENTRY
+
+
+File: guidelines.info,  Node: configuration files - /etc/skel vs /usr/doc/examples,  Next: How to write the Description control file field,  Prev: Appendix,  Up: Appendix
+
+configuration files - /etc/skel vs /usr/doc/examples
+====================================================
+
+   There seems to be a certain amount of confusion about `/etc/skel'
+and `/usr/doc/examples'. The most important thing to remember is the
+following:
+
+   Files in `/etc/skel' will *automatically* be copied into *new* user
+accounts by `adduser'.  They should not be referenced there by any
+program. Files in `/usr/doc/examples' should not be installed
+automatically.
+
+   Therefore, if the program in question need a dotfile to exist in
+advance in `$HOME' to work *sensibly* that dotfile should be installed
+in `/etc/skel' (and listed in conffiles; *note conffiles::.).
+
+   However, programs that require dotfiles in order to operate sensibly
+(dotfiles that they do not create themselves automatically, that is) are
+a bad thing, and that programs should be configured by the Debian
+default installation as close to normal as possible.
+
+   Therefore, if a program in a Debian package needs to be configured in
+some way in order to operate sensibly that configuration should be done
+in a site-wide global configuration file elsewhere in `/etc' (and that
+file should be listed in conffiles).  Only if the program doesn't
+support a site-wide default configuration should a default per-user file
+be placed in `/etc/skel' (and listed in conffiles; *note conffiles::.).
+
+   The idea is as follows:
+
+   The sysadmin should ideally not have to do any configuration other
+than that done (semi-)automatically by the postinst script.
+
+   However, if they wish to change their configuration themselves
+(because the configuration they want is beyond the scope of the
+autoconfiguration, or because the autoconfiguration doesn't exist yet,
+or because they just want to do it themselves for any reason) then
+`/usr/doc/examples' exists as *documentation* for their benefit.
+
+   The only time these files should be read are by the sysadmin using
+their favourite editor or pager, or *perhaps* (in very complex packages)
+by the postinst as a template to build on or modify.
+
+   `/etc/skel' is part of the *implementation* of this configuration.
+It contains the files that are copied into new user accounts.  It
+should probably be as empty as we can make it.
+
+   Examples:
+`.profile'
+     `/etc/skel' should not contain a `.profile' file.  Anything that
+     needs to be done there should be done in `/etc/profile'.  Anything
+     that should not go in `/etc/profile' (users can't avoid running
+     `/etc/profile') probably should not be in the default
+     configuration.  bash has generally good default behaviour.
+
+`.bash_logout'
+     Likewise, bash functions perfectly happily without a
+     `.bash_logout', so none should be provided, since anything in it is
+     a deviation from the sensible default behaviour.
+
+`.xsession'
+     `/etc/skel' should not contain a `.xsession'.  `xdm''s system-wide
+     startup file `/usr/lib/X11/xdm/Xsession' supports a system-wide
+     default user configuration (which should probably be
+     `/etc/X11/Xsession' or some such) which may be overridden by
+     `.xsession' in the user's home directory.  Therefore there is no
+     need for a `.xsession' to be installed by default and none should
+     be provided.
+
+     Instead, a sensible `/etc/X11/Xsession' should be provided, and if
+     desired this can be used as a template by users who wish to install
+     their own configuration, or alternatively a more comprehensive
+     example with much commented-out interesting stuff could be put in
+     `/usr/doc/examples'.
+
+     If the sysadmin wishes to change the system-wide default they
+     should probably do this by editing `/etc/X11/Xsession' rather than
+     creating the file in `/etc/skel', because the former will affect
+     all user accounts that haven't explicitly overridden things by
+     creating their own file while the latter will only affect new
+     accounts.
+
+     All the configuration necessary for a program to function should be
+     provided.  Therefore sysadmins will not need to go through
+     `/usr/doc/examples' while editing configuration files in `/etc'
+     except in extreme cases (like INN) where the configuration was too
+     difficult to do automatically.
+
+`site-wide defaults'
+     Site-wide defaults should not go in `/etc/skel'.  In the case of
+     twm, for example, the system-wide default should be in
+     `/etc/X11/system.twmrc'.  (The default location for this in X11R5,
+     btw, is in `/usr/lib/X11' somewhere, but we can't put it on `/usr'
+     because of CDROM distributions, etc - hence the FSSTND's mandate
+     to put configuration files in `/etc'.)
+
+`.twmrc'
+     There should be no `.twmrc' file in `/etc/skel'.  You can have one
+     in `/usr/doc/examples' if you *like*, but why bother if
+     `system.twmrc' is a good example (and indeed is the one the user is
+     using before they create their own)?
+
+`m4'
+     `/usr/doc/examples' isn't mainly for example *configuration
+     files*.  It's for any kind of example file distributed with a
+     package.  For example, GNU m4 comes with a whole pile of example
+     m4 macro scripts, which is exactly what `/usr/doc/examples' is for.
+
+   Summary
+
+   Files that should be installed in new user accounts should be in
+`/etc/skel', as that will ensure that they *are* installed in new user
+accounts!  However, we should try to avoid the need for this.
+
+   `/usr/doc/examples' is just what it says: documentation in the form
+of examples.  If a sysadmin is required to go and read these files for
+their system to work they should be told about it.  For example, here
+is what the Smail postinst script says right at the start:
+
+     I can do certain kinds of automatic configuration of your
+     mail system, by asking you a number of questions.  Later you
+     may to confirm and/or correct your answers.  In any case,
+     comprehensive information on configuring Smail is in
+     smail(5) and in /usr/doc/examples/smail and
+     /usr/doc/smail-admin-guide.
+
+
+File: guidelines.info,  Node: How to write the Description control file field,  Next: Configuration of init,  Prev: configuration files - /etc/skel vs /usr/doc/examples,  Up: Appendix
+
+How to write the Description control file field
+===============================================
+
+   The format of the `Description' field is as follows:
+
+     Description: <single line synopsis>
+      <extended description over several lines>
+
+   The extended description has several kinds of line:
+
+   * Those starting with a single space are part of a paragraph.
+     Successive lines of this form will be word-wrapped when displayed.
+     The leading space will usually be stripped off.
+
+   * Those starting with two or more spaces.  These will be displayed
+     verbatim.  If the display cannot be panned horizontally the
+     displaying program will linewrap them `hard' (ie, without taking
+     account of word breaks).  If it can they will be allowed to trail
+     off to the right.  None, one or two initial spaces may be deleted,
+     but the number of spaces deleted from each line will be the same
+     (so that you can have indenting work correctly, for example).
+
+   * Those containing a single space followed by a single full stop
+     character.  These are rendered as blank lines.  This is the *only*
+     way to get a blank line - see below.
+
+   * Those containing a space, a full stop and some more characters.
+     These are for future expansion.  *Do not* use them.
+
+   IMPORTANT and not so important TIPS:
+
+   * *Always* start extended description lines with at least *one*
+     whitespace character.  Fields in the control file and in the
+     Packages file are separated by field names starting in the first
+     column, just as in RFC822.  Forgetting the whitespace will cause
+     `dpkg-deb' (>=0.93.23) to produce a syntax error when trying to
+     build the package.  If you force it to build anyway `dpkg' will
+     refuse to install the resulting mess.
+
+   * *Do not* include any completely *empty* lines. These separate
+     different records in the Packages file, and are forbidden in
+     control files.  See the previous paragraph for what happens if you
+     get this wrong.
+
+   * The single line synopsis should be kept brief - certainly under 80
+     characters.  `dselect' displays the *first 49* characters if
+     you're using an 80-column terminal.
+
+   * Do not include the package name in the synopsis line.  The display
+     software knows how to display this already, and you do not need to
+     state it.  Remember that in many situations the user may only see
+     the synopsis line - make it as informative as you can.
+
+   * The extended description should describe what the package does and
+     how it relates to the rest of the system (in terms of, for
+     example, which subsystem it is which part of).
+
+   * Put important information first, both in the synopis and extended
+     description.  Sometimes only the first part of the synopsis or of
+     the description will be displayed.  You can assume that there will
+     usually be a way to see the whole extended description.
+
+   * You may include information about dependencies and so forth in the
+     extended description, if you wish.
+
+   * Do not use tab characters.  Their effect is not predictable.
+
+   Example control file for Smail:
+
+     Package: smail
+     Version: 3.1.29.1-13
+     Maintainer: Ian Jackson <iwj10@cus.cam.ac.uk>
+     Recommends: pine | mailx | elm | emacs | mail-user-agent
+     Suggests: metamail
+     Depends: cron, libc5
+     Conflicts: sendmail
+     Provides: mail-transport-agent
+     Description: Electronic mail transport system.
+      Smail is the recommended mail transport agent (MTA) for Debian.
+      .
+      An MTA is the innards of the mail system - it takes messages from
+      user-friendly mailer programs and arranges for them to be delivered
+      locally or passed on to other systems as required.
+      .
+      In order to make use of it you must have one or more user level
+      mailreader programs such as elm, pine, mailx or Emacs (which has Rmail
+      and VM as mailreaders) installed.  If you wish to send messages other
+      than just to other users of your system you must also have appropriate
+      networking support, in the form of IP or UUCP.
+
+
+File: guidelines.info,  Node: Configuration of init,  Next: Maintainer script arguments and how `dpkg' does things,  Prev: How to write the Description control file field,  Up: Appendix
+
+Configuration of init
+=====================
+
+   The `/etc/init.d' directory contains the scripts executed by init(8)
+when init state (or "runlevel") is changed.  This includes the boot
+process, when the multi-user state begins.  Several of these scripts
+are included with init and are intended to be executed *once*, usually
+at boot time.  An example is `/etc/init.d/boot', which is executed at
+boot time to check and mount file systems, activate swap, load kernel
+modules, etc.-everything that needs to be done before the multi-user
+state begins.  `/etc/init.d' also contains the scripts that are
+executed when entering runlevel 0 (halt), runlevel 1 (single-user) and
+runlevel 6 (reboot).
+
+   Packages can (and should) place scripts in `/etc/init.d' to start or
+stop services at boot time or during a change of runlevel.  These
+scripts should be named `/etc/init.d/'<package>, and they should accept
+one of two arguments: "start", which starts the services, or "stop",
+which stops the services.  These scripts should ensure that they will
+behave sensibly if invoked with "start" when the service is already
+running, or with "stop2 when it isn't--the best way to achieve this is
+often to use `start-stop-daemon'.
+
+   This script should not fail obscurely when the configuration files
+remain but the package has been removed, as the default in dpkg is to
+leave configuration files on the system after the package has been
+removed.  Only when it is executed with the `-purge' option will dpkg
+remove configuration files.  Therefore, you should include a `test'
+statement at the top of the script, like this:
+
+     test -f <program-executed-later-in-script> || exit 0
+
+   These scripts should be referenced, when appropriate, by symbolic
+links in the `/etc/rc?.d' directories, as below.
+
+   When changing runlevels, init looks in the directory `/etc/rc<n>.d'
+for the scripts it should execute, where <n> is the runlevel that is
+being changed to.  Please note that the "scripts" in `/etc/rc?.d' are
+not actually scripts; they are symbolic links, referencing actual
+scripts in `/etc/init.d'.  For simplicity, we refer to them as
+"scripts".
+
+   First, the scripts prefixed with a "K" are executed, followed by the
+scripts prefixed with an "S".  The "K" scripts are responsible for
+killing certain services and the "S" scripts for starting certain
+services upon *entering* the runlevel.  For example, if we are changing
+from runlevel 2 to runlevel 3, init will first execute all of the "K"
+prefixed scripts it finds in `/etc/rc3.d' (to kill services), and then
+all of the "S" prefixed scripts it finds in `/etc/rc3.d' (to start
+services).  The "K" scripts will execute the file it references with an
+argument of "stop", and the "S" scripts will execute this file with an
+argument of "start".
+
+   After the "K" or "S" prefix, there should be a number specified, and
+this number should be between 00 and 99.  The number determines the
+order in which the scripts are run.  For example, the "K20" scripts will
+be executed before the "K30" scripts.  You can use this number to make
+sure that a certain service is started before another.  For example, on
+some machines, the program `setserial' may need to properly set an IRQ
+before the `ppp' program uses a modem to connect to a network.  In this
+case, the script that runs `setserial' should have a lower number than
+the script that starts `ppp' so that it runs first:
+
+     `/etc/rc2.d/S10setserial'
+     `/etc/rc2.d/S20ppp'
+
+   If it does not matter when or in which order the script is run, use
+the number "20".  If it does, then you should talk to the maintainer of
+the `sysvinit' package or post to `debian-devel', and they will help
+you choose a number.
+
+   In Debian GNU/Linux, we try to ship our software in as much of a
+"default" state as possible.  Therefore, unless there is a good reason
+for doing differently, we ask that you start and stop the services in
+each of the multi-user state runlevels (2, 3, 4, and 5).  If a service
+needs to be stopped before a file system can be unmounted (an example is
+process accounting or quota services), then be sure to stop them in the
+halt runlevel (0), the single-user runlevel (1) and the reboot runlevel
+(6).
+
+   The system administrator will have the opportunity to customize
+runlevels by simply adding, moving, or removing the symbolic links in
+`/etc/rc?.d'.  This is why we default to running everything in the
+multi-user state-a reasonable default-and the administrator can easily
+customize init to be as complex and sophisticated as he or she wants it
+to be beyond this.
+
+   We provide a script, `update-rc.d', to make it easier for package
+maintainers to arrange for the proper creation and removal of
+`/etc/rc?.d' symbolic links from their postinst and postrm scripts.
+You should use this script to make changes to `/etc/rc?.d' and *never*
+include any `/etc/rc.?.d' symbolic links in the actual archive.
+
+   * In the postinst script, you need only do the following to setup
+     `/etc/rc?.d'.  You should redirect standard output to `/dev/null',
+     as `update-rc.d' produces insignificant output:
+
+          update-rc.d <package> default >/dev/null
+
+     where <package> is the name of the file as it appears in
+     `/etc/init.d'.  It will use the default number of "20", as
+     mentioned above.  If you need to use a different number, you can
+     specify it after "default":
+
+          update-rc.d <package> default 30 >/dev/null
+
+   * In the postrm script, you need only do the following *if and only
+     if* it is called with the `purge' argument:
+
+          if [ purge = "$1" ]
+          then
+            update-rc.d <package> remove >/dev/null
+          fi
+
+Important Note:
+---------------
+
+   *Do not* include the `/etc/rc?.d/*' symbolic links in the archive!
+*This will cause problems!*  You should create them with update-rc.d,
+as above.
+
+   *Do not* include the `/etc/rc?.d/*' symbolic links in conffiles!
+*This will cause problems!*  *Do*, however, include the `/etc/init.d'
+scripts in conffiles.
+
+Example:
+--------
+
+   The process accounting package wants to make sure that process
+accounting is started at boot time and that it is stopped before the
+system is halted, enters the single-user state, or is rebooted (so that
+the `/var' file system can be properly unmounted).  It puts a script
+that does this in `/etc/init.d', naming the script appropriately
+"acct".  This script accepts one of two arguments: either "start",
+which starts process accounting, or "stop", which stops it.  To ensure
+that it does not fail obscurely when the configuration files remain but
+the package has been removed, we include a `test' statement at the top
+of the script:
+
+     #! /bin/sh
+     #
+     # Start process accounting.
+     . /etc/init.d/functions
+     test -f /usr/sbin/accton || exit 0
+     case "$1" in
+       start)
+         echo "Starting process accounting"
+         /usr/sbin/accton /var/account/pacct
+         ;;
+       stop)
+         echo "Stopping process accounting"
+         /usr/sbin/accton
+         ;;
+       *)
+         echo "Usage: /etc/init.d/acct {start|stop}"
+         exit 1
+     esac
+     exit 0
+
+   You may find a skeletal script from which to base your `/etc/init.d'
+scripts in `/etc/init.d/skeleton'.
+
+   We want to stop then (re)start process accounting when entering a
+multi-user state-runlevels 2, 3, 4, and 5-and we want to stop it when
+leaving such a state-runlevels 0 (halt), 1 (single) and 6 (reboot).
+These are good defaults, and we accomplish this by including the
+following in the postinst:
+
+     update-rc.d acct default >/dev/null
+
+   When the user removes the acct packages with the `-purge' option, we
+want to make sure the `/etc/rc?.d' symbolic links are properly removed,
+so we include the following in the postrm:
+
+     update-rc.d acct remove >/dev/null
+
+   Otherwise, the `/etc/rc?.d' symbolic links will remain on the system
+along with `/etc/init.d/acct' script.
+
+
+File: guidelines.info,  Node: Maintainer script arguments and how `dpkg' does things,  Next: Mail processing packages,  Prev: Configuration of init,  Up: Appendix
+
+Maintainer script arguments and how `dpkg' does things
+======================================================
+
+   This appendix describes exactly how maintainer scripts are called,
+with what arguments, in what order, and what `dpkg' does in between.
+
+   In all cases version numbers are <version>-<revision>, if the package
+has both, or just <version>.  `upgrade' is used even when the new
+version number looks lower than the old.
+
+Summary
+-------
+
+     <new preinst> install
+     <new preinst> install <old-version>
+     <new preinst> upgrade <old-version>
+     <old preinst> abort-upgrade <new-version>
+     
+     <postinst> configure
+     <old postinst> abort-upgrade <new version>
+     <conflictor's postinst> abort-remove in-favour <package> <new version>
+     <deconfigured's postinst> abort-deconfigure \
+                   in-favour <package-being-installed-but-failed> <version>
+                   removing <conflicting-package> <version>
+     
+     <prerm> remove
+     <old prerm> upgrade <new version>
+     <new prerm> failed-upgrade <old-vppersion>
+     <conflictor's prerm> remove in-favour <package> <new version>
+     <deconfigured's prerm> deconfigure \
+                   in-favour <package-being-installed> <version> \
+                   removing <conflicting-package> <version>
+     
+     <postrm> remove
+     <postrm> purge
+     <old postrm> upgrade <new-version>
+     <new postrm> failed-upgrade <old-version>
+     <new postrm> abort-install
+     <new postrm> abort-install <old-version>
+     <new postrm> abort-upgrade <old-version>
+     <disappearer's postrm> disappear <overwriter> <new version>
+
+Details of unpack phase of installation or upgrade
+--------------------------------------------------
+
+   The procedure on installation/upgrade/overwrite/disappear (ie, when
+running `dpkg --unpack', or the unpack stage of `dpkg --install') is as
+follows.  In each case if an error occurs the actions in are general
+run backwards - this means that the maintainer scripts are run with
+different arguments in reverse order.  These are the `error unwind'
+calls listed below.
+
+  1.
+       a. If a version the package is already installed, call
+               <old prerm> upgrade <new version>
+
+       b. If this gives an error (ie, a non-zero exit status), dpkg will
+          attempt instead:
+               <new prerm> failed-upgrade <old-version>
+           error unwind, for both the above cases:
+               <old postinst> abort-upgrade <new version>
+
+  2. If a `conflicting' package is being removed at the same time:
+       a. If any packages depended on that conflicting package and
+          `--auto-deconfigure' is specified, call, for each such
+          package:
+               <deconfigured's prerm> deconfigure \
+                in-favour <package-being-installed> <version> \
+                removing <conflicting-package> <version>
+           error unwind:
+               <deconfigured's postinst> abort-deconfigure \
+                in-favour <package-being-installed-but-failed> <version>
+                removing <conflicting-package> <version>
+          The deconfigured packages are marked as requiring
+          configuration, so that if -install is used they will be
+          configured again if possible.
+
+       b. To prepare for removal of the conflicting package, call:
+               <conflictor's prerm> remove in-favour <package> <new version>
+           error unwind:
+               <conflictor's postinst> abort-remove in-favour <package> <new version>
+
+  3.
+       a. If the package is being upgraded, call
+               <new preinst> upgrade <old-version>
+
+       b. otherwise, if the package had some configuration files from a
+          previous version installed (ie, it is in the conffiles-only
+          state):
+               <new preinst> install <old-version>
+
+       c. otherwise (ie, the package was completely purged):
+               <new preinst> install
+           error unwind versions, respectively:
+               <new postrm> abort-upgrade <old-version>
+               <new postrm> abort-install <old-version>
+               <new postrm> abort-install
+
+  4. The new package's files are unpacked, overwriting any that may be
+     on the system already, for example any from the old package or
+     from another package (backups of the old files are left around,
+     and if anything goes wrong dpkg will attempt to put them back as
+     part of the error unwind).
+
+  5.
+       a. If the package is being upgraded, call
+               <old postrm> upgrade <new-version>
+
+       b. If this fails, dpkg will attempt:
+               <new postrm> failed-upgrade <old-version>
+           error unwind, for both cases:
+               <old preinst> abort-upgrade <new-version>
+          This is the point of no return - if dpkg gets this far, it
+     won't back off past this point if an error occurs.  This will
+     leave the package in a fairly bad state, which will require a
+     successful reinstallation to clear up, but it's when dpkg starts
+     doing things that are irreversible.
+
+  6. Any files which were in the old version of the package but not in
+     the new are removed.
+
+  7. The new file list replaces the old.
+
+  8. The new maintainer scripts replace the old.
+
+  9. Any packages all of whose files have been overwritten during the
+     installation, and which aren't required for dependencies, are
+     considered to have been removed.  For each such package,
+       a. dpkg calls:
+               <disappearer's postrm> disappear <overwriter> <new version>
+
+       b. The package's maintainer scripts are removed.
+
+       c. It is noted in the status database as being in a sane state,
+          namely not installed (any conffiles it may have are ignored).
+          Note that disappearing packages do not have their prerm
+          called, because dpkg doesn't know in advance that the package
+          is going to vanish.
+
+ 10. Any files in the package we're unpacking that are also listed in
+     the file lists of other packages are removed from those lists.
+     (This will lobotomise the file list of the `conflicting' package
+     if there is one.)
+
+ 11. The backup files made at 4. are deleted.
+
+ 12. The new package's status is now sane, and recorded as `unpacked'.
+     Here is another point of no return - if the conflicting package's
+     removal fails we do not unwind the rest of the installation; the
+     conflicting package is left in a half-removed limbo.
+
+ 13. If there was a conflicting package we go and do the removal
+     actions, starting from point 2. of the removal, below.
+
+Details of configuration
+------------------------
+
+   When we configure a package (this happens with `dpkg --install', or
+with `--configure'), we first update the conffiles and then call:
+     <postinst> configure <most-recently-configured-version>
+
+   No attempt is made to unwind after errors during configuration.
+
+Details of removal and/or configration purging
+----------------------------------------------
+
+  1.      <prerm> remove
+
+  2. The package's files are removed (except conffiles).
+
+  3.      <postrm> remove
+
+  4. All the maintainer scripts except the postrm are removed.
+
+     If we aren't purging the package we stop here.  Note that packages
+     which have no postrm and no conffiles are automatically purged
+     when removed, as there is no difference except for the dpkg status.
+
+  5. The conffiles and any backup files (`~'-files, `#*#' files,
+     `%'-files, .dpkg-{old,new,tmp}, etc.) are removed.
+
+  6.      <postrm> purge
+
+  7. The package's file list is removed.
+        No attempt is made to unwind after errors during removal.
+
+
+File: guidelines.info,  Node: Mail processing packages,  Next: Virtual dependencies,  Prev: Maintainer script arguments and how `dpkg' does things,  Up: Appendix
+
+Mail processing packages
+========================
+
+   Debian packages which process electronic mail (whether
+mail-user-agents (MUA) or alternative mail-transport-agents (MTA))
+*must* make sure that they are compatible with the configuration
+decisions below.  Failure to do this may result in lost mail, broken
+`From:' lines, and other serious brain damage!
+
+   * The mail spool is `/var/spool/mail' and the interface to send a
+     mail message is `/usr/sbin/sendmail' (as per the FSSTND).  The mail
+     spool is part of the base and not part of the MTA package.
+
+   * Mailboxes are locked using the `.lock' lockfile convention, rather
+     than fcntl, flock or lockf.
+
+   * Mailboxes are generally 660 `<user>.mail' unless the user has
+     chosen otherwise.  A MUA may remove a mailbox (unless it has
+     nonstandard permissions) in which case the MTA or another MUA must
+     recreate it if needed.  Mailboxes must be writeable by group mail.
+
+   * The mail spool is 2775 mail.mail, and MUA's need to be setgid mail
+     to do the locking mentioned above (and obviously need to avoid
+     accessing other users' mailboxes using this privilege).
+
+   * `/etc/aliases' is the source file for the system mail aliases (e.g.
+     postmaster, usenet, etc.) - it is the one which the sysadmin and
+     postinst scripts may edit.
+
+   * The convention of writing `forward to <address>' in the mailbox
+     itself is not supported.  Use a `.forward' file instead.
+
+   * The location for the `rmail' program used by UUCP for incoming mail
+     is `/usr/sbin/rmail', as per the FSSTND.  Likewise, `rsmtp', for
+     receiving batch-SMTP-over-UUCP, is in `/usr/sbin/rsmtp' if it is
+     supported.
+
+   * Smail is not using HoneyDanBer UUCP, whose uux apparently accepts
+     -a and -g options.
+
+   * If you need to know what name to use (for example) on outgoing
+     news and mail messages which are generated locally, you should use
+     the file `/etc/mailname'.  It will contain the portion after the
+     username and `@' sign for email addresses of users on the machine
+     (followed by a newline).
+
+   A package should check for the existence of this file.  If it exists
+it should use it without comment (1).  If it does not exist it should
+prompt the user for the value and store it in `/etc/mailname' as well
+as using it in the package's configuration.  The prompt should make it
+clear that the name will not just be used by that package.  E.g., in
+the same situation the INN package says:
+
+     Please enter the `mail name' of your system.  This is the hostname
+     portion of the address to be shown on outgoing news and mail messages.
+     The default is `$syshostname', your system's host name.
+     Mail name [`$syshostname']:
+   ($syshostname is the output of `hostname -fqdn').
+
+   ---------- Footnotes ----------
+
+   (1)  An MTA's prompting configuration script may wish to prompt the
+user even if it finds this file exists.
+
+
+File: guidelines.info,  Node: Virtual dependencies,  Prev: Mail processing packages,  Up: Appendix
+
+Virtual dependencies
+====================
+
+   Virtual packages are in the same namespace as real packages, and may
+have the same name.  The meaning of a virtual package in a
+dependency/conflicts list is exactly that of listing all the real
+packages which state that they are an instantiation of that virtual
+package.
+
+   This is done with a new Provides field in the control file, with a
+syntax much like the Conflicts field.
+
+   The idea is that we can have something like:
+     Package: elm
+     Depends: mta
+     
+     Package: smail
+     Provides: mta
+     Conflicts: mta
+     
+     Package: sendmail
+     Provides: mta
+     Conflicts: mta
+    The result is equivalent to elm having said
+     Package: elm
+     Depends: smail | sendmail
+
+   (There'll be a special case to say that a package may conflict with a
+virtual package which it provides - clearly ...)
+
+   If there are both a real and a virtual package of the same name then
+the dependency may be satisfied (or the conflict caused) by either the
+real package or any of the virtual packages which provide it.  This is
+so that, for example, supposing we have
+     Package: lout
+     Optional: ghostview
+   (this is a fictional example - the Lout package should not mention
+ghostview), and someone else comes up with a nice PostScript previewer,
+then they can just say
+     Package: marvelpostview
+     Provides: ghostview
+   and all will work in the interim (until, say, the Lout maintainer
+changes things).
+
+   If a dependency or a conflict has a version number attached then only
+real packages will be considered to see whether the relationship is
+satisfied (or prohibited, for a conflict) - it is assumed that a real
+package which provides virtual package is not of the `right' version.
+If there is demand it can be arranged that a package which provides a
+virtual package may mention a version number, though this is unlikely to
+be helpful:
+     Provides: mta (2.0)
+
+   If you want to specify which of a set of real packages should be the
+default to satisfy a particular dependency on a virtual package, you can
+simply list the real package as alternative before the virtual one:
+     Package: xbaseR6
+     Recommended: xsvga | x-server
+     Provides: x-base, xr6shlib
+     
+     Package: xsvga
+     Recommended: x-base
+     Provides: x-server
+     
+     Package: x8514
+     Recommended: x-base
+     Provides: x-server
+
+   Virtual package names should generally not be used in the names of
+`/etc/init.d' scripts, configuration files, logfiles, and so on, so
+that several programs providing the same virtual package name can be
+installed.
+
+

File diff suppressed because it is too large
+ 1936 - 0
doc/guidelines.texi


File diff suppressed because it is too large
+ 1056 - 0
doc/guidelines.texi.beforeeric


+ 33 - 0
doc/guidelines.texi.rej

@@ -0,0 +1,33 @@
+***************
+*** 376,390 ****
+  Generally the following compilation parameters should be used:
+  
+  @display
+-         CC = gcc
+-         CFLAGS = -O2
+-         LDFLAGS = -s (and -N, if appropriate; see below)
+  @end display
+  
+  All installed binaries should be stripped, hence @code{-s}.  @code{-N}
+  should only be used on binaries that are very small (less than 8K with
+  the @code{-N} option, roughly) and are not likely to have multiple
+- instances in memory.  Do not use @code{-N} on daemons, no matter how
+  small they are.
+  
+  It is up to the package maintainer to decide what compilation options
+--- 383,397 ----
+  Generally the following compilation parameters should be used:
+  
+  @display
++ CC = gcc
++ CFLAGS = -O2
++ LDFLAGS = -s (and -N, if appropriate; see below)
+  @end display
+  
+  All installed binaries should be stripped, hence @code{-s}.  @code{-N}
+  should only be used on binaries that are very small (less than 8K with
+  the @code{-N} option, roughly) and are not likely to have multiple
++ instances in memory.  Don't use @code{-N} on daemons, no matter how
+  small they are.
+  
+  It is up to the package maintainer to decide what compilation options

+ 29 - 0
doc/junk

@@ -0,0 +1,29 @@
+
+@table @file
+@item virtual-package-names-list.text
+The list of virtual package names currently in use, together with the
+procedure for getting new virtual package names allocated.
+@item (obsolete) README.etc-skel
+A description of @file{/etc/skel} and @file{/usr/doc/examples}
+(@pxref{Skeleton and examples}).
+@item (obsolete) descriptions.txt
+The description of the package. How to write an extended and more useful
+description field (@pxref{Package description}).
+@item (obsolete) README.init
+How to use the features of Init under Debian GNU/Linux in packages
+(@pxref{Configuration of init}).
+@item (obsolete) mailers.txt
+How to properly configure packages to use the Debian GNU/Linux mail
+nnsystem (@pxref{Mail processing packages}).
+@item (obsolete) maintainer-script-args.txt
+All the ways that the package maintainer scripts inside a package can be
+called by dpkg (@pxref{Maintainer script arguments}).
+@item (obsolete) dpkg-upgrades+errors.txt
+What order things happen in during a package upgrade (@pxref{What
+happends during a package upgrade?}).
+@item (obsolete) virtual-dependencies.txt
+How to use ``virtual dependencies'' in packages (@pxref{Virtual
+dependencies}).
+@item (obsolete) dependency-ordering.txt
+How to properly order package names in the @file{DEPENDS} field.
+@end table

+ 173 - 0
doc/maintainer-script-args.txt

@@ -0,0 +1,173 @@
+Richard Kettlewell has asked me to document this, so here is a brief
+summary.  More documentation will probably have to wait until someone
+has time ...
+
+... hmm, it has turned out not to be so brief, and I've spent the last
+hour or so writing it.  Perhaps someone can use it as the basis for a
+spec or a manpage or something.
+
+In all cases version numbers are <version>-<revision>, if the package
+has both, or just <version>.  `upgrade' is used even when the new
+version number looks lower than the old.
+
+*** SUMMARY - listing of possible scripts with arguments:
+
+ <new preinst> install
+ <new preinst> install <old-version>
+ <new preinst> upgrade <old-version>
+ <old preinst> abort-upgrade <new-version>
+
+ <postinst> configure
+ <old postinst> abort-upgrade <new version>
+ <conflictor's postinst> abort-remove in-favour <package> <new version>
+ <deconfigured's postinst> abort-deconfigure \
+               in-favour <package-being-installed-but-failed> <version>
+               removing <conflicting-package> <version>
+
+ <prerm> remove
+ <old prerm> upgrade <new version>
+ <new prerm> failed-upgrade <old-vppersion>
+ <conflictor's prerm> remove in-favour <package> <new version>
+ <deconfigured's prerm> deconfigure \
+               in-favour <package-being-installed> <version> \
+               removing <conflicting-package> <version>
+
+ <postrm> remove
+ <postrm> purge
+ <old postrm> upgrade <new-version>
+ <new postrm> failed-upgrade <old-version>
+ <new postrm> abort-install
+ <new postrm> abort-install <old-version>
+ <new postrm> abort-upgrade <old-version>
+ <disappearer's postrm> disappear <overwriter> <new version>
+
+*** INSTALLATION (unpack):
+
+The procedure on installation/upgrade/overwrite/disappear (ie, when
+running dpkg --unpack, or the unpack stage of dpkg --install) is as
+follows.  In each case if an error occurs the actions in are general
+run backwards - this means that the maintainer scripts are run with
+different arguments in reverse order.  These are the `error unwind'
+calls listed below.
+
+1a. If a version the package is already installed, call
+       <old prerm> upgrade <new version>
+1b. If this gives an error (ie, a non-zero exit status), dpkg will
+attempt instead:
+       <new prerm> failed-upgrade <old-version>
+   ... error unwind, for both the above cases:
+       <old postinst> abort-upgrade <new version>
+
+2. If a `conflicting' package is being removed at the same time:
+2a. If any packages depended on that conflicting package and
+--auto-deconfigure is specified, call, for each such package:
+       <deconfigured's prerm> deconfigure \
+               in-favour <package-being-installed> <version> \
+               removing <conflicting-package> <version>
+   ... error unwind:
+       <deconfigured's postinst> abort-deconfigure \
+               in-favour <package-being-installed-but-failed> <version>
+               removing <conflicting-package> <version>
+The deconfigured packages are marked as requiring configuration, so
+that if --install is used they will be configured again if possible.
+2b. To prepare for removal of the conflicting package, call:
+       <conflictor's prerm> remove in-favour <package> <new version>
+   ... error unwind:
+       <conflictor's postinst> abort-remove in-favour <package> <new version>
+
+3a. If the package is being upgraded, call
+       <new preinst> upgrade <old-version>
+3b. otherwise, if the package had some configuration files from a
+previous version installed (ie, it is in the conffiles-only state):
+       <new preinst> install <old-version>
+3c. otherwise (ie, the package was completely purged):
+       <new preinst> install
+   ... error unwind versions, respectively:
+       <new postrm> abort-upgrade <old-version>
+       <new postrm> abort-install <old-version>
+       <new postrm> abort-install
+
+4. The new package's files are unpacked, overwriting any that may be
+on the system already, for example any from the old package or from
+another package (backups of the old files are left around, and if
+anything goes wrong dpkg will attempt to put them back as part of the
+error unwind).
+
+5a. If the package is being upgraded, call
+       <old postrm> upgrade <new-version>
+5b. If this fails, dpkg will attempt:
+       <new postrm> failed-upgrade <old-version>
+   ... error unwind, for both cases:
+       <old preinst> abort-upgrade <new-version>
+
+This is the point of no return - if dpkg gets this far, it won't back
+off past this point if an error occurs.  This will leave the package
+in a fairly bad state, which will require a successful reinstallation
+to clear up, but it's when dpkg starts doing things that are
+irreversible.
+
+6. Any files which were in the old version of the package but not in
+   the new are removed.
+7. The new file list replaces the old.
+8. The new maintainer scripts replace the old.
+
+9. Any packages all of whose files have been overwritten during the
+installation, and which aren't required for dependencies, are
+considered to have been removed.  For each such package, 
+9a. dpkg calls:
+       <disappearer's postrm> disappear <overwriter> <new version>
+9b. The package's maintainer scripts are removed.
+9c. It is noted in the status database as being in a sane state,
+namely not installed (any conffiles it may have are ignored).
+Note that disappearing packages don't have their prerm called, because
+dpkg doesn't know in advance that the package is going to vanish.
+
+10. Any files in the package we're unpacking that are also listed in
+the file lists of other packages are removed from those lists.  (This
+will lobotomise the file list of the `conflicting' package if there is
+one.)
+
+11. The backup files made at 4. are deleted.
+12. The new package's status is now sane, and recorded as `unpacked'.
+
+Here is another point of no return - if the conflicting package's
+removal fails we don't unwind the rest of the installation; the
+conflicting package is left in a half-removed limbo.
+
+13. If there was a conflicting package we go and do the removal
+actions, starting from point 2. of the removal, below.
+
+
+*** CONFIGURATION:
+
+When we configure a package (this happens with dpkg --install, or with
+--configure), we first update the conffiles and then call:
+       <postinst> configure
+(I'm planning to make available as an argument the version of the most
+recent successfully-configured version of the package.)
+
+No attempt is made to unwind after errors during configuration.
+
+
+*** REMOVAL:
+
+1.     <prerm> remove
+
+2. The package's files are removed (except conffiles).
+
+3.     <postrm> remove
+
+4. All the maintainer scripts except the postrm are removed.
+
+If we aren't purging the package we stop here.  Note that packages
+which have no postrm and no conffiles are automatically purged when
+removed, as there is no difference except for the dpkg status.
+
+5. The conffiles and any backup files (~-files, #*# files, %-files,
+.dpkg-{old,new,tmp}, &c &c &c) are removed.
+
+6.     <postrm> purge
+
+7. The package's file list is removed.
+
+No attempt is made to unwind after errors during removal.

+ 220 - 0
doc/upgrades+errors.txt

@@ -0,0 +1,220 @@
+From ian Wed Nov 16 15:12:56 1994 
+X-VM-v5-Data: ([nil nil nil nil t nil nil nil nil]
+	[nil "Wed" "16" "November" "1994" "15:12:56" nil "ian" "ian" "" nil "dpkg - upgrades and error handling, take 2" "^To:" nil nil "11" nil nil nil nil]
+	nil)
+To: Debian dpkg list <debian-dpkg@pixar.com>
+Subject: dpkg - upgrades and error handling, take 2
+
+Here is a revised scheme for upgrade procedure and error handling.
+
+If you can see any serious problems with this please say so; if there
+are no compelling reasons not to I intend to implement the following.
+
+
+Procedure for new unpack:
+  * Run the preinst script (argument: `install').
+  * Back up the conffiles.
+  * Unpack the files in the package.
+This leaves the package in the `unpacked but not configured'
+state.
+
+If the preinst fails the installation is aborted immediately, leaving
+the package in whatever state it was originally.  The preinst should
+clean up after its own failure.
+
+If the conffiles can't be backed up then any which have been are
+restored to their original names, if possible, and the postrm script
+is run if there is one (argument: `abort-install').  This leaves the
+package in its original state.
+
+If the unpack fails any files already unpacked are removed, the
+conffiles are restored to their original names, and the postrm is run
+(argument: `abort-install').  Again, the package remains in its
+original state.
+
+Errors found when running the postrm are ignored.
+
+
+Procedure for configuration:
+  * Do the conffile updating, including prompting, as in the spec.
+  * Run the postinst (argument: `configure').
+
+If the conffile updating fails anything that has been done is undone
+if possible and the package is left in the `unpacked but not
+configured' state.
+
+If the postinst fails dpkg gives up and leaves the package in the
+`postinst failed' state.  Next time it will just rerun the
+postinst; if the postinst has a bug a new *.deb can be provided.  In
+that case installation of the new *.deb will proceed almost as if it
+were a normal upgrade.
+
+
+Procedure for removal:
+  * Run the prerm (argument: `remove').
+  * Delete the files in the package and any resulting empty
+    directories.
+  * Run the postrm (argument: `remove').
+
+If the prerm fails dpkg leaves the package in the original state; if
+the user asks again to remove the package the prerm will be run again.
+
+If the deletion fails the removal is aborted, and the package left in
+the `removal failed' state.
+
+If the postrm fails dpkg leaves the package in the `removal failed'
+state.
+
+If the package is in the `removal failed' state to start with it will
+start again with deleting the files and empty directories and rerun
+the postrm.
+
+If the postrm has a bug a new *.deb must be installed first (using the
+upgrade procedure) and then removed.  This is so that a working postrm
+script is provided.
+
+
+Procedure for upgrade:
+   * Run the old prerm script (arguments: `upgrade <new-version>').
+   * Move aside all existing files (not directories) for the
+     package being overwritten.
+   * Run the old postrm script (arguments: `upgrade <new-version>').
+   * Run the new preinst script (arguments: `upgrade <old-version>').
+   * Back up the conffiles.
+   * Unpack the files in the package.
+   * Remove the files which were moved aside.
+This leaves the package in the `unpacked but not configured'
+state.
+
+Errors during the removal of the files which were moved aside are
+flagged, but don't cause dpkg to attempt to abort the upgrade.
+
+If the old prerm or postrm script fails the corresponding script from
+the new package is run instead (arguments: `failed-upgrade
+<old-version>').  If there is no corresponding script in the new
+package the error is ignored.
+
+If any other stage fails, or if we try to use the script in the new
+package because the old prerm/postrm script failed but the new script
+fails too, we attempt to undo everything in reverse order, as follows:
+
+Unpacking the files in the package is undone by removing the files we
+unpacked and any empty directories, in reverse order.  Errors are
+ignored.
+
+The conffiles backup is undone as much as possible, ignoring errors.
+
+The new preinst is undone by running the new postrm (arguments:
+`abort-upgrade <old-version>'); errors are ignored.
+
+The old postrm is undone by running the old preinst (arguments:
+`abort-upgrade <new-version>'); errors are ignored.
+
+Files we backed up are restored if possible; errors here leave the
+package in the `removal failed' state.
+
+The old prerm is undone by running the old postinst (arguments:
+`abort-upgrade <new-version>').  Errors here leave the package in the
+`postinst failed' state.
+
+
+Ian.
+
+From ian Wed May 17 02:14:09 +0100 1995
+X-VM-v5-Data: ([nil nil nil nil nil nil nil nil nil]
+	[nil nil nil nil nil nil nil nil nil nil nil nil "^To:" nil nil nil nil nil nil nil]
+	nil)
+To: Debian developers list <debian-devel@pixar.com>
+Subject: New dpkg overwriting handling
+
+Here is a comment that describes how I plan to have the new C dpkg act
+with respect to overwriting, upgrades, &c.
+
+The sequence of events during upgrade will change, because the removal
+of the old package and the installation of the new will take place
+together.  So we have,
+
+ (noninteractive, during `dpkg --unpack' ...)
+  old prerm
+  new preinst
+  unpack new archive, possibly overwriting old files
+  delete any files in the old but not the new package
+  old postrm
+  run `postrm disappear' for any vanished packages, then forget them
+
+ (interactive, during `dpkg --configure' ...)
+  conffile updates
+  new postinst
+
+Furthermore, conffiles will not be backed up before unpack and have
+the user's old version hang around as `.dpkg-tmp'; instead, the old
+file will be left in place and the new one extracted into `.dpkg-new'.
+It will only be installed (if desired) at a conffile update.
+
+Thanks to Bruce for providing nice tar-in-a-function code that will
+allow me to handle each file individually rather than having tar splat
+them all out (and often do it buggily anyway).
+
+Ian.
+
+  /*
+   * Now we unpack the archive, backing things up as we go.
+   * For each file, we check to see if it already exists.
+   * There are several possibilities:
+   * + We are trying to install a non-directory ...
+   *  - It doesn't exist.  In this case we simply extract it.
+   *  - It is a plain file, device, symlink, &c.  We do an `atomic
+   *    overwrite' using link() and rename(), but leave a backup copy.
+   *    Later, when we delete the backup, we remove it from any other
+   *    packages' lists.
+   * -  It is a directory.  We move it aside and extract the file.
+   *    Later, when we delete the backed-up directory, we remove it
+   *    from any other packages' lists.
+   * + We are trying to install a directory ...
+   *  - It doesn't exist.  We create it with the appropriate modes.
+   *  - It is a plain file or a symlink.  We move it aside and create
+   *    the directory.  Later, when we delete the backup, we remove it
+   *    from any other packages' lists.
+   *  - It exists as a directory.  We do nothing.
+   *
+   *                   Install non-dir              Install dir
+   *  Exists not               X                          C
+   *  File/node/symlink       LXR                        BCR
+   *  Directory               BXR                         -
+   *
+   *    C: create directory
+   *    X: extract file/node/link
+   *   LX: atomic overwrite leaving backup
+   *    B: ordinary backup
+   *    R: later remove from other packages' lists
+   *    -: do nothing
+   * 
+   * After we've done this we go through the remaining things in the
+   * lists of packages we're trying to remove (including the old
+   * version of the current package).  This happens in reverse order,
+   * so that we process files before the directories (or symlinks-to-
+   * directories) containing them.
+   * + If the thing is a conffile then we leave it alone for the purge
+   *   operation.
+   * + Otherwise, there are several possibilities too:
+   *  - The listed thing does not exist.  We ignore it.
+   *  - The listed thing is a directory or a symlink to a directory.
+   *    We delete it only if it isn't listed in any other package.
+   *  - The listed thing is not a directory or a symlink to one (ie,
+   *    it's a plain file, device, pipe, &c, or a symlink to one, or a
+   *    dangling symlink).  We delete it.
+   * The removed packages' list becomes empty (of course, the new
+   * version of the package we're installing will have a new list,
+   * which replaces the old version's list).
+   *
+   * If at any stage we remove a file from a package's list, and the
+   * package isn't one we're already processing, and the package's
+   * list becomes empty as a result, we `vanish' the package.  This
+   * means that we run its postrm with the `disappear' argument, and
+   * put the package in the `not-installed' state.  Its conffiles are
+   * ignored and forgotten about.
+   *
+   * NOTE THAT THE OLD POSTRM IS RUN AFTER THE NEW PREINST, since the
+   * files get replaced `as we go'.
+   */
+

+ 59 - 0
doc/version-ordering.txt

@@ -0,0 +1,59 @@
+(This has been edited to conform to the intent in dpkg 1.0.16.
+ When recent versions of dpkg compare versions they break the Version
+ into an upstream version and debian revision first, by splitting the
+ Version at the last hyphen.  The revisions are only considered if the
+ upstream versions compare equal.)
+
+To: debian-devel@pixar.com
+Subject: Re: dpkg 0.93.8 released
+
+[...]
+Well, here is what I came up with after a bit of thought and testing.
+I propose the following algorithm for comparing version numbers:
+
+   forever {
+     remove initial non-digit substring from string a
+     remove initial non-digit substring from string b
+     compare initial non-digit substrings lexically,
+       counting letters as coming before punctuation
+     if (they differ) return the answer
+     remove initial digit substring from string a
+     remove initial digit substring from string b
+     compare initial digit substrings numerically
+     if (they differ) return the answer
+     if (both strings are now empty)
+       the version numbers are the same, stop
+     if (one string is now empty)
+       it is the `lesser', return the answer
+   }
+
+This will have the desired results:
+   2.1 < 2.7 < 2.7a < 2.7a-2 < 2.15
+
+An implementation in Perl is attached below.
+
+Ian.
+
+#!/usr/bin/perl --
+
+if (@ARGV) {
+    print &compare(@ARGV),"\n";
+} else {
+    while(<>) { chop; chop($x=<>); print &compare($_,$x),"\n"; }
+}                
+
+sub compare {
+    local ($a,$b) = @_;
+    do {
+        $a =~ s/^\D*//; $ad= $&; $ad =~ s/\W/ /g;
+        $b =~ s/^\D*//; $bd= $&; $bd =~ s/\W/ /g;
+print "\t[$ad|$a] [$bd|$b]\n";
+        $cm = $ad cmp $bd;  return $cm if $cm;
+        $a =~ s/^\d*//; $ad= $&;
+        $b =~ s/^\d*//; $bd= $&;
+print "\t<$ad|$a> <$bd|$b>\n";
+        $cm = $ad <=> $bd;  return $cm if $cm;
+    } while (length($a) && length($b));
+print "\t{$a} {$b}\n";
+    return length($a) cmp length($b);
+}

+ 105 - 0
doc/virtual-dependencies.txt

@@ -0,0 +1,105 @@
+To: Debian users list <debian-user@pixar.com>
+Subject: dpkg 0.93.36: dselect does virtual packages
+
+This release contains virtual package support in the C parts of the
+system, which at the moment includes dselect and dpkg-deb.
+
+It works as I outlined in a mail to debian-devel a little while ago.
+
+Package maintainers: please start adding `Provides:' fields to your
+packages.  dselect will use and understand them; dpkg-deb will check
+the syntax of the Provides field instead of warning you about it.
+dpkg will not understand the new field and will ignore it.
+
+When almost all the packages have Provides: fields in place we can
+start replacing old-style Recommended: fields.
+
+Note that we can't change Depends: fields since they're also
+interpreted by dpkg, which doesn't know about Provides (yet).
+
+[...]
+--------------------
+
+From: iwj10@cus.cam.ac.uk (Ian Jackson)
+To: debian-devel@pixar.com
+Subject: `virtual' packages in Depends, Conflicts &c
+Date: Fri, 31 Mar 95 15:44 BST
+
+We're starting to have a problem with package name changes and
+multiple packages providing the same service.
+
+I liked the idea (put forward by [Bruce Perens]) of having `virtual'
+packages; it seems that it would solve many of these problems straight
+away.
+
+What I'm proposing to do is as follows:
+
+Depends, Conflicts, Recommended and Optional lines will now be able to
+contain `virtual' package names as well as real package names.
+
+Virtual packages are in the same namespace as real packages, and may
+have the same name.  The meaning of a virtual package in a
+dependency/conflicts list is exactly that of listing all the real
+packages which state that they are an instantiation of that virtual
+package.
+
+This is done with a new Provides field in the control file, with a
+syntax much like the Conflicts field.
+
+The idea is that we can have something like:
+ Package: elm
+ Depends: mta
+
+ Package: smail
+ Provides: mta
+ Conflicts: mta
+
+ Package: sendmail
+ Provides: mta
+ Conflicts: mta
+&c.  The result is equivalent to elm having said
+ Depends: smail | sendmail
+
+(There'll be a special case to say that a package may conflict with a
+virtual package which it provides - clearly ...)
+
+If there are both a real and a virtual package of the same name then
+the dependency may be satisfied (or the conflict caused) by either the
+real package or any of the virtual packages which provide it.  This is
+so that, for example, supposing we have
+ Package: lout
+ Optional: ghostview
+(this is a fictional example - the Lout package shouldn't mention
+ghostview), and someone else comes up with a nice PostScript
+previewer, then they can just say
+ Package: marvelpostview
+ Provides: ghostview
+and all will work in the interim (until, say, the Lout maintainer
+changes things).
+
+If a dependency or a conflict has a version number attached then only
+real packages will be considered to see whether the relationship is
+satisfied (or prohibited, for a conflict) - it is assumed that a real
+package which provides virtual package is not of the `right' version.
+If there is demand I could arrange that a package which provides a
+virtual package may mention a version number, eg.
+  Provides: mta (2.0)
+though I tbink this is unlikely to be helpful.
+
+If you want to specify which of a set of real packages should be the
+default to satisfy a particular dependency on a virtual package, you
+can simply list the real package as alternative before the virtual
+one.  E.g.:
+ Package: xbaseR6
+ Recommended: xsvga | x-server
+ Provides: x-base, xr6shlib
+
+ Package: xsvga
+ Recommended: x-base
+ Provides: x-server
+
+ Package: x8514
+ Recommended: x-base
+ Provides: x-server
+
+Ian.

+ 66 - 0
dpkg-deb/Makefile.in

@@ -0,0 +1,66 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+
+SRC = main.c build.c extract.c info.c
+OBJ = main.o build.o extract.o info.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+LDFLAGS = $(XLDFLAGS)
+LIBS = -L../lib -ldpkg $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+
+.SUFFIXES:	.c .o
+
+.c.o:
+		$(CC) $(ALL_CFLAGS) -c $<
+
+all:		dpkg-deb
+
+dpkg-deb:	$(OBJ) ../lib/libdpkg.a
+		$(CC) $(LDFLAGS) -o dpkg-deb $(OBJ) $(LIBS)
+
+$(OBJ):				dpkg-deb.h ../config.h ../include/dpkg.h
+build.o:			../include/dpkg-db.h
+info.o extract.o main.o:	../include/myopt.h
+main.o:				../version.h
+
+clean:
+		rm -f *.o core dpkg-deb
+
+distclean:	clean
+		rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:	all
+		$(INSTALL_PROGRAM) -s dpkg-deb $(bindir)/dpkg-deb
+		$(INSTALL_DATA) dpkg-deb.8 $(man8dir)/dpkg-deb.$(man8)

+ 267 - 0
dpkg-deb/build.c

@@ -0,0 +1,267 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * build.c - building archives
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "dpkg-deb.h"
+
+#ifndef S_ISLNK
+# define S_ISLNK(mode) ((mode&0xF000) == S_IFLNK)
+#endif
+
+static void checkversion(const char *vstring, const char *fieldname, int *errs) {
+  const char *p;
+  if (!vstring || !*vstring) return;
+  for (p=vstring; *p; p++) if (isdigit(*p)) return;
+  fprintf(stderr, BACKEND " - error: %s field (`%s') doesn't contain any digits\n",
+          fieldname, vstring);
+  (*errs)++;
+}
+
+void do_build(const char *const *argv) {
+  static const char *const maintainerscripts[]= {
+    PREINSTFILE, POSTINSTFILE, PRERMFILE, POSTRMFILE, 0
+  };
+  
+  char *m;
+  const char *debar, *directory, *const *mscriptp;
+  char *controlfile;
+  struct pkginfo *checkedinfo;
+  struct arbitraryfield *field;
+  FILE *ar, *gz, *cf;
+  int p1[2],p2[2], warns, errs, n, c;
+  pid_t c1,c2,c3,c4,c5;
+  struct stat controlstab, datastab, mscriptstab;
+  char conffilename[MAXCONFFILENAME+1];
+  time_t thetime= 0;
+  
+  directory= *argv++; if (!directory) badusage("--build needs a directory argument");
+  if ((debar= *argv++) !=0) {
+    if (*argv) badusage("--build takes at most two arguments");
+  } else {
+    m= m_malloc(strlen(directory) + sizeof(DEBEXT));
+    strcpy(m,directory); strcat(m,DEBEXT);
+    debar= m;
+  }
+  
+  if (nocheckflag) {
+    printf(BACKEND ": warning, not checking contents of control area.\n"
+           BACKEND ": building an unknown package in `%s'.\n", debar);
+  } else {
+    controlfile= m_malloc(strlen(directory) + sizeof(BUILDCONTROLDIR) +
+                          sizeof(CONTROLFILE) + sizeof(CONFFILESFILE) +
+                          sizeof(POSTINSTFILE) + sizeof(PREINSTFILE) +
+                          sizeof(POSTRMFILE) + sizeof(PRERMFILE) +
+                          MAXCONFFILENAME + 5);
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/" CONTROLFILE);
+    warns= 0; errs= 0;
+    parsedb(controlfile, pdb_recordavailable|pdb_rejectstatus,
+            &checkedinfo, stderr, &warns);
+    assert(checkedinfo->available.valid);
+    if (checkedinfo->priority == pri_other) {
+      fprintf(stderr, "warning, `%s' contains user-defined Priority value `%s'\n",
+              controlfile, checkedinfo->otherpriority);
+      warns++;
+    }
+    for (field= checkedinfo->available.arbs; field; field= field->next) {
+      fprintf(stderr, "warning, `%s' contains user-defined field `%s'\n",
+              controlfile, field->name);
+      warns++;
+    }
+    checkversion(checkedinfo->available.version,"Version",&errs);
+    checkversion(checkedinfo->available.revision,"Revision",&errs);
+    if (errs) ohshit("%d errors in control file",errs);
+    printf(BACKEND ": building package `%s' in `%s'.\n", checkedinfo->name, debar);
+
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/");
+    if (lstat(controlfile,&mscriptstab)) ohshite("unable to stat control directory");
+    if (!S_ISDIR(mscriptstab.st_mode)) ohshit("control directory is not a directory");
+    if ((mscriptstab.st_mode & 07757) != 0755)
+      ohshit("control directory has bad permissions %03lo (must be >=0755 "
+             "and <=0775)", (unsigned long)(mscriptstab.st_mode & 07777));
+
+    for (mscriptp= maintainerscripts; *mscriptp; mscriptp++) {
+      strcpy(controlfile, directory);
+      strcat(controlfile, "/" BUILDCONTROLDIR "/");
+      strcat(controlfile, *mscriptp);
+
+      if (!lstat(controlfile,&mscriptstab)) {
+        if (S_ISLNK(mscriptstab.st_mode)) continue;
+        if (!S_ISREG(mscriptstab.st_mode))
+          ohshit("maintainer script `%.50s' is not a plain file or symlink",*mscriptp);
+        if ((mscriptstab.st_mode & 07557) != 0555)
+          ohshit("maintainer script `%.50s' has bad permissions %03lo "
+                 "(must be >=0555 and <=0775)",
+                 *mscriptp, (unsigned long)(mscriptstab.st_mode & 07777));
+      } else if (errno != ENOENT) {
+        ohshite("maintainer script `%.50s' is not stattable",*mscriptp);
+      }
+    }
+
+    strcpy(controlfile, directory);
+    strcat(controlfile, "/" BUILDCONTROLDIR "/" CONFFILESFILE);
+    if ((cf= fopen(controlfile,"r"))) {
+      while (fgets(conffilename,MAXCONFFILENAME+1,cf)) {
+        n= strlen(conffilename);
+        if (!n) ohshite("empty string from fgets reading conffiles");
+        if (conffilename[n-1] != '\n') {
+          fprintf(stderr, "warning, conffile name `%.50s...' is too long", conffilename);
+          warns++;
+          while ((c= getc(cf)) != EOF && c != '\n');
+          continue;
+        }
+        conffilename[n-1]= 0;
+        strcpy(controlfile, directory);
+        strcat(controlfile, "/");
+        strcat(controlfile, conffilename);
+        if (lstat(controlfile,&controlstab)) {
+          if (errno == ENOENT)
+            ohshit("conffile `%.250s' does not appear in package",conffilename);
+          else
+            ohshite("conffile `%.250s' is not stattable",conffilename);
+        } else if (!S_ISREG(controlstab.st_mode)) {
+          fprintf(stderr, "warning, conffile `%s'"
+                  " is not a plain file\n", conffilename);
+          warns++;
+        }
+      }
+      if (ferror(cf)) ohshite("error reading conffiles file");
+      fclose(cf);
+    } else if (errno != ENOENT) {
+      ohshite("error opening conffiles file");
+    }
+    if (warns) {
+      if (fprintf(stderr, BACKEND ": ignoring %d warnings about the control"
+                  " file(s)\n", warns) == EOF) werr("stderr");
+    }
+  }
+  if (ferror(stdout)) werr("stdout");
+  
+  if (!(ar=fopen(debar,"wb"))) ohshite("unable to create `%.255s'",debar);
+  if (setvbuf(ar, 0, _IONBF, 0)) ohshite("unable to unbuffer `%.255s'",debar);
+  m_pipe(p1);
+  if (!(c1= m_fork())) {
+    m_dup2(p1[1],1); close(p1[0]); close(p1[1]);
+    if (chdir(directory)) ohshite("failed to chdir to `%.255s'",directory);
+    if (chdir(BUILDCONTROLDIR)) ohshite("failed to chdir to .../" BUILDCONTROLDIR);
+    execlp(TAR,"tar","-cf","-",".",(char*)0); ohshite("failed to exec tar -cf");
+  }
+  close(p1[1]);
+  if (!(gz= tmpfile())) ohshite("failed to make tmpfile (control)");
+  if (!(c2= m_fork())) {
+    m_dup2(p1[0],0); m_dup2(fileno(gz),1); close(p1[0]);
+    execlp(GZIP,"gzip","-9c",(char*)0); ohshite("failed to exec gzip -9c");
+  }
+  close(p1[0]);
+  waitsubproc(c2,"gzip -9c",0);
+  waitsubproc(c1,"tar -cf",0);
+  if (fstat(fileno(gz),&controlstab)) ohshite("failed to fstat tmpfile (control)");
+  if (oldformatflag) {
+    if (fprintf(ar, "%-8s\n%ld\n", OLDARCHIVEVERSION, (long)controlstab.st_size) == EOF)
+      werr(debar);
+  } else {
+    thetime= time(0);
+    if (fprintf(ar,
+                "!<arch>\n"
+                "debian-binary   %-12lu0     0     100644  %-10ld`\n"
+                ARCHIVEVERSION "\n"
+                "%s"
+                ADMINMEMBER "%-12lu0     0     100644  %-10ld`\n",
+                thetime,
+                (long)sizeof(ARCHIVEVERSION),
+                (sizeof(ARCHIVEVERSION)&1) ? "\n" : "",
+                (unsigned long)thetime,
+                (long)controlstab.st_size) == EOF)
+      werr(debar);
+  }                
+                
+  if (lseek(fileno(gz),0,SEEK_SET)) ohshite("failed to rewind tmpfile (control)");
+  if (!(c3= m_fork())) {
+    m_dup2(fileno(gz),0); m_dup2(fileno(ar),1);
+    execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat (control)");
+  }
+  waitsubproc(c3,"cat (control)",0);
+  
+  if (!oldformatflag) {
+    fclose(gz);
+    if (!(gz= tmpfile())) ohshite("failed to make tmpfile (data)");
+  }
+  m_pipe(p2);
+  if (!(c4= m_fork())) {
+    m_dup2(p2[1],1); close(p2[0]); close(p2[1]);
+    if (chdir(directory)) ohshite("failed to chdir to `%.255s'",directory);
+    execlp(TAR,"tar","--exclude",BUILDCONTROLDIR,"-cf","-",".",(char*)0);
+    ohshite("failed to exec tar --exclude");
+  }
+  close(p2[1]);
+  if (!(c5= m_fork())) {
+    m_dup2(p2[0],0); close(p2[0]);
+    m_dup2(oldformatflag ? fileno(ar) : fileno(gz),1);
+    execlp(GZIP,"gzip","-9c",(char*)0);
+    ohshite("failed to exec gzip -9c from tar --exclude");
+  }
+  close(p2[0]);
+  waitsubproc(c5,"gzip -9c from tar --exclude",0);
+  waitsubproc(c4,"tar --exclude",0);
+  if (!oldformatflag) {
+    if (fstat(fileno(gz),&datastab)) ohshite("failed to fstat tmpfile (data)");
+    if (fprintf(ar,
+                "%s"
+                DATAMEMBER "%-12lu0     0     100644  %-10ld`\n",
+                (controlstab.st_size & 1) ? "\n" : "",
+                (unsigned long)thetime,
+                (long)datastab.st_size) == EOF)
+      werr(debar);
+
+    if (lseek(fileno(gz),0,SEEK_SET)) ohshite("failed to rewind tmpfile (data)");
+    if (!(c3= m_fork())) {
+      m_dup2(fileno(gz),0); m_dup2(fileno(ar),1);
+      execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat (data)");
+    }
+    waitsubproc(c3,"cat (data)",0);
+
+    if (datastab.st_size & 1)
+      if (putc('\n',ar) == EOF)
+        werr(debar);
+  }
+  if (fclose(ar)) werr(debar);
+                             
+  exit(0);
+}
+

+ 3 - 0
dpkg-deb/debugmake

@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make XCFLAGS='-g -O0' LDFLAGS=-g LIBS='-lefence -L../lib -ldpkg' "$@"

+ 130 - 0
dpkg-deb/dpkg-deb.8

@@ -0,0 +1,130 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.\" Authors: Raul Miller and Ian Jackson
+.TH DPKG\-DEB 8 "29 Nov 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME 
+dpkg\-deb \- Debian GNU/Linux package archive backend
+.SH SYNOPSIS
+.B dpkg-deb --version
+.LP
+.B dpkg-deb
+.BR -X | --vextract
+.I <deb>
+.RI [ <directory> ]
+.LP
+.B dpkg-deb
+.BR -b | --build
+.RB [ --nocheck ]
+.I <directory>
+.RI [ <deb> ]
+.LP
+.B dpkg-deb
+.BR -c | --contents
+.I <deb>
+.LP
+.B dpkg-deb
+.BR -e | --control
+.I <deb>
+.RI [ <directory> ]
+.LP
+.B dpkg-deb
+.BR -f | --field
+.I <deb>
+.RI [ <cfield> ]...
+.LP
+.B dpkg-deb
+.BR -h | --help
+.LP
+.B dpkg-deb
+.BR -I | --info
+.I <deb>
+.RI [ <cfile> ]
+.LP
+.B dpkg-deb
+.BR -x | --extract 
+.I <deb> <directory>
+.LP
+.B dpkg-deb
+.BR -D | --debug
+.I <invocation-options>
+.SH DESCRIPTION
+.B dpkg-deb
+packs and unpacks debian archives.  It tracks file permissions, and
+includes support for the staged unpacking mechanism required by debian.
+.SH OPTIONS
+.I <deb>
+is the filename of a Debian format archive.
+.I <cfile>
+is the name of an administrative file component.
+.I <cfield>
+is the name of a field in the main `control' file.
+.LP
+.B --version
+displays the version number.
+.LP
+.BR -X | --vextract
+extracts files from archive and lists archive's contents.
+.LP
+.BR -b | --build
+makes a debian archive from the image of
+.IR <directory> .
+.I <directory>
+must have a
+.B DEBIAN
+subdirectory, which is treated specially for the debian-specific
+control file and any pre- or post-install scripts.
+
+The
+.B DEBIAN
+directory must contain a file called
+.B control
+whose contents is a valid control file for the Debian package
+management system.  Errors in this file will abort the processing of
+the package.  This check can be bypassed by the use of the
+.B --nocheck
+option.
+.LP
+.BR -c | --contents
+lists the contents of the archive on stdout.
+.LP
+.BR -e | --control
+extracts the control file from the archive.
+If no target directory is specified, the control files are extracted
+into
+.BR ./DEBIAN .
+.LP
+.BR -f | --field
+displays [named field(s) from] the control file.
+.LP
+.BR -h | --help
+displays summary of usage.
+.LP
+.BR -I | --info
+describes the archive, on stdout.
+.LP
+.BR -x | --extract
+extracts files from archive.
+.LP
+.BR -D | --debug
+would enable debugging.
+.SH NOTES
+.B dpkg-deb
+packs and unpacks *.deb files, but does not deal with any of the
+larger administrative issues of installing/de-installing packages.
+.SH SEE ALSO
+.BR deb (5),
+.BR deb-control (5),
+.BR dpkg (5),
+.BR dpkg (8),
+.BR dselect (8).
+.SH BUGS
+.B dpkg-deb -I 
+.IB package1 .deb
+.IB package2 .deb
+does the wrong thing.
+
+This manpage is too terse and fails to document all the options.  If
+you are a competent and accurate writer and are willing to spend the
+time reading the source and writing good manpages please
+please write a better man page than this one.
+.LP
+Still being developed, as of 29th November 1995.

+ 133 - 0
dpkg-deb/dpkg-deb.8-vuori

@@ -0,0 +1,133 @@
+.TH dpkg-deb 8
+.SH NAME
+dpkg-deb - a low-level package manager for Debian GNU/Linux
+
+.SH SYNOPSIS
+
+.B dpkb-deb
+[options] action
+
+.SH DESCRIPTION
+
+.B Dpkg-deb
+is a low-level tool to build, and manage Debian GNU/Linux packages.
+The dpkg-deb is intended to be used via
+.B dpkg(8)
+tool. The actions described here can be given to
+.B dpkg
+also. What
+.B dpkg
+actually does with them is that it runs
+.B dpkg-deb
+with those parameters. However, using
+.B dpkg
+instead of
+.B dpkg-deb
+is a better idea, for it can be used more generally with all Debian
+package handling.
+
+dpkg-deb is operated via two different types of command
+line parameters: actions and options. The actions tell dpkg-deb what
+to do and options control the behaviour of the action in some way.
+
+.SS ACTIONS
+
+.TP
+.B dpkg-deb -b|--build <directory> [<filename>]
+Build a Debian package named
+.I <filename>
+from files in
+.I <directory>.
+If filename is not specified, a file called
+.I <directory>.deb
+is created instead. The directory
+.I <directory>/DEBIAN
+must contain a special file named 
+.I control
+and may optionally contain other control files too.
+See
+.B deb(5)
+for more information about those files.
+.TP
+.B dpkg-deb -I|--info <filename> [<control-file>...]
+Show information about a package named
+.I <filename>.
+By default this command shows the control-file of this package (see
+.B deb-control(5)
+) and some statistics (file lengths, etc.). If
+.I <control-file>
+is specified, the specified file is displayed instead. See
+.B deb(5)
+for more information about control-files.
+.TP
+.B dpkg-deb -c|--contents <filename>
+List contents of Debian GNU/Linux package
+.I <filename>.
+.TP
+.B dpkg-deb -e|--control <filename> [<directory>]
+Extract control-information from a package named
+.I <filename>.
+This action creates a directory named
+.I <directory>,
+or if it isn't specified, a directory named
+.I DEBIAN,
+containing control files of specified package. See
+.B deb(5)
+for more information about those files.
+.TP
+.B dpkg-deb -f|--field <filename> [<control-field>]
+Display control field(s) of a package
+.I <filename>.
+By default all fields are displayed. See
+.B deb-control(5)
+for more information about these fields.
+.TP
+.B dpkg-deb --fsys-tarfile <filename>
+Display the filesystem tar-file contained by a Debian package
+.I <filename>.
+This tar-file is the file that is extracted to
+.I /
+while the package is installed.
+.TP
+.B dpkg-deb -X|--vextract | -x|--extract <filename> <directory>
+Extract the files contained by a package named
+.I <filename>
+to
+.I <directory>.
+.B --vextract
+also displays the names of files contained by the package.
+.TP
+.B dpkg-deb --help|-h
+Type a brief help.
+.TP
+.B dpkg-deb --licence
+Type licence of
+.B dpkg-deb.
+.TP
+.B dpkg-deb --version
+Type version information.
+
+
+.SS OPTIONS
+
+.TP
+.B -D | --debug
+Set debugging on.
+.TP
+.B --new | --old
+Select new or old package format. The default format is old.
+
+.SH SEE ALSO
+.B deb(5)
+,
+.B dpkg-deb(8)
+,
+.B dselect(8)
+and
+.B deb-control(5)
+
+.SH AUTHOR
+.B dpkg
+is written by Ian Jackson (ian@chiark.chu.cam.ac.uk). Manual page added
+by Juho Vuori (javuori@cc.helsinki.fi).
+

+ 40 - 0
dpkg-deb/dpkg-deb.h

@@ -0,0 +1,40 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * dpkg-deb.h - external definitions for this program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_DEB_H
+#define DPKG_DEB_H
+
+typedef void dofunction(const char *const *argv);
+dofunction do_build, do_contents, do_control;
+dofunction do_info, do_field, do_extract, do_vextract, do_fsystarfile;
+
+extern int debugflag, nocheckflag, oldformatflag;
+extern const struct cmdinfo *cipaction;
+extern dofunction *action;
+
+void extracthalf(const char *debar, const char *directory,
+                 const char *taroption, int admininfo);
+
+#define DEBMAGIC     "!<arch>\ndebian-binary   "
+#define ADMINMEMBER  "control.tar.gz  "
+#define DATAMEMBER   "data.tar.gz     "
+
+#endif /* DPKG_DEB_H */

+ 316 - 0
dpkg-deb/extract.c

@@ -0,0 +1,316 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * extract.c - extracting archives
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+#include <ar.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-deb.h"
+#include "myopt.h"
+
+static void movecontrolfiles(const char *thing) {
+  char buf[200];
+  pid_t c1;
+  
+  sprintf(buf, "mv %s/* . && rmdir %s", thing, thing);
+  if (!(c1= m_fork())) {
+    execlp("sh","sh","-c",buf,(char*)0); ohshite("failed to exec sh -c mv foo/* &c");
+  }
+  waitsubproc(c1,"sh -c mv foo/* &c",0);
+}
+
+static void readfail(FILE *a, const char *filename, const char *what) {
+  if (ferror(a)) {
+    ohshite("error reading %s from %.255s",what,filename);
+  } else {
+    ohshit("unexpected end of file in %s in %.255s",what,filename);
+  }
+}
+
+static unsigned long parseheaderlength(const char *inh, size_t len,
+                                       const char *fn, const char *what) {
+  char lintbuf[15];
+  unsigned long r;
+  char *endp;
+
+  if (memchr(inh,0,len))
+    ohshit("file `%.250s' is corrupt - %.250s length contains nulls",fn,what);
+  assert(sizeof(lintbuf) > len);
+  memcpy(lintbuf,inh,len);
+  lintbuf[len]= ' ';
+  *strchr(lintbuf,' ')= 0;
+  r= strtoul(lintbuf,&endp,10);
+  if (*endp)
+    ohshit("file `%.250s' is corrupt - bad digit (code %d) in %s",fn,*endp,what);
+  return r;
+}
+
+static void skipmember(FILE *ar, const char *fn, long memberlen) {
+  int c;
+  
+  memberlen += (memberlen&1);
+  while (memberlen > 0) {
+    if ((c= getc(ar)) == EOF) readfail(ar,fn,"skipped member data");
+    memberlen--;
+  }
+}
+
+void extracthalf(const char *debar, const char *directory,
+                 const char *taroption, int admininfo) {
+  char versionbuf[40];
+  float versionnum;
+  char ctrllenbuf[40], *infobuf;
+  long ctrllennum, memberlen= 0;
+  int dummy, l= 0;
+  pid_t c1=0,c2,c3;
+  unsigned char *ctrlarea= 0;
+  int p1[2], p2[2];
+  FILE *ar, *pi;
+  struct stat stab;
+  char nlc;
+  char *cur;
+  struct ar_hdr arh;
+  int readfromfd, oldformat, header_done, adminmember, c;
+  
+  ar= fopen(debar,"r"); if (!ar) ohshite("failed to read archive `%.255s'",debar);
+  if (fstat(fileno(ar),&stab)) ohshite("failed to fstat archive");
+  if (!fgets(versionbuf,sizeof(versionbuf),ar)) readfail(ar,debar,"version number");
+
+  if (!strcmp(versionbuf,"!<arch>\n")) {
+    oldformat= 0;
+
+    ctrllennum= 0;
+    header_done= 0;
+    for (;;) {
+      if (fread(&arh,1,sizeof(arh),ar) != sizeof(arh))
+        readfail(ar,debar,"between members");
+      if (memcmp(arh.ar_fmag,ARFMAG,sizeof(arh.ar_fmag)))
+        ohshit("file `%.250s' is corrupt - bad magic at end of first header",debar);
+      memberlen= parseheaderlength(arh.ar_size,sizeof(arh.ar_size),
+                                   debar,"member length");
+      if (memberlen<0)
+        ohshit("file `%.250s' is corrupt - negative member length %ld",debar,memberlen);
+      if (!header_done) {
+        if (memcmp(arh.ar_name,"debian-binary   ",sizeof(arh.ar_name)))
+          ohshit("file `%.250s' is not a debian binary archive (try dpkg-split?)",debar);
+        infobuf= m_malloc(memberlen+1);
+        if (fread(infobuf,1, memberlen + (memberlen&1), ar) != memberlen + (memberlen&1))
+          readfail(ar,debar,"header info member");
+        infobuf[memberlen]= 0;
+        cur= strchr(infobuf,'\n');
+        if (!cur) ohshit("archive has no newlines in header");
+        *cur= 0;
+        cur= strchr(infobuf,'.');
+        if (!cur) ohshit("archive has no dot in version number");
+        *cur= 0;
+        if (strcmp(infobuf,"2"))
+          ohshit("archive version %.250s not understood, get newer " BACKEND, infobuf);
+        *cur= '.';
+        strncpy(versionbuf,infobuf,sizeof(versionbuf));
+        versionbuf[sizeof(versionbuf)-1]= 0;
+        header_done= 1;
+      } else if (arh.ar_name[0] == '_') {
+          /* Members with `_' are noncritical, and if we don't understand them
+           * we skip them.
+           */
+        skipmember(ar,debar,memberlen);
+      } else {
+        adminmember=
+          !memcmp(arh.ar_name,ADMINMEMBER,sizeof(arh.ar_name)) ? 1 :
+          !memcmp(arh.ar_name,DATAMEMBER,sizeof(arh.ar_name)) ? 0 :
+          -1;
+        if (adminmember == -1) {
+          ohshit("file `%.250s' contains ununderstood data member %.*s, giving up",
+                 debar, (int)sizeof(arh.ar_name), arh.ar_name);
+        }
+        if (adminmember == 1) {
+          if (ctrllennum != 0)
+            ohshit("file `%.250s' contains two control members, giving up", debar);
+          ctrllennum= memberlen;
+        }
+        if (!adminmember != !admininfo) {
+          skipmember(ar,debar,memberlen);
+        } else {
+          break; /* Yes ! - found it. */
+        }
+      }
+    }
+
+    if (admininfo >= 2)
+      if (printf(" new debian package, version %s.\n"
+                 " size %ld bytes: control archive= %ld bytes.\n",
+                 versionbuf, (long)stab.st_size, ctrllennum) == EOF ||
+          fflush(stdout)) werr("stdout");
+    
+  } else if (!strncmp(versionbuf,"0.93",4) &&
+             sscanf(versionbuf,"%f%c%d",&versionnum,&nlc,&dummy) == 2 &&
+             nlc == '\n') {
+    
+    oldformat= 1;
+    l= strlen(versionbuf); if (l && versionbuf[l-1]=='\n') versionbuf[l-1]=0;
+    if (!fgets(ctrllenbuf,sizeof(ctrllenbuf),ar))
+      readfail(ar,debar,"ctrl information length");
+    if (sscanf(ctrllenbuf,"%ld%c%d",&ctrllennum,&nlc,&dummy) !=2 || nlc != '\n')
+      ohshit("archive has malformatted ctrl len `%s'",ctrllenbuf);
+
+    if (admininfo >= 2)
+      if (printf(" old debian package, version %s.\n"
+                 " size %ld bytes: control archive= %ld, main archive= %ld.\n",
+                 versionbuf, (long)stab.st_size, ctrllennum,
+                 (long) (stab.st_size - ctrllennum - strlen(ctrllenbuf) - l)) == EOF ||
+          fflush(stdout)) werr("stdout");
+    
+    ctrlarea= malloc(ctrllennum); if (!ctrlarea) ohshite("malloc ctrlarea failed");
+
+    errno=0; if (fread(ctrlarea,1,ctrllennum,ar) != ctrllennum)
+      readfail(ar,debar,"ctrlarea");
+
+  } else {
+    ohshit("`%.255s' is not a debian format archive",debar);
+  }
+
+  fflush(ar);
+  if (oldformat) {
+    if (admininfo) {
+      m_pipe(p1);
+      if (!(c1= m_fork())) {
+        close(p1[0]);
+        if (!(pi= fdopen(p1[1],"w"))) ohshite("failed to fdopen p1 in paste");
+        errno=0; if (fwrite(ctrlarea,1,ctrllennum,pi) != ctrllennum)
+          ohshit("failed to write to gzip -dc");
+        if (fclose(pi)) ohshit("failed to close gzip -dc");
+        exit(0);
+      }
+      close(p1[1]);
+      readfromfd= p1[0];
+    } else {
+      if (lseek(fileno(ar),l+strlen(ctrllenbuf)+ctrllennum,SEEK_SET) == -1)
+        ohshite("failed to syscall lseek to files archive portion");
+      c1= -1;
+      readfromfd= fileno(ar);
+    }
+  } else {
+    m_pipe(p1);
+    if (!(c1= m_fork())) {
+      close(p1[0]);
+      if (!(pi= fdopen(p1[1],"w"))) ohshite("failed to fdopen p1 in copy");
+      while (memberlen > 0) {
+        if ((c= getc(ar)) == EOF) readfail(ar,debar,"member data");
+        if (putc(c,pi) == EOF) ohshite("failed to write to pipe in copy");
+        memberlen--;
+      }
+      if (fclose(pi) == EOF) ohshite("failed to close pipe in copy");
+      exit(0);
+    }
+    close(p1[1]);
+    readfromfd= p1[0];
+  }
+  
+  if (taroption) m_pipe(p2);
+  
+  if (!(c2= m_fork())) {
+    m_dup2(readfromfd,0);
+    if (admininfo) close(p1[0]);
+    if (taroption) { m_dup2(p2[1],1); close(p2[0]); close(p2[1]); }
+    execlp(GZIP,"gzip","-dc",(char*)0); ohshite("failed to exec gzip -dc");
+  }
+  if (readfromfd != fileno(ar)) close(readfromfd);
+  close(p2[1]);
+
+  if (taroption && directory) {
+    if (chdir(directory)) {
+      if (errno == ENOENT) {
+        if (mkdir(directory,0777)) ohshite("failed to create directory");
+        if (chdir(directory)) ohshite("failed to chdir to directory after creating it");
+      } else {
+        ohshite("failed to chdir to directory");
+      }
+    }
+  }
+
+  if (taroption) {
+    if (!(c3= m_fork())) {
+      char buffer[30+2];
+      if(strlen(taroption) > 30) internerr(taroption);
+      strcpy(buffer, taroption);
+      strcat(buffer, "f");
+      m_dup2(p2[0],0);
+      execlp(TAR,"tar",buffer,"-",(char*)0);
+      ohshite("failed to exec tar");
+    }
+    close(p2[0]);
+    waitsubproc(c3,"tar",0);
+  }
+  
+  waitsubproc(c2,"gzip -dc",1);
+  if (c1 != -1) waitsubproc(c1,"paste",0);
+  if (oldformat && admininfo) {
+    if (versionnum == 0.931F) {
+      movecontrolfiles(OLDOLDDEBDIR);
+    } else if (versionnum == 0.932F || versionnum == 0.933F) {
+      movecontrolfiles(OLDDEBDIR);
+    }
+  }
+}
+
+static void controlextractvextract(int admin,
+                                   const char *taroptions,
+                                   const char *const *argv) {
+  const char *debar, *directory;
+  
+  if (!(debar= *argv++))
+    badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (!(directory= *argv++)) {
+    if (admin) directory= EXTRACTCONTROLDIR;
+    else ohshit("--%s needs a target directory.\n"
+                "Perhaps you should be using " DPKG " --install ?",cipaction->olong);
+  } else if (*argv) {
+    badusage("--%s takes at most two arguments (.deb and directory",cipaction->olong);
+  }
+  extracthalf(debar, directory, taroptions, admin);
+}
+
+void do_fsystarfile(const char *const *argv) {
+  const char *debar;
+  
+  if (!(debar= *argv++))
+    badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (*argv)
+    badusage("--%s takes only one argument (.deb filename)",cipaction->olong);
+  extracthalf(debar,0,0,0);
+}
+   
+void do_control(const char *const *argv) { controlextractvextract(1, "x", argv); }
+void do_extract(const char *const *argv) { controlextractvextract(0, "xp", argv); }
+void do_vextract(const char *const *argv) { controlextractvextract(0, "xpv", argv); }

+ 240 - 0
dpkg-deb/info.c

@@ -0,0 +1,240 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * info.c - providing information
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-deb.h"
+#include "myopt.h"
+
+static void cu_info_prepare(int argc, void **argv) {
+  pid_t c1;
+  int status;
+  char *directory;
+  struct stat stab;
+
+  directory= (char*)(argv[0]);
+  if (chdir("/")) { perror("failed to chdir to `/' for cleanup"); return; }
+  if (lstat(directory,&stab) && errno==ENOENT) return;
+  if ((c1= fork()) == -1) { perror("failed to fork for cleanup"); return; }
+  if (!c1) {
+    execlp(RM,"rm","-r",directory,(char*)0);
+    perror("failed to exec " RM " for cleanup"); _exit(1);
+  }
+  if (waitpid(c1,&status,0) != c1) { perror("failed to wait for rm cleanup"); return; }
+  if (status) { fprintf(stderr,"rm cleanup failed, code %d\n",status); }
+} 
+
+static void info_prepare(const char *const **argvp,
+                         const char **debarp,
+                         const char **directoryp,
+                         int admininfo) {
+  static char dbuf[L_tmpnam];
+  pid_t c1;
+  
+  *debarp= *(*argvp)++;
+  if (!*debarp) badusage("--%s needs a .deb filename argument",cipaction->olong);
+  if (!tmpnam(dbuf)) ohshite("failed to make temporary filename");
+  *directoryp= dbuf;
+
+  if (!(c1= m_fork())) {
+    execlp(RM,"rm","-rf",dbuf,(char*)0); ohshite("failed to exec rm -rf");
+  }
+  waitsubproc(c1,"rm -rf",0);
+  push_cleanup(cu_info_prepare,-1, 0,0, 1, (void*)dbuf);
+  extracthalf(*debarp, dbuf, "mx", admininfo);
+}
+
+static int ilist_select(const struct dirent *de) {
+  return strcmp(de->d_name,".") && strcmp(de->d_name,"..");
+}
+
+static void info_spew(const char *debar, const char *directory,
+                      const char *const *argv) {
+  const char *component;
+  FILE *co;
+  pid_t c1;
+  int re= 0;
+
+  while ((component= *argv++) != 0) {
+    co= fopen(component,"r");
+    if (co) {
+      if (!(c1= m_fork())) {
+        m_dup2(fileno(co),0);
+        execlp(CAT,"cat",(char*)0); ohshite("failed to exec cat component");
+      }
+      waitsubproc(c1,"cat component",0);
+    } else if (errno == ENOENT) {
+      if (fprintf(stderr, BACKEND ": `%.255s' contains no control component `%.255s'\n",
+                  debar, component) == EOF) werr("stderr");
+      re= 1;
+    } else {
+      ohshite("open component `%.255s' (in %.255s) failed in an unexpected way",
+              component, directory);
+    }
+  }
+  if (re) ohshit("at least one requested control component missing");
+}
+
+static void info_list(const char *debar, const char *directory) {
+  char interpreter[INTERPRETER_MAX+1], *p;
+  int il, lines;
+  struct dirent **cdlist, *cdep;
+  int cdn;
+  FILE *cc;
+  struct stat stab;
+  int c;
+
+  cdn= scandir(".", &cdlist, &ilist_select, alphasort);
+  if (cdn == -1) ohshite("cannot scan directory `%.255s'",directory);
+
+  while (cdn-- >0) {
+    cdep= *cdlist++;
+    if (stat(cdep->d_name,&stab))
+      ohshite("cannot stat `%.255s' (in `%.255s')",cdep->d_name,directory);
+    if (S_ISREG(stab.st_mode)) {
+      if (!(cc= fopen(cdep->d_name,"r")))
+        ohshite("cannot open `%.255s' (in `%.255s')",cdep->d_name,directory);
+      lines= 0; interpreter[0]= 0;
+      if ((c= getc(cc))== '#') {
+        if ((c= getc(cc))== '!') {
+          while ((c= getc(cc))== ' ');
+          p=interpreter; *p++='#'; *p++='!'; il=2;
+          while (il<INTERPRETER_MAX && !isspace(c) && c!=EOF) {
+            *p++= c; il++; c= getc(cc);
+          }
+          *p++= 0;
+          if (c=='\n') lines++;
+        }
+      }
+      while ((c= getc(cc))!= EOF) { if (c == '\n') lines++; }
+      if (ferror(cc)) ohshite("failed to read `%.255s' (in `%.255s')",
+                              cdep->d_name,directory);
+      fclose(cc);
+      if (printf(" %7ld bytes, %5d lines   %c  %-20.127s %.127s\n",
+                 (long)stab.st_size, lines,
+                 S_IXUSR & stab.st_mode ? '*' : ' ',
+                 cdep->d_name, interpreter) == EOF)
+        werr("stdout");
+    } else {
+      if (printf("     not a plain file          %.255s\n",cdep->d_name) == EOF)
+        werr("stdout");
+    }
+  }
+  if (!(cc= fopen("control","r"))) {
+    if (errno != ENOENT) ohshite("failed to read `control' (in `%.255s')",directory);
+    if (!fputs("(no `control' file in control archive!)\n",stdout)) werr("stdout");
+  } else {
+    lines= 1;
+    while ((c= getc(cc))!= EOF) {
+      if (lines) if (putc(' ',stdout) == EOF) werr("stdout");
+      if (putc(c,stdout) == EOF) werr("stdout");
+      lines= c=='\n';
+    }
+    if (!lines) if (putc('\n',stdout) == EOF) werr("stdout");
+  }
+}
+
+static void info_field(const char *debar, const char *directory,
+                       const char *const *fields, int showfieldname) {
+  FILE *cc;
+  char fieldname[MAXFIELDNAME+1];
+  char *pf;
+  const char *const *fp;
+  int doing, c, lno, fnl;
+
+  if (!(cc= fopen("control","r"))) ohshite("could not open the `control' component");
+  doing= 1; lno= 1;
+  for (;;) {
+    c= getc(cc);  if (c==EOF) { doing=0; break; }
+    if (c == '\n') { lno++; doing=1; continue; }
+    if (!isspace(c)) {
+      doing= 0;
+      for (pf=fieldname, fnl=0;
+           fnl <= MAXFIELDNAME && c!=EOF && !isspace(c) && c!=':';
+           c= getc(cc)) { *pf++= c; fnl++; }
+      *pf++= 0;
+      doing= fnl >= MAXFIELDNAME || c=='\n' || c==EOF;
+      for (fp=fields; !doing && *fp; fp++)
+        if (!strcasecmp(*fp,fieldname)) doing=1;
+      if (showfieldname) {
+        if (doing)
+          fputs(fieldname,stdout);
+      } else {
+        if (c==':') c= getc(cc);
+        while (c != '\n' && isspace(c)) c= getc(cc);
+      }
+    }
+    for(;;) {
+      if (c == EOF) break;
+      if (doing) putc(c,stdout);
+      if (c == '\n') { lno++; break; }
+      c= getc(cc);
+    }
+    if (c == EOF) break;
+  }
+  if (ferror(cc)) ohshite("failed during read of `control' component");
+  if (doing) putc('\n',stdout);
+  if (ferror(stdout)) werr("stdout");
+}
+
+void do_info(const char *const *argv) {
+  const char *debar, *directory;
+
+  if (*argv && argv[1]) {
+    info_prepare(&argv,&debar,&directory,1);
+    info_spew(debar,directory, argv);
+  } else {
+    info_prepare(&argv,&debar,&directory,2);
+    info_list(debar,directory);
+  }
+}
+
+void do_field(const char *const *argv) {
+  const char *debar, *directory;
+
+  info_prepare(&argv,&debar,&directory,1);
+  if (*argv) {
+    info_field(debar, directory, argv, argv[1]!=0);
+  } else {
+    static const char *const controlonly[]= { "control", 0 };
+    info_spew(debar,directory, controlonly);
+  }
+}
+
+void do_contents(const char *const *argv) {
+  const char *debar;
+  
+  if (!(debar= *argv++) || *argv) badusage("--contents takes exactly one argument");
+  extracthalf(debar, 0, "tv", 0);
+}

+ 151 - 0
dpkg-deb/main.c

@@ -0,0 +1,151 @@
+/*
+ * dpkg-deb - construction and deconstruction of *.deb archives
+ * main.c - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "version.h"
+#include "myopt.h"
+#include "dpkg-deb.h"
+
+static void printversion(void) {
+  if (!fputs("Debian GNU/Linux `" BACKEND "' package archive backend "
+             "version " DPKG_VERSION_ARCH ".\n"
+             "Copyright (C) 1994,1995 Ian Jackson.  This is free software; see the\n"
+             "GNU General Public Licence version 2 or later for copying conditions.\n"
+             "There is NO warranty.  See dpkg-deb --licence for details.\n",
+             stderr)) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs("\
+Usage: " BACKEND " -b|--build <directory> [<deb>]    Build an archive.\n\
+       " BACKEND " -c|--contents <deb>               List contents.\n\
+       " BACKEND " -I|--info <deb> [<cfile>...]      Show info to stdout.\n\
+       " BACKEND " -f|--field <deb> [<cfield>...]    Show field(s) to stdout.\n\
+       " BACKEND " -e|--control <deb> [<directory>]  Extract control info.\n\
+       " BACKEND " -x|--extract <deb> <directory>    Extract files.\n\
+       " BACKEND " -X|--vextract <deb> <directory>   Extract & list files.\n\
+       " BACKEND " --fsys-tarfile <deb>              Output filesystem tarfile.\n\
+       " BACKEND " -h|--help                         Display this message.\n\
+       " BACKEND " --version | --licence             Show version/licence.\n\
+<deb> is the filename of a Debian format archive.\n\
+<cfile> is the name of an administrative file component.\n\
+<cfield> is the name of a field in the main `control' file.\n\
+Options:  -D for debugging output; --old or --new controls archive format;\n\
+          --no-check to suppress control file check (build bad package).\n\
+\n\
+Use `" DPKG "' to install and remove packages from your system, or\n\
+`" DSELECT "' for user-friendly package management.  Packages unpacked\n\
+using `" BACKEND " --extract' will be incorrectly installed !\n",
+             stderr)) werr("stderr");
+}
+
+const char thisname[]= BACKEND;
+const char printforhelp[]=
+ "Type " BACKEND " --help for help about manipulating *.deb files;\n"
+ "Type " DPKG " --help for help about installing and deinstalling packages.";
+
+int debugflag=0, nocheckflag=0, oldformatflag=BUILDOLDPKGFORMAT;
+const struct cmdinfo *cipaction=0;
+dofunction *action=0;
+
+static void helponly(const struct cmdinfo *cip, const char *value) {
+  usage(); exit(0);
+}
+static void versiononly(const struct cmdinfo *cip, const char *value) {
+  printversion(); exit(0);
+}
+
+static void setaction(const struct cmdinfo *cip, const char *value);
+
+static dofunction *const dofunctions[]= {
+  do_build,
+  do_contents,
+  do_control,
+  do_info,
+  do_field,
+  do_extract,
+  do_vextract,
+  do_fsystarfile
+};
+
+/* NB: the entries using setaction must appear first and be in the
+ * same order as dofunctions:
+ */
+static const struct cmdinfo cmdinfos[]= {
+  { "build",        'b',  0,  0, 0,               setaction        },
+  { "contents",     'c',  0,  0, 0,               setaction        },
+  { "control",      'e',  0,  0, 0,               setaction        },
+  { "info",         'I',  0,  0, 0,               setaction        },
+  { "field",        'f',  0,  0, 0,               setaction        },
+  { "extract",      'x',  0,  0, 0,               setaction        },
+  { "vextract",     'X',  0,  0, 0,               setaction        },
+  { "fsys-tarfile",  0,   0,  0, 0,               setaction        },
+  { "new",           0,   0,  &oldformatflag, 0,  0,            0  },
+  { "old",           0,   0,  &oldformatflag, 0,  0,            1  },
+  { "debug",        'D',  0,  &debugflag,     0,  0,            1  },
+  { "nocheck",       0,   0,  &nocheckflag,   0,  0,            1  },
+  { "help",         'h',  0,  0, 0,               helponly         },
+  { "version",       0,   0,  0, 0,               versiononly      },
+  { "licence",       0,   0,  0, 0,               showcopyright    }, /* UK spelling */
+  { "license",       0,   0,  0, 0,               showcopyright    }, /* US spelling */
+  {  0,              0                                             }
+};
+
+static void setaction(const struct cmdinfo *cip, const char *value) {
+  if (cipaction)
+    badusage("conflicting actions --%s and --%s",cip->olong,cipaction->olong);
+  cipaction= cip;
+  assert(cip-cmdinfos < sizeof(dofunctions)*sizeof(dofunction*));
+  action= dofunctions[cip-cmdinfos];
+}
+
+int main(int argc, const char *const *argv) {
+  jmp_buf ejbuf;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  myopt(&argv,cmdinfos);
+  if (!cipaction) badusage("need an action option");
+
+  unsetenv("GZIP");
+  action(argv);
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+  exit(0);
+}

+ 67 - 0
dpkg-deb/mkdeb.sh

@@ -0,0 +1,67 @@
+#!/bin/bash
+# This script is only supposed to be called by dpkg-deb.
+# Its arguments are: <sourcefile> <partsize> <prefix> <totalsize>
+# Stdin is also redirected from the source archive by dpkg-split.
+
+# Copyright (C) 1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+set -e
+
+if [ "$#" != 4 ]; then echo >&2 'Bad invocation of mksplit.sh.'; exit 1; fi
+
+sourcefile="$1"
+partsize="$2"
+prefix="$3"
+orgsize="$4"
+
+myversion=2.0
+binary=i386-linux
+#csum=`md5sum <"$sourcefile"`
+#package="`dpkg-deb --field \"$sourcefile\" Package`"
+#version="`dpkg-deb --field \"$sourcefile\" Version`"
+#revision="`dpkg-deb --field \"$sourcefile\" Package_Revision`"
+startat=0
+partnum=0
+
+mkdir /tmp/ds$$
+ec=1
+trap "rm -r /tmp/ds$$; exit $ec" 0
+dsp=/tmp/ds$$/debian-binary
+
+echo -n "Splitting package $package into $nparts parts: "
+
+while [ $startat -lt $orgsize ]
+do
+	showpartnum=$[$partnum+1]
+	echo $myversion >$dsp
+	echo $binary >>$dsp
+	tar -C DEBIAN -cf /tmp/ds$$/control .
+	tar --
+	dd bs=$partsize skip=$partnum count=1 \
+	   of=/tmp/ds$$/data.$showpartnum \
+	 2>&1 | (egrep -v '.* records (in|out)' || true)
+	rm -f /tmp/ds$$/part
+	echo -n "$showpartnum "
+	(cd /tmp/ds$$ &&
+	 ar qc part debian-split data.$showpartnum)
+	mv /tmp/ds$$/part $prefix.${showpartnum}of$nparts.deb
+	startat=$[$startat+$partsize]
+	partnum=$showpartnum
+done
+echo "done"
+
+ec=0

+ 119 - 0
dselect/Makefile.in

@@ -0,0 +1,119 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+exec_prefix = $(prefix)
+bindir = $(exec_prefix)/bin
+libdir = $(prefix)/lib
+mandir = $(prefix)/man
+man8dir = $(mandir)/man8
+man8 = 8
+
+SRC =                                                                       \
+ main.cc        bindings.cc    curkeys.cc     helpmsgs.cc                   \
+ basecmds.cc    baselist.cc    basetop.cc                                   \
+ pkgcmds.cc     pkgdepcon.cc   pkgdisplay.cc  pkginfo.cc     pkgkeys.cc     \
+ pkglist.cc     pkgsublist.cc  pkgtop.cc                                    \
+ methkeys.cc    method.cc      methparse.cc   methlist.cc
+
+OBJ =                                                                       \
+ main.o         bindings.o     curkeys.o      helpmsgs.o                    \
+ basecmds.o     baselist.o     basetop.o                                    \
+ pkgcmds.o      pkgdepcon.o    pkgdisplay.o   pkginfo.o      pkgkeys.o      \
+ pkglist.o      pkgsublist.o   pkgtop.o                                     \
+ methkeys.o     method.o       methparse.o    methlist.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+CPLUSPLUS = @CXX@
+
+CFLAGS = @CFLAGS@ @CWARNS@ -g $(XCFLAGS)
+OPTCFLAGS = @OPTCFLAGS@
+LDFLAGS = $(XLDFLAGS)
+
+EXTERNLIBS = -lncurses
+LIBS = -L../lib -ldpkg $(EXTERNLIBS) $(XLIBS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+ALL_CFLAGS_OPT = $(ALL_CFLAGS) $(OPTCFLAGS)
+
+.SUFFIXES:	.cc .o .c
+
+.cc.o:
+		$(CPLUSPLUS) $(ALL_CFLAGS) -c $<
+
+.c.o:
+		$(CC) $(ALL_CFLAGS) -c $<
+
+all:		dselect
+
+dselect:	$(OBJ) ../lib/libdpkg.a
+		$(CC) $(LDFLAGS) -o dselect $(OBJ) $(LIBS)
+
+# These next few files are very heavily used, and should be optimised
+# for speed rather than space.  (ALL_CFLAGS_OPT usually means -O3.)
+pkgdepcon.o:	pkgdepcon.cc
+		$(CPLUSPLUS) $(ALL_CFLAGS_OPT) -c $<
+
+pkgdisplay.o:	pkgdisplay.cc
+		$(CPLUSPLUS) $(ALL_CFLAGS_OPT) -c $<
+
+curkeys.o:	curkeys.cc curkeys.inc
+		$(CPLUSPLUS) $(ALL_CFLAGS) -c curkeys.cc
+
+helpmsgs.h helpmsgs.cc:	helpmsgs.src mkhelpmsgs.pl
+		perl mkhelpmsgs.pl
+
+curkeys.inc:	keyoverride mkcurkeys.pl
+		perl mkcurkeys.pl keyoverride \
+			`echo '#include <ncurses/curses.h>' | \
+			 $(CC) -E - | grep ncurses | head -1 | \
+			 sed -e 's/^[^"]*"//; s/".*$$//'` > curkeys.inc.new
+		mv curkeys.inc.new curkeys.inc
+
+kt:		kt.o
+		$(CC) $(LDFLAGS) -o kt kt.o $(LIBS)
+
+kt.o:		kt.c curkeys.inc
+
+clean:
+		rm -f curkeys.inc curkeys.inc.new
+		rm -f helpmsgs.h helpmsgs.cc helpmsgs.h.new helpmsgs.cc.new
+		rm -f *.o core dselect kt
+
+distclean:	clean
+		rm -f Makefile *.orig *~ *.~* ./#*#
+		rm -rf t updates status available *.old
+
+install:	all
+		$(INSTALL_PROGRAM) -s dselect $(bindir)/dselect
+
+# $(INSTALL_DATA) dselect.8 $(man8dir)/dselect.$(man8)
+
+$(OBJ):			dselect.h ../config.h ../include/dpkg.h ../include/dpkg-db.h
+main.o:						../version.h ../include/myopt.h
+method.o:					method.h
+pkgcmds.o pkgdepcon.o pkgdisplay.o pkgtop.o:	pkglist.h
+baselist.o bindings.o curkeys.o main.o:		bindings.h method.h pkglist.h
+methlist.o methkeys.o pkginfo.o pkgkeys.o:	bindings.h method.h pkglist.h
+pkglist.o pkgsublist.o methparse.o:		bindings.h method.h pkglist.h
+helpmsgs.o methlist.o pkginfo.o basecmds.o:	helpmsgs.h helpmsgs.cc

+ 264 - 0
dselect/basecmds.cc

@@ -0,0 +1,264 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bcommands.cc - base list keyboard commands display
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "helpmsgs.h"
+
+void baselist::kd_scrollon() {
+  topofscreen += list_height;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  if (cursorline < topofscreen)
+    setcursor(topofscreen);
+  refreshlist();
+}
+
+void baselist::kd_scrollon1() {
+  if (topofscreen >= nitems - list_height) return;
+  topofscreen++;
+  if (cursorline < topofscreen)
+    setcursor(topofscreen);
+  refreshlist();
+}
+
+void baselist::kd_scrollback() {
+  topofscreen -= list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  if (cursorline >= topofscreen + list_height)
+    setcursor(topofscreen + list_height - 1);
+  refreshlist();
+}
+
+void baselist::kd_scrollback1() {
+  if (topofscreen <= 0) return;
+  topofscreen--;
+  if (cursorline >= topofscreen + list_height)
+    setcursor(topofscreen + list_height - 1);
+  refreshlist();
+}
+
+void baselist::kd_top() {
+  topofscreen= 0; setcursor(0);
+}
+
+void baselist::kd_bottom() {
+  topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setcursor(lesserint(topofscreen + list_height - 1, nitems-1));
+}
+
+void baselist::kd_redraw() {
+//#define RFSH(x) werase(x); redrawwin(x)
+//  RFSH(listpad);
+//  RFSH(infopad); 
+//  RFSH(colheadspad); 
+//  RFSH(thisstatepad); 
+//  RFSH(titlewin); 
+//  RFSH(whatinfowin); /* fixme-ncurses: why does ncurses need this ? */
+  clearok(curscr,TRUE);
+  redrawall();
+  if (debug) fprintf(debug,"baselist[%p]::kd_redraw() done\n",this);
+}
+
+void baselist::kd_searchagain() {
+  if (!searchstring[0]) { beep(); return; }
+  dosearch();
+}
+
+void baselist::kd_search() {
+  werase(querywin);
+  mvwaddstr(querywin,0,0, "Search for ? ");
+  echo();
+  /* fixme: make / RET do `search again' and / DEL to abort */
+  if (wgetnstr(querywin,searchstring,sizeof(searchstring)-1) == ERR)
+    searchstring[0]= 0;
+  noecho();
+  if (whatinfo_height) { touchwin(whatinfowin); refreshinfo(); }
+  else if (info_height) { touchwin(infopad); refreshinfo(); }
+  else if (thisstate_height) redrawthisstate();
+  else { touchwin(listpad); refreshlist(); }
+  if (searchstring[0]) dosearch();
+}
+
+void baselist::displayhelp(const struct helpmenuentry *helpmenu, int key) {
+  const struct helpmenuentry *hme;
+  int maxx, maxy, i, y, x, nextkey;
+  
+  getmaxyx(stdscr,maxy,maxx);
+  clearok(stdscr,TRUE);
+  for (;;) {
+    werase(stdscr);
+    for (hme= helpmenu; hme->key && hme->key != key; hme++);
+    if (hme->key) {
+      attrset(list_attr);
+      mvaddstr(1,0, hme->msg->text);
+      attrset(title_attr);
+      mvaddstr(0,0, "Help: ");
+      addstr(hme->msg->title);
+      getyx(stdscr,y,x);
+      while (++x<maxx) addch(' ');
+      attrset(thisstate_attr);
+      mvaddstr(maxy-1,0,
+"? = help menu    Space = exit help    . = next help    or a help page key "
+               );
+      getyx(stdscr,y,x);
+      while (++x<maxx) addch(' ');
+      move(maxy,maxx);
+      attrset(A_NORMAL);
+      nextkey= hme[1].key;
+    } else {
+      mvaddstr(1,1, "Help information is available under the following topics:");
+      for (i=0, hme=helpmenu; hme->key; hme++,i++) {
+        attrset(A_BOLD);
+        mvaddch(i+3,3, hme->key);
+        attrset(A_NORMAL);
+        mvaddstr(i+3,6, hme->msg->title);
+      }
+      mvaddstr(i+4,1,
+               "Press a key from the list above, Space to exit help,\n"
+               "  or `.' (full stop) to read each help page in turn. ");
+      nextkey= helpmenu[0].key;
+    }
+    refresh();
+    key= getch();
+    if (key == EOF) ohshite("error reading keyboard in help");
+    if (key == ' ') {
+      break;
+    } else if (key == '?') {
+      key= 0;
+    } else if (key == '.') {
+      key= nextkey;
+    }
+  }
+  werase(stdscr);
+  clearok(stdscr,TRUE);
+  wnoutrefresh(stdscr);
+
+  redrawtitle();
+  refreshcolheads();
+  refreshlist();
+  redrawthisstate();
+  refreshinfo();
+  wnoutrefresh(whatinfowin);
+}     
+
+void baselist::kd_help() {
+  displayhelp(helpmenulist(),0);
+}
+
+void baselist::setcursor(int index) {
+  if (listpad && cursorline != -1) {
+    redrawitemsrange(cursorline,cursorline+1);
+    redraw1itemsel(cursorline,0);
+  }
+  if (cursorline != index) infotopofscreen= 0;
+  cursorline= index;
+  if (listpad) {
+    redrawitemsrange(cursorline,cursorline+1);
+    redraw1itemsel(cursorline,1);
+    refreshlist();
+    redrawthisstate();
+  }
+  redrawinfo();
+}
+
+void baselist::kd_down() {
+  int ncursor= cursorline;
+  // scroll by one line unless the bottom is already visible
+  // or we're in the top half of the screen ...
+  if (topofscreen < nitems - list_height &&
+      ncursor >= topofscreen + list_height - 3) topofscreen++;
+  // move cursor if there are any more ...
+  if (cursorline+1 < nitems) ncursor++;
+  setcursor(ncursor);
+}
+  
+void baselist::kd_up() {
+  int ncursor= cursorline;
+  // scroll by one line if there are any lines not shown yet
+  // and we're not in the bottom half the screen ...
+  if (topofscreen > 0 &&
+      ncursor <= topofscreen + 2) topofscreen--;
+  // move cursor if there are any to move it to ...
+  if (cursorline > 0) ncursor--;
+  setcursor(ncursor);
+}
+
+void baselist::kd_iscrollon() {
+  infotopofscreen += info_height;
+  if (infotopofscreen > infolines - info_height)
+    infotopofscreen= infolines - info_height;
+  if (infotopofscreen < 0) infotopofscreen= 0;
+  refreshinfo();
+}
+
+void baselist::kd_iscrollback() {
+  infotopofscreen -= info_height;
+  if (infotopofscreen < 0) infotopofscreen= 0;
+  refreshinfo();
+}
+
+void baselist::kd_iscrollon1() {
+  if (infotopofscreen >= infolines - info_height) return;
+  infotopofscreen++; refreshinfo();
+}
+
+void baselist::kd_iscrollback1() {
+  if (infotopofscreen <= 0) return;
+  infotopofscreen--; refreshinfo();
+}
+
+void baselist::kd_panon() {
+  leftofscreen += xmax/3;
+  if (leftofscreen > total_width - xmax) leftofscreen= total_width - xmax;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panback() {
+  leftofscreen -= xmax/3;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panon1() {
+  leftofscreen++;
+  if (leftofscreen > total_width - xmax) leftofscreen= total_width - xmax;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}
+
+void baselist::kd_panback1() {
+  leftofscreen--;
+  if (leftofscreen < 0) leftofscreen= 0;
+  refreshcolheads(); refreshlist(); redrawthisstate(); refreshinfo();
+}

+ 351 - 0
dselect/baselist.cc

@@ -0,0 +1,351 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * baselist.cc - list of somethings
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+void mywerase(WINDOW *win) {
+  int my,mx,y,x;
+  getmaxyx(win,my,mx);
+  for (y=0; y<my; y++) {
+    wmove(win,y,0); for (x=0; x<mx; x++) waddch(win,' ');
+  }
+  wmove(win,0,0);
+}
+
+baselist *baselist::signallist= 0;
+void baselist::sigwinchhandler(int) {
+  baselist *p= signallist;
+  p->enddisplay();
+  endwin(); initscr();
+  p->startdisplay();
+  if (doupdate() == ERR) ohshite("doupdate in SIGWINCH handler failed");
+}
+
+static void cu_sigwinch(int, void **argv) {
+  struct sigaction *osigactp= (struct sigaction*)argv[0];
+  sigset_t *oblockedp= (sigset_t*)argv[1];
+  
+  if (sigaction(SIGWINCH,osigactp,0)) ohshite("failed to restore old SIGWINCH sigact");
+  delete osigactp;
+  if (sigprocmask(SIG_SETMASK,oblockedp,0)) ohshite("failed to restore old signal mask");
+  delete oblockedp;
+} 
+
+void baselist::setupsigwinch() {
+  sigemptyset(&sigwinchset);
+  sigaddset(&sigwinchset,SIGWINCH);
+    
+  osigactp= new(struct sigaction);
+  oblockedp= new(sigset_t);
+  if (sigprocmask(0,0,oblockedp)) ohshite("failed to get old signal mask");
+  if (sigaction(SIGWINCH,0,osigactp)) ohshite("failed to get old SIGWINCH sigact");
+
+  push_cleanup(cu_sigwinch,~0, 0,0, 2,(void*)osigactp,(void*)oblockedp);
+
+  if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to block SIGWINCH");
+  memset(&nsigact,0,sizeof(nsigact));
+  nsigact.sa_handler= sigwinchhandler;
+  sigemptyset(&nsigact.sa_mask);
+  nsigact.sa_flags= SA_INTERRUPT;
+  if (sigaction(SIGWINCH,&nsigact,0)) ohshite("failed to set new SIGWINCH sigact");
+}
+
+void baselist::startdisplay() {
+  if (debug) fprintf(debug,"baselist[%p]::startdisplay()\n",this);
+  cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
+  clear(); wnoutrefresh(stdscr);
+
+  // find attributes
+  if (has_colors() && start_color()==OK && COLOR_PAIRS >= 3) {
+    if (init_pair(1,COLOR_WHITE,COLOR_BLACK) != OK ||
+        init_pair(2,COLOR_WHITE,COLOR_RED) != OK ||
+        init_pair(3,COLOR_WHITE,COLOR_BLUE) != OK)
+      ohshite("failed to allocate colour pairs");
+    list_attr= COLOR_PAIR(1);
+    listsel_attr= list_attr|A_REVERSE;
+    title_attr= COLOR_PAIR(2);
+    thisstate_attr= COLOR_PAIR(3);
+    selstate_attr= list_attr|A_BOLD;
+    selstatesel_attr= listsel_attr|A_BOLD;
+  } else {
+    title_attr= A_REVERSE;
+    thisstate_attr= A_STANDOUT;
+    list_attr= 0;
+    listsel_attr= A_STANDOUT;
+    selstate_attr= A_BOLD;
+    selstatesel_attr= A_STANDOUT;
+  }
+  query_attr= title_attr;
+  info_attr= list_attr;
+  colheads_attr= info_headattr= A_BOLD;
+  whatinfo_attr= thisstate_attr;
+
+  // set up windows and pads, based on screen size
+  int y;  
+  getmaxyx(stdscr,ymax,xmax);
+  title_height= ymax>=6;
+  colheads_height= ymax>=5;
+  thisstate_height= ymax>=3;
+  whatinfo_height= ymax>=2;
+  y= ymax - (title_height + colheads_height +
+               thisstate_height + whatinfo_height);
+  assert(y>=1);
+  y-= list_height + info_height;
+  if (y>0) {
+    list_height += (y+1)/2;
+    info_height += y/2;
+  } else if (y<0) {
+    list_height -= (-y)/2;
+    info_height -= (-y+1)/2;
+  }
+  colheads_row= title_height;
+  list_row= colheads_row + colheads_height;
+  thisstate_row= list_row + list_height;
+  info_row= thisstate_row + thisstate_height;
+  whatinfo_row= info_row + info_height;
+
+  setwidths();
+  
+  titlewin= newwin(1,xmax, 0,0);
+  if (!titlewin) ohshite("failed to create title window");
+  wattrset(titlewin,title_attr);
+  
+  whatinfowin= newwin(1,xmax, whatinfo_row,0);
+  if (!whatinfowin) ohshite("failed to create whatinfo window");
+  wattrset(whatinfowin,whatinfo_attr);
+  
+  listpad= newpad(nitems+1, total_width);
+  if (!listpad) ohshite("failed to create baselist pad");
+  
+  colheadspad= newpad(1, total_width);
+  if (!colheadspad) ohshite("failed to create heading pad");
+  wattrset(colheadspad,colheads_attr);
+  
+  thisstatepad= newpad(1, total_width);
+  if (!thisstatepad) ohshite("failed to create thisstate pad");
+  wattrset(thisstatepad,thisstate_attr);
+
+  infopad= newpad(MAX_DISPLAY_INFO, total_width);
+  if (!infopad) ohshite("failed to create info pad");
+  wattrset(infopad,info_attr);
+
+  querywin= newwin(1,xmax,ymax-1,0);
+  if (!querywin) ohshite("failed to create query window");
+
+  if (cursorline >= topofscreen + list_height) topofscreen= cursorline;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+
+  infotopofscreen= 0; leftofscreen= 0;
+
+  redrawall();
+
+  if (debug)
+    fprintf(debug,
+            "baselist::startdisplay() done ...\n\n"
+            " xmax=%d, ymax=%d;\n\n"
+            " title_height=%d, colheads_height=%d, list_height=%d;\n"
+            " thisstate_height=%d, info_height=%d, whatinfo_height=%d;\n\n"
+            " colheads_row=%d, thisstate_row=%d, info_row=%d;\n"
+            " whatinfo_row=%d, list_row=%d;\n\n",
+            xmax, ymax,
+            title_height, colheads_height, list_height,
+            thisstate_height, info_height, whatinfo_height,
+            colheads_row, thisstate_row, info_row,
+            whatinfo_row, list_row);
+
+}
+
+void baselist::enddisplay() {
+  delwin(titlewin);
+  delwin(whatinfowin);
+  delwin(listpad);  
+  delwin(colheadspad);  
+  delwin(thisstatepad);
+  delwin(infopad);
+  wmove(stdscr,ymax,0); wclrtoeol(stdscr);
+  listpad= 0;
+}
+
+void baselist::redrawall() {
+  redrawtitle();
+  redrawcolheads();
+  wattrset(listpad,list_attr); mywerase(listpad);
+  ldrawnstart= ldrawnend= -1; // start is first drawn; end is first undrawn; -1=none
+  refreshlist();
+  redrawthisstate();
+  redrawinfo();
+}
+
+void baselist::redraw1item(int index) {
+  redraw1itemsel(index, index == cursorline);
+}
+
+baselist::baselist(keybindings *kb) {
+  if (debug)
+    fprintf(debug,"baselist[%p]::baselist()\n",this);
+
+  bindings= kb;
+  nitems= 0;
+
+  xmax= -1;
+  list_height=0; info_height=0;
+  topofscreen= 0; leftofscreen= 0;
+  listpad= 0; cursorline= -1;
+
+  searchstring[0]= 0;
+}  
+
+void baselist::itd_keys() {
+  whatinfovb("keybindings");
+  
+  const int givek= xmax/3;
+  bindings->describestart();
+  const char **ta;
+  while ((ta= bindings->describenext()) != 0) {
+    const char **tap= ta+1;
+    for (;;) {
+      waddstr(infopad, *tap);
+      tap++;  if (!*tap) break;
+      waddstr(infopad, ", ");
+    }
+    int y,x;
+    getyx(infopad,y,x);
+    if (x >= givek) y++;
+    mvwaddstr(infopad, y,givek, ta[0]);
+    waddch(infopad,'\n');
+  }
+}
+
+void baselist::dosearch() {
+  int offset, index, searchlen;
+  searchlen= strlen(searchstring);
+  if (debug) fprintf(debug,"packagelist[%p]::dosearch(); searchstring=`%s' len=%d\n",
+                     this,searchstring,searchlen);
+  for (offset=1, index=greaterint(topofscreen,cursorline+1);
+       offset<nitems;
+       offset++, index++) {
+    if (index >= nitems) index -= nitems;
+    int lendiff, i;
+    const char *thisname;
+    thisname= itemname(index);
+    if (!thisname) continue;
+    lendiff= strlen(thisname) - searchlen;
+    for (i=0; i<=lendiff; i++)
+      if (!strncasecmp(thisname + i, searchstring, searchlen)) {
+        topofscreen= index-1;
+        if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
+        if (topofscreen < 0) topofscreen= 0;
+        setcursor(index);
+        return;
+      }
+  }
+  beep();
+}
+
+void baselist::refreshinfo() {
+  pnoutrefresh(infopad, infotopofscreen,leftofscreen, info_row,0,
+               lesserint(info_row + info_height - 1, info_row + MAX_DISPLAY_INFO - 1),
+               lesserint(total_width - leftofscreen - 1, xmax - 1));
+  
+  if (whatinfo_height) {
+    mywerase(whatinfowin);
+    mvwaddstr(whatinfowin,0,0, whatinfovb.string());
+    if (infolines > info_height) {
+      wprintw(whatinfowin,"  -- %d%%, press ",
+              (int)((infotopofscreen + info_height) * 100.0 / infolines));
+      if (infotopofscreen + info_height < infolines) {
+        wprintw(whatinfowin,"%s for more", bindings->find("iscrollon"));
+        if (infotopofscreen) waddstr(whatinfowin, ", ");
+      }
+      if (infotopofscreen)
+        wprintw(whatinfowin, "%s to go back",bindings->find("iscrollback"));
+      waddch(whatinfowin,'.');
+    }
+    wnoutrefresh(whatinfowin);
+  }
+}
+
+void baselist::wordwrapinfo(int offset, const char *m) {
+  int usemax= xmax-5;
+  if (debug) fprintf(debug,"baselist[%p]::wordwrapinfo(%d, `%s')\n",this,offset,m);
+  int wrapping=0;
+  for (;;) {
+    int offleft=offset; while (*m == ' ' && offleft>0) { m++; offleft--; }
+    const char *p= strchr(m,'\n');
+    int l= p ? (int)(p-m) : strlen(m);
+    while (l && isspace(m[l-1])) l--;
+    if (!l || *m == '.' && l == 1) {
+      if (wrapping) waddch(infopad,'\n');
+      waddch(infopad,'\n');
+      wrapping= 0;
+    } else if (*m == ' ' || usemax < 10) {
+      if (wrapping) waddch(infopad,'\n');
+      waddnstr(infopad, m, l);
+      waddch(infopad,'\n'); wrapping= 0;
+    } else {
+      int x,y;
+      if (wrapping) {
+        getyx(infopad, y,x);
+        if (x+1 >= usemax) {
+          waddch(infopad,'\n');
+        } else {
+          waddch(infopad,' ');
+        }
+      }
+      for (;;) {
+        getyx(infopad, y,x);
+        int dosend= usemax-x;
+        if (l <= dosend) {
+          dosend=l;
+        } else {
+          int i=dosend;
+          while (i > 0 && m[i] != ' ') i--;
+          if (i > 0 || x > 0) dosend=i;
+        }
+        if (dosend) waddnstr(infopad, m, dosend);
+        while (dosend < l && m[dosend] == ' ') dosend++;
+        l-= dosend; m+= dosend;
+        if (l <= 0) break;
+        waddch(infopad,'\n');
+      }
+      wrapping= 1;
+    }
+    if (!p) break;
+    m= ++p;
+  }
+  if (debug) fprintf(debug,"baselist[%p]::wordwrapinfo() done\n",this);
+}
+
+baselist::~baselist() { }

+ 61 - 0
dselect/basetop.cc

@@ -0,0 +1,61 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bdrawtop.cc - base list class redraw of top
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+
+void baselist::refreshlist() {
+  redrawitemsrange(topofscreen,lesserint(nitems,topofscreen+list_height));
+  int y, x, maxy, maxx;
+  y= lesserint(list_row + list_height - 1,
+               list_row + nitems - topofscreen - 1);
+  x= lesserint(total_width - leftofscreen - 1,
+               xmax - 1);
+  pnoutrefresh(listpad, topofscreen,leftofscreen, list_row,0, y,x);
+  getmaxyx(listpad,maxy,maxx);
+  y++;
+  while (y < list_row + list_height - 1) {
+    pnoutrefresh(listpad, maxy-1,leftofscreen, y,0, y,x);
+    y++;
+  }
+}
+
+void baselist::redrawitemsrange(int start, int end) {
+  if (ldrawnstart==-1) { ldrawnstart= ldrawnend= end; }
+  while (ldrawnstart > start) { ldrawnstart--; redraw1item(ldrawnstart); }
+  while (ldrawnend < end) { redraw1item(ldrawnend); ldrawnend++; }
+}
+
+void baselist::refreshcolheads() {
+  pnoutrefresh(colheadspad, 0,leftofscreen, colheads_row,0,
+               colheads_row, lesserint(total_width - leftofscreen - 1, xmax - 1));
+}

+ 166 - 0
dselect/bindings.cc

@@ -0,0 +1,166 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * bindings.cc - keybinding manager object definitions and default bindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+keybindings::keybindings(const interpretation *ints, const orgbinding *orgbindings) {
+  interps= ints;
+  bindings=0;
+  const orgbinding *b= orgbindings;
+  while (b->action) { bind(b->key,b->action); b++; }
+  describestart();
+}
+
+int keybindings::bind(int key, const char *action) {
+  if (key == -1) return 0;
+  
+  const interpretation *interp;
+  for (interp=interps; interp->action && strcmp(interp->action,action); interp++);
+  if (!interp->action) return 0;
+  
+  const description *desc;
+  for (desc=descriptions; desc->action && strcmp(desc->action,action); desc++);
+
+  binding *bind;
+  for (bind=bindings; bind && bind->key != key; bind=bind->next);
+  
+  if (!bind) {
+    bind= new binding;
+    bind->key= key;
+    bind->next= bindings;
+    bindings= bind;
+  }
+  bind->interp= interp;
+  bind->desc= desc ? desc->desc : 0;
+  return 1;
+}
+
+const char *keybindings::find(const char *action) {
+  binding *b;
+  for (b=bindings; b && strcmp(action,b->interp->action); b=b->next);
+  if (!b) return "[not bound]";
+  const char *n= key2name(b->key);
+  if (n) return n;
+  static char buf[50];
+  sprintf(buf,"[unk: %d]",b->key);
+  return buf;
+}
+
+const keybindings::interpretation *keybindings::operator()(int key) {
+  binding *b;
+  for (b=bindings; b && b->key != key; b=b->next);
+  if (!b) return 0;
+  return b->interp;
+}
+
+const char **keybindings::describenext() {
+  binding *search;
+  int count;
+  for (;;) {
+    if (!iterate->action) return 0;
+    for (count=0, search=bindings; search; search=search->next)
+      if (!strcmp(search->interp->action,iterate->action))
+        count++;
+    if (count) break;
+    iterate++;
+  }
+  const char **retarray= new const char *[count+2];
+  retarray[0]= iterate->desc;
+  for (count=1, search=bindings; search; search=search->next)
+    if (!strcmp(search->interp->action,iterate->action))
+      retarray[count++]= key2name(search->key);
+  retarray[count]= 0;
+  iterate++;
+  return retarray;
+}
+
+const char *keybindings::key2name(int key) {
+  const keyname *search;
+  for (search=keynames; search->key != -1 && search->key != key; search++);
+  return search->kname;
+}
+
+int keybindings::name2key(const char *name) {
+  const keyname *search;
+  for (search=keynames; search->kname && strcasecmp(search->kname,name); search++);
+  return search->key;
+}
+
+keybindings::~keybindings() {
+  binding *search, *next;
+  for (search=bindings; search; search=next) {
+    next= search->next;
+    delete search;
+  }
+}
+
+const keybindings::description keybindings::descriptions[]= {
+  // Actions which apply to both types of list.
+  { "iscrollon",       "Scroll onwards through help/information"               },
+  { "iscrollback",     "Scroll backwards through help/information"             },
+  { "up",              "Move up"                                               },
+  { "down",            "Move down"                                             },
+  { "top",             "Go to top of list"                                     },
+  { "bottom",          "Go to end of list"                                     },
+  { "help",            "Request help (cycle through help screens)"             },
+  { "info",            "Cycle through information displays"                    },
+  { "redraw",          "Redraw display"                                        },
+  { "scrollon1",       "Scroll onwards through list by 1 line"                 },
+  { "scrollback1",     "Scroll backwards through list by 1 line"               },
+  { "iscrollon1",      "Scroll onwards through help/information by 1 line"     },
+  { "iscrollback1",    "Scroll backwards through help/information by 1 line"   },
+  { "scrollon",        "Scroll onwards through list"                           },
+  { "scrollback",      "Scroll backwards through list"                         },
+
+  // Actions which apply only to lists of packages.
+  { "select",          "Select package(s) for installation"                    },
+  { "deselect",        "Mark package(s) for deinstallation"                    },
+  { "purge",           "Mark package(s) for deinstall and purge"               },
+  { "morespecific",    "Make highlight more specific"                          },
+  { "lessspecific",    "Make highlight less specific"                          },
+  { "search",          "Search for a package whose name contains a string"     },
+  { "searchagain",     "Repeat last search."                                   },
+  { "swaporder",       "Swap sort order priority/section"                      },
+  { "quitcheck",       "Quit, confirming, and checking dependencies"           },
+  { "quitnocheck",     "Quit, confirming without check"                        },
+  { "quitrejectsug",   "Quit, rejecting conflict/dependency suggestions"       },
+  { "abortnocheck",    "Abort - quit without making changes"                   },
+  { "revert",          "Revert to old state for all packages"                  },
+  { "revertsuggest",   "Revert to suggested state for all packages"            },
+  { "revertdirect",    "Revert to directly requested state for all packages"   },
+  
+  // Actions which apply only to lists of methods.
+  { "select-and-quit", "Select currently-highlighted access method"            },
+  { "abort",           "Quit without changing selected access method"          },
+  {  0,                0                                                       }
+};

+ 94 - 0
dselect/bindings.h

@@ -0,0 +1,94 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * bindings.h - keybindings class header file
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef BINDINGS_H
+#define BINDINGS_H
+
+enum quitaction;
+
+struct keybindings {
+  struct interpretation;
+
+  struct orgbinding {
+    int key;
+    const char *action;
+  };
+  
+  struct keyname {
+    int key;
+    const char *kname;
+  };
+  
+  struct description {
+    const char *action, *desc;
+  };
+
+  struct binding {
+    binding *next;
+    int key;
+    const struct interpretation *interp;
+    const char *desc;
+  };
+  
+ private:
+  static const keyname keynames[];
+  static const description descriptions[];
+
+  binding *bindings;
+  const description *iterate;
+  const interpretation *interps;
+  
+  int bind(int key, const char *action);
+  
+ public:
+  int name2key(const char *name);
+  const char *key2name(int key);
+  
+  int bind(const char *name, const char *action) { return bind(name2key(name),action); }
+  const interpretation *operator()(int key);
+  const char *find(const char *action);
+
+  void describestart() { iterate=descriptions; }
+  const char **describenext();
+  //... returns array, null-term, first element is description, rest are key strings
+  // caller must delete[] the array.  Null means end.
+
+  keybindings(const interpretation *ints, const orgbinding *orgbindings);
+  ~keybindings();
+};
+
+#include "pkglist.h"
+#include "method.h"
+
+struct keybindings::interpretation {
+  const char *action;
+  void (methodlist::*mfn)();
+  void (packagelist::*pfn)();
+  quitaction qa;
+};
+
+extern const keybindings::interpretation packagelist_kinterps[];
+extern const keybindings::orgbinding packagelist_korgbindings[];
+
+extern const keybindings::interpretation methodlist_kinterps[];
+extern const keybindings::orgbinding methodlist_korgbindings[];
+
+#endif /* BINDINGS_H */

+ 17 - 0
dselect/checkunimp.pl

@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+while(<>) {
+    if (m/^\s+\{\s+\"(\w[^"]+)\",\s+0,\s+\w+list\:\:kd_\w+,\s+qa_\w+\s+\},\s*$/ ||
+        m/^\s+\{\s+\"(\w[^"]+)\",\s+\w+list\:\:kd_\w+,\s+0,\s+qa_\w+\s+\},\s*$/) {
+        $implem{$1}= 1;
+    } elsif (m/^\s+\{\s+(\S.{0,15}\S),\s+\"(\w[^"]+)\"\s+\},\s*$/) {
+        $bound{$2} .= $1.', ';
+    } elsif (m/^\s+\{\s+0,/ || m/^\s+\{\s+-1,/) {
+    } elsif (m/^\s+\{\s+/) {
+        print "huh ? $_";
+    }
+}
+for $f (sort keys %bound) {
+    next if defined($implem{$f});
+    $b=$bound{$f}; $b =~ s/, $//;
+    printf "unimplemented: %-20s (%s)\n", $f, $b;
+}

+ 33 - 0
dselect/curkeys.cc

@@ -0,0 +1,33 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * curkeys.cc - list of ncurses keys for name <-> key mapping
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+extern "C" {
+#include <ncurses/curses.h>
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::keyname keybindings::keynames[] = {
+#include "curkeys.inc"
+};

+ 3 - 0
dselect/debugmake

@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -O0' LDFLAGS=-g 'EXTERNLIBS= -lncurses_g -lefence' "$@"

+ 89 - 0
dselect/dselect.8

@@ -0,0 +1,89 @@
+.\" Hey, Emacs!  This is an -*- nroff -*- source file.
+.TH DSELECT 8 "29th November 1995" "Debian Project" "Debian GNU/Linux"
+.SH NAME
+dselect \- a user tool to manage Debian GNU/Linux packages
+
+.SH SYNOPSIS
+.B dselect
+[options]
+.br
+.B dselect
+[options] action ...
+
+.SH DESCRIPTION
+.B dselect
+is the primary user interface for installing, removing and managing
+Debian GNU/Linux packages. It is an front-end to
+.B dpkg(8).
+Normally
+.B dselect
+is invoked without parameters, but some commandline parameters are still
+available.
+
+The usage of
+.B dselect
+is pretty self-explanatory, and also an internal help-system is
+included, which describes the keystrokes and some general concepts.
+.I Read the help.
+
+.SS ACTIONS
+.TP
+.B access, update, select, install, config, remove
+These actions automatically selects corresponding commands from the main
+menu, without even showing the main menu to you.
+.TP
+.B quit
+Do nothing but quit.
+.TP
+.B menu
+Displays the default menu. This is equivalent to starting
+.B dselect
+with no parameters.
+
+.SS OPTIONS
+.TP
+.B --admindir <directory>
+Changes the directory where datafiles are located. This defaults to
+.I /var/lib/dpkg.
+Note, that these files are just some internal datafiles, actual Debian
+packages doesn't have to be located here.
+.TP
+.B --debug <file> | -D<file>
+Turn on debugging. Debugging information is sent to
+.I <file>.
+.TP
+.B --help
+Print a brief help text.
+.TP
+.B --licence
+Print the licence of
+.B dselect.
+.TP
+.B --version
+Print version information.
+
+.SH BUGS
+This manpage doesn't document the options quite correctly, and has
+formatting inconsistent with other manpages.
+
+The
+.B dselect
+package selection interface is confusing or even alarming to the new
+user.
+
+There is no easy way automatically to download and install packages
+via anonymous FTP.
+
+.SH SEE ALSO
+.B deb(5)
+,
+.B dpkg-deb(8)
+,
+.B dpkg(8)
+and
+.B deb-control(5)
+
+.SH AUTHOR
+.B dselect
+was written by Ian Jackson (ijackson@gnu.ai.mit.edu).
+This manual page is by Juho Vuori (javuori@cc.helsinki.fi).

+ 149 - 0
dselect/dselect.h

@@ -0,0 +1,149 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * dselect.h - external definitions for this program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DSELECT_H
+#define DSELECT_H
+
+#define TOTAL_LIST_WIDTH 180
+#define MAX_DISPLAY_INFO 120
+
+struct helpmenuentry {
+  char key;
+  const struct helpmessage *msg;
+};
+
+class keybindings;
+
+class baselist {
+protected:
+  // Screen dimensions &c.
+  int xmax, ymax;
+  int title_height, colheads_height, list_height;
+  int thisstate_height, info_height, whatinfo_height;
+  int colheads_row, thisstate_row, info_row, whatinfo_row, list_row;
+  int list_attr, listsel_attr, title_attr, colheads_attr, info_attr;
+  int info_headattr, whatinfo_attr;
+  int thisstate_attr, query_attr;
+  int selstate_attr, selstatesel_attr;
+  
+  int total_width;
+  
+  // (n)curses stuff
+  WINDOW *listpad, *infopad, *colheadspad, *thisstatepad;
+  WINDOW *titlewin, *whatinfowin, *querywin;
+  // If listpad is null, then we have not started to display yet, and
+  // so none of the auto-displaying update routines need to display.
+
+  // SIGWINCH handling
+  struct sigaction *osigactp, nsigact;
+  sigset_t *oblockedp, sigwinchset;
+  void setupsigwinch();
+
+  static baselist *signallist;
+  static void sigwinchhandler(int);
+
+  int nitems, ldrawnstart, ldrawnend;
+  int topofscreen, leftofscreen, cursorline;
+  int infotopofscreen, infolines;
+  varbuf whatinfovb;
+  char searchstring[50];
+
+  void unsizes();
+  void dosearch();
+  void displayhelp(const struct helpmenuentry *menu, int key);
+
+  void redrawall();
+  void redrawitemsrange(int start /*inclusive*/, int end /*exclusive*/);
+  void redraw1item(int index);
+  void refreshlist();
+  void refreshinfo();
+  void refreshcolheads();
+  void setcursor(int index);
+
+  void itd_keys();
+
+  virtual void redraw1itemsel(int index, int selected) =0;
+  virtual void redrawcolheads() =0;
+  virtual void redrawthisstate() =0;
+  virtual void redrawinfo() =0;
+  virtual void redrawtitle() =0;
+  virtual void setwidths() =0;
+  virtual const char *itemname(int index) =0;
+  virtual const struct helpmenuentry *helpmenulist() =0;
+
+  void wordwrapinfo(int offset, const char *string);
+  
+public:
+
+  keybindings *bindings;
+
+  void kd_up();
+  void kd_down();
+  void kd_redraw();
+  void kd_scrollon();
+  void kd_scrollback();
+  void kd_scrollon1();
+  void kd_scrollback1();
+  void kd_panon();
+  void kd_panback();
+  void kd_panon1();
+  void kd_panback1();
+  void kd_top();
+  void kd_bottom();
+  void kd_iscrollon();
+  void kd_iscrollback();
+  void kd_iscrollon1();
+  void kd_iscrollback1();
+  void kd_search();
+  void kd_searchagain();
+  void kd_help();
+
+  void startdisplay();
+  void enddisplay();
+
+  baselist(keybindings*);
+  virtual ~baselist();
+};
+
+static inline int lesserint(int a, int b) { return a<b ? a : b; }
+static inline int greaterint(int a, int b) { return a>b ? a : b; }
+
+void displayhelp(const struct helpmenuentry *menu, int key);
+
+void mywerase(WINDOW *win);
+
+void curseson();
+void cursesoff();
+
+extern const char *admindir;
+extern FILE *debug;
+
+enum urqresult { urqr_normal, urqr_fail, urqr_quitmenu };
+enum quitaction { qa_noquit, qa_quitchecksave, qa_quitnochecksave };
+
+typedef urqresult urqfunction(void);
+urqfunction urq_list, urq_quit, urq_menu;
+urqfunction urq_setup, urq_update, urq_install, urq_config, urq_remove;
+
+urqresult falliblesubprocess(const char *exepath, const char *name,
+                             const char *const *args);
+
+#endif /* DSELECT_H */

+ 179 - 0
dselect/helpmsgs.src

@@ -0,0 +1,179 @@
+@@@ listkeys Keystrokes
+
+Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:
+  n, Down-arrow         p, Up-arrow             move highlight
+  N, Page-down, Space   P, Page-up, Backspace   scroll list by 1 page
+  ^n                    ^p                      scroll list by 1 line
+  t, Home               e, End                  jump to top/end of list
+  u                     d                       scroll info by 1 page
+  ^u                    ^d                      scroll info by 1 line
+  B, Left-arrow         F, Right-arrow          pan display by 1/3 screen
+  ^b                    ^f                      pan display by 1 character
+
+Package states - selection:                    Package states - hold flag:
+  +, Insert   select package(s)                  H  put package(s) `on hold'
+  -, Delete   deselect package(s)                G  `go' - take off hold
+  _           deselect, purge configuration
+                                             Miscellaneous:
+Quit, exit, overwrite (note capitals!):         ? request help (also Help, F1)
+ Return  Confirm and quit (check dependencies)  i toggle/cycle info displays      
+   Q     Confirm and quit (override dep.s)      o cycle through sort orders       
+   X     eXit, abandoning any changes made      v toggle verbose status display   
+   R     Revert to state before this list      ^l redraw display                  
+   U     set all to sUggested state             / search (hit Return to cancel)
+   D     set all to Directly selected state     \\ repeat last search             
+
+@@@ mainintro Introduction to package list
+
+Welcome to the main package listing.  Please read the help that is available !
+
+You will be presented with a list of packages which are installed or available
+for installation.  You can navigate around the list using the cursor keys,
+selecting packages for installation (using `+') or deinstallation (using `-').
+
+Packages can be selected either singly or in groups; initially you will see
+that the line `All packages' is highlighted.  (De)selecting will affect all the
+packages described by the highlighted line.  Use `o' to change the order of the
+list (this also changes which kinds of group selections are possible).
+
+(Mainly for new installations:) Standard packages will be selected by default.
+Use capital `D' or `R' key to override this - see the keybindings help screen.
+
+Some of your choices will cause conflicts or dependency problems; you will be
+given a sub-list of the relevant packages, so that you can solve the problems.
+
+When you are satisfied with your choices you should press Return to confirm
+your changes and leave the package listing.  A final check on conflicts and
+dependencies will be done - here too you may see a sublist.
+
+Press Space to leave help and enter the list; press `?' at any time for help.
+
+@@@ readonlyintro Introduction to package list browser (read-only)
+
+Welcome to dselect's main package listing.  Since you do not have the
+privilege necessary to update package selections you are in read-only mode.
+
+Much on-line help is available, please make use of it !  Press `?' for help.
+You should read the list of keys and the explanations of the display.
+
+You will be presented with a list of packages which are installed or available
+for installation.  You can navigate around the list using the cursor keys (just
+as you would be able to do if you had read/write access - see the keystrokes
+help screen) and observe the status of the packages and read information about
+them.
+
+Press Space to leave help and enter the list; press `?' at any time for help.
+When you have finished browsing, press `q' or Return to quit.
+
+@@@ recurintro Introduction to conflict/dependency resolution sub-list
+
+Dependency/conflict resolution - introduction.
+
+One or more of your choices have raised a conflict or dependency problem -
+some packages should only be installed in conjunction with certain others, and
+some combinations of packages may not be installed together.
+
+You will see a sub-list containing the packages involved.  The bottom half of
+the display shows relevant conflicts and dependencies; use `i' to cycle between
+that, the package descriptions and the internal control information.
+
+A set of `suggested' selections has been calculated, and the initial selections
+in this sub-list have been set to match those, so you can just hit Return to
+accept the suggestions if you wish.  You may abort the change(s) which caused
+the problem(s), and go back to the main list, by pressing capital `X'.
+
+You can also move around the list and change the selections so that they are
+more like what you want, and you can `reject' my suggestions by using the
+capital `D' or `R' keys (see the keybindings help screen).  You can use capital
+`Q' to force me to accept the current selections, in case you want to override
+a recommendation or think that the program is mistaken.
+
+Press Space to leave help and enter the sub-list; remember: press `?' for help.
+
+@@@ displayexplain1 Display, part 1: package listing and status chars
+
+The top half of the screen shows a list of packages.  For each package you see
+four columns for its current status and selected-ness.  In terse mode (use `v'
+to toggle verbose display) these are single characters, from left to right:
+
+ Hold/error flag: h - you have put the package on Hold - it won't be processed
+                  R - serious error during installation, needs reinstallation;
+                  X - serious error, needs reinstallation, package also on hold
+ Installed state: Space - not installed;
+                   `*'  - installed;
+                   `-'  - not installed but config files remain;
+                   `u'  - unpacked but not yet configured;
+                   `C'  - half-configured (an error happened);
+                   `I'  - half-installed (an error happened).
+ Old selection: whether this package was selected before presenting this list;
+ Selection: whether this package is selected for installation:
+  `*': selected for installation;
+  `-': deselected (selected for removal, but configuration files will remain);
+  `_': deselected (purge completely, even remove configuration);
+  `n': package is new to this system (appears under `Old selection').
+
+Following those four columns are the Priority and Section of the package,
+its name (possibly truncated to fit) and the summary description.
+
+@@@ displayexplain2 Display, part 2: list highlight; information display
+
+* Highlight: One line in the package list will be highlighted.  It indicates
+  which package(s) will be selected/deselected by presses of `+', '-' and `_'.
+
+* The dividing line in the middle of the screen shows a brief explanation of
+  the status of the currently-highlighted package, or a description of which
+  group is highlighted if a group line is.  If you don't understand the
+  meaning of some of the status characters displayed, go to the relevant
+  package and look at this divider line, or use the `v' key for a verbose
+  display (press `v' again to go back to the terse display).
+
+* The bottom of the screen shows more information about the
+  currently-highlighted package (if there is only one).
+
+  It can show an extended description of the package, the internal package
+  control details, or information about conflicts and dependencies involving
+  the current package (in conflict/dependency resolution sublists).
+
+  Use the `i' key to cycle through the displays.
+
+@@@ methintro Introduction to method selection display
+
+dselect and dpkg can do automatic installation, loading the package files to be
+installed from one of a number of different possible places.
+
+This list allows you to select one of these installation methods.
+
+Move the highlight to the method you wish to use, and hit Enter.  You will then
+be prompted for the information required to do the installation.
+
+As you move the highlight a description of each method, where available, is
+displayed in the bottom half of the screen.
+
+If you wish to quit without changing anything use the `x' key while in the list
+of installation methods.
+
+A full list of keystrokes is available by pressing `k' now, or from the help
+menu reachable by pressing `?'.
+
+@@@ methkeys Keystrokes for method selection
+
+Motion keys: Next/Previous, Top/End, Up/Down, Backwards/Forwards:
+  n, Down-arrow         p, Up-arrow             move highlight
+  N, Page-down, Space   P, Page-up, Backspace   scroll list by 1 page
+  ^n                    ^p                      scroll list by 1 line
+  t, Home               e, End                  jump to top/end of list
+  u                     d                       scroll info by 1 page
+  ^u                    ^d                      scroll info by 1 line
+  B, Left-arrow         F, Right-arrow          pan display by 1/3 screen
+  ^b                    ^f                      pan display by 1 character
+(These are the same motion keys as in the package list display.)
+
+Quit:
+ Return, Enter    select this method and go to its configuration dialogue
+ x, X             exit without changing or setting up the installation method
+
+Miscellaneous:
+  ?, Help, F1      request help
+ ^l                redraw display                  
+  /                search (just return to cancel)  
+  \\                repeat last search             

+ 162 - 0
dselect/junk

@@ -0,0 +1,162 @@
+const packagelist::infotype packagelist::helpinfos[]= {
+  { itr_nonrecursive,  itd_mainwelcome      },
+  { itr_recursive,     itd_recurwelcome     },
+  { 0,                 itd_keys             },
+  { 0,                 itd_explaindisplay   },
+  { 0,                 0                    }
+};
+
+int packagelist::itr_nonrecursive() { return !recursive; }
+
+void packagelist::itd_mainwelcome() {
+  whatinfovb("main welcome page");
+
+  varbuf vb;
+  vb("This is dselect's main package listing screen.");
+  if (!readwrite) vb("  (read-only access.)");
+  vb("\n\n"
+     "Please press `");
+  vb(bindings->find("help"));
+  vb("' repeatedly to show more help, including the list of "
+     "keystrokes and an explanation of the display; use `");
+  vb(bindings->find("iscrollon"));
+  vb("' and `");
+  vb(bindings->find("iscrollback"));
+  vb("' to scroll this help screen.  Press `");
+  vb(bindings->find("info"));
+  vb("' repeatedly to see more information about the highlighted package(s).\n"
+     "\n");
+  if (readwrite) {
+    vb("Move the highlight and use `");
+    vb(bindings->find("select"));
+    vb("' and `");
+    vb(bindings->find("deselect"));
+    vb("' to select and deselect packages for "
+       "installation.  Press `");
+    vb(bindings->find("quit"));
+    vb("' to confirm your changes and quit, or `");
+    vb(bindings->find("abortnocheck"));
+    vb("' to abort without making changes.\n"
+       "\n"
+       "Deselecting a package that is currently "
+       "installed will arrange for it to be deinstalled later.  If you "
+       "select a package for purging its configuration files will be "
+       "deleted when the package is; usually they are kept.\n");
+  } else {
+    vb("You do not have read/write access to the package administration "
+       "area, so you may only examine the state of packages.\n");
+  }
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_explaindisplay() {
+  whatinfovb("explanation of the display");
+
+  varbuf vb;
+  vb("The top half of the screen shows a list of packages.  For each "
+     "package its status (explained in more detail below), class, "
+     "section, name and a summary of its description is shown.\n"
+     "\n"
+     "In the middle of the screen is a status line containing a description "
+     "of the status of the currently highlighted package (or a description "
+     "of which packages are highlighted if this is more than one package).\n"
+     "\n"
+     "The bottom half of the screen is used to display more extended "
+     "information about the highlighed package(s), and for help displays "
+     "like this one.\n"
+     "\n"
+     "The four characters at the start of each package's entry in the list "
+     "show its status: Error, Installed, Old, Wanted.\n"
+     "\n"
+     "`Wanted' is whether it is currently "
+     "selected or not (ie, its desired state as currently being edited); "
+     "`Old', immediately to the left of that, gives the desired state before "
+     "this package list was entered, if different (or a space if not)."
+     "\n"
+     "`Installed' shows the package's current actual state on "
+     "the system; the `Error' column is used to mark packages for which "
+     "installation or removal errors have occurred.\n");
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_recurwelcome() {
+  whatinfovb("recursive package listing welcome page");
+  
+  varbuf vb;
+  vb("Some of the packages you have selected require or recommend "
+     "the installation of other packages you haven't selected, or "
+     "some of them conflict with packages you have selected.\n"
+     "Details of problems for each package are available by pressing `");
+  vb(bindings->find("info"));
+  vb("'.\n"
+     "This sub-list of packages is to allow you to resolve these "
+     "dependencies and conflicts.  You may accept my suggestions "
+     "about which related packages to select or deselect by pressing `");
+  vb(bindings->find("quitcheck"));
+  vb("'.\n"
+     "\n"
+     "Alternatively, you can edit the setup I have suggested, or use `");
+  vb(bindings->find("revertdirect"));
+  vb("' to reject my suggestions, before using `");
+  vb(bindings->find("quitcheck"));
+  vb("'.\n"
+     "\n"
+     "For a list of the keys available, consult the keymap "
+     "help screen (available by pressing `");
+  vb(bindings->find("help"));
+  vb("'); see the manual for detailed information.\n"
+     "\n"
+     "If you wish to replace a package on which many others depend with "
+     "a conflicting one you'll probably find it easier to try selecting "
+     "the new one rather than deselecting the old one first, as doing "
+     "the latter will cause me to suggest deselecting all that depend on it.");
+  wordwrapinfo(0,vb.string());
+}
+
+void methodlist::kd_info() {
+  showinghelp=0;
+  redrawinfo();
+}
+
+void methodlist::kd_help() {
+  if (showinghelp) ifhelpthenkeys= !ifhelpthenkeys;
+  showinghelp=1;
+  redrawinfo();
+}
+
+void methodlist::itd_welcome() {
+  whatinfovb("method selection welcome page");
+
+  varbuf vb;
+  vb("This is dselect's access method selection screen.");
+  vb("\n\n"
+     "Please press `");
+  vb(bindings->find("help"));
+  vb("' to show more help; in particular, you should read the list of "
+     "keystrokes; use `");
+  vb(bindings->find("iscrollon"));
+  vb("' and `");
+  vb(bindings->find("iscrollback"));
+  vb("' to scroll this help screen.  Press `");
+  vb(bindings->find("info"));
+  vb("' to see more information about the highlighted method.\n"
+     "\n");
+  vb("Move the highlight and use `");
+  vb(bindings->find("select-and-quit"));
+  vb("' to select the highlighted method.  Press `");
+  vb(bindings->find("abort"));
+  vb("' to abort without changing the access method.\n"
+     "\n"
+     "When you have selected the access method you will "
+     "be prompted for the information it requires to do the "
+     "installation.\n");
+  wordwrapinfo(0,vb.string());
+}
+
+  if (showinghelp)
+    if (ifhelpthenkeys)
+      itd_keys();
+    else
+      itd_welcome();
+  else
+

+ 59 - 0
dselect/keyoverride

@@ -0,0 +1,59 @@
+# dselect - Debian GNU/Linux package maintenance user interface
+# keyoverride - override strings for ncurses key names
+#
+# Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+# This 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,
+# or (at your option) any later version.
+#
+# This 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; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+32		Space
+13		Return
+27		Escape
+28		^\
+29		^]
+30		^^
+31		^_
+34		Quote
+39		Apostrophe
+44		Comma
+45		Hyphen
+47		Slash
+59		Semicolon
+92		Backslash
+96		Backquote
+127		DEL
+KEY_UP		Up
+KEY_DOWN	Down
+KEY_RIGHT	Right
+KEY_LEFT	Left
+KEY_IC		Insert
+KEY_SIC		Shift Insert
+KEY_DC		Delete
+KEY_SDC		Shift Delete
+KEY_NPAGE	Page Down
+KEY_PPAGE	Page Up
+KEY_CATAB	Clear Tabs
+KEY_EIC		EIC
+KEY_EOL		EOL
+KEY_SEOL	Shift EOL
+KEY_EOS		EOS
+KEY_LL		Bottom
+KEY_SF		Scroll Forward
+KEY_SR		Scroll Reverse
+KEY_SRESET	Soft Reset
+KEY_SLEFT	Shift Left
+KEY_SRIGHT	Shift Right
+KEY_SPREVIOUS	Shift Previous
+KEY_MAX		[elide]
+KEY_MIN		[elide]

+ 91 - 0
dselect/keys.c

@@ -0,0 +1,91 @@
+{ KEY_MIN		, "MIN" },
+{ KEY_BREAK       , "BREAK" },
+{ KEY_DOWN        , "DOWN" },
+{ KEY_UP          , "UP" },
+{ KEY_LEFT        , "LEFT" },
+{ KEY_RIGHT       , "RIGHT" },
+{ KEY_HOME        , "HOME" },
+{ KEY_BACKSPACE   , "BACKSPACE" },
+{ KEY_F0          , "F0" },
+{ KEY_DL          , "DL" },
+{ KEY_IL          , "IL" },
+{ KEY_DC          , "DC" },
+{ KEY_IC          , "IC" },
+{ KEY_EIC         , "EIC" },
+{ KEY_CLEAR       , "CLEAR" },
+{ KEY_EOS         , "EOS" },
+{ KEY_EOL         , "EOL" },
+{ KEY_SF          , "SF" },
+{ KEY_SR          , "SR" },
+{ KEY_NPAGE       , "NPAGE" },
+{ KEY_PPAGE       , "PPAGE" },
+{ KEY_STAB        , "STAB" },
+{ KEY_CTAB        , "CTAB" },
+{ KEY_CATAB       , "CATAB" },
+{ KEY_ENTER       , "ENTER" },
+{ KEY_SRESET      , "SRESET" },
+{ KEY_RESET       , "RESET" },
+{ KEY_PRINT       , "PRINT" },
+{ KEY_LL          , "LL" },
+{ KEY_A1		, "A1" },
+{ KEY_A3		, "A3" },
+{ KEY_B2		, "B2" },
+{ KEY_C1		, "C1" },
+{ KEY_C3		, "C3" },
+{ KEY_BTAB	, "BTAB" },
+{ KEY_BEG		, "BEG" },
+{ KEY_CANCEL	, "CANCEL" },
+{ KEY_CLOSE	, "CLOSE" },
+{ KEY_COMMAND	, "COMMAND" },
+{ KEY_COPY	, "COPY" },
+{ KEY_CREATE	, "CREATE" },
+{ KEY_END		, "END" },
+{ KEY_EXIT	, "EXIT" },
+{ KEY_FIND	, "FIND" },
+{ KEY_HELP	, "HELP" },
+{ KEY_MARK	, "MARK" },
+{ KEY_MESSAGE	, "MESSAGE" },
+{ KEY_MOVE	, "MOVE" },
+{ KEY_NEXT	, "NEXT" },
+{ KEY_OPEN	, "OPEN" },
+{ KEY_OPTIONS	, "OPTIONS" },
+{ KEY_PREVIOUS	, "PREVIOUS" },
+{ KEY_REDO	, "REDO" },
+{ KEY_REFERENCE	, "REFERENCE" },
+{ KEY_REFRESH	, "REFRESH" },
+{ KEY_REPLACE	, "REPLACE" },
+{ KEY_RESTART	, "RESTART" },
+{ KEY_RESUME	, "RESUME" },
+{ KEY_SAVE	, "SAVE" },
+{ KEY_SBEG	, "SBEG" },
+{ KEY_SCANCEL	, "SCANCEL" },
+{ KEY_SCOMMAND	, "SCOMMAND" },
+{ KEY_SCOPY	, "SCOPY" },
+{ KEY_SCREATE	, "SCREATE" },
+{ KEY_SDC		, "SDC" },
+{ KEY_SDL		, "SDL" },
+{ KEY_SELECT	, "SELECT" },
+{ KEY_SEND	, "SEND" },
+{ KEY_SEOL	, "SEOL" },
+{ KEY_SEXIT	, "SEXIT" },
+{ KEY_SFIND	, "SFIND" },
+{ KEY_SHELP	, "SHELP" },
+{ KEY_SHOME	, "SHOME" },
+{ KEY_SIC		, "SIC" },
+{ KEY_SLEFT	, "SLEFT" },
+{ KEY_SMESSAGE	, "SMESSAGE" },
+{ KEY_SMOVE	, "SMOVE" },
+{ KEY_SNEXT	, "SNEXT" },
+{ KEY_SOPTIONS	, "SOPTIONS" },
+{ KEY_SPREVIOUS	, "SPREVIOUS" },
+{ KEY_SPRINT	, "SPRINT" },
+{ KEY_SREDO	, "SREDO" },
+{ KEY_SREPLACE	, "SREPLACE" },
+{ KEY_SRIGHT	, "SRIGHT" },
+{ KEY_SRSUME	, "SRSUME" },
+{ KEY_SSAVE	, "SSAVE" },
+{ KEY_SSUSPEND	, "SSUSPEND" },
+{ KEY_SUNDO	, "SUNDO" },
+{ KEY_SUSPEND	, "SUSPEND" },
+{ KEY_UNDO	, "UNDO" },
+{ KEY_MAX		, "MAX" },

+ 30 - 0
dselect/kt.c

@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ncurses/curses.h>
+
+struct kd { int v; const char *n; } kds[]= {
+#include "curkeys.inc"
+};
+
+int main(int argc, char **argv) {
+  int n=0, c, y,x;
+  struct kd *kdp;
+
+  initscr(); cbreak(); noecho(); nonl();
+  keypad(stdscr,TRUE);
+  getmaxyx(stdscr,y,x);
+  mvprintw(5,5,"q to quit; b to beep; (y%d x%d)",y,x);
+
+  for (;;) {
+    refresh();
+    c= getch(); if (c==ERR) { endwin(); perror("err"); exit(1); }
+    for (kdp=kds; kdp->v != -1 && kdp->v != c; kdp++);
+    n++; mvprintw(10 + (n%4),10,"n %10d  keycode %4d  %-10s  F0 + %4d",n,c,
+                  kdp->n ? kdp->n : "<none>", c-KEY_F0);
+    if (c == 'q') break;
+    if (c == 'b') beep();
+  }
+  endwin();
+  return 0;
+}

+ 30 - 0
dselect/kt.cc

@@ -0,0 +1,30 @@
+#include <stdio.h>
+#include <string.h>
+#include <assert.h>
+#include <ncurses/curses.h>
+
+struct kd { int v; const char *n; } kds[]= {
+#include "curkeys.inc"
+};
+
+int main(int argc, char **argv) {
+  int n=0, c, y,x;
+  struct kd *kdp;
+
+  initscr(); cbreak(); noecho(); nonl();
+  keypad(stdscr,TRUE);
+  getmaxyx(stdscr,y,x);
+  mvprintw(5,5,"q to quit; b to beep; (y%d x%d)",y,x);
+
+  for (;;) {
+    refresh();
+    c= getch(); if (c==ERR) { endwin(); perror("err"); exit(1); }
+    for (kdp=kds; kdp->v != -1 && kdp->v != c; kdp++);
+    n++; mvprintw(10 + (n%4),10,"n %10d  keycode %4d  %-10s  F0 + %4d",n,c,
+                  kdp->n, c-KEY_F0);
+    if (c == 'q') break;
+    if (c == 'b') beep();
+  }
+  endwin();
+  return 0;
+}

+ 308 - 0
dselect/main.cc

@@ -0,0 +1,308 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * main.cc - main program
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <ncurses.h>
+#include <term.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+#include "version.h"
+#include "myopt.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "pkglist.h"
+
+const char thisname[]= DSELECT;
+const char printforhelp[]= "Type " DPKG " --help for help.";
+
+modstatdb_rw readwrite;
+const char *admindir= ADMINDIR;
+FILE *debug;
+
+static keybindings packagelistbindings(packagelist_kinterps,packagelist_korgbindings);
+
+struct menuentry {
+  const char *option;
+  const char *menuent;
+  urqfunction *fn;
+};
+
+static const menuentry menuentries[]= {
+  { "access",  "Choose the access method to use.",                 &urq_setup   },
+  { "update",  "Update list of available packages, if possible.",  &urq_update  },
+  { "select",  "Select which packages to install (or deinstall).", &urq_list    },
+  { "install", "Install selected software.",                       &urq_install },
+  { "config",  "Configure packages that are unconfigured.",        &urq_config  },
+  { "remove",  "Remove software selected for deinstallation.",     &urq_remove  },
+  { "quit",    "Quit dselect.",                                    &urq_quit    },
+  { "menu",     0,                                                 &urq_menu    },
+  {  0                                                                          }
+};
+
+static const char programdesc[]=
+      "Debian GNU/Linux `" DSELECT "' package handling frontend.";
+
+static const char copyrightstring[]=
+      "Version " DPKG_VERSION_ARCH ".  Copyright (C) 1994,1995 Ian Jackson.   This is\n"
+      "free software; see the GNU General Public Licence version 2 or later for\n"
+      "copying conditions.  There is NO warranty.  See dselect --licence for details.\n";
+
+static void printversion(void) {
+  if (fprintf(stderr,"%s\n%s",programdesc,copyrightstring) == EOF) werr("stderr");
+}
+
+static void usage(void) {
+  if (!fputs
+      ("Usage: dselect [options]\n"
+       "       dselect [options] action ...\n"
+       "Options:  --admindir <directory>  (default is /var/lib/dpkg)\n"
+       "          --help  --version  --licence   --debug <file> | -D<file> | -D\n"
+       "Actions:  access update select install config remove quit menu\n",
+       stderr)) werr("stderr");
+}
+
+/* These are called by C code, so need to have C calling convention */
+extern "C" {
+
+  static void helponly(const struct cmdinfo*, const char*) {
+    usage(); exit(0);
+  }
+  static void versiononly(const struct cmdinfo*, const char*) {
+    printversion(); exit(0);
+  }
+
+  static void setdebug(const struct cmdinfo*, const char *v) {
+    debug= fopen(v,"a");
+    if (!debug) ohshite("couldn't open debug file `%.255s'\n",v);
+    setvbuf(debug,0,_IONBF,0);
+  }
+
+} /* End of extern "C" */
+
+static const struct cmdinfo cmdinfos[]= {
+  { "admindir",   0,   1,  0,  &admindir,  0                      },
+  { "debug",     'D',  1,  0,  0,          setdebug               },
+  { "help",      'h',  0,  0,  0,          helponly               },
+  { "version",    0,   0,  0,  0,          versiononly            },
+  { "licence",    0,   0,  0,  0,          showcopyright          }, /* UK spelling */
+  { "license",    0,   0,  0,  0,          showcopyright          }, /* US spelling */
+  {  0,           0                                               }
+};
+
+static int cursesareon= 0;
+void curseson() {
+  if (!cursesareon) {
+    const char *cup, *smso;
+    initscr();
+    cup= tigetstr("cup");
+    smso= tigetstr("smso");
+    if (!cup || !smso) {
+      endwin();
+      if (!cup)
+        fputs("Terminal does not appear to support cursor addressing.\n",stderr);
+      if (!smso)
+        fputs("Terminal does not appear to support highlighting.\n",stderr);
+      fputs("Set your TERM variable correctly, use a better terminal,\n"
+            "or make do with the per-package management tool " DPKG ".\n",stderr);
+      ohshit("terminal lacks necessary features, giving up");
+    }
+  }
+  cursesareon= 1;
+}
+
+void cursesoff() {
+  if (cursesareon) {
+    clear();
+    refresh();
+    endwin();
+  }
+  cursesareon=0;
+}
+
+extern void *operator new(size_t size) {
+  void *p;
+  p= m_malloc(size);
+  assert(p);
+  return p;
+}
+
+extern void operator delete(void *p) {
+  free(p);
+}
+
+urqresult urq_list(void) {
+  readwrite= modstatdb_init(admindir,
+                            msdbrw_writeifposs|msdbrw_availablepreferversion);
+
+  curseson();
+
+  packagelist *l= new packagelist(&packagelistbindings);
+  l->resolvesuggest();
+  l->display();
+  delete l;
+
+  modstatdb_shutdown();
+  resetpackages();
+  return urqr_normal;
+}
+
+void dme(int i, int so) {
+  char buf[120];
+  const menuentry *me= &menuentries[i];
+  sprintf(buf," %c %d. [%c]%-10.10s %-80.80s ",
+          so ? '*' : ' ', i,
+          toupper(me->option[0]), me->option+1,
+          me->menuent);
+  
+  int y,x;
+  getmaxyx(stdscr,y,x);
+
+  attrset(so ? A_REVERSE : A_NORMAL);
+  mvaddnstr(i+2,0, buf,x-1);
+  attrset(A_NORMAL);
+}
+
+int refreshmenu(void) {
+  curseson(); cbreak(); noecho(); nonl(); keypad(stdscr,TRUE);
+
+  int y,x;
+  getmaxyx(stdscr,y,x);
+
+  clear();
+  attrset(A_BOLD);
+  mvaddnstr(0,0, programdesc,x-1);
+
+  attrset(A_NORMAL);
+  const struct menuentry *mep; int i;
+  for (mep=menuentries, i=0; mep->option && mep->menuent; mep++, i++)
+    dme(i,0);
+
+  attrset(A_BOLD);
+  addstr("\n\n"
+         "Use ^P and ^N, cursor keys, initial letters, or digits to select;\n"
+         "Press ENTER to confirm selection.   ^L to redraw screen.\n\n");
+
+  attrset(A_NORMAL);
+  addstr(copyrightstring);
+
+  return i;
+}
+
+urqresult urq_menu(void) {
+#define C(x) ((x)-'a'+1)
+  int entries, c, i;
+  entries= refreshmenu();
+  int cursor=0;
+  dme(0,1);
+  for (;;) {
+    refresh();
+    c= getch();  if (c==ERR) ohshite("failed to getch in main menu");
+    if (c==C('n') || c==KEY_DOWN || c==' ') {
+      dme(cursor,0); cursor++; cursor %= entries; dme(cursor,1);
+    } else if (c==C('p') || c==KEY_UP || c==C('h') ||
+               c==KEY_BACKSPACE || c==KEY_DC) {
+      dme(cursor,0); cursor+= entries-1; cursor %= entries; dme(cursor,1);
+    } else if (c=='\n' || c=='\r' || c==KEY_ENTER) {
+      clear(); refresh();
+      switch (menuentries[cursor].fn()) { /* fixme: trap errors in urq_... */
+      case urqr_quitmenu:
+        return urqr_quitmenu;
+      case urqr_normal:
+        cursor++; cursor %= entries;
+      case urqr_fail:
+        break;
+      default:
+        internerr("unknown menufn");
+      }
+      refreshmenu(); dme(cursor,1);
+    } else if (c==C('l')) {
+      clearok(stdscr,TRUE); clear(); refreshmenu(); dme(cursor,1);
+    } else if (isdigit(c)) {
+      char buf[2]; buf[0]=c; buf[1]=0; c=atoi(buf);
+      if (c < entries) {
+        dme(cursor,0); cursor=c; dme(cursor,1);
+      } else {
+        beep();
+      }
+    } else if (isalpha(c)) {
+      c= tolower(c);
+      for (i=0; i<entries && menuentries[i].option[0] != c; i++);
+      if (i < entries) {
+        dme(cursor,0); cursor=i; dme(cursor,1);
+      } else {
+        beep();
+      }
+    } else {
+      beep();
+    }
+  }
+}
+
+urqresult urq_quit(void) {
+  return urqr_quitmenu;
+  /* fixme: check packages OK */
+}
+
+int main(int, const char *const *argv) {
+  jmp_buf ejbuf;
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    cursesoff();
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  myopt(&argv,cmdinfos);
+
+  if (*argv) {
+    const char *a;
+    while ((a= *argv++) != 0) {
+      const menuentry *me;
+      for (me= menuentries; me->option && strcmp(me->option,a); me++);
+      if (!me->option) badusage("unknown action string `%.50s'",a);
+      me->fn();
+    }
+  } else {
+    urq_menu();
+  }
+
+  cursesoff();
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+  return(0);
+}

+ 112 - 0
dselect/methkeys.cc

@@ -0,0 +1,112 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methkeys.cc - method list keybindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::interpretation methodlist_kinterps[] = {
+  { "up",              methodlist::kd_up,             0,    qa_noquit           },
+  { "down",            methodlist::kd_down,           0,    qa_noquit           },
+  { "top",             methodlist::kd_top,            0,    qa_noquit           },
+  { "bottom",          methodlist::kd_bottom,         0,    qa_noquit           },
+  { "scrollon",        methodlist::kd_scrollon,       0,    qa_noquit           },
+  { "scrollback",      methodlist::kd_scrollback,     0,    qa_noquit           },
+  { "iscrollon",       methodlist::kd_iscrollon,      0,    qa_noquit           },
+  { "iscrollback",     methodlist::kd_iscrollback,    0,    qa_noquit           },
+  { "scrollon1",       methodlist::kd_scrollon1,      0,    qa_noquit           },
+  { "scrollback1",     methodlist::kd_scrollback1,    0,    qa_noquit           },
+  { "iscrollon1",      methodlist::kd_iscrollon1,     0,    qa_noquit           },
+  { "iscrollback1",    methodlist::kd_iscrollback1,   0,    qa_noquit           },
+  { "panon",           methodlist::kd_panon,          0,    qa_noquit           },
+  { "panback",         methodlist::kd_panback,        0,    qa_noquit           },
+  { "panon1",          methodlist::kd_panon1,         0,    qa_noquit           },
+  { "panback1",        methodlist::kd_panback1,       0,    qa_noquit           },
+  { "help",            methodlist::kd_help,           0,    qa_noquit           },
+  { "search",          methodlist::kd_search,         0,    qa_noquit           },
+  { "searchagain",     methodlist::kd_searchagain,    0,    qa_noquit           },
+  { "redraw",          methodlist::kd_redraw,         0,    qa_noquit           },
+  { "select-and-quit", methodlist::kd_quit,           0,    qa_quitchecksave    },
+  { "abort",           methodlist::kd_abort,          0,    qa_quitnochecksave  },
+  {  0,                0,                                   qa_noquit           }
+};
+
+#define C(x) ((x)-'a'+1)
+
+const keybindings::orgbinding methodlist_korgbindings[]= {
+  { 'n',            "down"           },
+  { KEY_DOWN,       "down"           },
+  { 'p',            "up"             },
+  { KEY_UP,         "up"             },
+  
+  { 'N',            "scrollon"       },
+  { KEY_NPAGE,      "scrollon"       },
+  { ' ',            "scrollon"       },
+  { 'P',            "scrollback"     },
+  { KEY_PPAGE,      "scrollback"     },
+  { KEY_BACKSPACE,  "scrollback"     },
+  { 0177,/*DEL*/    "scrollback"     },
+  { C('h'),         "scrollback"     },
+  { C('n'),         "scrollon1"      },
+  { C('p'),         "scrollback1"    },
+  
+  { 't',            "top"            },
+  { KEY_HOME,       "top"            },
+  { 'e',            "bottom"         },
+  { KEY_LL,         "bottom"         },
+  { KEY_END,        "bottom"         },
+  
+  { 'u',            "iscrollback"    },
+  { 'd',            "iscrollon"      },
+  { C('u'),         "iscrollback1"   },
+  { C('d'),         "iscrollon1"     },
+  
+  { 'B',            "panback"        },
+  { KEY_LEFT,       "panback"        },
+  { 'F',            "panon"          },
+  { KEY_RIGHT,      "panon"          },
+  { C('b'),         "panback1"       },
+  { C('f'),         "panon1"         },
+                                      
+  { '?',            "help"             },
+  { KEY_HELP,       "help"             },
+  { KEY_F(1),       "help"             },
+  { '/',            "search"           },
+  { '\\',           "searchagain"      },
+  { C('l'),         "redraw"           },
+
+  { KEY_ENTER,      "select-and-quit"  },
+  { '\r',           "select-and-quit"  },
+  { 'x',            "abort"            },
+  { 'X',            "abort"            },
+  
+  {  -1,             0                 }
+};

+ 213 - 0
dselect/methlist.cc

@@ -0,0 +1,213 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methlist.cc - list of access methods and options
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "method.h"
+#include "helpmsgs.h"
+
+static keybindings methodlistbindings(methodlist_kinterps,methodlist_korgbindings);
+
+const char *methodlist::itemname(int index) {
+  return table[index]->name;
+}
+
+void methodlist::kd_abort() { }
+
+void methodlist::kd_quit() {
+  if (debug) fprintf(debug,"methodlist[%p]::kd_quit() setting coption=%p\n",
+                     this, table[cursorline]);
+  coption= table[cursorline];
+}
+
+void methodlist::setwidths() {
+  if (debug) fprintf(debug,"methodlist[%p]::setwidths()\n",this);
+
+  status_width= 1;
+  gap_width= 1;
+  name_width= 14;
+  name_column= status_width + gap_width;
+  description_column= name_column + name_width + gap_width;
+
+  total_width= TOTAL_LIST_WIDTH;
+  description_width= total_width - description_column;
+}
+
+void methodlist::redrawtitle() {
+  if (title_height) {
+    mywerase(titlewin);
+    mvwaddnstr(titlewin,0,0,"dselect - list of access methods",xmax);
+    wnoutrefresh(titlewin);
+  }
+}
+
+void methodlist::redrawthisstate() {
+  if (!thisstate_height) return;
+  mywerase(thisstatepad);
+  wprintw(thisstatepad,
+          "Access method `%s'.",
+          table[cursorline]->name);
+  pnoutrefresh(thisstatepad, 0,0, thisstate_row,0,
+               thisstate_row, lesserint(total_width - 1, xmax - 1));
+}
+
+void methodlist::redraw1itemsel(int index, int selected) {
+  int i;
+  const char *p;
+
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+  mvwaddch(listpad,index,0,
+           table[index] == coption ? '*' : ' ');
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+  mvwprintw(listpad,index,name_column-1, " %-*.*s ",
+            name_width, name_width, table[index]->name);
+  
+  i= description_width;
+  p= table[index]->summary ? table[index]->summary : "";
+  while (i>0 && *p && *p != '\n') {
+    waddch(listpad,*p);
+    i--; p++;
+  }
+  while (i>0) {
+    waddch(listpad,' ');
+    i--;
+  }
+}
+
+void methodlist::redrawcolheads() {
+  if (colheads_height) {
+    wattrset(colheadspad,colheads_attr);
+    mywerase(colheadspad);
+    mvwaddstr(colheadspad,0,0, "  ");
+    mvwaddnstr(colheadspad,0,name_column, "Abbrev.", name_width);
+    mvwaddnstr(colheadspad,0,description_column, "Description", description_width);
+  }
+  refreshcolheads();
+}
+
+methodlist::methodlist() : baselist(&methodlistbindings) {
+  if (debug)
+    fprintf(debug,"methodlist[%p]::methodlist()\n",this);
+
+  table= new struct option*[noptions];
+
+  struct option *opt, **ip;
+  for (opt=options, ip=table, nitems=0; opt; opt=opt->next, nitems++) *ip++= opt;
+  assert(nitems==noptions);
+
+  setcursor(0);
+
+  if (debug)
+    fprintf(debug,"methodlist[%p]::methodlist done; noptions=%d\n", this, noptions);
+}
+
+methodlist::~methodlist() {
+  if (debug) fprintf(debug,"methodlist[%p]::~methodlist()\n",this);
+  delete[] table;
+}
+
+quitaction methodlist::display() {
+  int response;
+  const keybindings::interpretation *interp;
+
+  if (debug) fprintf(debug,"methodlist[%p]::display()\n",this);
+
+  setupsigwinch();
+  startdisplay();
+  
+  if (debug) fprintf(debug,"methodlist[%p]::display() entering loop\n",this);
+  for (;;) {
+    if (whatinfo_height) wcursyncup(whatinfowin);
+    if (doupdate() == ERR) ohshite("doupdate failed");
+    signallist= this;
+    if (sigprocmask(SIG_UNBLOCK,&sigwinchset,0)) ohshite("failed to unblock SIGWINCH");
+    response= getch();
+    if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to re-block SIGWINCH");
+    if (response == ERR) ohshite("getch failed");
+    interp= (*bindings)(response);
+    if (debug)
+      fprintf(debug,"methodlist[%p]::display() response=%d interp=%s\n",
+              this,response, interp ? interp->action : "[none]");
+    if (!interp) { beep(); continue; }
+    (this->*(interp->mfn))();
+    if (interp->qa != qa_noquit) break;
+  }
+  pop_cleanup(ehflag_normaltidy); // unset the SIGWINCH handler
+  enddisplay();
+  
+  if (debug) fprintf(debug,"methodlist[%p]::display() done\n",this);
+
+  return interp->qa;
+}
+
+void methodlist::itd_description() {
+  whatinfovb("explanation of ");
+  whatinfovb(table[cursorline]->name);
+
+  wattrset(infopad,info_headattr);
+  waddstr(infopad, table[cursorline]->name);
+  waddstr(infopad," - ");
+  waddstr(infopad, table[cursorline]->summary);
+  wattrset(infopad,info_attr);
+
+  const char *m= table[cursorline]->description;
+  if (!m || !*m) m= "No explanation available.";
+  waddstr(infopad,"\n\n");
+  wordwrapinfo(0,m);
+}
+
+void methodlist::redrawinfo() {
+  if (!info_height) return;
+  whatinfovb.reset();
+  werase(infopad); wmove(infopad,0,0);
+  
+  if (debug) fprintf(debug,"methodlist[%p]::redrawinfo()\n", this);
+
+  itd_description();
+
+  whatinfovb.terminate();
+  int y,x;
+  getyx(infopad, y,x);
+  if (x) y++;
+  infolines= y;
+
+  refreshinfo();
+}
+
+const struct helpmenuentry *methodlist::helpmenulist() {
+  static const struct helpmenuentry list[]= {
+    { 'i', &hlp_methintro            },
+    { 'k', &hlp_methkeys             },
+    {  0                             }
+  };
+  return list;
+};

+ 272 - 0
dselect/method.cc

@@ -0,0 +1,272 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * method.cc - access method handling
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/file.h>
+
+#include <ncurses.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "method.h"
+
+static const char *const methoddirectories[]= {
+  LIBDIR "/" METHODSDIR,
+  LOCALLIBDIR "/" METHODSDIR,
+  0
+};    
+
+static char *methodlockfile= 0;
+static int methlockfd= -1;
+
+static void cu_unlockmethod(int, void**) {
+  assert(methodlockfile);
+  assert(methlockfd);
+  if (flock(methlockfd,LOCK_UN))
+    ohshite("unable to unlock access method area");
+}
+
+static enum urqresult ensureoptions(void) {
+  const char *const *ccpp;
+  option *newoptions;
+  int nread;
+
+  if (!options) {
+    newoptions= 0;
+    nread= 0;
+    for (ccpp= methoddirectories; *ccpp; ccpp++)
+      readmethods(*ccpp, &newoptions, &nread);
+    if (!newoptions) {
+      curseson();
+      addstr("No access methods are available.\n\n"
+             "Press RETURN to continue.");
+      refresh(); getch();
+      return urqr_fail;
+    }
+    options= newoptions;
+    noptions= nread;
+  }
+  return urqr_normal;
+}
+
+static void lockmethod(void) {
+  if (!methodlockfile) {
+    int l;
+    l= strlen(admindir);
+    methodlockfile= new char[l+sizeof(METHLOCKFILE)+2];
+    strcpy(methodlockfile,admindir);
+    strcpy(methodlockfile+l, "/" METHLOCKFILE);
+  }
+  if (methlockfd == -1) {
+    methlockfd= open(methodlockfile, O_RDWR|O_CREAT|O_TRUNC, 0660);
+    if (methlockfd == -1) {
+      if (errno == EPERM)
+        ohshit("you do not have permission to change the access method");
+      ohshite("unable to open/create access method lockfile");
+    }
+  }
+  if (flock(methlockfd,LOCK_EX|LOCK_NB)) {
+    if (errno == EWOULDBLOCK || errno == EAGAIN)
+      ohshit("the access method area is already locked");
+    ohshite("unable to lock access method area");
+  }
+  push_cleanup(cu_unlockmethod,~0, 0,0, 0);
+}
+
+static int catchsignals[]= { SIGQUIT, SIGINT, 0 };
+#define NCATCHSIGNALS ((signed)(sizeof(catchsignals)/sizeof(int))-1)
+static struct sigaction uncatchsignal[NCATCHSIGNALS];
+
+void cu_restoresignals(int, void**) {
+  int i;
+  for (i=0; i<NCATCHSIGNALS; i++)
+    if (sigaction(catchsignals[i],&uncatchsignal[i],0))
+      fprintf(stderr,"error un-catching signal %d: %s\n",
+              catchsignals[i],strerror(errno));
+}
+
+urqresult falliblesubprocess(const char *exepath, const char *name,
+                             const char *const *args) {
+  pid_t c1, cr;
+  int status, i, c;
+  struct sigaction catchsig;
+  
+  cursesoff();
+
+  memset(&catchsig,0,sizeof(catchsig));
+  catchsig.sa_handler= SIG_IGN;
+  sigemptyset(&catchsig.sa_mask);
+  catchsig.sa_flags= 0;
+  for (i=0; i<NCATCHSIGNALS; i++)
+    if (sigaction(catchsignals[i],&catchsig,&uncatchsignal[i]))
+      ohshite("unable to ignore signal %d before running %.250s",
+              catchsignals[i], name);
+  push_cleanup(cu_restoresignals,~0, 0,0, 0);
+
+  if (!(c1= m_fork())) {
+    cu_restoresignals(0,0);
+    execvp(exepath,(char* const*) args);
+    ohshite("unable to run %.250s process `%.250s'",name,exepath);
+  }
+
+  while ((cr= waitpid(c1,&status,0)) == -1)
+    if (errno != EINTR) ohshite("unable to wait for %.250s",name);
+  if (cr != c1)
+    ohshit("got wrong child's status - asked for %ld, got %ld",(long)c1,(long)cr);
+
+  pop_cleanup(ehflag_normaltidy);
+
+  if (WIFEXITED(status) && !WEXITSTATUS(status)) {
+    sleep(1);
+    return urqr_normal;
+  }
+  fprintf(stderr,"\n%s ",name);
+  if (WIFEXITED(status)) {
+    i= WEXITSTATUS(status);
+    fprintf(stderr,"returned error exit status %d.\n",i);
+  } else if (WIFSIGNALED(status)) {
+    i= WTERMSIG(status);
+    if (i == SIGINT) {
+      fprintf(stderr,"was interrupted.\n");
+    } else {
+      fprintf(stderr,"was terminated by a signal: %s.\n",strsignal(i));
+    }
+    if (WCOREDUMP(status))
+      fprintf(stderr,"(It left a coredump.)\n");
+  } else {
+    fprintf(stderr,"failed with an unknown wait return code %d.\n",status);
+  }
+  fprintf(stderr,"Press RETURN to continue.\n");
+  if (ferror(stderr))
+    ohshite("write error on standard error");
+  do { c= fgetc(stdin); } while (c != EOF && c != '\n');
+  if (c == EOF)
+    ohshite("error reading acknowledgement of program failure message");
+  return urqr_fail;
+}
+
+static urqresult runscript(const char *exepath, const char *name) {
+  urqresult ur;  
+
+  ur= ensureoptions();  if (ur != urqr_normal) return ur;
+  lockmethod();
+  getcurrentopt();
+
+  if (coption) {
+    strcpy(coption->meth->pathinmeth,exepath);
+    const char *fallibleargs[] = {
+      exepath,
+      admindir,
+      coption->meth->name,
+      coption->name,
+      0
+      };
+    ur= falliblesubprocess(coption->meth->path,name,fallibleargs);
+  } else {
+    curseson();
+    addstr("No access method is selected/configured.\n\n"
+           "Press RETURN to continue.");
+    refresh(); getch();
+    ur= urqr_fail;
+  }
+  pop_cleanup(ehflag_normaltidy);
+
+  return ur;
+}
+
+urqresult urq_update(void) {
+  return runscript(METHODUPDATESCRIPT,"update available list script");
+}
+
+urqresult urq_install(void) {
+  return runscript(METHODINSTALLSCRIPT,"installation script");
+}
+
+static urqresult rundpkgauto(const char *name, const char *dpkgmode) {
+  const char *fallibleargs[] = {
+    DPKG,
+    "--pending",
+    dpkgmode,
+    0
+  };
+  cursesoff();
+  printf("running dpkg --pending %s ...\n",dpkgmode);
+  fflush(stdout);
+  return falliblesubprocess(DPKG,name,fallibleargs);
+}
+
+urqresult urq_remove(void) {
+  return rundpkgauto("dpkg --remove","--remove");
+}
+
+urqresult urq_config(void) {
+  return rundpkgauto("dpkg --configure","--configure");
+}
+
+urqresult urq_setup(void) {
+  quitaction qa;
+  urqresult ur;
+
+  ur= ensureoptions();  if (ur != urqr_normal) return ur;
+  lockmethod();  
+  getcurrentopt();
+
+  curseson();
+  methodlist *l= new methodlist();
+  qa= l->display();
+  delete l;
+
+  if (qa == qa_quitchecksave) {
+    strcpy(coption->meth->pathinmeth,METHODSETUPSCRIPT);
+    const char *fallibleargs[] = {
+      METHODSETUPSCRIPT,
+      admindir,
+      coption->meth->name,
+      coption->name,
+      0
+    };
+    ur= falliblesubprocess(coption->meth->path,"query/setup script",fallibleargs);
+    if (ur == urqr_normal) writecurrentopt();
+  } else {
+    ur= urqr_fail;
+  }
+  
+  pop_cleanup(ehflag_normaltidy);
+  return ur;
+}

+ 79 - 0
dselect/method.h

@@ -0,0 +1,79 @@
+/* -*- c++ -*-
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * method.h - access method handling declarations
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef METHOD_H
+#define METHOD_H
+
+struct method {
+  struct method *next, *back;
+  char *name, *path, *pathinmeth;
+};
+
+struct option {
+  option *next;
+  method *meth;
+  char index[OPTIONINDEXMAXLEN];
+  char *name, *summary;
+  char *description;
+};
+
+class methodlist : public baselist {
+  int status_width, gap_width, name_width, description_width;
+  int name_column, description_column;
+
+  // Table of methods
+  struct option **table;
+
+  // Misc.
+  char searchstring[50];
+  
+  // Information displays
+  void itd_description();
+  
+  // Define these virtuals
+  void redraw1itemsel(int index, int selected);
+  void redrawcolheads();
+  void redrawthisstate();
+  void redrawinfo();
+  void redrawtitle();
+  void setwidths();
+  const char *itemname(int index);
+  const struct helpmenuentry *helpmenulist();
+
+ public:
+  // Keybinding functions */
+  void kd_quit();
+  void kd_abort();
+  
+  methodlist();
+  quitaction display();
+  ~methodlist();
+};
+
+extern int noptions;
+extern struct option *options, *coption;
+extern struct method *methods;
+
+extern void readmethods(const char *pathbase, option **optionspp, int *nread);
+extern void getcurrentopt();
+extern void writecurrentopt();
+
+#endif /* METHOD_H */

+ 289 - 0
dselect/methparse.cc

@@ -0,0 +1,289 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * methparse.cc - access method list parsing
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include <ncurses.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+int noptions=0;
+struct option *options=0, *coption=0;
+struct method *methods=0;
+
+static void badmethod(const char *pathname, const char *why) __NORETURN;
+static void badmethod(const char *pathname, const char *why) {
+  ohshit("syntax error in method options file `%.250s' -- %s", pathname, why);
+}
+
+static void eofmethod(const char *pathname, FILE *f, const char *why) __NORETURN;
+static void eofmethod(const char *pathname, FILE *f, const char *why) {
+  if (ferror(f)) ohshite("error reading options file `%.250s'",pathname);
+  badmethod(pathname,why);
+}
+
+void readmethods(const char *pathbase, option **optionspp, int *nread) {
+  static const char *const methodprograms[]= {
+    METHODSETUPSCRIPT, METHODUPDATESCRIPT, METHODINSTALLSCRIPT, 0
+  };
+  const char *const *ccpp;
+  int methodlen, c, baselen;
+  char *p, *pathinmeth, *pathbuf, *pathmeth;
+  DIR *dir;
+  FILE *names, *descfile;
+  struct dirent *dent;
+  struct varbuf vb;
+  method *meth;
+  option *opt, **optinsert;
+  struct stat stab;
+
+  baselen= strlen(pathbase);
+  pathbuf= new char[baselen+IMETHODMAXLEN+IOPTIONMAXLEN+sizeof(OPTIONSDESCPFX)+10];
+  strcpy(pathbuf,pathbase);
+  strcpy(pathbuf+baselen,"/");
+  pathmeth= pathbuf+baselen+1;
+
+  dir= opendir(pathbuf);
+  if (!dir) {
+    if (errno == ENOENT) return;
+    ohshite("unable to read `%.250s' directory for reading methods",pathbuf);
+  }
+
+  if (debug) fprintf(debug,"readmethods(`%s',...) directory open\n", pathbase);
+  
+  while ((dent= readdir(dir)) != 0) {
+    c= dent->d_name[0];
+    if (debug) fprintf(debug,"readmethods(`%s',...) considering `%s' ...\n",
+                       pathbase,dent->d_name);
+    if (c != '_' && !isalpha(c)) continue;
+    for (p= dent->d_name+1; (c= *p) != 0 && isalnum(c) && c != '_'; p++);
+    if (c) continue;
+    methodlen= strlen(dent->d_name);
+    if (methodlen > IMETHODMAXLEN)
+      ohshit("method `%.250s' has name that is too long (%d > %d characters)",
+             dent->d_name, methodlen, IMETHODMAXLEN);
+    strcpy(pathmeth, dent->d_name);
+    strcpy(pathmeth+methodlen, "/");
+    pathinmeth= pathmeth+methodlen+1;
+
+    for (ccpp= methodprograms; *ccpp; ccpp++) {
+      strcpy(pathinmeth,*ccpp);
+      if (access(pathbuf,R_OK|X_OK))
+        ohshite("unable to access method script `%.250s'",pathbuf);
+    }
+    if (debug) fprintf(debug," readmethods(`%s',...) scripts ok\n", pathbase);
+
+    strcpy(pathinmeth,METHODOPTIONSFILE);
+    names= fopen(pathbuf,"r");
+    if (!names) ohshite("unable to read method options file `%.250s'",pathbuf);
+
+    meth= new method;
+    meth->name= new char[strlen(dent->d_name)+1];
+    strcpy(meth->name,dent->d_name);
+    meth->path= new char[baselen+1+methodlen+2+50];
+    strncpy(meth->path,pathbuf,baselen+1+methodlen);
+    strcpy(meth->path+baselen+1+methodlen,"/");
+    meth->pathinmeth= meth->path+baselen+1+methodlen+1;
+    meth->next= methods;
+    meth->back= 0;
+    if (methods) methods->back= meth;
+    methods= meth;
+    if (debug) fprintf(debug," readmethods(`%s',...) new method"
+                       " name=`%s' path=`%s' pathinmeth=`%s'\n",
+                       pathbase, meth->name, meth->path, meth->pathinmeth);
+    
+    while ((c= fgetc(names)) != EOF) {
+      if (isspace(c)) continue;
+      opt= new option;
+      opt->meth= meth;
+      vb.reset();
+      do {
+        if (!isdigit(c)) badmethod(pathbuf,"non-digit where digit wanted");
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in index string");
+      } while (!isspace(c));
+      if (strlen(vb.string()) > OPTIONINDEXMAXLEN)
+        badmethod(pathbuf,"index string too long");
+      strcpy(opt->index,vb.string());
+      do {
+        if (c == '\n') badmethod(pathbuf,"newline before option name start");
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF before option name start");
+      } while (isspace(c));
+      vb.reset();
+      if (!isalpha(c) && c != '_')
+        badmethod(pathbuf,"nonalpha where option name start wanted");
+      do {
+        if (!isalnum(c) && c != '_') badmethod(pathbuf,"non-alphanum in option name");
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in option name");
+      } while (!isspace(c));
+      opt->name= new char[strlen(vb.string())+1];
+      strcpy(opt->name,vb.string());
+      do {
+        if (c == '\n') badmethod(pathbuf,"newline before summary");
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF before summary");
+      } while (isspace(c));
+      vb.reset();
+      do {
+        vb(c);
+        c= fgetc(names);
+        if (c == EOF) eofmethod(pathbuf,names,"EOF in summary - missing newline");
+      } while (c != '\n');
+      opt->summary= new char[strlen(vb.string())+1];
+      strcpy(opt->summary,vb.string());
+      
+      strcpy(pathinmeth,OPTIONSDESCPFX);
+      strcpy(pathinmeth+sizeof(OPTIONSDESCPFX)-1,opt->name);
+      descfile= fopen(pathbuf,"r");
+      if (!descfile) {
+        if (errno != ENOENT)
+          ohshite("unable to open option description file `%.250s'",pathbuf);
+        opt->description= 0;
+      } else { /* descfile != 0 */
+        if (fstat(fileno(descfile),&stab))
+          ohshite("unable to stat option description file `%.250s'",pathbuf);
+        opt->description= new char[stab.st_size+1];  errno=0;
+        if (fread(opt->description,1,stab.st_size+1,descfile) != stab.st_size)
+          ohshite("failed to read option description file `%.250s'",pathbuf);
+        opt->description[stab.st_size]= 0;
+        if (ferror(descfile))
+          ohshite("error during read of option description file `%.250s'",pathbuf);
+        fclose(descfile);
+      }
+      strcpy(pathinmeth,METHODOPTIONSFILE);
+      
+      if (debug) fprintf(debug," readmethods(`%s',...) new option"
+                         " index=`%s' name=`%s' summary=`%.20s'"
+                         " strlen(description=%s)=%d"
+                         " method name=`%s' path=`%s' pathinmeth=`%s'\n",
+                         pathbase,
+                         opt->index, opt->name, opt->summary,
+                         opt->description ? "`...'" : "null",
+                         opt->description ? strlen(opt->description) : -1,
+                         opt->meth->name, opt->meth->path, opt->meth->pathinmeth);
+      for (optinsert= optionspp;
+           *optinsert && strcmp(opt->index,(*optinsert)->index) > 0;
+           optinsert= &(*optinsert)->next);
+      opt->next= *optinsert;
+      *optinsert= opt;
+      (*nread)++;
+    }
+    if (ferror(names))
+      ohshite("error during read of method options file `%.250s'",pathbuf);
+    fclose(names);
+  }
+  closedir(dir);
+  if (debug) fprintf(debug,"readmethods(`%s',...) done\n", pathbase);
+  delete[] pathbuf;
+}
+
+static char *methoptfile= 0;
+
+void getcurrentopt() {
+  char methoptbuf[IMETHODMAXLEN+1+IOPTIONMAXLEN+2];
+  FILE *cmo;
+  int l;
+  int admindirlen;
+  char *p;
+  method *meth;
+  option *opt;
+  
+  if (!methoptfile) {
+    admindirlen= strlen(admindir);
+    methoptfile= new char[admindirlen + sizeof(CMETHOPTFILE) + 2];
+    strcpy(methoptfile,admindir);
+    strcpy(methoptfile+admindirlen, "/" CMETHOPTFILE);
+  }
+
+  coption= 0;
+  cmo= fopen(methoptfile,"r");
+  if (!cmo) {
+    if (errno == ENOENT) return;
+    ohshite("unable to open current option file `%.250s'",methoptfile);
+  }
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt open\n");
+  if (!fgets(methoptbuf,sizeof(methoptbuf),cmo)) { fclose(cmo); return; }
+  if (fgetc(cmo) != EOF) { fclose(cmo); return; }
+  if (!feof(cmo)) { fclose(cmo); return; }
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt eof\n");
+  fclose(cmo);
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt read\n");
+  l= strlen(methoptbuf);  if (!l || methoptbuf[l-1] != '\n') return;
+  methoptbuf[--l]= 0;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt len and newline\n");
+  p= strchr(methoptbuf,' ');  if (!p) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt space\n");
+  *p++= 0;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt meth name `%s'\n", methoptbuf);
+  for (meth= methods; meth && strcmp(methoptbuf,meth->name); meth= meth->next);
+  if (!meth) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt meth found; opt `%s'\n",p);
+  for (opt= options; opt && (opt->meth != meth || strcmp(p,opt->name)); opt= opt->next);
+  if (!opt) return;
+  if (debug) fprintf(debug,"getcurrentopt() cmethopt opt found\n");
+  coption= opt;
+}
+
+void writecurrentopt() {
+  FILE *cmo;
+  int l;
+  static char *newfile=0;
+
+  assert(methoptfile);
+  if (!newfile) {
+    l= strlen(methoptfile);
+    newfile= new char[l + sizeof(NEWDBEXT) + 1];
+    strcpy(newfile,methoptfile);
+    strcpy(newfile+l, NEWDBEXT);
+  }
+  cmo= fopen(newfile,"w");
+  if (!cmo) ohshite("unable to open new option file `%.250s'",newfile);
+  if (fprintf(cmo,"%s %s\n",coption->meth->name,coption->name) == EOF) {
+    fclose(cmo);
+    ohshite("unable to write new option to `%.250s'",newfile);
+  }
+  if (fclose(cmo))
+    ohshite("unable to close new option file `%.250s'",newfile);
+  if (rename(newfile,methoptfile))
+    ohshite("unable to install new option as `%.250s'",methoptfile);
+}

+ 121 - 0
dselect/mkcurkeys.pl

@@ -0,0 +1,121 @@
+#!/usr/bin/perl --
+#
+# dselect - Debian GNU/Linux package maintenance user interface
+# mkcurkeys.pl - generate strings mapping key names to ncurses numbers
+#
+# Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+#
+# This 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,
+# or (at your option) any later version.
+#
+# This 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; if not, write to the Free Software
+# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+@ARGV == 2 || die;
+
+open(OV,"<$ARGV[0]") || die $!;
+while (<OV>) {
+    m/^#/ && next;
+    m/\S/ || next;
+    m/^(\w+)\s+(\S.*\S)\s+$/ || die;
+    $over{$1}= $2;
+    $base{$1}= '';
+}
+close(OV);
+
+for ($i=1, $let='A'; $i<=26; $i++, $let++) {
+    $name{$i}= "^$let";
+    $base{$i}= '';
+}
+
+open(NCH,"<$ARGV[1]") || die $!;
+while (<NCH>) {
+    s/\s+$//;
+    m/#define KEY_(\w+)\s+\d+\s+/ || next;
+    $rhs= $';
+    $k= "KEY_$1";
+    $_= $1;
+    &capit;
+    $base{$k}= $_;
+    $_= $rhs;
+    s/(\w)[\(\)]/$1/g;
+    s/\w+ \((\w+)\)/$1/;
+    next unless m|^/\* (\w[\w ]+\w) \*/$|;
+    $_= $1;
+    s/ key$//;
+    next if s/^shifted /shift / ? m/ .* .* / : m/ .* /;
+    &capit;
+    $name{$k}= $_;
+}
+close(NCH);
+
+printf(<<'END') || die $!;
+/*
+ * WARNING - THIS FILE IS GENERATED AUTOMATICALLY - DO NOT EDIT
+ * It is generated by mkcurkeys.pl from <ncurses/curses.h>
+ * and keyoverride.  If you want to override things try adding
+ * them to keyoverride.
+ */
+
+END
+
+for ($i=33; $i<=126; $i++) {
+    $k= $i;
+    $v= pack("C",$i);
+    if ($v eq ',') { $comma=$k; next; }
+    &p;
+}
+
+for $k (sort {
+    $a+0 eq $a ?
+        $b+0 eq $b ? $a <=> $b : -1
+            : $b+0 eq $b ? 1 :
+                $a cmp $b
+                } keys %base) {
+    $v= $base{$k};
+    $v= $name{$k} if defined($name{$k});
+    $v= $over{$k} if defined($over{$k});
+    next if $v eq '[elide]';
+    &p;
+}
+
+for ($i=1; $i<64; $i++) {
+    $k= "KEY_F($i)"; $v= "F$i";
+    &p;
+}
+
+$k=$comma; $v=','; &p;
+
+print(<<'END') || die $!;
+  { -1,              0                    }
+END
+
+close(STDOUT) || die $!;
+exit(0);
+
+sub capit {
+    $o= ''; y/A-Z/a-z/; $_= " $_";
+    while (m/ (\w)/) {
+        $o .= $`.' ';
+        $_ = $1;
+        y/a-z/A-Z/;
+        $o .= $_;
+        $_ = $';
+    }
+    $_= $o.$_; s/^ //;
+}
+
+sub p {
+    $v =~ s/["\\]/\\$&/g;
+    printf("  { %-15s \"%-20s },\n",
+           $k.',',
+           $v.'"') || die $!;
+}

+ 74 - 0
dselect/mkhelpmsgs.pl

@@ -0,0 +1,74 @@
+#!/usr/bin/perl
+
+$maxnlines= 22;
+
+open(SRC,"helpmsgs.src") || die $!;
+open(NC,">helpmsgs.cc.new") || die $!;
+open(NH,">helpmsgs.h.new") || die $!;
+
+&autowarn('NC'); &autowarn('NH');
+
+print(NC "#include \"helpmsgs.h\"\n") || die $!;
+print(NH <<'END') || die $!;
+#ifndef HELPMSGS_H
+#define HELPMSGS_H
+struct helpmessage { const char *title; const char *text; };
+END
+
+$state= 'start';
+$nblanks= 0; $nlines= 0;
+while (<SRC>) {
+    s/\"/\\\"/g;
+    if (m/^\@\@\@ (\w+)\s+(\S.*\S)\s+$/) {
+        &finishif;
+        $currentname= $1; $currenttitle= $2;
+        print(NH "extern const struct helpmessage hlp_$currentname;\n") || die $!;
+        print(NC
+              "const struct helpmessage hlp_$currentname = {\n".
+              "  \"$currenttitle\", \"") || die $!;
+    } elsif (m/^\@\@\@/) {
+        die;
+    } elsif (!m/\S/) {
+        $nblanks++;
+    } else {
+        if ($state ne 'start' && $nblanks) {
+            print(NC ("\\n"x$nblanks)."\\\n") || die $!;
+            $nlines+= $nblanks;
+        }
+        $state= 'middle'; $nblanks= 0;
+        s/\s*\n$//;
+        print(NC "\\\n".$_."\\n") || die $!;
+        $nlines++;
+    }
+}
+
+&finishif;
+
+close(NC) || die $!;
+print(NH "#endif /* HELPMSGS_H */\n") || die $!;
+close(NH) || die $!;
+
+rename("helpmsgs.cc.new","helpmsgs.cc") || die $!;
+rename("helpmsgs.h.new","helpmsgs.h") || die $!;
+    
+sub finishif {
+    if ($state ne 'start') {
+        print(NC "\"\n};\n") || die $!;
+        printf "\t\t%s: %d lines\n",$currentname,$nlines;
+        if ($nlines > $maxnlines) { warn "Too many lines in $currentname"; }
+    }
+    $state= 'start';
+    $nblanks= 0; $nlines= 0;
+}
+
+
+sub autowarn {
+    $fh= $_[0];
+    print($fh <<'END') || die $!;
+/*
+ * WARNING - THIS FILE IS GENERATED AUTOMATICALLY - DO NOT EDIT
+ * It is generated by mkhelpmsgs.pl from helpmsgs.src.
+ */
+
+END
+}

+ 217 - 0
dselect/pkgcmds.cc

@@ -0,0 +1,217 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgcmds.cc - package list keyboard commands
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+static int matches(struct pkginfo *pkg, struct pkginfo *comparewith) {
+  if (comparewith->priority != pkginfo::pri_unset &&
+      (comparewith->priority != pkg->priority ||
+       comparewith->priority == pkginfo::pri_other &&
+       strcasecmp(comparewith->otherpriority,pkg->otherpriority)))
+    return 0;
+  if (comparewith->section &&
+      strcasecmp(comparewith->section,
+                 pkg->section ?
+                 pkg->section : ""))
+    return 0;
+  return 1;
+}
+
+void packagelist::affectedrange(int *startp, int *endp) {
+  if (table[cursorline]->pkg->name) {
+    *startp= cursorline;
+    *endp= cursorline+1;
+    return;
+  }
+  int index;
+  for (index= cursorline; index < nitems && !table[index]->pkg->name; index++);
+  if (index >= nitems) {
+    *startp= *endp= cursorline;
+    return;
+  }
+  *startp= index;
+  while (index < nitems && matches(table[index]->pkg,table[cursorline]->pkg)) index++;
+  *endp= index;
+}
+
+void packagelist::movecursorafter(int ncursor) {
+  if (ncursor >= nitems) ncursor= nitems-1;
+  topofscreen += ncursor-cursorline;
+  if (topofscreen > nitems - list_height) topofscreen= nitems - list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setcursor(ncursor);
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::setwant(pkginfo::pkgwant nw) {
+  int index, top, bot;
+
+  if (!readwrite) { beep(); return; }
+
+  if (recursive) {
+    redrawitemsrange(cursorline,cursorline+1);
+    table[cursorline]->selected= nw;
+    redraw1item(cursorline);
+    top= cursorline;
+    bot= cursorline+1;
+  } else {
+    packagelist *sub= new packagelist(bindings,0);
+
+    affectedrange(&top,&bot);
+    for (index= top; index < bot; index++) {
+      if (!table[index]->pkg->name ||
+          table[index]->selected == nw ||
+          table[index]->selected == pkginfo::want_purge && nw == pkginfo::want_deinstall)
+        continue;
+      sub->add(table[index]->pkg,nw);
+    }
+
+    repeatedlydisplay(sub,dp_may,this);
+    for (index=top; index < bot; index++)
+      redraw1item(index);
+  }
+  movecursorafter(bot);
+}
+
+void packagelist::kd_select()   { setwant(pkginfo::want_install);   }
+void packagelist::kd_deselect() { setwant(pkginfo::want_deinstall); }
+void packagelist::kd_purge()    { setwant(pkginfo::want_purge);     }
+
+void packagelist::sethold(int hold) {
+  int top, bot, index;
+
+  if (!readwrite) { beep(); return; }
+
+  affectedrange(&top,&bot);
+  for (index= top; index < bot; index++) {
+    // Sorry about the contortions, but GCC produces a silly warning otherwise
+    unsigned int neweflag= table[index]->pkg->eflag;
+    if (hold) neweflag |= pkginfo::eflagf_hold;
+    else neweflag &= ~pkginfo::eflagf_hold;
+    table[index]->pkg->eflag= (enum pkginfo::pkgeflag)neweflag;
+    redraw1item(index);
+  }
+  movecursorafter(bot);
+}
+
+void packagelist::kd_hold()     { sethold(1);                       }
+void packagelist::kd_unhold()   { sethold(0);                       }
+
+const char *packagelist::itemname(int index) {
+  return table[index]->pkg->name;
+}
+
+void packagelist::kd_swaporder() {
+  switch (sortorder) {
+  case so_priority:  sortorder= so_section;   break;
+  case so_section:   sortorder= so_alpha;     break;
+  case so_alpha:     sortorder= so_priority;  break;
+  case so_unsorted:                           return;
+  default: internerr("unknown sort in kd_swaporder");
+  }
+  const char *oldname= table[cursorline]->pkg->name;
+  sortmakeheads();
+  int newcursor;
+  newcursor= 0;
+  if (oldname) {
+    int index;
+    for (index=0; index<nitems; index++) {
+      if (table[index]->pkg->name && !strcasecmp(oldname,table[index]->pkg->name)) {
+        newcursor= index;
+        break;
+      }
+    }
+  }
+  topofscreen= newcursor-1;
+  if (topofscreen > nitems - list_height) topofscreen= nitems-list_height;
+  if (topofscreen < 0) topofscreen= 0;
+  setwidths();
+  redrawtitle();
+  redrawcolheads();
+  ldrawnstart= ldrawnend= -1;
+  cursorline= -1;
+  setcursor(newcursor);
+  refreshlist();
+}
+
+void packagelist::kd_verbose() {
+  verbose= !verbose;
+  setwidths();
+  leftofscreen= 0;
+  ldrawnstart= ldrawnend= -1;
+  redrawtitle();
+  redrawcolheads();
+  redrawitemsrange(topofscreen,lesserint(topofscreen+list_height,nitems));
+  refreshlist();
+}
+
+void packagelist::kd_quit_noop() { }
+
+void packagelist::kd_revert_abort() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->original;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::kd_revertdirect() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->direct;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+void packagelist::kd_revertsuggest() {
+  int index;
+  for (index=0; index<nitems; index++) {
+    if (table[index]->pkg->name)
+      table[index]->selected= table[index]->suggested;
+    ldrawnstart= ldrawnend= -1;
+  }
+  refreshlist(); redrawthisstate();
+}
+
+/* fixme: configurable purge/deselect */
+/* fixme: un-hold things */
+
+void packagelist::kd_info() {
+  currentinfo++;
+  infotopofscreen=0;
+  redrawinfo();
+}

+ 303 - 0
dselect/pkgdepcon.cc

@@ -0,0 +1,303 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgdepcon.cc - dependency and conflict resolution
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+static const int depdebug= 1;
+
+int packagelist::resolvesuggest() {
+  // We continually go around looking for things to change, but we may
+  // only change the `suggested' value if we also increase the `priority'
+  // Return 2 if we made a change due to a Recommended, Depends or Conficts,
+  // or 1 if we offered or made a change because of an Optional line.
+  if (debug)
+    fprintf(debug,"packagelist[%p]::resolvesuggest()\n",this);
+  int changemade, maxchangemade;
+  maxchangemade= 0;
+  for (;;) {
+    changemade= 0;
+    int index;
+    for (index=0; index<nitems; index++) {
+      if (!table[index]->pkg->name) continue;
+      if (depdebug)
+        fprintf(debug,"packagelist[%p]::resolvesuggest() loop[%i] %s / %d\n",
+                this, index, table[index]->pkg->name, changemade);
+      dependency *depends;
+      for (depends= table[index]->pkg->available.depends;
+           depends;
+           depends= depends->next)
+        changemade= greaterint(changemade, resolvedepcon(depends));
+      deppossi *possi;
+      for (possi= table[index]->pkg->available.depended;
+           possi;
+           possi= possi->nextrev) 
+        changemade= greaterint(changemade, resolvedepcon(possi->up));
+      for (depends= table[index]->pkg->available.depends;
+           depends;
+           depends= depends->next)
+        if (depends->type == dep_provides)
+          for (possi= depends->list->ed->available.valid
+                      ? depends->list->ed->available.depended : 0;
+               possi;
+               possi= possi->nextrev)
+            changemade= greaterint(changemade, resolvedepcon(possi->up));
+      if (depdebug)
+        fprintf(debug,"packagelist[%p]::resolvesuggest() loop[%i] %s / -> %d\n",
+                this, index, table[index]->pkg->name, changemade);
+    }
+    if (!changemade) break;
+    maxchangemade= greaterint(maxchangemade, changemade);
+  }
+  if (debug)
+    fprintf(debug,"packagelist[%p]::resolvesuggest() done; maxchangemade=%d\n",
+            this,maxchangemade);
+  return maxchangemade;
+}
+
+static int dep_update_best_to_change_stop(perpackagestate *& best, pkginfo *trythis) {
+  // There's no point trying to select a pure virtual package.
+  if (!trythis->clientdata) return 0;
+  
+  if (depdebug)
+    fprintf(debug,"update_best_to_change(best=%s{%d}, test=%s{%d});\n",
+            best ? best->pkg->name : "", best ? (int)best->spriority : -1,
+            trythis->name, trythis->clientdata->spriority);
+
+  // If the problem is caused by us deselecting one of these packages
+  // we should not try to select another one instead.
+  if (trythis->clientdata->spriority == sp_deselecting) return 1;
+
+  // If we haven't found anything yet then this is our best so far.
+  if (!best) goto yes;
+  
+  // Select the package with the lowest priority (ie, the one of whom
+  // we were least sure we wanted it deselected).
+  if (trythis->clientdata->spriority > best->spriority) return 0;
+  if (trythis->clientdata->spriority < best->spriority) goto yes;
+
+  // Pick the package with the must fundamental recommendation level.
+  if (trythis->priority > best->pkg->priority) return 0;
+  if (trythis->priority < best->pkg->priority) goto yes;
+
+  // If we're still unsure we'll change the first one in the list.
+  return 0;
+  
+ yes:
+  if (depdebug) fprintf(debug,"update_best_to_change(); yes\n");
+
+  best=trythis->clientdata; return 0;
+}
+
+int packagelist::deselect_one_of(pkginfo *per, pkginfo *ped, dependency *display) {
+  perpackagestate *er= per->clientdata;
+  perpackagestate *ed= ped->clientdata;
+  
+  if (!er || er->selected != pkginfo::want_install ||
+      !ed || ed->selected != pkginfo::want_install) return 0;
+  
+  add(display,dp_must);
+  
+  er= per->clientdata;  // these can be changed by add
+  ed= ped->clientdata;
+  
+  if (depdebug)
+    fprintf(debug,"packagelist[%p]::deselect_one_of(): er %s{%d} ed %s{%d} [%p]\n",
+            this, er->pkg->name, er->spriority, ed->pkg->name, ed->spriority, display);
+  
+  perpackagestate *best;
+  if (er->spriority < ed->spriority) best= er;        // We'd rather change the
+  else if (er->spriority > ed->spriority) best= ed;   // one with the lowest priority.
+  
+  else if (er->pkg->priority >
+           er->pkg->priority) best= er;         // ... failing that the one with
+  else if (er->pkg->priority <                  //  the highest priority
+           er->pkg->priority) best= ed;
+  
+  else best= ed;                                      // ... failing that, the second
+
+  if (depdebug)
+    fprintf(debug,"packagelist[%p]::deselect_one_of(): best %s{%d}\n",
+            this, best->pkg->name, best->spriority);
+
+  if (best->spriority >= sp_deselecting) return 0;
+  best->suggested=
+    best->pkg->status == pkginfo::stat_notinstalled
+      ? pkginfo::want_purge : pkginfo::want_deinstall; /* fixme: configurable */
+  best->selected= best->suggested;
+  best->spriority= sp_deselecting;
+
+  return 2;
+}
+
+int packagelist::resolvedepcon(dependency *depends) {
+  perpackagestate *best;
+  deppossi *possi, *provider;
+  int r, foundany;
+
+  if (depdebug) {
+    fprintf(debug,"packagelist[%p]::resolvedepcon([%p] %s --%s-->",
+            this,depends,depends->up->name,relatestrings[depends->type]);
+    for (possi=depends->list; possi; possi=possi->next)
+      fprintf(debug," %s",possi->ed->name);
+    fprintf(debug,"); (ing)->want=%s\n",
+            depends->up->clientdata
+            ? wantstrings[depends->up->clientdata->suggested]
+            : "(no clientdata)");
+  }
+  
+  if (!depends->up->clientdata) return 0;
+  
+  if (depends->up->clientdata->selected != pkginfo::want_install) return 0;
+
+  switch (depends->type) {
+
+  case dep_provides:
+  case dep_replaces:
+    return 0;
+    
+  case dep_suggests:
+    if (0) return 0; /* fixme: configurable */
+    // fall through ...
+  case dep_recommends:
+  case dep_depends:
+  case dep_predepends:
+    for (possi= depends->list;
+         possi && !deppossatisfied(possi);
+         possi= possi->next);
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): depends found %s\n",
+              this,depends, possi ? possi->ed->name : "[none]");
+    if (possi) return 0;
+
+    // Ensures all in the recursive list; adds info strings; ups priorities
+    r= add(depends, depends->type == dep_suggests ? dp_may : dp_must);
+
+    if (depends->type == dep_suggests) return r;
+
+    best= 0;
+    for (possi= depends->list;
+         possi;
+         possi= possi->next) {
+      foundany= 0;
+      if (possi->ed->clientdata) foundany= 1;
+      if (dep_update_best_to_change_stop(best, possi->ed)) goto mustdeselect;
+      for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+           provider;
+           provider= provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+        if (provider->up->up->clientdata) foundany= 1;
+        if (dep_update_best_to_change_stop(best, provider->up->up)) goto mustdeselect;
+      }
+      if (!foundany) addunavailable(possi);
+    }
+
+    if (!best) {
+      if (depdebug) fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): "
+                            "mustdeselect nobest\n", this,depends);
+      return r;
+    }
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): select best=%s{%d}\n",
+              this,depends, best->pkg->name, best->spriority);
+    if (best->spriority >= sp_selecting) return r;
+    best->selected= best->suggested= pkginfo::want_install;
+    best->spriority= sp_selecting;
+    return 2;
+    
+  mustdeselect:
+    best= depends->up->clientdata;
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): mustdeselect best=%s{%d}\n",
+              this,depends, best->pkg->name, best->spriority);
+
+    if (best->spriority >= sp_deselecting) return r;
+    best->selected= best->suggested=
+      best->pkg->status == pkginfo::stat_notinstalled
+        ? pkginfo::want_purge : pkginfo::want_deinstall; /* fixme: configurable */
+    best->spriority= sp_deselecting;
+    return 2;
+    
+  case dep_conflicts:
+    if (!deppossatisfied(depends->list)) return 0;
+    if (depends->up != depends->list->ed) {
+      r= deselect_one_of(depends->up, depends->list->ed, depends);  if (r) return r;
+    }
+    for (provider= depends->list->ed->available.valid ?
+                   depends->list->ed->available.depended : 0;
+         provider;
+         provider= provider->nextrev) {
+      if (provider->up->type != dep_provides) continue;
+      if (provider->up->up == depends->up) continue; // conflicts & provides same thing
+      r= deselect_one_of(depends->up, provider->up->up, depends);  if (r) return r;
+    }
+    if (depdebug)
+      fprintf(debug,"packagelist[%p]::resolvedepcon([%p]): no desel\n", this,depends);
+    return 0;
+    
+  default:
+    internerr("unknown deptype");
+  }
+}
+
+int deppossatisfied(deppossi *possi) {
+  if (possi->ed->clientdata &&
+      possi->ed->clientdata->selected == pkginfo::want_install &&
+      !(possi->up->type == dep_conflicts && possi->up->up == possi->ed)) {
+    // If it's installed, then either it's of the right version,
+    // and therefore OK, or a version must have been specified,
+    // in which case we don't need to look at the rest anyway.
+    if (possi->verrel == deppossi::dvr_none) return 1;
+    int r= versioncompare(possi->ed->available.version,
+                          possi->ed->available.revision,
+                          possi->version,
+                          possi->revision);
+    switch (possi->verrel) {
+    case deppossi::dvr_earlierequal:   return r <= 0;
+    case deppossi::dvr_laterequal:     return r >= 0;
+    case deppossi::dvr_earlierstrict:  return r < 0;
+    case deppossi::dvr_laterstrict:    return r > 0;
+    case deppossi::dvr_exact:          return r == 0;
+    default:                           internerr("unknown verrel");
+    }
+  }
+  if (possi->verrel != deppossi::dvr_none) return 0;
+  deppossi *provider;
+  for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+       provider;
+       provider= provider->nextrev) {
+    if (provider->up->type != dep_provides) continue;
+    if (provider->up->up->clientdata &&
+        provider->up->up->clientdata->selected == pkginfo::want_install)
+      return 1;
+  }
+  return 0;
+}

+ 142 - 0
dselect/pkgdisplay.cc

@@ -0,0 +1,142 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgdisplay.cc - package list display
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+/* These MUST be in the same order as the corresponding enums in dpkg-db.h */
+const char
+  *const wantstrings[]=   { "new package", "selected", "deselected", "purge", 0 },
+  *const holdstrings[]=   { "", "on hold", "REINSTALL",
+                            "hold,REINSTALL", 0 },
+  *const statusstrings[]= { "not installed", "unpacked (not set up)",
+                            "failed config", "installed", "half installed",
+                            "removed (configs remain)", 0                            },
+  *const prioritystrings[]=  { "Required", "Important", "Standard", "Recommended",
+                               "Optional", "Extra", "Contrib",
+                               "!Bug!", "Unclassified", 0                          },
+  *const relatestrings[]= { "suggests", "recommends", "depends on", "pre-depends on",
+                            "conflicts with", "provides", 0              },
+  *const priorityabbrevs[]=  { "Req", "Imp", "Std", "Rec",
+                               "Opt", "Xtr", "Ctb",
+                               "bUG", "?"                  };
+const char statuschars[]=   " uF*H-";
+const char holdchars[]=     " hRX";
+const char wantchars[]=     "n*-_";
+
+static int maximumstring(const char *const *array) {
+  int maxlen= 0;
+  while (*array) {
+    int l= strlen(*array);
+    const char *p= strchr(*array, '(');
+    if (p && p > *array && *--p == ' ') l= p - *array;
+    if (l > maxlen) maxlen= l;
+    array++;
+  }
+  return maxlen;
+}
+
+void packagelist::setwidths() {
+  if (debug) fprintf(debug,"packagelist[%p]::setwidths()\n",this);
+
+  if (verbose) {
+    status_hold_width= 9;
+    status_status_width= maximumstring(statusstrings);
+    status_want_width= maximumstring(wantstrings);
+    status_width= status_hold_width+status_status_width+status_want_width*2+3;
+    priority_width= 8;
+   package_width= 16;
+  } else {
+    status_width= 4;
+    priority_width= 3;
+    package_width= 12;
+  }
+  section_width= 8;
+
+  gap_width= 1;
+
+  if (sortorder == so_section) {
+    section_column= status_width + gap_width;
+    priority_column= section_column + section_width + gap_width;
+    package_column= priority_column + priority_width + gap_width;
+  } else {
+    priority_column= status_width + gap_width;
+    section_column= priority_column + priority_width + gap_width;
+    package_column= section_column + section_width + gap_width;
+  }
+
+  description_column= package_column + package_width + gap_width;
+
+  total_width= TOTAL_LIST_WIDTH;
+  description_width= total_width - description_column;
+}
+
+void packagelist::redrawtitle() {
+  int x,y;
+  
+  if (title_height) {
+    mywerase(titlewin);
+    mvwaddnstr(titlewin,0,0,
+               recursive ?  "dselect - recursive package listing" :
+               !readwrite ? "dselect - inspection of package states" :
+                            "dselect - main package listing",
+               xmax);
+    getyx(titlewin,y,x);
+    if (x < xmax) {
+      switch (sortorder) {
+      case so_section:
+        waddnstr(titlewin, " (by section)", xmax-x);
+        break;
+      case so_priority:
+        waddnstr(titlewin, " (by priority)", xmax-x);
+        break;
+      case so_alpha:
+        waddnstr(titlewin, " (alphabetically)", xmax-x);
+        break;
+      case so_unsorted:
+        break;
+      default:
+        internerr("bad sort in redrawtitle");
+      }
+    }
+    const char *helpstring= readwrite ? (verbose ? " +/-=select v=terse ?=help"
+                                                 : " +/-=select v=verbose ?=help")
+                                      : (verbose ? " v=terse ?=help"
+                                                 : " v=verbose ?=help");
+    int l= strlen(helpstring);
+    getyx(titlewin,y,x);
+    if (xmax-l > 0) {
+      mvwaddstr(titlewin,0,xmax-l, helpstring);
+    }
+    wnoutrefresh(titlewin);
+  }
+}

+ 163 - 0
dselect/pkginfo.cc

@@ -0,0 +1,163 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkginfo.cc - handles (re)draw of package list window infopad
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+#include "helpmsgs.h"
+
+const struct helpmenuentry *packagelist::helpmenulist() {
+  static const struct helpmenuentry
+    rw[]= {
+      { 'i', &hlp_mainintro       },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    },
+    ro[]= {
+      { 'i', &hlp_readonlyintro   },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    },
+    recur[]= {
+      { 'i', &hlp_recurintro      },
+      { 'k', &hlp_listkeys        },
+      { 'l', &hlp_displayexplain1 },
+      { 'd', &hlp_displayexplain2 },
+      {  0                        }
+    };
+  return
+    !readwrite ? ro :
+    !recursive ? rw :
+                 recur;
+}
+
+int packagelist::itr_recursive() { return recursive; }
+
+const packagelist::infotype packagelist::infoinfos[]= {
+  { itr_recursive,     itd_relations    },
+  { 0,                 itd_description  },
+  { 0,                 itd_controlfile  },
+  { 0,                 0                }
+};
+
+const packagelist::infotype *const packagelist::baseinfo= infoinfos;
+
+void packagelist::severalinfoblurb(const char *whatinfoline) {
+  whatinfovb(whatinfoline);
+  varbuf vb;
+  vb("The line you have highlighted represents many packages; "
+     "if you ask to select or deselect it you will affect all the "
+     "packages which match the criterion shown.\n"
+     "\n"
+     "If you move the highlight to a line for a particular package "
+     "you will see information about that package displayed here.");
+  wordwrapinfo(0,vb.string());
+}
+
+void packagelist::itd_relations() {
+  if (table[cursorline]->pkg->name) {
+    whatinfovb("interrelationships affecting ");
+    whatinfovb(table[cursorline]->pkg->name);
+    if (debug) fprintf(debug,"packagelist[%p]::idt_relations(); `%s'\n",
+                       this,table[cursorline]->relations.string());
+    waddstr(infopad,table[cursorline]->relations.string());
+  } else {
+    severalinfoblurb("interrelationships");
+  }
+}
+
+void packagelist::itd_description() {
+  if (table[cursorline]->pkg->name) {
+    whatinfovb("description of ");
+    whatinfovb(table[cursorline]->pkg->name);
+
+    const char *m= table[cursorline]->pkg->available.description;
+    if (!m || !*m) m= "no description available.";
+    const char *p= strchr(m,'\n');
+    int l= p ? (int)(p-m) : strlen(m);
+    wattrset(infopad,info_headattr);
+    waddstr(infopad, table[cursorline]->pkg->name);
+    waddstr(infopad," - ");
+    waddnstr(infopad,m,l);
+    wattrset(infopad,info_attr);
+    if (p) {
+      waddstr(infopad,"\n\n");
+      wordwrapinfo(1,++p);
+    }
+  } else {
+    severalinfoblurb("description");
+  }
+}
+
+void packagelist::itd_controlfile() {
+  werase(infopad);
+  if (!table[cursorline]->pkg->name) {
+    severalinfoblurb("control file information");
+  } else {
+    whatinfovb("control file information for ");
+    whatinfovb(table[cursorline]->pkg->name);
+    varbuf vb;
+    varbufrecord(&vb,table[cursorline]->pkg,&table[cursorline]->pkg->available);
+    vb.terminate();
+    if (debug)
+      fprintf(debug,"packagelist[%p]::idt_controlfile(); `%s'\n",this,vb.string());
+    waddstr(infopad,vb.string());
+  }
+}
+
+void packagelist::redrawinfo() {
+  for (;;) {
+    if (!currentinfo || !currentinfo->display) currentinfo= baseinfo;
+    if (!currentinfo->relevant) break;
+    if ((this->*currentinfo->relevant)()) break;
+    currentinfo++;
+  }
+  if (!info_height) return;
+  whatinfovb.reset();
+  werase(infopad); wmove(infopad,0,0);
+  
+  if (debug)
+    fprintf(debug,"packagelist[%p]::redrawinfo(); #=%d\n", this,
+            (int)(currentinfo - baseinfo));
+  
+  (this->*currentinfo->display)();
+  whatinfovb.terminate();
+  int y,x;
+  getyx(infopad, y,x);
+  if (x) y++;
+  infolines= y;
+
+  refreshinfo();
+}

+ 139 - 0
dselect/pkgkeys.cc

@@ -0,0 +1,139 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgkeys.cc - package list keybindings
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+const keybindings::interpretation packagelist_kinterps[] = {
+  { "up",             0,  packagelist::kd_up,               qa_noquit           },
+  { "down",           0,  packagelist::kd_down,             qa_noquit           },
+  { "top",            0,  packagelist::kd_top,              qa_noquit           },
+  { "bottom",         0,  packagelist::kd_bottom,           qa_noquit           },
+  { "scrollon",       0,  packagelist::kd_scrollon,         qa_noquit           },
+  { "scrollback",     0,  packagelist::kd_scrollback,       qa_noquit           },
+  { "iscrollon",      0,  packagelist::kd_iscrollon,        qa_noquit           },
+  { "iscrollback",    0,  packagelist::kd_iscrollback,      qa_noquit           },
+  { "scrollon1",      0,  packagelist::kd_scrollon1,        qa_noquit           },
+  { "scrollback1",    0,  packagelist::kd_scrollback1,      qa_noquit           },
+  { "iscrollon1",     0,  packagelist::kd_iscrollon1,       qa_noquit           },
+  { "iscrollback1",   0,  packagelist::kd_iscrollback1,     qa_noquit           },
+  { "panon",          0,  packagelist::kd_panon,            qa_noquit           },
+  { "panback",        0,  packagelist::kd_panback,          qa_noquit           },
+  { "panon1",         0,  packagelist::kd_panon1,           qa_noquit           },
+  { "panback1",       0,  packagelist::kd_panback1,         qa_noquit           },
+  { "select",         0,  packagelist::kd_select,           qa_noquit           },
+  { "deselect",       0,  packagelist::kd_deselect,         qa_noquit           },
+  { "purge",          0,  packagelist::kd_purge,            qa_noquit           },
+  { "hold",           0,  packagelist::kd_hold,             qa_noquit           },
+  { "unhold",         0,  packagelist::kd_unhold,           qa_noquit           },
+  { "info",           0,  packagelist::kd_info,             qa_noquit           },
+  { "verbose",        0,  packagelist::kd_verbose,          qa_noquit           },
+  { "help",           0,  packagelist::kd_help,             qa_noquit           },
+  { "search",         0,  packagelist::kd_search,           qa_noquit           },
+  { "searchagain",    0,  packagelist::kd_searchagain,      qa_noquit           },
+  { "swaporder",      0,  packagelist::kd_swaporder,        qa_noquit           },
+  { "redraw",         0,  packagelist::kd_redraw,           qa_noquit           },
+  { "quitcheck",      0,  packagelist::kd_quit_noop,        qa_quitchecksave    },
+  { "quitrejectsug",  0,  packagelist::kd_revertdirect,     qa_quitnochecksave  },
+  { "quitnocheck",    0,  packagelist::kd_quit_noop,        qa_quitnochecksave  },
+  { "abortnocheck",   0,  packagelist::kd_revert_abort,     qa_quitnochecksave  },
+  { "revert",         0,  packagelist::kd_revert_abort,     qa_noquit           },
+  { "revertsuggest",  0,  packagelist::kd_revertsuggest,    qa_noquit           },
+  { "revertdirect",   0,  packagelist::kd_revertdirect,     qa_noquit           },
+  {  0,               0,                                    qa_noquit           }
+};
+
+#define C(x) ((x)-'a'+1)
+
+const keybindings::orgbinding packagelist_korgbindings[]= {
+  { 'n',            "down"           },
+  { KEY_DOWN,       "down"           },
+  { 'p',            "up"             },
+  { KEY_UP,         "up"             },
+  
+  { 'N',            "scrollon"       },
+  { KEY_NPAGE,      "scrollon"       },
+  { ' ',            "scrollon"       },
+  { 'P',            "scrollback"     },
+  { KEY_PPAGE,      "scrollback"     },
+  { KEY_BACKSPACE,  "scrollback"     },
+  { 0177,/*DEL*/    "scrollback"     },
+  { C('h'),         "scrollback"     },
+  { C('n'),         "scrollon1"      },
+  { C('p'),         "scrollback1"    },
+  
+  { 't',            "top"            },
+  { KEY_HOME,       "top"            },
+  { 'e',            "bottom"         },
+  { KEY_LL,         "bottom"         },
+  { KEY_END,        "bottom"         },
+  
+  { 'u',            "iscrollback"    },
+  { 'd',            "iscrollon"      },
+  { C('u'),         "iscrollback1"   },
+  { C('d'),         "iscrollon1"     },
+  
+  { 'B',            "panback"        },
+  { KEY_LEFT,       "panback"        },
+  { 'F',            "panon"          },
+  { KEY_RIGHT,      "panon"          },
+  { C('b'),         "panback1"       },
+  { C('f'),         "panon1"         },
+
+  { '+',            "select"         },
+  { KEY_IC,         "select"         },
+  { '-',            "deselect"       },
+  { KEY_DC,         "deselect"       },
+  { '_',            "purge"          },
+  { 'H',            "hold"           },
+  { 'G',            "unhold"         },
+  
+  { '?',            "help"           },
+  { KEY_HELP,       "help"           },
+  { KEY_F(1),       "help"           },
+  { 'i',            "info"           },
+  { 'o',            "swaporder"      },
+  { 'v',            "verbose"        },
+  { C('l'),         "redraw"         },
+  { '/',            "search"         },
+  { '\\',           "searchagain"    },
+
+  { KEY_ENTER,      "quitcheck"      },
+  { '\r',           "quitcheck"      },
+  { 'Q',            "quitnocheck"    },
+  { 'X',            "abortnocheck"   },
+  { 'R',            "revert"         },
+  { 'U',            "revertsuggest"  },
+  { 'D',            "revertdirect"   },
+
+  {  -1,             0               }
+};

+ 378 - 0
dselect/pkglist.cc

@@ -0,0 +1,378 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkglist.cc - package list administration
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+int packagelist::compareentries(struct perpackagestate *a,
+                                struct perpackagestate *b) {
+  const char *asection= a->pkg->section;
+  if (!asection && a->pkg->name) asection= "";
+  const char *bsection= b->pkg->section;
+  if (!bsection && b->pkg->name) bsection= "";
+  int c_section=
+    !asection || !bsection ?
+      (!bsection) - (!asection) :
+    !*asection || !*bsection ?
+      (!asection) - (!bsection) :
+    strcasecmp(asection,bsection);
+  int c_priority=
+    a->pkg->priority - b->pkg->priority;
+  if (!c_priority && a->pkg->priority == pkginfo::pri_other)
+    c_priority= strcasecmp(a->pkg->otherpriority, b->pkg->otherpriority);
+  int c_name=
+    a->pkg->name && b->pkg->name ?
+      strcasecmp(a->pkg->name, b->pkg->name) :
+    (!b->pkg->name) - (!a->pkg->name);
+
+  switch (sortorder) {
+  case so_section:
+    return c_section ? c_section : c_priority ? c_priority : c_name;
+  case so_priority:
+    return c_priority ? c_priority : c_section ? c_section : c_name;
+  case so_alpha:
+    return c_name;
+  case so_unsorted:
+  default:
+    internerr("unsorted or unknown in compareentries");
+  }
+}
+
+void packagelist::discardheadings() {
+  int a,b;
+  for (a=0, b=0; a<nitems; a++) {
+    if (table[a]->pkg->name) {
+      table[b++]= table[a];
+    }
+  }
+  nitems= b;
+
+  struct perpackagestate *head, *next;
+  head= headings;
+  while (head) {
+    next= head->uprec;
+    delete head->pkg;
+    delete head;
+    head= next;
+  }
+  headings= 0;
+}
+
+void packagelist::addheading(pkginfo::pkgpriority priority,
+                             const char *otherpriority,
+                             const char *section) {
+  assert(nitems <= nallocated);
+  if (nitems == nallocated) {
+    nallocated += nallocated+50;
+    struct perpackagestate **newtable= new struct perpackagestate*[nallocated];
+    memcpy(newtable,table,nallocated*sizeof(struct perpackagestate*));
+    table= newtable;
+  }
+  
+  if (debug) fprintf(debug,"packagelist[%p]::addheading(%d,%s,%s)\n",
+                     this,priority,
+                     otherpriority ? otherpriority : "<null>",
+                     section ? section : "<null>");
+
+  struct pkginfo *newhead= new pkginfo;
+  newhead->name= 0;
+  newhead->priority= priority;
+  newhead->otherpriority= (char*)otherpriority;
+  newhead->section= (char*)section;
+
+  struct perpackagestate *newstate= new perpackagestate;
+  newstate->pkg= newhead;
+  newstate->uprec= headings;
+  headings= newstate;
+ 
+  table[nitems++]= newstate;
+}
+
+static packagelist *sortpackagelist;
+
+int qsort_compareentries(const void *a, const void *b) {
+  return sortpackagelist->compareentries(*(perpackagestate**)a,
+                                         *(perpackagestate**)b);
+}
+
+void packagelist::sortinplace() {
+  sortpackagelist= this;
+
+  if (debug) fprintf(debug,"packagelist[%p]::sortinplace()\n",this);
+  qsort(table,nitems,sizeof(struct pkginfoperfile*),qsort_compareentries);
+}
+
+void packagelist::sortmakeheads() {
+  discardheadings();
+  sortinplace();
+  assert(nitems);
+
+  if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads() sortorder=%d\n",
+                     this,sortorder);
+  
+  int nrealitems= nitems;
+  addheading(pkginfo::pri_unset,0,0);
+
+  if (sortorder == so_alpha) { sortinplace(); return; }
+  
+  assert(sortorder == so_section || sortorder == so_priority);
+
+  // Important: do not save pointers into table in this function, because
+  // addheading may need to reallocate table to make it larger !
+  
+  struct pkginfo *lastpkg;
+  struct pkginfo *thispkg;
+  lastpkg= 0;
+  int a;
+  for (a=0; a<nrealitems; a++) {
+    thispkg= table[a]->pkg;
+    assert(thispkg->name);
+    int prioritydiff= (!lastpkg ||
+                       thispkg->priority != lastpkg->priority ||
+                       (thispkg->priority == pkginfo::pri_other &&
+                        strcasecmp(thispkg->otherpriority,lastpkg->otherpriority)));
+    int sectiondiff= (!lastpkg ||
+                      strcasecmp(thispkg->section ? thispkg->section : "",
+                                 lastpkg->section ? lastpkg->section : ""));
+
+    if (debug) fprintf(debug,"packagelist[%p]::sortmakeheads()"
+                       " pkg=%s  priority=%d otherpriority=%s %s  section=%s %s\n",
+                       this, thispkg->name, thispkg->priority,
+                       thispkg->otherpriority ? thispkg->otherpriority : "<null>",
+                       prioritydiff ? "*diff*" : "same",
+                       thispkg->section ? thispkg->section : "<null>",
+                       sectiondiff ? "*diff*" : "same");
+
+    if (sortorder == so_section && sectiondiff)
+      addheading(pkginfo::pri_unset,0, thispkg->section ? thispkg->section : "");
+    if (sortorder == so_priority && prioritydiff)
+      addheading(thispkg->priority,thispkg->otherpriority, 0);
+    if (prioritydiff || sectiondiff) 
+      addheading(thispkg->priority,thispkg->otherpriority,
+                 thispkg->section ? thispkg->section : "");
+    lastpkg= thispkg;
+  }
+
+  if (listpad) {
+    int maxx, maxy;
+    getmaxyx(listpad,maxx,maxy);
+    if (nitems > maxy) {
+      delwin(listpad);
+      listpad= newpad(nitems+1, total_width);
+      if (!listpad) ohshite("failed to create larger baselist pad");
+    } else if (nitems < maxy) {
+      werase(listpad);
+    }
+  }
+  
+  sortinplace();
+}
+
+void packagelist::initialsetup() {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::initialsetup()\n",this);
+
+  int allpackages= countpackages();
+  datatable= new struct perpackagestate[allpackages];
+
+  nallocated= allpackages+150; // will realloc if necessary, so 150 not critical
+  table= new struct perpackagestate*[nallocated];
+
+  depsdone= 0;
+  unavdone= 0;
+  currentinfo= 0;
+  headings= 0;
+  verbose= 0;
+}
+
+void packagelist::finalsetup() {
+  setcursor(0);
+
+  if (debug)
+    fprintf(debug,"packagelist[%p]::finalsetup done; recursive=%d nitems=%d\n",
+            this, recursive, nitems);
+}
+
+packagelist::packagelist(keybindings *kb) : baselist(kb) {
+  // nonrecursive
+  initialsetup();
+  struct pkgiterator *iter;
+  struct pkginfo *pkg;
+  
+  for (iter=iterpkgstart(), nitems=0;
+       (pkg=iterpkgnext(iter));
+       ) {
+    struct perpackagestate *state= &datatable[nitems];
+    state->pkg= pkg;
+    if (!informativeperfile(&pkg->available) &&
+        pkg->status == pkginfo::stat_notinstalled &&
+        pkg->priority == pkginfo::pri_unknown &&
+        !(pkg->section && *pkg->section) &&
+        !pkg->files &&
+        pkg->want != pkginfo::want_install) {
+      pkg->clientdata= 0; continue;
+    }
+    if (!pkg->available.valid) blankpackageperfile(&pkg->available);
+    state->direct= state->original= pkg->want;
+    if (readwrite && pkg->want == pkginfo::want_unknown) {
+      state->suggested= pkg->priority <= pkginfo::pri_standard
+        ? pkginfo::want_install : pkginfo::want_purge; /* fixme: configurable */
+      state->spriority= sp_inherit;
+    } else {
+      state->suggested= pkg->want;
+      state->spriority= sp_fixed;
+    }
+    state->dpriority= dp_must;
+    state->selected= state->suggested;
+    state->uprec= 0;
+    state->relations.init();
+    pkg->clientdata= state;
+    table[nitems]= state;
+    nitems++;
+  }
+  if (!nitems) ohshit("There are no packages to select.");
+  recursive= 0;
+  sortorder= so_priority;
+  sortmakeheads();
+  finalsetup();
+}
+
+packagelist::packagelist(keybindings *kb, pkginfo **pkgltab) : baselist(kb) {
+  // takes over responsibility for pkgltab (recursive)
+  initialsetup();
+  
+  recursive= 1;
+  nitems= 0;
+  if (pkgltab) {
+    add(pkgltab);
+    delete[] pkgltab;
+  }
+    
+  sortorder= so_unsorted;
+  finalsetup();
+}
+
+void perpackagestate::free(int recursive) {
+  if (pkg->name) {
+    if (readwrite) {
+      if (uprec) {
+        assert(recursive);
+        uprec->selected= selected;
+        pkg->clientdata= uprec;
+      } else {
+        assert(!recursive);
+        if (pkg->want != selected) {
+          pkg->want= selected;
+        }
+        pkg->clientdata= 0;
+      }
+    }
+    relations.free();
+  }
+}
+
+packagelist::~packagelist() {
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist()\n",this);
+
+  discardheadings();
+  
+  int index;
+  for (index=0; index<nitems; index++) table[index]->free(recursive);
+  delete[] table;
+  delete[] datatable;
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist() tables freed\n",this);
+  
+  doneent *search, *next;
+  for (search=depsdone; search; search=next) {
+    next= search->next;
+    delete search;
+  }
+  
+  if (debug) fprintf(debug,"packagelist[%p]::~packagelist() done\n",this);
+}
+
+pkginfo **packagelist::display() {
+  // returns list of packages as null-terminated array, which becomes owned
+  // by the caller, if a recursive check is desired.
+  // returns 0 if no recursive check is desired.
+  int response, index;
+  const keybindings::interpretation *interp;
+  pkginfo **retl;
+
+  if (debug) fprintf(debug,"packagelist[%p]::display()\n",this);
+
+  setupsigwinch();
+  startdisplay();
+  displayhelp(helpmenulist(),'i');
+
+  if (debug) fprintf(debug,"packagelist[%p]::display() entering loop\n",this);
+  for (;;) {
+    if (whatinfo_height) wcursyncup(whatinfowin);
+    if (doupdate() == ERR) ohshite("doupdate failed");
+    signallist= this;
+    if (sigprocmask(SIG_UNBLOCK,&sigwinchset,0)) ohshite("failed to unblock SIGWINCH");
+    response= getch();
+    if (sigprocmask(SIG_BLOCK,&sigwinchset,0)) ohshite("failed to re-block SIGWINCH");
+    if (response == ERR) ohshite("getch failed");
+    interp= (*bindings)(response);
+    if (debug)
+      fprintf(debug,"packagelist[%p]::display() response=%d interp=%s\n",
+              this,response, interp ? interp->action : "[none]");
+    if (!interp) { beep(); continue; }
+    (this->*(interp->pfn))();
+    if (interp->qa != qa_noquit) break;
+  }
+  pop_cleanup(ehflag_normaltidy); // unset the SIGWINCH handler
+  enddisplay();
+  
+  if (interp->qa == qa_quitnochecksave || !readwrite) {
+    if (debug) fprintf(debug,"packagelist[%p]::display() done - quitNOcheck\n",this);
+    return 0;
+  }
+  
+  if (recursive) {
+    retl= new pkginfo*[nitems+1];
+    for (index=0; index<nitems; index++) retl[index]= table[index]->pkg;
+    retl[nitems]= 0;
+    if (debug) fprintf(debug,"packagelist[%p]::display() done, retl=%p\n",this,retl);
+    return retl;
+  } else {
+    packagelist *sub= new packagelist(bindings,0);
+    for (index=0; index < nitems; index++)
+      if (table[index]->pkg->name)
+        sub->add(table[index]->pkg);
+    repeatedlydisplay(sub,dp_must);
+    if (debug)
+      fprintf(debug,"packagelist[%p]::display() done, not recursive no retl\n",this);
+    return 0;
+  }
+}

+ 183 - 0
dselect/pkglist.h

@@ -0,0 +1,183 @@
+/* -*- c++ -*-
+ * dselect - selection of Debian packages
+ * pkglist.h - external definitions for package list handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef PKGLIST_H
+#define PKGLIST_H
+
+enum showpriority {
+  dp_none,      // has not been involved in any unsatisfied things
+  dp_may,       // has been involved in an unsatisfied Optional
+  dp_must       // has been involved in an unsatisfied Recommended/Depends/Conflicts
+};
+
+enum selpriority {
+  // where did the currently suggested value come from, and how important
+  //  is it to display this package ?
+  // low
+  sp_inherit,     // inherited from our parent list
+  sp_selecting,   // propagating a selection
+  sp_deselecting, // propagating a deselection
+  sp_fixed        // it came from the `status' file and we're not a recursive list
+  // high
+};
+
+struct perpackagestate {
+  struct pkginfo *pkg;
+  /* The `heading' entries in the list, for `all packages of type foo',
+   * point to a made-up pkginfo, which has pkg->name==0.
+   * pkg->priority and pkg->section are set to the values if appropriate, or to
+   * pri_unset resp. null if the heading refers to all priorities resp. sections.
+   * uprec is used when constructing the list initially and when tearing it
+   * down and should not otherwise be used; other fields are undefined.
+   */
+  pkginfo::pkgwant original;         // set by caller
+  pkginfo::pkgwant direct;           // set by caller
+  pkginfo::pkgwant suggested;        // set by caller, modified by resolvesuggest
+  pkginfo::pkgwant selected;         // not set by caller, will be set by packagelist
+  selpriority spriority;             // monotonically increases (used by sublists)
+  showpriority dpriority;            // monotonically increases (used by sublists)
+  struct perpackagestate *uprec;     // 0 if this is not part of a recursive list
+  varbuf relations;
+
+  void free(int recursive);
+};
+
+class packagelist : public baselist {
+  int status_width, gap_width, section_width, priority_width;
+  int package_width, description_width;
+  int section_column, priority_column, package_column, description_column;
+
+  // Only used when `verbose' is set
+  int status_hold_width, status_status_width, status_want_width;
+
+  // Table of packages
+  struct perpackagestate *datatable;
+  struct perpackagestate **table;
+
+  // Misc.
+  int recursive, nallocated, verbose;
+  enum { so_unsorted, so_section, so_priority, so_alpha } sortorder;
+  struct perpackagestate *headings;
+
+  // Information displays
+  struct infotype {
+    int (packagelist::*relevant)(); // null means always relevant
+    void (packagelist::*display)(); // null means end of table
+  };
+  const infotype *currentinfo;
+  static const infotype infoinfos[];
+  static const infotype *const baseinfo;
+  int itr_recursive();
+  int itr_nonrecursive();
+  void severalinfoblurb(const char *whatinfoline);
+  void itd_mainwelcome();
+  void itd_explaindisplay();
+  void itd_recurwelcome();
+  void itd_relations();
+  void itd_description();
+  void itd_controlfile();
+  
+  // Dependency and sublist processing
+  struct doneent { doneent *next; void *dep; } *depsdone, *unavdone;
+  int alreadydone(doneent**, void*);
+  int resolvedepcon(dependency*);
+  int deselect_one_of(pkginfo *er, pkginfo *ed, dependency *display);
+  
+  // Define these virtuals
+  void redraw1itemsel(int index, int selected);
+  void redrawcolheads();
+  void redrawthisstate();
+  void redrawinfo();
+  void redrawtitle();
+  void setwidths();
+  const char *itemname(int index);
+  const struct helpmenuentry *helpmenulist();
+
+  // Miscellaneous internal routines
+  
+  void redraw1package(int index, int selected);
+  int compareentries(struct perpackagestate *a, struct perpackagestate *b);
+  friend int qsort_compareentries(const void *a, const void *b);
+
+  void sortmakeheads();
+  void movecursorafter(int ncursor);
+  void initialsetup();
+  void finalsetup();
+
+  // To do with building the list, with heading lines in it
+  void discardheadings();
+  void addheading(pkginfo::pkgpriority,const char*, const char *section);
+  void sortinplace();
+  void affectedrange(int *startp, int *endp);
+  void setwant(pkginfo::pkgwant nw);
+  void sethold(int hold);
+  
+ public:
+
+  // Keybinding functions */
+  void kd_quit_noop();
+  void kd_revert_abort();
+  void kd_revertsuggest();
+  void kd_revertdirect();  
+  void kd_morespecific();
+  void kd_lessspecific();
+  void kd_swaporder();
+  void kd_select();
+  void kd_deselect();
+  void kd_purge();
+  void kd_hold();
+  void kd_unhold();
+  void kd_info();
+  void kd_verbose();
+  
+  packagelist(keybindings *kb); // nonrecursive
+  packagelist(keybindings *kb, pkginfo **pkgltab); // recursive
+  void add(pkginfo **arry) { while (*arry) add(*arry++); }
+  void add(pkginfo*);
+  void add(pkginfo*, pkginfo::pkgwant);
+  void add(pkginfo*, const char *extrainfo, showpriority displayimportance);
+  int add(dependency*, showpriority displayimportance);
+  void addunavailable(deppossi*);
+
+  int resolvesuggest();
+  int deletelessimp_anyleft(showpriority than);
+  pkginfo **display();
+  ~packagelist();
+};
+
+void repeatedlydisplay(packagelist *sub, showpriority, packagelist *unredisplay =0);
+
+extern const char *const wantstrings[];
+extern const char *const holdstrings[];
+extern const char *const statusstrings[];
+extern const char *const prioritystrings[];
+extern const char *const priorityabbrevs[];
+extern const char *const relatestrings[];
+extern const char statuschars[];
+extern const char holdchars[];
+extern const char wantchars[];
+
+const struct pkginfoperfile *i2info(struct pkginfo *pkg);
+int deppossatisfied(deppossi *possi);
+
+extern modstatdb_rw readwrite;
+
+#endif /* PKGLIST_H */

+ 206 - 0
dselect/pkgsublist.cc

@@ -0,0 +1,206 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgsublist.cc - status modification and recursive package list handling
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "bindings.h"
+
+void packagelist::add(pkginfo *pkg) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s)\n",this,pkg->name);
+  if (!recursive ||  // never add things to top level
+      !pkg->clientdata ||  // don't add pure virtual packages
+      pkg->clientdata->uprec)  // don't add ones already in the recursive list
+    return;
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s) adding\n",this,pkg->name);
+  perpackagestate *state= &datatable[nitems];
+  state->pkg= pkg;
+  state->direct= state->original= pkg->clientdata->selected;
+  state->suggested= state->selected= pkg->clientdata->selected;
+  state->spriority= sp_inherit; state->dpriority= dp_none;
+  state->uprec= pkg->clientdata;
+  state->relations.init();
+  pkg->clientdata= state;
+  table[nitems]= state;
+  nitems++;
+}   
+
+void packagelist::add(pkginfo *pkg, pkginfo::pkgwant nw) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s, %s)\n",
+                     this,pkg->name,wantstrings[nw]);
+  add(pkg);  if (!pkg->clientdata) return;
+  pkg->clientdata->direct= nw;
+  selpriority np;
+  np= (nw == pkginfo::want_install) ? sp_selecting : sp_deselecting;
+  if (pkg->clientdata->spriority > np) return;
+  if (debug) fprintf(debug,"packagelist[%p]::add(pkginfo %s, %s) setting\n",
+                     this,pkg->name,wantstrings[nw]);
+  pkg->clientdata->suggested= pkg->clientdata->selected= nw;
+  pkg->clientdata->spriority= np;
+    
+}   
+
+void packagelist::add(pkginfo *pkg, const char *extrainfo, showpriority showimp) {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::add(pkginfo %s, \"...\", showpriority %d)\n",
+            this,pkg->name,showimp);
+  add(pkg);  if (!pkg->clientdata) return;
+  if (pkg->clientdata->dpriority < showimp) pkg->clientdata->dpriority= showimp;
+  pkg->clientdata->relations(extrainfo);
+  pkg->clientdata->relations.terminate();
+}   
+
+int packagelist::alreadydone(doneent **done, void *check) {
+  doneent *search;
+  
+  for (search= *done; search && search->dep != check; search=search->next);
+  if (search) return 1;
+  if (debug) fprintf(debug,"packagelist[%p]::alreadydone(%p,%p) new\n",
+                     this,done,check);
+  search= new doneent;
+  search->next= *done;
+  search->dep= check;
+  *done= search;
+  return 0;
+}
+
+void packagelist::addunavailable(deppossi *possi) {
+  if (debug) fprintf(debug,"packagelist[%p]::addunavail(%p)\n",this,possi);
+
+  if (!recursive) return;
+  if (alreadydone(&unavdone,possi)) return;
+
+  assert(possi->up->up->clientdata);
+  assert(possi->up->up->clientdata->uprec);
+
+  varbuf& vb= possi->up->up->clientdata->relations;
+  vb(possi->ed->name);
+  vb(" does not appear to be available\n");
+}
+
+int packagelist::add(dependency *depends, showpriority displayimportance) {
+  if (debug) fprintf(debug,"packagelist[%p]::add(dependency[%p])\n",this,depends);
+
+  if (alreadydone(&depsdone,depends)) return 0;
+  
+  const char *comma= "";
+  varbuf info;
+  info(depends->up->name);
+  info(' ');
+  info(relatestrings[depends->type]);
+  info(' ');
+  deppossi *possi;
+  for (possi=depends->list;
+       possi;
+       possi=possi->next, comma=(possi && possi->next ? ", " : " or ")) {
+    info(comma);
+    info(possi->ed->name);
+    if (possi->version && *possi->version) {
+      switch (possi->verrel) {
+      case deppossi::dvr_earlierequal:  info(" (<= "); break;
+      case deppossi::dvr_laterequal:    info(" (>= "); break;
+      case deppossi::dvr_earlierstrict: info(" (<< "); break;
+      case deppossi::dvr_laterstrict:   info(" (>> "); break;
+      case deppossi::dvr_exact:         info(" (= "); break;
+      default: internerr("unknown verrel");
+      }
+      info(possi->version);
+      if (possi->revision && *possi->revision) {
+        info('-');
+        info(possi->revision);
+      }
+      info(")");
+    }
+  }
+  info('\n');
+  add(depends->up,info.string(),displayimportance);
+  for (possi=depends->list; possi; possi=possi->next) {
+    add(possi->ed,info.string(),displayimportance);
+    if (depends->type != dep_provides && (!possi->version || !*possi->version)) {
+      // providers aren't relevant if a version was specified, or
+      // if we're looking at a provider relationship already
+      deppossi *provider;
+      for (provider= possi->ed->available.valid ? possi->ed->available.depended : 0;
+           provider;
+           provider=provider->nextrev) {
+        if (provider->up->type != dep_provides) continue;
+        add(provider->up->up,info.string(),displayimportance);
+        add(provider->up,displayimportance);
+      }
+    }
+  }
+  return 1;
+}
+
+void repeatedlydisplay(packagelist *sub,
+                       showpriority initial,
+                       packagelist *unredisplay) {
+  pkginfo **newl;
+  keybindings *kb;
+  
+  if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p])\n",sub);
+  if (sub->resolvesuggest() != 0 && sub->deletelessimp_anyleft(initial)) {
+    if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) once\n",sub);
+    if (unredisplay) unredisplay->enddisplay();
+    for (;;) {
+      newl= sub->display();
+      if (!newl) break;
+      if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) newl\n",sub);
+      kb= sub->bindings; delete sub;
+      sub= new packagelist(kb,newl);
+      if (sub->resolvesuggest() <= 1) break;
+      if (!sub->deletelessimp_anyleft(dp_must)) break;
+      if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) again\n",sub);
+    }
+    if (unredisplay) unredisplay->startdisplay();
+  }
+  delete sub;
+  if (debug) fprintf(debug,"repeatedlydisplay(packagelist[%p]) done\n",sub);
+}
+
+int packagelist::deletelessimp_anyleft(showpriority than) {
+  if (debug)
+    fprintf(debug,"packagelist[%p]::dli_al(%d): nitems=%d\n",this,than,nitems);
+  int insat, runthr;
+  for (runthr=0, insat=0;
+       runthr < nitems;
+       runthr++) {
+    if (table[runthr]->dpriority < than) {
+      table[runthr]->free(recursive);
+    } else {
+      if (insat != runthr) table[insat]= table[runthr];
+      insat++;
+    }
+  }
+  nitems= insat;
+  if (debug) fprintf(debug,"packagelist[%p]::dli_al(%d) done; nitems=%d\n",
+                     this,than,nitems);
+  return nitems;
+}

+ 249 - 0
dselect/pkgtop.cc

@@ -0,0 +1,249 @@
+/*
+ * dselect - Debian GNU/Linux package maintenance user interface
+ * pkgtop.cc - handles (re)draw of package list windows colheads, list, thisstate
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <ncurses.h>
+#include <assert.h>
+#include <signal.h>
+#include <ctype.h>
+
+extern "C" {
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+}
+#include "dselect.h"
+#include "pkglist.h"
+
+const char *pkgprioritystring(const struct pkginfo *pkg) {
+  if (pkg->priority == pkginfo::pri_unset) {
+    return 0;
+  } else if (pkg->priority == pkginfo::pri_other) {
+    return pkg->otherpriority;
+  } else {
+    assert(pkg->priority <= pkginfo::pri_unknown);
+    return prioritystrings[pkg->priority];
+  }
+}
+
+static int describemany(char buf[], const char *prioritystring, const char *section) {
+  if (!prioritystring) {
+    if (!section) {
+      strcpy(buf, "All packages");
+      return 0;
+    } else {
+      if (!*section) {
+        strcpy(buf, "All packages without a section");
+      } else {
+        sprintf(buf, "All packages in section %s", section);
+      }
+      return 1;
+    }
+  } else {
+    if (!section) {
+      sprintf(buf, "All %s packages", prioritystring);
+      return 1;
+    } else {
+      if (!*section) {
+        sprintf(buf, "All %s packages without a section", prioritystring);
+      } else {
+        sprintf(buf, "All %s packages in section %s", prioritystring, section);
+      }
+      return 2;
+    }
+  }
+}
+
+void packagelist::redrawthisstate() {
+  if (!thisstate_height) return;
+  mywerase(thisstatepad);
+
+  const char *section= table[cursorline]->pkg->section;
+  const char *priority= pkgprioritystring(table[cursorline]->pkg);
+  char *buf= new char[220+
+                      greaterint((table[cursorline]->pkg->name
+                                  ? strlen(table[cursorline]->pkg->name) : 0),
+                                 (section ? strlen(section) : 0) +
+                                 (priority ? strlen(priority) : 0))];
+    
+  if (table[cursorline]->pkg->name) {
+    sprintf(buf,
+            "%-*s %s%s%s;  %s (was: %s).  %s",
+            package_width,
+            table[cursorline]->pkg->name,
+            statusstrings[table[cursorline]->pkg->status],
+            holdstrings[table[cursorline]->pkg->eflag][0] ? " - " : "",
+            holdstrings[table[cursorline]->pkg->eflag],
+            wantstrings[table[cursorline]->selected],
+            wantstrings[table[cursorline]->original],
+            priority);
+  } else {
+    describemany(buf,priority,section);
+  }
+  mvwaddnstr(thisstatepad,0,0, buf, total_width);
+  pnoutrefresh(thisstatepad, 0,leftofscreen, thisstate_row,0,
+               thisstate_row, lesserint(total_width - 1, xmax - 1));
+
+  delete[] buf;
+}
+
+void packagelist::redraw1itemsel(int index, int selected) {
+  int i, indent, j;
+  const char *p;
+  const struct pkginfo *pkg= table[index]->pkg;
+  const struct pkginfoperfile *info= &pkg->available;
+
+  wattrset(listpad, selected ? listsel_attr : list_attr);
+
+  if (pkg->name) {
+
+    if (verbose) {
+
+      mvwprintw(listpad,index,0, "%-*.*s ",
+                status_hold_width, status_hold_width,
+                holdstrings[pkg->eflag]);
+      wprintw(listpad, "%-*.*s ",
+              status_status_width, status_status_width,
+              statusstrings[pkg->status]);
+      wprintw(listpad, "%-*.*s ",
+              status_want_width, status_want_width,
+              /* fixme: keep this ? */
+              /*table[index]->original == table[index]->selected ? "(same)"
+              : */wantstrings[table[index]->original]);
+      wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+      wprintw(listpad, "%-*.*s",
+              status_want_width, status_want_width,
+              wantstrings[table[index]->selected]);
+      wattrset(listpad, selected ? listsel_attr : list_attr);
+      waddch(listpad, ' ');
+  
+      mvwprintw(listpad,index,priority_column-1, " %-*.*s",
+                priority_width, priority_width,
+                pkg->priority == pkginfo::pri_other ? pkg->otherpriority :
+                prioritystrings[pkg->priority]);
+
+    } else {
+
+      mvwaddch(listpad,index,0, holdchars[pkg->eflag]);
+      waddch(listpad, statuschars[pkg->status]);
+      waddch(listpad,
+             /* fixme: keep this feature? */
+             /*table[index]->original == table[index]->selected ? ' '
+             : */wantchars[table[index]->original]);
+    
+      wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+      waddch(listpad, wantchars[table[index]->selected]);
+      wattrset(listpad, selected ? listsel_attr : list_attr);
+      
+      wmove(listpad,index,priority_column-1); waddch(listpad,' ');
+      if (pkg->priority == pkginfo::pri_other) {
+        int i;
+        char *p;
+        for (i=priority_width, p=pkg->otherpriority;
+             i > 0 && *p;
+             i--, p++)
+          waddch(listpad, tolower(*p));
+        while (i-- > 0) waddch(listpad,' ');
+      } else {
+        wprintw(listpad, "%-*.*s", priority_width, priority_width,
+                priorityabbrevs[pkg->priority]);
+      }
+
+    }
+
+    mvwprintw(listpad,index,section_column-1, " %-*.*s",
+              section_width, section_width,
+              pkg->section ? pkg->section : "?");
+  
+    mvwprintw(listpad,index,package_column-1, " %-*.*s ",
+              package_width, package_width, pkg->name);
+      
+    i= description_width;
+    p= info->description ? info->description : "";
+    while (i>0 && *p && *p != '\n') { waddch(listpad,*p); i--; p++; }
+      
+  } else {
+
+    const char *section= pkg->section;
+    const char *priority= pkgprioritystring(pkg);
+
+    char *buf= new char[220+
+                        (section ? strlen(section) : 0) +
+                        (priority ? strlen(priority) : 0)];
+    
+    indent= describemany(buf,priority,section);
+
+    mvwaddstr(listpad,index,0, "    ");
+    i= total_width-6;
+    j= (indent<<1) + 1;
+    while (j-- >0) { waddch(listpad,'-'); i--; }
+    waddch(listpad,' ');
+
+    wattrset(listpad, selected ? selstatesel_attr : selstate_attr);
+    p= buf;
+    while (i>0 && *p) { waddch(listpad, *p); p++; i--; }
+    wattrset(listpad, selected ? listsel_attr : list_attr);
+
+    waddch(listpad,' ');
+    j= (indent<<1) + 1;
+    while (j-- >0) { waddch(listpad,'-'); i--; }
+
+    delete[] buf;
+
+  }
+
+  while (i>0) { waddch(listpad,' '); i--; }
+}
+
+void packagelist::redrawcolheads() {
+  if (colheads_height) {
+    wattrset(colheadspad,colheads_attr);
+    mywerase(colheadspad);
+    if (verbose) {
+      wmove(colheadspad,0,0);
+      for (int i=0; i<status_width-status_want_width; i++) waddch(colheadspad,'.');
+      mvwaddnstr(colheadspad,0,
+                 0,
+                 "Hold/Err.",
+                 status_hold_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+1,
+                 "Installed?",
+                 status_status_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+status_status_width+2,
+                 "Old sel.",
+                 status_want_width);
+      mvwaddnstr(colheadspad,0,
+                 status_hold_width+status_status_width+status_want_width+3,
+                 "Selection",
+                 status_want_width);
+    } else {
+      mvwaddstr(colheadspad,0,0, "HIOS");
+    }
+    mvwaddnstr(colheadspad,0,section_column, "Section", section_width);
+    mvwaddnstr(colheadspad,0,priority_column, "Priority", priority_width);
+    mvwaddnstr(colheadspad,0,package_column, "Package", package_width);
+    mvwaddnstr(colheadspad,0,description_column, "Description", description_width);
+  }
+  refreshcolheads();
+}

+ 2 - 0
dselect/rp

@@ -0,0 +1,2 @@
+#!/bin/sh
+while cat p; do echo ===================; done

+ 1 - 0
dselect/t.c

@@ -0,0 +1 @@
+#include <ncurses/curses.h>

+ 26 - 0
include/Makefile.in

@@ -0,0 +1,26 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+all:
+
+clean:
+		rm -f core
+
+distclean:	clean
+		rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:	all

+ 272 - 0
include/dpkg-db.h

@@ -0,0 +1,272 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg-db.h - declarations for in-core package database management
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_DB_H
+#define DPKG_DB_H
+
+#include <stdio.h>
+#include <stdlib.h>
+
+enum deptype {
+  dep_suggests,
+  dep_recommends,
+  dep_depends,
+  dep_predepends,
+  dep_conflicts,
+  dep_provides,
+  dep_replaces
+};
+
+struct dependency { /* dy */
+  struct pkginfo *up;
+  struct dependency *next;
+  struct deppossi *list;
+  enum deptype type;
+};
+
+struct deppossi { /* do */
+  struct dependency *up;
+  struct pkginfo *ed;
+  struct deppossi *next, *nextrev, *backrev;
+  enum depverrel {
+    dvrf_earlier=      0001,
+    dvrf_later=        0002,
+    dvrf_strict=       0010,
+    dvrf_orequal=      0020,
+    dvrf_builtup=      0100,
+    dvr_none=          0200,
+    dvr_earlierequal=  dvrf_builtup | dvrf_earlier | dvrf_orequal,
+    dvr_earlierstrict= dvrf_builtup | dvrf_earlier | dvrf_strict,
+    dvr_laterequal=    dvrf_builtup | dvrf_later   | dvrf_orequal,
+    dvr_laterstrict=   dvrf_builtup | dvrf_later   | dvrf_strict,
+    dvr_exact=         0400
+  } verrel;
+  char *version, *revision;
+  int cyclebreak;
+};
+
+struct arbitraryfield {
+  struct arbitraryfield *next;
+  char *name;
+  char *value;
+};
+
+struct conffile {
+  struct conffile *next;
+  char *name;
+  char *hash;
+};
+
+struct filedetails {
+  struct filedetails *next;
+  char *name, *msdosname, *size, *md5sum;
+};
+
+struct pkginfoperfile { /* pif */
+  int valid;
+  struct dependency *depends;
+  struct deppossi *depended;
+  int essential; /* The `essential' flag, 1=yes, 0=no (absent) */
+  char *description, *maintainer, *version, *revision, *source, *architecture;
+  struct conffile *conffiles;
+  struct arbitraryfield *arbs;
+};
+
+struct perpackagestate; /* used by dselect only, but we keep a pointer here */
+
+struct pkginfo { /* pig */
+  struct pkginfo *next;
+  char *name;
+  enum pkgwant {
+    want_unknown, want_install, want_deinstall, want_purge
+  } want;
+  enum pkgeflag {
+    eflagv_ok=00, eflagv_hold=01, eflagv_reinstreq=02, eflagv_both=03,
+    eflagf_hold=01, eflagf_reinstreq=02
+  } eflag; /* bitmask */
+  enum pkgstatus {
+    stat_notinstalled, stat_unpacked, stat_halfconfigured,
+    stat_installed, stat_halfinstalled, stat_configfiles
+  } status;
+  enum pkgpriority {
+    pri_required, pri_important, pri_standard, pri_recommended,
+    pri_optional, pri_extra, pri_contrib,
+    pri_other, pri_unknown, pri_unset=-1
+  } priority;
+  char *otherpriority;
+  char *section;
+  char *configversion, *configrevision;
+  struct filedetails *files;
+  struct pkginfoperfile installed;
+  struct pkginfoperfile available;
+  struct perpackagestate *clientdata;
+};
+
+/*** from lock.c ***/
+
+void lockdatabase(const char *admindir);
+void unlockdatabase(const char *admindir);
+
+/*** from dbmodify.c ***/
+
+enum modstatdb_rw {
+  /* Those marked with \*s*\ are possible returns from modstatdb_init. */
+  msdbrw_readonly/*s*/, msdbrw_needsuperuserlockonly/*s*/,
+  msdbrw_writeifposs,
+  msdbrw_write/*s*/, msdbrw_needsuperuser,
+  /* Now some optional flags: */
+  msdbrw_flagsmask= ~077,
+  /* Prefer later versions from `status' in `available' info, but do not
+   * save `available' info: */
+  msdbrw_availablepreferversion= 0100
+};
+
+enum modstatdb_rw modstatdb_init(const char *admindir, enum modstatdb_rw reqrwflags);
+void modstatdb_note(struct pkginfo *pkg);
+void modstatdb_shutdown(void);
+
+extern char *statusfile, *availablefile; /* initialised by modstatdb_init */
+
+/*** from database.c ***/
+
+struct pkginfo *findpackage(const char *name);
+void blankpackage(struct pkginfo *pp);
+void blankpackageperfile(struct pkginfoperfile *pifp);
+int informative(struct pkginfo *info);
+int informativeperfile(struct pkginfoperfile *info);
+int countpackages(void);
+void resetpackages(void);
+
+struct pkgiterator *iterpkgstart(void);
+struct pkginfo *iterpkgnext(struct pkgiterator*);
+void iterpkgend(struct pkgiterator*);
+
+void hashreport(FILE*);
+
+/*** from parse.c ***/
+
+enum parsedbflags {
+  pdb_recordavailable   =001, /* Store in `available' in-core structures, not `status' */
+  pdb_rejectstatus      =002, /* Throw up an error if `Status' encountered             */
+  pdb_weakclassification=004, /* Ignore priority/section info if we already have any   */
+  pdb_preferversion=     010  /* Discard information about earlier versions            */
+};
+
+const char *illegal_packagename(const char *p, const char **ep);
+int parsedb(const char *filename, enum parsedbflags, struct pkginfo **donep,
+            FILE *warnto, int *warncount);
+void copy_dependency_links(struct pkginfo *pkg,
+                           struct dependency **updateme,
+                           struct dependency *newdepends,
+                           int available);
+
+/*** from parsehelp.c ***/
+
+struct namevalue {
+  const char *name;
+  int value;
+};
+
+extern const struct namevalue booleaninfos[];
+extern const struct namevalue priorityinfos[];
+extern const struct namevalue statusinfos[];
+extern const struct namevalue eflaginfos[];
+extern const struct namevalue wantinfos[];
+
+const char *skip_slash_dotslash(const char *p);
+
+/*** from varbuf.c ***/
+
+struct varbuf;
+
+extern void varbufaddc(struct varbuf *v, int c);
+void varbufinit(struct varbuf *v);
+void varbufreset(struct varbuf *v);
+void varbufextend(struct varbuf *v);
+void varbuffree(struct varbuf *v);
+void varbufaddstr(struct varbuf *v, const char *s);
+
+/* varbufinit must be called exactly once before the use of each varbuf
+ * (including before any call to varbuffree).
+ *
+ * However, varbufs allocated `static' are properly initialised anyway and
+ * do not need varbufinit; multiple consecutive calls to varbufinit before
+ * any use are allowed.
+ *
+ * varbuffree must be called after a varbuf is finished with, if anything
+ * other than varbufinit has been done.  After this you are allowed but
+ * not required to call varbufinit again if you want to start using the
+ * varbuf again.
+ *
+ * Callers using C++ need not worry about any of this.
+ */
+struct varbuf {
+  int used, size;
+  char *buf;
+
+#ifdef __cplusplus
+  void init() { varbufinit(this); }
+  void free() { varbuffree(this); }
+  varbuf() { varbufinit(this); }
+  ~varbuf() { varbuffree(this); }
+  inline void operator()(int c); // definition below
+  void operator()(const char *s) { varbufaddstr(this,s); }
+  inline void terminate(void/*to shut 2.6.3 up*/); // definition below
+  void reset() { used=0; }
+  const char *string() { terminate(); return buf; }
+#endif
+};
+
+#if HAVE_INLINE
+inline extern void varbufaddc(struct varbuf *v, int c) {
+  if (v->used >= v->size) varbufextend(v);
+  v->buf[v->used++]= c;
+}
+#endif
+
+#ifdef __cplusplus
+inline void varbuf::operator()(int c) { varbufaddc(this,c); }
+inline void varbuf::terminate(void/*to shut 2.6.3 up*/) { varbufaddc(this,0); used--; }
+#endif
+
+/*** from dump.c ***/
+
+void writerecord(FILE*, const char*,
+                 const struct pkginfo*, const struct pkginfoperfile*);
+
+void writedb(const char *filename, int available, int mustsync);
+
+void varbufrecord(struct varbuf*, const struct pkginfo*, const struct pkginfoperfile*);
+void varbufdependency(struct varbuf *vb, struct dependency *dep);
+  /* NB THE VARBUF MUST HAVE BEEN INITIALISED AND WILL NOT BE NULL-TERMINATED */
+
+/*** from vercmp.c ***/
+
+int versioncompare(const char *version, const char *revision,
+                   const char *refversion, const char *refrevision);
+
+/*** from nfmalloc.c ***/
+
+void *nfmalloc(size_t);
+char *nfstrsave(const char*);
+void nffreeall(void);
+
+#endif /* DPKG_DB_H */

+ 179 - 0
include/dpkg.h

@@ -0,0 +1,179 @@
+
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg.h - general header for Debian package handling
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DPKG_H
+#define DPKG_H
+
+#include <setjmp.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <sys/types.h>
+
+#define ARCHIVEVERSION     "2.0"
+#define SPLITVERSION       "2.1"
+#define OLDARCHIVEVERSION  "0.939000"
+#define SPLITPARTDEFMAX    (450*1024)
+#define MAXFIELDNAME        200
+#define MAXCONFFILENAME     1000
+#define MAXDIVERTFILENAME   1024
+#define MAXCONTROLFILENAME  100
+#define BUILDCONTROLDIR    "DEBIAN"
+#define EXTRACTCONTROLDIR   BUILDCONTROLDIR
+#define DEBEXT             ".deb"
+#define OLDDBEXT           "-old"
+#define NEWDBEXT           "-new"
+#define OLDOLDDEBDIR       ".DEBIAN"
+#define OLDDEBDIR          "DEBIAN"
+#define REMOVECONFFEXTS    "~", ".bak", "%", \
+                           DPKGTEMPEXT, DPKGNEWEXT, DPKGOLDEXT, DPKGDISTEXT
+
+#define DPKG_VERSION_ARCH  DPKG_VERSION " (" ARCHITECTURE ")"
+
+#define NEWCONFFILEFLAG    "newconffile"
+#define NONEXISTENTFLAG    "nonexistent"
+
+#define DPKGTEMPEXT        ".dpkg-tmp"
+#define DPKGNEWEXT         ".dpkg-new"
+#define DPKGOLDEXT         ".dpkg-old"
+#define DPKGDISTEXT        ".dpkg-dist"
+
+#define CONTROLFILE        "control"
+#define CONFFILESFILE      "conffiles"
+#define PREINSTFILE        "preinst"
+#define POSTINSTFILE       "postinst"
+#define PRERMFILE          "prerm"
+#define POSTRMFILE         "postrm"
+#define LISTFILE           "list"
+
+#define ADMINDIR        "/var/lib/dpkg"
+#define STATUSFILE      "status"
+#define AVAILFILE       "available"
+#define LOCKFILE        "lock"
+#define CMETHOPTFILE    "cmethopt"
+#define METHLOCKFILE    "methlock"
+#define DIVERSIONSFILE  "diversions"
+#define UPDATESDIR      "updates/"
+#define INFODIR         "info/"
+#define PARTSDIR        "parts/"
+#define CONTROLDIRTMP   "tmp.ci/"
+#define IMPORTANTTMP    "tmp.i"
+#define REASSEMBLETMP   "reassemble" DEBEXT
+#define IMPORTANTMAXLEN  10
+#define IMPORTANTFMT    "%04d" /* change => also change lib/database.c:cleanup_updates */
+#define MAXUPDATES       50
+
+#define LIBDIR              "/usr/lib/dpkg"
+#define LOCALLIBDIR         "/usr/local/lib/dpkg"
+#define METHODSDIR          "methods"
+
+#define NOJOBCTRLSTOPENV    "DPKG_NO_TSTP"
+#define SHELLENV            "SHELL"
+#define DEFAULTSHELL        "sh"
+
+#define IMETHODMAXLEN        50
+#define IOPTIONMAXLEN        IMETHODMAXLEN
+#define METHODOPTIONSFILE   "names"
+#define METHODSETUPSCRIPT   "setup"
+#define METHODUPDATESCRIPT  "update"
+#define METHODINSTALLSCRIPT "install"
+#define OPTIONSDESCPFX      "desc."
+#define OPTIONINDEXMAXLEN    5
+
+#define PKGSCRIPTMAXARGS     10
+#define MD5HASHLEN           32
+
+#define CONFFOPTCELLS  /* int conffoptcells[2] {* 1= user edited *}              \
+                                           [2] {* 1= distributor edited *} = */  \
+                                  /* dist not */     /* dist edited */           \
+   /* user did not edit */    {     cfo_keep,           cfo_install    },        \
+   /* user did edit     */    {     cfo_keep,         cfo_prompt_keep  }
+
+#define ARCHIVE_FILENAME_PATTERN "*.deb"
+
+#define BACKEND      "dpkg-deb"
+#define SPLITTER     "dpkg-split"
+#define MD5SUM       "md5sum"
+#define DSELECT      "dselect"
+#define DPKG         "dpkg"
+
+#define TAR          "tar"
+#define GZIP         "gzip"
+#define CAT          "cat"
+#define RM           "rm"
+#define FIND         "find"
+#define SHELL        "sh"
+
+#define SHELLENVIR   "SHELL"
+
+#define FIND_EXPRSTARTCHARS "-(),!"
+
+#define TARBLKSZ     512
+
+extern const char thisname[]; /* defined separately in each program */
+extern const char printforhelp[];
+
+/*** from ehandle.c ***/
+
+void push_error_handler(jmp_buf *jbufp,
+                        void (*printerror)(const char *, const char *),
+                        const char *contextstring);
+void set_error_display(void (*printerror)(const char *, const char *),
+                       const char *contextstring);
+void print_error_fatal(const char *emsg, const char *contextstring);
+void error_unwind(int flagset);
+void push_cleanup(void (*f1)(int argc, void **argv), int flagmask1,
+                  void (*f2)(int argc, void **argv), int flagmask2,
+                  int nargs, ...);
+void push_checkpoint(int mask, int value);
+void pop_cleanup(int flagset);
+enum { ehflag_normaltidy=01, ehflag_bombout=02, ehflag_recursiveerror=04 };
+
+void do_internerr(const char *string, int line, const char *file) NONRETURNING;
+#define internerr(s) do_internerr(s,__LINE__,__FILE__)
+
+struct varbuf;
+void ohshit(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void ohshitv(const char *fmt, va_list al) NONRETURNING;
+void ohshite(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void ohshitvb(struct varbuf*) NONRETURNING;
+void badusage(const char *fmt, ...) NONRETURNPRINTFFORMAT(1,2);
+void werr(const char *what) NONRETURNING;
+
+/*** from mlib.c ***/
+
+void *m_malloc(size_t);
+void *m_realloc(void*, size_t);
+int m_fork(void);
+void m_dup2(int oldfd, int newfd);
+void m_pipe(int fds[2]);
+
+void checksubprocerr(int status, const char *description, int sigpipeok);
+void waitsubproc(pid_t pid, const char *description, int sigpipeok);
+
+extern volatile int onerr_abort;
+
+/*** from showcright.c ***/
+
+struct cmdinfo;
+void showcopyright(const struct cmdinfo*, const char*);
+
+#endif /* DPKG_H */

+ 38 - 0
include/myopt.h

@@ -0,0 +1,38 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * myopt.h - declarations for my very own option parsing
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 file; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef MYOPT_H
+#define MYOPT_H
+
+struct cmdinfo {
+  const char *olong;
+  char oshort;
+  int takesvalue; /* 0 = normal   1 = standard value   2 = option string cont */
+  int *iassignto;
+  const char **sassignto;
+  void (*call)(const struct cmdinfo*, const char *value);
+  int arg;
+  void *parg;
+};
+
+void myopt(const char *const **argvp, const struct cmdinfo *cmdinfos);
+
+#endif /* MYOPT_H */

+ 57 - 0
include/tarfn.h

@@ -0,0 +1,57 @@
+#ifndef	_TAR_FUNCTION_H_
+#define	_TAR_FUNCTION_H_
+
+/*
+ * Functions for extracting tar archives.
+ * Bruce Perens, April-May 1995
+ * Copyright (C) 1995 Bruce Perens
+ * This is free software under the GNU General Public License.
+ */
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+enum TarFileType {
+	NormalFile0 = '\0',	/* For compatibility with decades-old bug */
+	NormalFile1 = '0',
+	HardLink = '1',
+	SymbolicLink = '2',
+	CharacterDevice = '3',
+	BlockDevice = '4',
+	Directory = '5',
+	FIFO = '6'
+};
+typedef enum TarFileType	TarFileType;
+
+struct	TarInfo {
+	void *		UserData;	/* User passed this in as argument */
+	char *		Name;		/* File name */
+	mode_t		Mode;		/* Unix mode, including device bits. */
+	size_t		Size;		/* Size of file */
+	time_t		ModTime;	/* Last-modified time */
+	TarFileType	Type;		/* Regular, Directory, Special, Link */
+	char *		LinkName;	/* Name for symbolic and hard links */
+	dev_t		Device;		/* Special device for mknod() */
+	uid_t		UserID;		/* Numeric UID */
+	gid_t		GroupID;	/* Numeric GID */
+};
+typedef struct TarInfo	TarInfo;
+
+typedef	int	(*TarReadFunction)(void * userData, char * buffer, int length);
+
+typedef int	(*TarFunction)(TarInfo * h);
+
+struct TarFunctions {
+	TarReadFunction	Read;
+	TarFunction	ExtractFile;
+	TarFunction	MakeDirectory;
+	TarFunction	MakeHardLink;
+	TarFunction	MakeSymbolicLink;
+	TarFunction	MakeSpecialFile;
+};
+typedef struct TarFunctions	TarFunctions;
+
+extern int	TarExtractor(void * userData, const TarFunctions * functions);
+
+#endif

+ 14 - 0
insert-version.pl

@@ -0,0 +1,14 @@
+#!/usr/bin/perl --
+chop($v=`pwd`);
+$v =~ s,^.*/dpkg-,, || die;
+$v =~ s,/\w+$,,;
+$v =~ m,^[-0-9.]+$, || die;
+while (<STDIN>) {
+    $_= $1.$v.$2."\n" if
+        m|^(#define DPKG_VERSION ")[-0-9.]+(" /\* This line modified by Makefile \*/)$|;
+    $_= $1.$v.$2."\n" if
+        m/^(\$version= ')[-0-9.]+('; # This line modified by Makefile)$/;
+    $_= $1.$v.$2."\n" if
+        m/^(version=")[-0-9.]+("; # This line modified by Makefile)$/;
+    print || die;
+}

+ 119 - 0
install.sh

@@ -0,0 +1,119 @@
+#!/bin/sh
+
+#
+# install - install a program, script, or datafile
+# This comes from X11R5; it is not part of GNU.
+#
+# $XConsortium: install.sh,v 1.2 89/12/18 14:47:22 jim Exp $
+#
+# This script is compatible with the BSD install script, but was written
+# from scratch.
+#
+
+
+# set DOITPROG to echo to test this script
+
+# Don't use :- since 4.3BSD and earlier shells don't like it.
+doit="${DOITPROG-}"
+
+
+# put in absolute paths if you don't have them in your path; or use env. vars.
+
+mvprog="${MVPROG-mv}"
+cpprog="${CPPROG-cp}"
+chmodprog="${CHMODPROG-chmod}"
+chownprog="${CHOWNPROG-chown}"
+chgrpprog="${CHGRPPROG-chgrp}"
+stripprog="${STRIPPROG-strip}"
+rmprog="${RMPROG-rm}"
+
+instcmd="$mvprog"
+chmodcmd=""
+chowncmd=""
+chgrpcmd=""
+stripcmd=""
+rmcmd="$rmprog -f"
+mvcmd="$mvprog"
+src=""
+dst=""
+
+while [ x"$1" != x ]; do
+    case $1 in
+	-c) instcmd="$cpprog"
+	    shift
+	    continue;;
+
+	-m) chmodcmd="$chmodprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-o) chowncmd="$chownprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-g) chgrpcmd="$chgrpprog $2"
+	    shift
+	    shift
+	    continue;;
+
+	-s) stripcmd="$stripprog"
+	    shift
+	    continue;;
+
+	*)  if [ x"$src" = x ]
+	    then
+		src=$1
+	    else
+		dst=$1
+	    fi
+	    shift
+	    continue;;
+    esac
+done
+
+if [ x"$src" = x ]
+then
+	echo "install:  no input file specified"
+	exit 1
+fi
+
+if [ x"$dst" = x ]
+then
+	echo "install:  no destination specified"
+	exit 1
+fi
+
+
+# If destination is a directory, append the input filename; if your system
+# does not like double slashes in filenames, you may need to add some logic
+
+if [ -d $dst ]
+then
+	dst="$dst"/`basename $src`
+fi
+
+# Make a temp file name in the proper directory.
+
+dstdir=`dirname $dst`
+dsttmp=$dstdir/#inst.$$#
+
+# Move or copy the file name to the temp name
+
+$doit $instcmd $src $dsttmp
+
+# and set any options; do chmod last to preserve setuid bits
+
+if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; fi
+if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; fi
+if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; fi
+if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; fi
+
+# Now rename the file to the real destination.
+
+$doit $rmcmd $dst
+$doit $mvcmd $dsttmp $dst
+
+
+exit 0

+ 91 - 0
lib/Makefile.in

@@ -0,0 +1,91 @@
+# Copyright (C) 1994 Ian Murdock <imurdock@debian.org>
+# Copyright (C) 1994,1995 Ian Jackson <ijackson@nyx.cs.du.edu>
+#
+#   This 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,
+#   or (at your option) any later version.
+#
+#   This 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 dpkg; if not, write to the Free Software
+#   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+
+srcdir = @srcdir@
+VPATH = @srcdir@
+
+prefix = @prefix@
+copyingfile = $(prefix)/doc/copyright/dpkg
+
+SRC =	ehandle.c mlib.c parse.c parsehelp.c fields.c dump.c nfmalloc.c \
+	varbuf.c database.c myopt.c vercmp.c compat.c lock.c dbmodify.c \
+	showcright.c tarfn.c star.c
+OBJ =	ehandle.o mlib.o parse.o parsehelp.o fields.o dump.o nfmalloc.o \
+	varbuf.o database.o myopt.o vercmp.o compat.o lock.o dbmodify.o \
+	showcright.o tarfn.o star.o
+
+INSTALL = @INSTALL@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_DATA = @INSTALL_DATA@
+
+CC = @CC@
+
+CFLAGS = @CFLAGS@ @CWARNS@ $(XCFLAGS) -g # fixme: remove -g
+OPTCFLAGS = @OPTCFLAGS@
+LDFLAGS = -s $(XLDFLAGS)
+ALL_CFLAGS = -I../include -I.. @DEFS@ $(CFLAGS)
+ALL_CFLAGS_OPT = $(ALL_CFLAGS) $(OPTCFLAGS)
+
+AR = ar crv
+RANLIB = @RANLIB@
+
+.SUFFIXES:	.c .o
+
+all:		libdpkg.a
+
+libdpkg.a:	$(OBJ)
+		$(AR) libdpkg.a $(OBJ)
+		$(RANLIB) libdpkg.a
+
+showcright.o:	showcright.c
+		$(CC) -DCOPYINGFILE=\"$(copyingfile)\" $(ALL_CFLAGS) -c $<
+
+.c.o:
+		$(CC) $(ALL_CFLAGS) -c $<
+
+# These next few files are very heavily used, and should be optimised
+# for speed rather than space.  (ALL_CFLAGS_OPT usually means -O3.)
+database.o:	database.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+fields.o:	fields.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+nfmalloc.o:	nfmalloc.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+parse.o:	parse.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+parsehelp.o:	parsehelp.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+varbuf.o:	varbuf.c
+		$(CC) $(ALL_CFLAGS_OPT) -c $<
+
+clean:
+		rm -f *.o core libdpkg.a
+
+distclean:	clean
+		rm -f Makefile *.orig *~ *.~* ./#*#
+
+install:	all
+
+dump.o fields.o parse.o parsehelp.o vercmp.o:	parsedump.h
+$(OBJ):			../include/dpkg.h ../include/dpkg-db.h
+myopt.o:		../include/myopt.h
+tarfn.o star.o:		../include/tarfn.h

+ 102 - 0
lib/compat.c

@@ -0,0 +1,102 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * compat.c - compatibility functions
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <errno.h>
+#include <signal.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+
+#include "config.h"
+
+#ifndef HAVE_STRERROR
+extern const char *const sys_errlist[];
+extern const int sys_nerr;
+const char *strerror(int e) {
+  static char buf[100];
+  if (e >= 0 && e < sys_nerr) return sys_errlist[e];
+  sprintf(buf, "System error no.%d", e);
+  return buf;
+}
+#endif
+
+#ifndef HAVE_STRSIGNAL
+extern const char *const sys_siglist[];
+const char *strsignal(int e) {
+  static char buf[100];
+  if (e >= 0 && e < NSIG) return sys_siglist[e];
+  sprintf(buf, "Signal no.%d", e);
+  return buf;
+}
+#endif
+
+#ifndef HAVE_SCANDIR
+
+static int (*scandir_comparfn)(const void*, const void*);
+static int scandir_compar(const void *a, const void *b) {
+  return scandir_comparfn(*(const struct dirent**)a,*(const struct dirent**)b);
+}
+      
+int scandir(const char *dir, struct dirent ***namelist,
+            int (*select)(const struct dirent *),
+            int (*compar)(const void*, const void*)) {
+  DIR *d;
+  int used, avail;
+  struct dirent *e, *m;
+  d= opendir(dir);  if (!d) return -1;
+  used=0; avail=20;
+  *namelist= malloc(avail*sizeof(struct dirent*));
+  if (!*namelist) return -1;
+  while ((e= readdir(d)) != 0) {
+    if (!select(e)) continue;
+    m= malloc(sizeof(struct dirent) + strlen(e->d_name));
+    if (!m) return -1;
+    *m= *e;
+    strcpy(m->d_name,e->d_name);
+    if (used >= avail-1) {
+      avail+= avail;
+      *namelist= realloc(*namelist, avail*sizeof(struct dirent*));
+      if (!*namelist) return -1;
+    }
+    (*namelist)[used]= m;
+    used++;
+  }
+  (*namelist)[used]= 0;
+  scandir_comparfn= compar;
+  qsort(*namelist, used, sizeof(struct dirent*), scandir_compar);
+  return used;
+}
+#endif
+
+#ifndef HAVE_ALPHASORT
+int alphasort(const struct dirent *a, const struct dirent *b) {
+  return strcmp(a->d_name,b->d_name);
+}
+#endif
+
+#ifndef HAVE_UNSETENV
+void unsetenv(const char *p) {
+  char *q;
+  q= malloc(strlen(p)+3); if (!q) return;
+  strcpy(q,p); strcat(q,"="); putenv(q);
+}
+#endif

+ 249 - 0
lib/database.c

@@ -0,0 +1,249 @@
+/*
+ * libdpkg - Debian packaging suite library routines
+ * dpkg-db.h - Low level package database routines (hash tables, etc.)
+ *
+ * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <ctype.h>
+#include <string.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+#define BINS (1 << 7)
+ /* This must always be a power of two.  If you change it
+  * consider changing the per-character hashing factor (currently 5) too.
+  */
+
+static struct pkginfo *bins[BINS];
+static int npackages;
+
+static int hash(const char *name) {
+  int v= 0;
+  while (*name) { v *= 5; v += tolower(*name); name++; }
+  return v;
+/* These results were achieved with 128 bins, and the list of packages
+ * shown at the bottom of this file.
+ */
+/*  while (*name) { v *= 17; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     0 times
+ *  size       3 occurs     7 times
+ *  size       2 occurs    32 times
+ *  size       1 occurs    51 times
+ *  size       0 occurs    37 times
+ */
+/*  while (*name) { v *= 5; v += tolower(*name); name++; }
+ *  size       4 occurs     1 times
+ *  size       3 occurs    14 times
+ *  size       2 occurs    20 times
+ *  size       1 occurs    55 times
+ *  size       0 occurs    38 times
+ */
+/*  while (*name) { v *= 11; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     4 times
+ *  size       3 occurs     9 times
+ *  size       2 occurs    25 times
+ *  size       1 occurs    43 times
+ *  size       0 occurs    46 times
+ */
+/*  while (*name) { v *= 31; v += tolower(*name); name++; }
+ *  size       6 occurs     1 times
+ *  size       5 occurs     0 times
+ *  size       4 occurs     1 times
+ *  size       3 occurs    11 times
+ *  size       2 occurs    27 times
+ *  size       1 occurs    44 times
+ *  size       0 occurs    44 times
+ */
+/*  while (*name) { v *= 111; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     1 times
+ *  size       3 occurs    14 times
+ *  size       2 occurs    23 times
+ *  size       1 occurs    44 times
+ *  size       0 occurs    45 times
+ */
+/*  while (*name) { v += (v<<3); v += tolower(*name); name++; }
+ *  size       4 occurs     5 times
+ *  size       3 occurs    12 times
+ *  size       2 occurs    22 times
+ *  size       1 occurs    41 times
+ *  size       0 occurs    48 times
+ */
+/*  while (*name) { v *= 29; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     2 times
+ *  size       3 occurs    10 times
+ *  size       2 occurs    26 times
+ *  size       1 occurs    46 times
+ *  size       0 occurs    43 times
+ */
+/*  while (*name) { v *= 13; v += tolower(*name); name++; }
+ *  size       5 occurs     1 times
+ *  size       4 occurs     2 times
+ *  size       3 occurs     5 times
+ *  size       2 occurs    30 times
+ *  size       1 occurs    53 times
+ *  size       0 occurs    37 times
+ */
+}
+
+void blankpackage(struct pkginfo *pigp) {
+  pigp->name= 0;
+  pigp->status= stat_notinstalled;
+  pigp->eflag= eflagv_ok;
+  pigp->want= want_unknown;
+  pigp->priority= pri_unknown;
+  pigp->section= pigp->configversion= pigp->configrevision= 0;
+  pigp->files= 0;
+  pigp->installed.valid= 0;
+  pigp->available.valid= 0;
+  pigp->clientdata= 0;
+}
+
+void blankpackageperfile(struct pkginfoperfile *pifp) {
+  pifp->essential= 0;
+  pifp->depends= 0;
+  pifp->depended= 0;
+  pifp->description= pifp->maintainer= pifp->source= 0;
+  pifp->architecture= pifp->version= pifp->revision= 0;
+  pifp->conffiles= 0;
+  pifp->arbs= 0;
+  pifp->valid= 1;
+}
+
+static int nes(const char *s) { return s && *s; }
+
+int informativeperfile(struct pkginfoperfile *info) {
+  /* Used by dselect as an aid to decide whether to display things. */
+  if (!info->valid) return 0;
+  if (info->depends ||
+      nes(info->description) ||
+      nes(info->maintainer) ||
+      nes(info->source) ||
+      nes(info->architecture) ||
+      nes(info->version) ||
+      nes(info->revision) ||
+      info->conffiles ||
+      info->arbs) return 1;
+  return 0;
+}
+
+int informative(struct pkginfo *pkg) {
+  return ((pkg->want != want_unknown && pkg->want != want_purge) ||
+          pkg->eflag != eflagv_ok ||
+          pkg->status != stat_notinstalled ||
+          nes(pkg->section) ||
+          pkg->files ||
+          pkg->priority != pri_unknown);
+}
+
+struct pkginfo *findpackage(const char *name) {
+  struct pkginfo **pointerp, *newpkg;
+
+  pointerp= bins + (hash(name) & (BINS-1));
+  while (*pointerp && strcasecmp((*pointerp)->name,name))
+    pointerp= &(*pointerp)->next;
+  if (*pointerp) return *pointerp;
+
+  newpkg= nfmalloc(sizeof(struct pkginfo));
+  blankpackage(newpkg);
+  newpkg->name= nfstrsave(name);
+  newpkg->next= 0;
+  *pointerp= newpkg;
+  npackages++;
+
+  return newpkg;
+}
+
+int countpackages(void) {
+  return npackages;
+}
+
+struct pkgiterator {
+  struct pkginfo *pigp;
+  int nbinn;
+};
+
+struct pkgiterator *iterpkgstart(void) {
+  struct pkgiterator *i;
+  i= m_malloc(sizeof(struct pkgiterator));
+  i->pigp= 0;
+  i->nbinn= 0;
+  return i;
+}
+
+struct pkginfo *iterpkgnext(struct pkgiterator *i) {
+  struct pkginfo *r;
+  while (!i->pigp) {
+    if (i->nbinn >= BINS) return 0;
+    i->pigp= bins[i->nbinn++];
+  }
+  r= i->pigp; i->pigp= r->next; return r;
+}
+
+void iterpkgend(struct pkgiterator *i) {
+  free(i);
+}
+
+void resetpackages(void) {
+  int i;
+  nffreeall();
+  npackages= 0;
+  for (i=0; i<BINS; i++) bins[i]= 0;
+}
+
+void hashreport(FILE *file) {
+  int i, c;
+  struct pkginfo *pkg;
+  int *freq;
+
+  freq= m_malloc(sizeof(int)*npackages+1);
+  for (i=0; i<=npackages; i++) freq[i]= 0;
+  for (i=0; i<BINS; i++) {
+    for (c=0, pkg= bins[i]; pkg; c++, pkg= pkg->next);
+    fprintf(file,"bin %5d has %7d\n",i,c);
+    freq[c]++;
+  }
+  for (i=npackages; i>0 && freq[i]==0; i--);
+  while (i>=0) { fprintf(file,"size %7d occurs %5d times\n",i,freq[i]); i--; }
+  if (ferror(file)) ohshite("failed write during hashreport");
+}
+
+/*
+ * Test dataset package names were:
+ *
+ * agetty bash bc bdflush biff bin86 binutil binutils bison bsdutils
+ * byacc chfn cron dc dictionaries diff dlltools dpkg e2fsprogs ed
+ * elisp19 elm emacs emacs-nox emacs-x emacs19 file fileutils find
+ * flex fsprogs gas gawk gcc gcc1 gcc2 gdb ghostview ghstview glibcdoc
+ * gnuplot grep groff gs gs_both gs_svga gs_x gsfonts gxditviw gzip
+ * hello hostname idanish ifrench igerman indent inewsinn info inn
+ * ispell kbd kern1148 language ldso less libc libgr libgrdev librl
+ * lilo linuxsrc login lout lpr m4 mailx make man manpages more mount
+ * mtools ncurses netbase netpbm netstd patch perl4 perl5 procps
+ * psutils rcs rdev sed sendmail seyon shar shellutils smail svgalib
+ * syslogd sysvinit tar tcpdump tcsh tex texidoc texinfo textutils
+ * time timezone trn unzip uuencode wenglish wu-ftpd x8514 xaxe xbase
+ * xbdm2 xcomp xcoral xdevel xfig xfnt100 xfnt75 xfntbig xfntscl
+ * xgames xherc xmach32 xmach8 xmono xnet xs3 xsvga xtexstuff xv
+ * xvga16 xxgdb zip
+ */

+ 256 - 0
lib/dbmodify.c

@@ -0,0 +1,256 @@
+/*
+ * dpkg - main program for package management
+ * dbmodify.c - routines for managing dpkg database updates
+ *
+ * Copyright (C) 1994,1995 Ian Jackson <iwj10@cus.cam.ac.uk>
+ *
+ * This 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,
+ * or (at your option) any later version.
+ *
+ * This 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 dpkg; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <limits.h>
+#include <ctype.h>
+#include <assert.h>
+
+#include "config.h"
+#include "dpkg.h"
+#include "dpkg-db.h"
+
+char *statusfile=0, *availablefile=0;
+
+static enum modstatdb_rw cstatus=-1, cflags=0;
+static char *importanttmpfile=0;
+static FILE *importanttmp;
+static int nextupdate;
+static int updateslength;
+static char *updatefnbuf, *updatefnrest;
+static const char *admindir;
+static struct varbuf uvb;
+
+static int ulist_select(const struct dirent *de) {
+  const char *p;
+  int l;
+  for (p= de->d_name, l=0; *p; p++, l++)
+    if (!isdigit(*p)) return 0;
+  if (l > IMPORTANTMAXLEN)
+    ohshit("updates directory contains file `%.250s' whose name is too long "
+           "(length=%d, max=%d)", de->d_name, l, IMPORTANTMAXLEN);
+  if (updateslength == -1) updateslength= l;
+  else if (l != updateslength)
+    ohshit("updates directory contains files with different length names "
+           "(both %d and %d)", l, updateslength);
+  return 1;
+}
+
+static void cleanupdates(void) {
+  struct dirent **cdlist;
+  int cdn, i;
+
+  parsedb(statusfile, pdb_weakclassification, 0,0,0);
+
+  *updatefnrest= 0;
+  updateslength= -1;
+  cdn= scandir(updatefnbuf, &cdlist, &ulist_select, alphasort);
+  if (cdn == -1) ohshite("cannot scan updates directory `%.255s'",updatefnbuf);
+
+  if (cdn) {
+    
+    for (i=0; i<cdn; i++) {
+      strcpy(updatefnrest, cdlist[i]->d_name);
+      parsedb(updatefnbuf, pdb_weakclassification, 0,0,0);
+      if (cstatus < msdbrw_write) free(cdlist[i]);
+    }
+
+    if (cstatus >= msdbrw_write) {
+      writedb(statusfile,0,1);
+    
+      for (i=0; i<cdn; i++) {
+        strcpy(updatefnrest, cdlist[i]->d_name);
+        if (unlink(updatefnbuf))
+          ohshite("failed to remove incorporated update file %.255s",updatefnbuf);
+        free(cdlist[i]);
+      }
+    }
+    
+  }
+  free(cdlist);
+
+  nextupdate= 0;
+}
+
+static void createimptmp(void) {
+  int i;
+  
+  onerr_abort++;
+  
+  importanttmp= fopen(importanttmpfile,"w");
+  if (!importanttmp) ohshite("unable to create %.250s",importanttmpfile);
+  for (i=0; i<512; i++) fputs("#padding\n",importanttmp);
+  if (ferror(importanttmp))
+    ohshite("unable to fill %.250s with padding",importanttmpfile);
+  if (fflush(importanttmp))
+    ohshite("unable flush %.250s after padding",importanttmpfile);
+  if (fseek(importanttmp,0,SEEK_SET))
+    ohshite("unable seek to start of %.250s after padding",importanttmpfile);
+
+  onerr_abort--;
+}
+
+enum modstatdb_rw modstatdb_init(const char *adir, enum modstatdb_rw readwritereq) {
+  static const struct fni { const char *suffix; char **store; } fnis[]= {
+    {   STATUSFILE,                 &statusfile         },
+    {   AVAILFILE,                  &availablefile      },
+    {   UPDATESDIR IMPORTANTTMP,    &importanttmpfile   },
+    {   0                                               }
+  }, *fnip;
+
+  admindir= adir;
+  
+  for (fnip=fnis; fnip->suffix; fnip++) {
+    free(*fnip->store);
+    *fnip->store= m_malloc(strlen(adir)+strlen(fnip->suffix)+2);
+    sprintf(*fnip->store, "%s/%s", adir, fnip->suffix);
+  }
+
+  cflags= readwritereq & msdbrw_flagsmask;
+  readwritereq &= ~msdbrw_flagsmask;
+
+  switch (readwritereq) {
+  case msdbrw_needsuperuser:
+  case msdbrw_needsuperuserlockonly:
+    if (getuid() || geteuid())
+      ohshit("requested operation requires superuser privilege");
+    /* fall through */
+  case msdbrw_write: case msdbrw_writeifposs:
+    if (access(adir,W_OK)) {
+      if (errno != EACCES)
+        ohshite("unable to access dpkg status area");
+      else if (readwritereq == msdbrw_write)
+        ohshit("operation requires read/write access to dpkg status area");
+      cstatus= msdbrw_readonly;
+    } else {
+      lockdatabase(adir);
+      cstatus= (readwritereq == msdbrw_needsuperuserlockonly ?
+                msdbrw_needsuperuserlockonly :
+                msdbrw_write);
+    }
+    break;
+  case msdbrw_readonly:
+    cstatus= msdbrw_readonly; break;
+  default:
+    internerr("unknown readwritereq");
+  }
+
+  updatefnbuf= m_malloc(strlen(adir)+sizeof(UPDATESDIR)+IMPORTANTMAXLEN+5);
+  strcpy(updatefnbuf,adir);
+  strcat(updatefnbuf,"/" UPDATESDIR);
+  updatefnrest= updatefnbuf+strlen(updatefnbuf);
+
+  cleanupdates();
+
+  if (cstatus >= msdbrw_write) {
+    createimptmp();
+    uvb.used= 0;
+    uvb.size= 10240;
+    uvb.buf= m_malloc(uvb.size);
+  }
+
+  if (cstatus != msdbrw_needsuperuserlockonly) {
+    parsedb(statusfile, pdb_weakclassification, 0,0,0);
+    parsedb(statusfile, pdb_recordavailable, 0,0,0);
+    parsedb(availablefile,
+            pdb_recordavailable|pdb_rejectstatus|
+            (cflags & msdbrw_availablepreferversion ? pdb_preferversion : 0),
+            0,0,0);
+  }
+
+  return cstatus;
+}
+
+static void checkpoint(void) {
+  int i;
+
+  assert(cstatus >= msdbrw_write);
+  writedb(statusfile,0,1);
+  
+  for (i=0; i<nextupdate; i++) {
+    sprintf(updatefnrest, IMPORTANTFMT, i);
+    assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); /* or we've made a real mess */
+    if (unlink(updatefnbuf))
+      ohshite("failed to remove my own update file %.255s",updatefnbuf);
+  }
+  nextupdate= 0;
+}
+
+void modstatdb_shutdown(void) {
+  switch (cstatus) {
+  case msdbrw_write:
+    checkpoint();
+    if (!(cflags & msdbrw_availablepreferversion))
+      writedb(availablefile,1,0);
+
+    /* tidy up a bit, but don't worry too much about failure */
+    fclose(importanttmp);
+    strcpy(updatefnrest, IMPORTANTTMP); unlink(updatefnbuf);
+    varbuffree(&uvb);
+    /* fall through */
+  case msdbrw_needsuperuserlockonly:
+    unlockdatabase(admindir);
+  default:
+    break;
+  }
+
+  free(updatefnbuf);
+}
+
+void modstatdb_note(struct pkginfo *pkg) {
+  assert(cstatus >= msdbrw_write);
+
+  onerr_abort++;
+
+  varbufreset(&uvb);
+  varbufrecord(&uvb, pkg, &pkg->installed);
+  if (fwrite(uvb.buf, 1, uvb.used, importanttmp) != uvb.used)
+    ohshite("unable to write updated status of `%.250s'", pkg->name);
+  if (fflush(importanttmp))
+    ohshite("unable to flush updated status of `%.250s'", pkg->name);
+  if (ftruncate(fileno(importanttmp), uvb.used))
+    ohshite("unable to truncate for updated status of `%.250s'", pkg->name);
+  if (fsync(fileno(importanttmp)))
+    ohshite("unable to fsync updated status of `%.250s'", pkg->name);
+  if (fclose(importanttmp))
+    ohshite("unable to close updated status of `%.250s'", pkg->name);
+  sprintf(updatefnrest, IMPORTANTFMT, nextupdate);
+  if (rename(importanttmpfile, updatefnbuf))
+    ohshite("unable to install updated status of `%.250s'", pkg->name);
+  assert(strlen(updatefnrest)<=IMPORTANTMAXLEN); /* or we've made a real mess */
+
+  nextupdate++;  
+
+  if (nextupdate > MAXUPDATES) checkpoint();
+
+  createimptmp();
+
+  onerr_abort--;
+}

+ 3 - 0
lib/debugmake

@@ -0,0 +1,3 @@
+#!/bin/sh
+set -x
+make 'XCFLAGS=-g -DMDEBUG -O0' LDFLAGS=-g 'LIBS= -lefence -L../lib -ldpkg' "$@"

+ 0 - 0
lib/dump.c


Some files were not shown because too many files changed in this diff