]> err.no Git - dpkg/commitdiff
Split out code for commands -sSlLp into a separate binary, dpkg-query, and
authorAdam Heath <doogie@debian.org>
Thu, 3 May 2001 01:41:58 +0000 (01:41 +0000)
committerAdam Heath <doogie@debian.org>
Thu, 3 May 2001 01:41:58 +0000 (01:41 +0000)
have the normal dpkg binary exec this.  Also, dpkg now uses a macro to
define external backends to call.

ChangeLog
include/dpkg.h.in
main/Makefile.in
main/enquiry.c
main/main.c
main/query.c [new file with mode: 0644]

index 5c1754319493c8417fecbfbebc61685d38d502f6..674f8295e9c8dcb29d75634b2fdf137f018cceb0 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Wed May  2 20:41:10 CDT 2001 Adam Heath <doogie@debian.org>
+
+  * include/dpkg.h.in, main/Makefile.in main/enquiry.c main/main.c,
+    main/query.c: Split out code for commands -sSlLp into a separate
+    binary, dpkg-query, and have the normal dpkg binary exec this.  Also,
+    dpkg now uses a macro to define external backends to call.
+
 Wed May  2 12:32:24 CDT 2001 Adam Heath <doogie@debian.org>
 
   * configure.in: If --without-zlib was given, and static programs were
index ba54593832934fe82b6819e4778bb60d1e087efc..3e614b83bec38eaf2959024074506781f911dd41 100644 (file)
 #define ARCHIVE_FILENAME_PATTERN "*.deb"
 
 #define BACKEND                "dpkg-deb"
+#define DPKGQUERY      "dpkg-query"
 #define SPLITTER       "dpkg-split"
 #define MD5SUM         "md5sum"
 #define DSELECT                "dselect"
index 84bb48b00f4ed88504dc2297bc4954417d4afb63..2776e5fb6dba0e3c7fd01ec08b0171b54dea1993 100644 (file)
@@ -14,8 +14,10 @@ MAN8PAGES    = dpkg.8
 OBJECTS                = $(patsubst %.c, %.o, $(SOURCES))
 GENFILES       = $(OBJECTS) archtable.h dpkg dpkg-static
 
+dpkg-query:    SOURCES = query.c filesdb.c errors.c
+
 .PHONY: all
-all:: dpkg
+all:: dpkg dpkg-query
 
 ifdef ALSO_STATIC
 all:: dpkg-static
@@ -56,6 +58,8 @@ install-doc:
 
 dpkg-static: LDFLAGS += -static
 dpkg dpkg-static: $(OBJECTS) ../lib/libdpkg.a
+dpkg-query: $(OBJECTS) query.o ../lib/libdpkg.a
+dpkg dpkg-static dpkg-query:
        $(CC) $(LDFLAGS) -L../lib -o $@ $(OBJECTS) $(LIBS) $(NLS_LIBS) -ldpkg
 
 enquiry.o: archtable.h
index 84fcba4a319266a6ee98adc2cbc69cb08061977d..5d14d1ce49c3b57a763b9a07535887a0121514a2 100644 (file)
@@ -60,112 +60,6 @@ static void limiteddescription(struct pkginfo *pkg, int maxl,
   *pdesc_r=pdesc; *l_r=l;
 }
 
-static int getwidth() {
-  int fd;
-  int res;
-  struct winsize ws;
-  const char* columns;
-
-  if ((columns=getenv("COLUMNS")) && ((res=atoi(columns))>0))
-    ws.ws_col=res;
-  else if (!isatty(1))
-    ws.ws_col=80;
-  else {
-    if ((fd=open("/dev/tty",O_RDONLY))!=-1) {
-      if (ioctl(fd, TIOCGWINSZ, &ws)==-1)
-        ws.ws_col=80;
-      close(fd);
-    }
-  }
-  return ws.ws_col;
-}
-
-static void list1package(struct pkginfo *pkg, int *head) {
-  int l,w;
-  static int nw,vw,dw;
-  const char *pdesc;
-  static char format[80]   = "";
-    
-  if (format[0]==0) {
-    w=getwidth()-80;   /* get spare width */
-    if (w<0) w=0;              /* lets not try to deal with terminals that are too small */
-    w>>=2;             /* halve that so we can add that to the both the name and description */
-    nw=(14+w);         /* name width */
-    vw=(14+w);         /* version width */
-    dw=(44+(2*w));     /* description width */
-    sprintf(format,"%%c%%c%%c %%-%d.%ds %%-%d.%ds %%.*s\n", nw, nw, vw, vw);
-  }
-
-  if (!*head) {
-    fputs(_("\
-Desired=Unknown/Install/Remove/Purge/Hold\n\
-| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed\n\
-|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)\n"), stdout);
-    printf(format,'|','|','/', _("Name"), _("Version"), 40, _("Description"));
-    printf("+++-");                                    /* status */
-    for (l=0;l<nw;l++) printf("="); printf("-");       /* packagename */
-    for (l=0;l<vw;l++) printf("="); printf("-");       /* version */
-    for (l=0;l<dw;l++) printf("=");                    /* description */
-    printf("\n");
-    *head= 1;
-  }
-  if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
-  limiteddescription(pkg,dw,&pdesc,&l);
-  printf(format,
-         "uihrp"[pkg->want],
-         "nUFiHc"[pkg->status],
-         " R?#"[pkg->eflag],
-         pkg->name,
-         versiondescribe(&pkg->installed.version,vdew_never),
-         l, pdesc);
-}         
-
-void listpackages(const char *const *argv) {
-  struct pkgiterator *it;
-  struct pkginfo *pkg;
-  struct pkginfo **pkgl;
-  const char *thisarg;
-  int np, i, head, found;
-
-  modstatdb_init(admindir,msdbrw_readonly);
-
-  np= countpackages();
-  pkgl= m_malloc(sizeof(struct pkginfo*)*np);
-  it= iterpkgstart(); i=0;
-  while ((pkg= iterpkgnext(it))) {
-    assert(i<np);
-    pkgl[i++]= pkg;
-  }
-  iterpkgend(it);
-  assert(i==np);
-
-  qsort(pkgl,np,sizeof(struct pkginfo*),pkglistqsortcmp);
-  head=0;
-  
-  if (!*argv) {
-    for (i=0; i<np; i++) {
-      pkg= pkgl[i];
-      if (pkg->status == stat_notinstalled) continue;
-      list1package(pkg,&head);
-    }
-  } else {
-    while ((thisarg= *argv++)) {
-      found= 0;
-      for (i=0; i<np; i++) {
-        pkg= pkgl[i];
-        if (fnmatch(thisarg,pkg->name,0)) continue;
-        list1package(pkg,&head); found++;
-      }
-      if (!found) {
-        fprintf(stderr,_("No packages found matching %s.\n"),thisarg);
-       nerrs++;
-      }
-    }
-  }
-  if (ferror(stdout)) werr("stdout");
-  if (ferror(stderr)) werr("stderr");  
-}
-
 struct badstatinfo {
   int (*yesno)(struct pkginfo*, const struct badstatinfo *bsi);
   int val;
@@ -343,174 +237,6 @@ void unpackchk(const char *const *argv) {
   if (ferror(stdout)) werr("stdout");
 }
 
-static int searchoutput(struct filenamenode *namenode) {
-  int found, i;
-  struct filepackages *packageslump;
-
-  if (namenode->divert) {
-    for (i=0; i<2; i++) {
-      if (namenode->divert->pkg) printf(_("diversion by %s"),namenode->divert->pkg->name);
-      else printf(_("local diversion"));
-      printf(" %s: %s\n", i ? _("to") : _("from"),
-             i ?
-             (namenode->divert->useinstead
-              ? namenode->divert->useinstead->name
-              : namenode->name)
-             :
-             (namenode->divert->camefrom
-              ? namenode->divert->camefrom->name
-              : namenode->name));
-    }
-  }
-  found= 0;
-  for (packageslump= namenode->packages;
-       packageslump;
-       packageslump= packageslump->more) {
-    for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
-      if (found) fputs(", ",stdout);
-      fputs(packageslump->pkgs[i]->name,stdout);
-      found++;
-    }
-  }
-  if (found) printf(": %s\n",namenode->name);
-  return found + (namenode->divert ? 1 : 0);
-}
-
-void searchfiles(const char *const *argv) {
-  struct filenamenode *namenode;
-  struct fileiterator *it;
-  const char *thisarg;
-  int found;
-  static struct varbuf vb;
-  
-  if (!*argv)
-    badusage(_("--search needs at least one file name pattern argument"));
-
-  modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
-  ensure_allinstfiles_available_quiet();
-  ensure_diversions();
-
-  while ((thisarg= *argv++) != 0) {
-    found= 0;
-    if (!strchr("*[?/",*thisarg)) {
-      varbufreset(&vb);
-      varbufaddc(&vb,'*');
-      varbufaddstr(&vb,thisarg);
-      varbufaddc(&vb,'*');
-      varbufaddc(&vb,0);
-      thisarg= vb.buf;
-    }
-    if (strcspn(thisarg,"*[?\\") == strlen(thisarg)) {
-      namenode= findnamenode(thisarg, 0);
-      found += searchoutput(namenode);
-    } else {
-      it= iterfilestart();
-      while ((namenode= iterfilenext(it)) != 0) {
-        if (fnmatch(thisarg,namenode->name,0)) continue;
-        found+= searchoutput(namenode);
-      }
-      iterfileend(it);
-    }
-    if (!found) {
-      fprintf(stderr,_("dpkg: %s not found.\n"),thisarg);
-      nerrs++;
-      if (ferror(stderr)) werr("stderr");
-    } else {
-      if (ferror(stdout)) werr("stdout");
-    }
-  }
-}
-
-void enqperpackage(const char *const *argv) {
-  int failures;
-  const char *thisarg;
-  struct fileinlist *file;
-  struct pkginfo *pkg;
-  struct filenamenode *namenode;
-  
-  if (!*argv)
-    badusage(_("--%s needs at least one package name argument"), cipaction->olong);
-
-  failures= 0;
-  if (cipaction->arg==act_listfiles)
-    modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
-  else 
-    modstatdb_init(admindir,msdbrw_readonly);
-
-  while ((thisarg= *argv++) != 0) {
-    pkg= findpackage(thisarg);
-
-    switch (cipaction->arg) {
-      
-    case act_status:
-      if (pkg->status == stat_notinstalled &&
-          pkg->priority == pri_unknown &&
-          !(pkg->section && *pkg->section) &&
-          !pkg->files &&
-          pkg->want == want_unknown &&
-          !informative(pkg,&pkg->installed)) {
-        fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
-        failures++;
-      } else {
-        writerecord(stdout, "<stdout>", pkg, &pkg->installed);
-      }
-      break;
-
-    case act_printavail:
-      if (!informative(pkg,&pkg->available)) {
-        fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
-        failures++;
-      } else {
-        writerecord(stdout, "<stdout>", pkg, &pkg->available);
-      }
-      break;
-      
-    case act_listfiles:
-      switch (pkg->status) {
-      case stat_notinstalled: 
-        fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
-        failures++;
-        break;
-        
-      default:
-        ensure_packagefiles_available(pkg);
-        ensure_diversions();
-        file= pkg->clientdata->files;
-        if (!file) {
-          printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
-        } else {
-          while (file) {
-            namenode= file->namenode;
-            puts(namenode->name);
-            if (namenode->divert && !namenode->divert->camefrom) {
-              if (!namenode->divert->pkg) printf(_("locally diverted"));
-              else if (pkg == namenode->divert->pkg) printf(_("package diverts others"));
-              else printf(_("diverted by %s"),namenode->divert->pkg->name);
-              printf(_(" to: %s\n"),namenode->divert->useinstead->name);
-            }
-            file= file->next;
-          }
-        }
-        break;
-      }
-      break;
-
-    default:
-      internerr("unknown action");
-    }
-        
-    putchar('\n');
-    if (ferror(stdout)) werr("stdout");
-  }
-
-  if (failures) {
-    nerrs++;
-    fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
-         "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
-    if (ferror(stdout)) werr("stdout");
-  }
-}
-
 static void assertversion(const char *const *argv,
                        struct versionrevision *verrev_buf,
                        const char *reqversion) {
index ed814830823615326f46935e5de32b88040993e7..48e2b27a83256d2b84d1c41aa526700c5589cdeb 100644 (file)
@@ -341,14 +341,9 @@ Forcing options marked [*] are enabled by default.\n"),
   }
 }
 
-static const char *const passlongopts[]= {
-  "build", "contents", "control", "info", "field", "extract", "new", "old",
-  "vextract", "fsys-tarfile", 0
-};
-
-static const char passshortopts[]= "bceIfxX";
 static const char okpassshortopts[]= "D";
 
+void execbackend(const char *const *argv) NONRETURNING;
 void commandfd(const char *const *argv);
 static const struct cmdinfo cmdinfos[]= {
   /* This table has both the action entries in it and the normal options.
@@ -359,6 +354,8 @@ static const struct cmdinfo cmdinfos[]= {
  { longopt, shortopt, 0,0,0, setaction, code, 0, (voidfnp)function }
 #define OBSOLETE(longopt,shortopt) \
  { longopt, shortopt, 0,0,0, setobsolete, 0, 0, 0 }
+#define ACTIONBACKEND(longopt,shortop, backend) \
+ { longopt, shortop, 0,0,0, setaction, 0, (void*)backend, (voidfnp)execbackend }
 
   ACTION( "install",                        'i', act_install,              archivefiles    ),
   ACTION( "unpack",                          0,  act_unpack,               archivefiles    ),
@@ -366,19 +363,19 @@ static const struct cmdinfo cmdinfos[]= {
   ACTION( "configure",                       0,  act_configure,            packages        ),
   ACTION( "remove",                         'r', act_remove,               packages        ),
   ACTION( "purge",                          'P', act_purge,                packages        ),
-  ACTION( "listfiles",                      'L', act_listfiles,     enqperpackage   ),
-  ACTION( "status",                         's', act_status,               enqperpackage   ),
+  ACTIONBACKEND( "listfiles",                     'L', DPKGQUERY),
+  ACTIONBACKEND( "status",                        's', DPKGQUERY),
   ACTION( "get-selections",                  0,  act_getselections,        getselections   ),
   ACTION( "set-selections",                  0,  act_setselections,        setselections   ),
-  ACTION( "print-avail",                    'p', act_printavail,           enqperpackage   ),
+  ACTIONBACKEND( "print-avail",                   'p', DPKGQUERY),
   ACTION( "update-avail",                    0,  act_avreplace,            updateavailable ),
   ACTION( "merge-avail",                     0,  act_avmerge,              updateavailable ),
   ACTION( "clear-avail",                     0,  act_avclear,              updateavailable ),
   ACTION( "forget-old-unavail",              0,  act_forgetold,            forgetold       ),
   ACTION( "audit",                          'C', act_audit,                audit           ),
   ACTION( "yet-to-unpack",                   0,  act_unpackchk,            unpackchk       ),
-  ACTION( "list",                           'l', act_listpackages,         listpackages    ),
-  ACTION( "search",                         'S', act_searchfiles,          searchfiles     ),
+  ACTIONBACKEND( "list",                          'l', DPKGQUERY),
+  ACTIONBACKEND( "search",                        'S', DPKGQUERY),
   ACTION( "print-architecture",              0,  act_printarch,            printarch       ),
   ACTION( "print-gnu-build-architecture",    0,  act_printgnuarch,         printarch       ),
   ACTION( "assert-support-predepends",       0,  act_assertpredep,         assertpredep    ),
@@ -417,19 +414,40 @@ static const struct cmdinfo cmdinfos[]= {
   { "version",            0,   0,  0, 0,               versiononly                   },
   { "licence",/* UK spelling */ 0,0,0,0,               showcopyright                 },
   { "license",/* US spelling */ 0,0,0,0,               showcopyright                 },
+  ACTIONBACKEND( "build",              'b', BACKEND),
+  ACTIONBACKEND( "contents",           'c', BACKEND),
+  ACTIONBACKEND( "control",            'e', BACKEND),
+  ACTIONBACKEND( "info",               'I', BACKEND),
+  ACTIONBACKEND( "field",              'f', BACKEND),
+  ACTIONBACKEND( "extract",            'x', BACKEND),
+  ACTIONBACKEND( "new",                        0,  BACKEND),
+  ACTIONBACKEND( "old",                        0,  BACKEND),
+  ACTIONBACKEND( "vextract",           'X', BACKEND),
+  ACTIONBACKEND( "fsys-tarfile",       0,   BACKEND),
   {  0,                   0                                                          }
 };
 
-static void execbackend(int argc, const char *const *argv) NONRETURNING;
-static void execbackend(int argc, const char *const *argv) {
-  char **nargv= malloc(sizeof(char *) * argc + 1);
-  int i;
+void execbackend(const char *const *argv) {
+  char **nargv;
+  int i, argc = 1;
+  char **arg = argv;
+  while(*arg != 0) { arg++; argc++; }
+  nargv= malloc(sizeof(char *) * argc + 2);
+
   if (!nargv) ohshite(_("couldn't malloc in execbackend"));
-  for (i= 0; i < argc; i++)
-    nargv[i]= strdup(argv[i]);
+  nargv[0]= strdup(cipaction->parg);
+  if (!nargv[0]) ohshite(_("couldn't strdup in execbackend"));
+  nargv[1]= malloc(strlen(cipaction->olong) + 3);
+  if (!nargv[1]) ohshite(_("couldn't malloc in execbackend"));
+  strcpy(nargv[1], "--");
+  strcat(nargv[1], cipaction->olong);
+  for (i= 2; i <= argc; i++) {
+    nargv[i]= strdup(argv[i-2]);
+    if (!nargv[i]) ohshite(_("couldn't strdup in execbackend"));
+  }
   nargv[i]= 0;
-  execvp(BACKEND, nargv);
-  ohshite(_("failed to exec dpkg-deb"));
+  execvp(cipaction->parg, nargv);
+  ohshite(_("failed to exec %s"),cipaction->parg);
 }
 void commandfd(const char *const *argv) {
   jmp_buf ejbuf;
@@ -527,8 +545,6 @@ printf("line=`%*s'\n",(int)linevb.used,linevb.buf);
 
 int main(int argc, const char *const *argv) {
   jmp_buf ejbuf;
-  int c;
-  const char *argp, *const *blongopts, *const *argvs;
   static void (*actionfunction)(const char *const *argv);
 
   setlocale(LC_ALL, "");
@@ -542,21 +558,6 @@ int main(int argc, const char *const *argv) {
 
   umask(022); /* Make sure all our status databases are readable. */
  
-  for (argvs=argv+1; (argp= *argvs) && *argp++=='-'; argvs++) {
-    if (*argp++=='-') {
-      if (!strcmp(argp,"-")) break;
-      for (blongopts=passlongopts; *blongopts; blongopts++) {
-        if (!strcmp(argp,*blongopts)) execbackend(argc,argv);
-      }
-    } else {
-      if (!*--argp) break;
-      while ((c= *argp++)) {
-        if (strchr(passshortopts,c)) execbackend(argc,argv);
-        if (!strchr(okpassshortopts,c)) break;
-      }
-    }
-  }
-
   myfileopt(CONFIGDIR "/" DPKG ".cfg", cmdinfos);
   myopt(&argv,cmdinfos);
   if (!cipaction) badusage(_("need an action option"));
diff --git a/main/query.c b/main/query.c
new file mode 100644 (file)
index 0000000..cb40082
--- /dev/null
@@ -0,0 +1,492 @@
+/*
+ * dpkg - main program for package management
+ * enquiry.c - status enquiry and listing options
+ *
+ * Copyright (C) 1995,1996 Ian Jackson <ijackson@gnu.ai.mit.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.
+ */
+
+/* fixme: per-package audit */
+
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <assert.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/termios.h>
+#include <fcntl.h>
+
+#include <config.h>
+#include <dpkg.h>
+#include <dpkg-db.h>
+#include <myopt.h>
+
+#include "filesdb.h"
+#include "main.h"
+
+void ensure_package_clientdata(struct pkginfo *pkg) {
+  if (pkg->clientdata) return;
+  pkg->clientdata= nfmalloc(sizeof(struct perpackagestate));
+  pkg->clientdata->istobe= itb_normal;
+  pkg->clientdata->fileslistvalid= 0;
+  pkg->clientdata->files= 0;
+}
+
+const char *pkgadminfile(struct pkginfo *pkg, const char *whichfile) {
+  static struct varbuf vb;
+  varbufreset(&vb);
+  varbufaddstr(&vb,admindir);
+  varbufaddstr(&vb,"/" INFODIR);
+  varbufaddstr(&vb,pkg->name);
+  varbufaddc(&vb,'.');
+  varbufaddstr(&vb,whichfile);
+  varbufaddc(&vb,0);
+  return vb.buf;
+}
+
+void cu_closepipe(int argc, void **argv) {
+  int *p1= (int*)argv[0];
+  close(p1[0]); close(p1[1]);
+}
+
+void cu_closefile(int argc, void **argv) {
+  FILE *f= (FILE*)(argv[0]);
+  fclose(f);
+}
+
+void cu_closefd(int argc, void **argv) {
+  int ip= *(int*)argv;
+  close(ip);
+}
+
+int pkglistqsortcmp(const void *a, const void *b) {
+  const struct pkginfo *pa= *(const struct pkginfo**)a;
+  const struct pkginfo *pb= *(const struct pkginfo**)b;
+  return strcmp(pa->name,pb->name);
+}
+
+static void limiteddescription(struct pkginfo *pkg, int maxl,
+                               const char **pdesc_r, int *l_r) {
+  const char *pdesc, *p;
+  int l;
+  
+  pdesc= pkg->installed.valid ? pkg->installed.description : 0;
+  if (!pdesc) pdesc= _("(no description available)");
+  p= strchr(pdesc,'\n');
+  if (!p) p= pdesc+strlen(pdesc);
+  l= (p - pdesc > maxl) ? maxl : (int)(p - pdesc);
+  *pdesc_r=pdesc; *l_r=l;
+}
+
+static int getwidth() {
+  int fd;
+  int res;
+  struct winsize ws;
+  const char* columns;
+
+  if ((columns=getenv("COLUMNS")) && ((res=atoi(columns))>0))
+    ws.ws_col=res;
+  else if (!isatty(1))
+    ws.ws_col=80;
+  else {
+    if ((fd=open("/dev/tty",O_RDONLY))!=-1) {
+      if (ioctl(fd, TIOCGWINSZ, &ws)==-1)
+        ws.ws_col=80;
+      close(fd);
+    }
+  }
+  return ws.ws_col;
+}
+
+static void list1package(struct pkginfo *pkg, int *head) {
+  int l,w;
+  static int nw,vw,dw;
+  const char *pdesc;
+  static char format[80]   = "";
+    
+  if (format[0]==0) {
+    w=getwidth()-80;   /* get spare width */
+    if (w<0) w=0;              /* lets not try to deal with terminals that are too small */
+    w>>=2;             /* halve that so we can add that to the both the name and description */
+    nw=(14+w);         /* name width */
+    vw=(14+w);         /* version width */
+    dw=(44+(2*w));     /* description width */
+    sprintf(format,"%%c%%c%%c %%-%d.%ds %%-%d.%ds %%.*s\n", nw, nw, vw, vw);
+  }
+
+  if (!*head) {
+    fputs(_("\
+Desired=Unknown/Install/Remove/Purge/Hold\n\
+| Status=Not/Installed/Config-files/Unpacked/Failed-config/Half-installed\n\
+|/ Err?=(none)/Hold/Reinst-required/X=both-problems (Status,Err: uppercase=bad)\n"), stdout);
+    printf(format,'|','|','/', _("Name"), _("Version"), 40, _("Description"));
+    printf("+++-");                                    /* status */
+    for (l=0;l<nw;l++) printf("="); printf("-");       /* packagename */
+    for (l=0;l<vw;l++) printf("="); printf("-");       /* version */
+    for (l=0;l<dw;l++) printf("=");                    /* description */
+    printf("\n");
+    *head= 1;
+  }
+  if (!pkg->installed.valid) blankpackageperfile(&pkg->installed);
+  limiteddescription(pkg,dw,&pdesc,&l);
+  printf(format,
+         "uihrp"[pkg->want],
+         "nUFiHc"[pkg->status],
+         " R?#"[pkg->eflag],
+         pkg->name,
+         versiondescribe(&pkg->installed.version,vdew_never),
+         l, pdesc);
+}         
+
+void listpackages(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  struct pkginfo **pkgl;
+  const char *thisarg;
+  int np, i, head, found;
+
+  modstatdb_init(admindir,msdbrw_readonly);
+
+  np= countpackages();
+  pkgl= m_malloc(sizeof(struct pkginfo*)*np);
+  it= iterpkgstart(); i=0;
+  while ((pkg= iterpkgnext(it))) {
+    assert(i<np);
+    pkgl[i++]= pkg;
+  }
+  iterpkgend(it);
+  assert(i==np);
+
+  qsort(pkgl,np,sizeof(struct pkginfo*),pkglistqsortcmp);
+  head=0;
+  
+  if (!*argv) {
+    for (i=0; i<np; i++) {
+      pkg= pkgl[i];
+      if (pkg->status == stat_notinstalled) continue;
+      list1package(pkg,&head);
+    }
+  } else {
+    while ((thisarg= *argv++)) {
+      found= 0;
+      for (i=0; i<np; i++) {
+        pkg= pkgl[i];
+        if (fnmatch(thisarg,pkg->name,0)) continue;
+        list1package(pkg,&head); found++;
+      }
+      if (!found) {
+        fprintf(stderr,_("No packages found matching %s.\n"),thisarg);
+       nerrs++;
+      }
+    }
+  }
+  if (ferror(stdout)) werr("stdout");
+  if (ferror(stderr)) werr("stderr");  
+}
+
+static int searchoutput(struct filenamenode *namenode) {
+  int found, i;
+  struct filepackages *packageslump;
+
+  if (namenode->divert) {
+    for (i=0; i<2; i++) {
+      if (namenode->divert->pkg) printf(_("diversion by %s"),namenode->divert->pkg->name);
+      else printf(_("local diversion"));
+      printf(" %s: %s\n", i ? _("to") : _("from"),
+             i ?
+             (namenode->divert->useinstead
+              ? namenode->divert->useinstead->name
+              : namenode->name)
+             :
+             (namenode->divert->camefrom
+              ? namenode->divert->camefrom->name
+              : namenode->name));
+    }
+  }
+  found= 0;
+  for (packageslump= namenode->packages;
+       packageslump;
+       packageslump= packageslump->more) {
+    for (i=0; i < PERFILEPACKAGESLUMP && packageslump->pkgs[i]; i++) {
+      if (found) fputs(", ",stdout);
+      fputs(packageslump->pkgs[i]->name,stdout);
+      found++;
+    }
+  }
+  if (found) printf(": %s\n",namenode->name);
+  return found + (namenode->divert ? 1 : 0);
+}
+
+void searchfiles(const char *const *argv) {
+  struct filenamenode *namenode;
+  struct fileiterator *it;
+  const char *thisarg;
+  int found;
+  static struct varbuf vb;
+  
+  if (!*argv)
+    badusage(_("--search needs at least one file name pattern argument"));
+
+  modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
+  ensure_allinstfiles_available_quiet();
+  ensure_diversions();
+
+  while ((thisarg= *argv++) != 0) {
+    found= 0;
+    if (!strchr("*[?/",*thisarg)) {
+      varbufreset(&vb);
+      varbufaddc(&vb,'*');
+      varbufaddstr(&vb,thisarg);
+      varbufaddc(&vb,'*');
+      varbufaddc(&vb,0);
+      thisarg= vb.buf;
+    }
+    if (strcspn(thisarg,"*[?\\") == strlen(thisarg)) {
+      namenode= findnamenode(thisarg, 0);
+      found += searchoutput(namenode);
+    } else {
+      it= iterfilestart();
+      while ((namenode= iterfilenext(it)) != 0) {
+        if (fnmatch(thisarg,namenode->name,0)) continue;
+        found+= searchoutput(namenode);
+      }
+      iterfileend(it);
+    }
+    if (!found) {
+      fprintf(stderr,_("dpkg: %s not found.\n"),thisarg);
+      nerrs++;
+      if (ferror(stderr)) werr("stderr");
+    } else {
+      if (ferror(stdout)) werr("stdout");
+    }
+  }
+}
+
+void enqperpackage(const char *const *argv) {
+  int failures;
+  const char *thisarg;
+  struct fileinlist *file;
+  struct pkginfo *pkg;
+  struct filenamenode *namenode;
+  
+  if (!*argv)
+    badusage(_("--%s needs at least one package name argument"), cipaction->olong);
+
+  failures= 0;
+  if (cipaction->arg==act_listfiles)
+    modstatdb_init(admindir,msdbrw_readonly|msdbrw_noavail);
+  else 
+    modstatdb_init(admindir,msdbrw_readonly);
+
+  while ((thisarg= *argv++) != 0) {
+    pkg= findpackage(thisarg);
+
+    switch (cipaction->arg) {
+      
+    case act_status:
+      if (pkg->status == stat_notinstalled &&
+          pkg->priority == pri_unknown &&
+          !(pkg->section && *pkg->section) &&
+          !pkg->files &&
+          pkg->want == want_unknown &&
+          !informative(pkg,&pkg->installed)) {
+        fprintf(stderr,_("Package `%s' is not installed and no info is available.\n"),pkg->name);
+        failures++;
+      } else {
+        writerecord(stdout, "<stdout>", pkg, &pkg->installed);
+      }
+      break;
+
+    case act_printavail:
+      if (!informative(pkg,&pkg->available)) {
+        fprintf(stderr,_("Package `%s' is not available.\n"),pkg->name);
+        failures++;
+      } else {
+        writerecord(stdout, "<stdout>", pkg, &pkg->available);
+      }
+      break;
+      
+    case act_listfiles:
+      switch (pkg->status) {
+      case stat_notinstalled: 
+        fprintf(stderr,_("Package `%s' is not installed.\n"),pkg->name);
+        failures++;
+        break;
+        
+      default:
+        ensure_packagefiles_available(pkg);
+        ensure_diversions();
+        file= pkg->clientdata->files;
+        if (!file) {
+          printf(_("Package `%s' does not contain any files (!)\n"),pkg->name);
+        } else {
+          while (file) {
+            namenode= file->namenode;
+            puts(namenode->name);
+            if (namenode->divert && !namenode->divert->camefrom) {
+              if (!namenode->divert->pkg) printf(_("locally diverted"));
+              else if (pkg == namenode->divert->pkg) printf(_("package diverts others"));
+              else printf(_("diverted by %s"),namenode->divert->pkg->name);
+              printf(_(" to: %s\n"),namenode->divert->useinstead->name);
+            }
+            file= file->next;
+          }
+        }
+        break;
+      }
+      break;
+
+    default:
+      internerr("unknown action");
+    }
+        
+    putchar('\n');
+    if (ferror(stdout)) werr("stdout");
+  }
+
+  if (failures) {
+    nerrs++;
+    fputs(_("Use dpkg --info (= dpkg-deb --info) to examine archive files,\n"
+         "and dpkg --contents (= dpkg-deb --contents) to list their contents.\n"),stderr);
+    if (ferror(stdout)) werr("stdout");
+  }
+}
+
+static void printversion(void) {
+  if (fputs(_("Debian GNU/Linux `"), stdout) < 0) werr("stdout");
+  if (fputs(DPKG, stdout) < 0) werr("stdout");
+  if (fputs(_("' package management program version "), stdout) < 0) werr("stdout");
+//  if (fputs( DPKG_VERSION_ARCH ".\n", stdout) < 0) werr("stdout");
+  if (fputs(_( "This is free software; see the GNU General Public Licence version 2 or\n"
+               "later for copying conditions.  There is NO warranty.\n"
+               "See dpkg --licence for copyright and license details.\n"),
+                stdout) < 0) werr("stdout");
+}
+/*
+   options that need fixing:
+  dpkg --yet-to-unpack                 \n\
+  */
+static void usage(void) {
+  if (fprintf (stdout, _("\
+Usage: \n\
+  dpkg -s|--status <package-name> ...      display package status details\n\
+  dpkg -p|--print-avail <package-name> ... display available version details\n\
+  dpkg -L|--listfiles <package-name> ...   list files `owned' by package(s)\n\
+  dpkg -l|--list [<pattern> ...]           list packages concisely\n\
+  dpkg -S|--search <pattern> ...           find package(s) owning file(s)\n\
+  dpkg --help | --version                  show this help / version number\n\
+  dpkg --licence                           print copyright licensing terms\n\
+\n\
+Options:\n\
+  --admindir=<directory>     Use <directory> instead of %s\n\
+  -D|--debug=<octal>         Enable debugging - see -Dhelp or --debug=help\n"),
+           ADMINDIR) < 0) werr ("stdout");
+}
+
+const char thisname[]= "dpkg";
+const char printforhelp[]= N_("\
+Type dpkg-query --help for help about installing and deinstalling packages [*];\n\
+Use dselect for user-friendly package management;\n\
+Type dpkg-query --licence for copyright licence and lack of warranty (GNU GPL) [*].\n\
+\n");
+
+const struct cmdinfo *cipaction= 0;
+int f_pending=0, f_recursive=0, f_alsoselect=1, f_skipsame=0, f_noact=0;
+int f_autodeconf=0, f_nodebsig=0;
+unsigned long f_debug=0;
+/* Change fc_overwrite to 1 to enable force-overwrite by default */
+int fc_hold=0;
+int fc_conflicts=0, fc_depends=0;
+int fc_badpath=0;
+
+int errabort = 50;
+const char *admindir= ADMINDIR;
+const char *instdir= "";
+struct packageinlist *ignoredependss=0;
+
+static void helponly(const struct cmdinfo *cip, const char *value) NONRETURNING;
+static void helponly(const struct cmdinfo *cip, const char *value) {
+  usage(); exit(0);
+}
+static void versiononly(const struct cmdinfo *cip, const char *value) NONRETURNING;
+static void versiononly(const struct cmdinfo *cip, const char *value) {
+  printversion(); exit(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;
+}
+
+static const struct cmdinfo cmdinfos[]= {
+  /* This table has both the action entries in it and the normal options.
+   * The action entries are made with the ACTION macro, as they all
+   * have a very similar structure.
+   */
+#define ACTION(longopt,shortopt,code,function) \
+ { longopt, shortopt, 0,0,0, setaction, code, 0, (voidfnp)function }
+#define OBSOLETE(longopt,shortopt) \
+ { longopt, shortopt, 0,0,0, setobsolete, 0, 0, 0 }
+
+  ACTION( "listfiles",                      'L', act_listfiles,     enqperpackage   ),         //
+  ACTION( "status",                         's', act_status,               enqperpackage   ),  //
+  ACTION( "print-avail",                    'p', act_printavail,           enqperpackage   ),  //
+  ACTION( "list",                           'l', act_listpackages,         listpackages    ),  //
+  ACTION( "search",                         'S', act_searchfiles,          searchfiles     ),  //
+
+  { "admindir",           0,   1,  0, &admindir,       0                             },
+  { "help",              'h',  0,  0, 0,               helponly                      },
+  { "version",            0,   0,  0, 0,               versiononly                   },
+  { "licence",/* UK spelling */ 0,0,0,0,               showcopyright                 },
+  { "license",/* US spelling */ 0,0,0,0,               showcopyright                 },
+  {  0,                   0                                                          }
+};
+
+int main(int argc, const char *const *argv) {
+  jmp_buf ejbuf;
+  static void (*actionfunction)(const char *const *argv);
+
+  setlocale(LC_ALL, "");
+  bindtextdomain(PACKAGE, LOCALEDIR);
+  textdomain(PACKAGE);
+
+  if (setjmp(ejbuf)) { /* expect warning about possible clobbering of argv */
+    error_unwind(ehflag_bombout); exit(2);
+  }
+  push_error_handler(&ejbuf,print_error_fatal,0);
+
+  umask(022); /* Make sure all our status databases are readable. */
+  myopt(&argv,cmdinfos);
+  if (!cipaction) badusage(_("need an action option"));
+
+  setvbuf(stdout,0,_IONBF,0);
+  filesdbinit();
+
+  actionfunction= (void (*)(const char* const*))cipaction->farg;
+
+  actionfunction(argv);
+
+  set_error_display(0,0);
+  error_unwind(ehflag_normaltidy);
+
+  return reportbroken_retexitstatus();
+}