Browse Source

Add support for configurable package listings (not complete yet)

Wichert Akkerman 25 years ago
parent
commit
54cc8a5f9c
6 changed files with 353 additions and 15 deletions
  1. 5 0
      ChangeLog
  2. 3 0
      debian/changelog
  3. 1 1
      main/main.h
  4. 75 14
      main/query.c
  5. 33 0
      main/query.h
  6. 236 0
      main/showpkg.c

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+Tue Jul 24 19:07:43 CEST 2001 Wichert Akkerman <wakkerma@debian.org>
+
+  * main/showpkg.c, main/query.h: new files
+  * main/query.c: add support for show options
+
 Wed Jul 18 17:28:38 CEST 2001 Wichert Akkerman <wakkerma@debian.org>
 
   * main/Makefile.in, debian/rules: install dpkg-query as well

+ 3 - 0
debian/changelog

@@ -29,6 +29,9 @@ dpkg (1.10) unstable; urgency=low
   * dselect now accepts regular expressions when searching for packages
     and can search in package descriptions as well.
     Closes: Bug#81009,#83139
+  * Move query commands into a seperate dpkg-query command. For the old options
+    (-L,-l,-s,-S) dpkg will still call it for you.
+  * Add configurable package listing support to dpkg-query
 
  -- Wichert Akkerman <wakkerma@debian.org>  Tue, 17 Jul 2001 22:05:38 +0200
 

+ 1 - 1
main/main.h

@@ -1,6 +1,6 @@
 /*
  * dpkg - main program for package management
- * dpkg-deb.h - external definitions for this program
+ * main.h - external definitions for this program
  *
  * Copyright (C) 1995 Ian Jackson <iwj10@cus.cam.ac.uk>
  *

+ 75 - 14
main/query.c

@@ -3,6 +3,7 @@
  * enquiry.c - status enquiry and listing options
  *
  * Copyright (C) 1995,1996 Ian Jackson <ijackson@gnu.ai.mit.edu>
+ * Copyright (C) 200,2001 Wichert Akkerman <wakkerma@debian.org>
  *
  * This is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as
@@ -40,6 +41,10 @@
 
 #include "filesdb.h"
 #include "main.h"
+#include "query.h"
+
+static const char* showformat		= "${pkg:Package}\t${pkg:Version}\n";
+
 
 void ensure_package_clientdata(struct pkginfo *pkg) {
   if (pkg->clientdata) return;
@@ -153,7 +158,7 @@ Desired=Unknown/Install/Remove/Purge/Hold\n\
          pkg->name,
          versiondescribe(&pkg->installed.version,vdew_never),
          l, pdesc);
-}         
+}
 
 void listpackages(const char *const *argv) {
   struct pkgiterator *it;
@@ -369,8 +374,60 @@ void enqperpackage(const char *const *argv) {
   }
 }
 
+void showpackages(const char *const *argv) {
+  struct pkgiterator *it;
+  struct pkginfo *pkg;
+  struct pkginfo **pkgl;
+  const char *thisarg;
+  int np, i, found;
+  const struct lstitem* fmt = parseformat(showformat);
+
+  if (!fmt) {
+    nerrs++;
+    return;
+  }
+
+  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);
+  
+  if (!*argv) {
+    for (i=0; i<np; i++) {
+      pkg= pkgl[i];
+      if (pkg->status == stat_notinstalled) continue;
+      show1package(fmt,pkg);
+    }
+  } else {
+    while ((thisarg= *argv++)) {
+      found= 0;
+      for (i=0; i<np; i++) {
+        pkg= pkgl[i];
+        if (fnmatch(thisarg,pkg->name,0)) continue;
+        show1package(fmt,pkg); found++;
+      }
+      if (!found) {
+        fprintf(stderr,_("No packages found matching %s.\n"),thisarg);
+	nerrs++;
+      }
+    }
+  }
+  if (ferror(stdout)) werr("stdout");
+  if (ferror(stderr)) werr("stderr");  
+  freeformat(fmt);
+}
+
 static void printversion(void) {
-  if (fputs(_("Debian GNU/Linux `"), stdout) < 0) werr("stdout");
+  if (fputs(_("Debian"), 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");
@@ -390,12 +447,14 @@ Usage: \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 -W|--show <pattern> ...             show information on package(s)\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\
+  --showformat=<format>      Use alternative format for --show\n\
   -D|--debug=<octal>         Enable debugging - see -Dhelp or --debug=help\n"),
 	    ADMINDIR) < 0) werr ("stdout");
 }
@@ -446,18 +505,20 @@ static const struct cmdinfo cmdinfos[]= {
 #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                                                          }
+  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     ),
+  ACTION( "show",                           'W', act_listpackages,  showpackages    ),
+
+  { "admindir",           0,   1,  0, &admindir,       0                            },
+  { "showformat",         0,   1,  0, &showformat,     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) {

+ 33 - 0
main/query.h

@@ -0,0 +1,33 @@
+/*
+ * dpkg-query - program to query the package database
+ * query.h - external definitions for this program
+ *
+ * Copyright (C) 2001 Wichert Akkerman <wakkerma@debian.org>
+ *
+ * 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 QUERY_H
+#define QUERY_H
+
+struct lstitem;
+
+/* from showpkg.c */
+struct lstitem* parseformat(const char* fmt);
+void freeformat(struct lstitem* head);
+void show1package(const struct lstitem* head, struct pkginfo *pkg);
+
+#endif
+

+ 236 - 0
main/showpkg.c

@@ -0,0 +1,236 @@
+/*
+ * dpkg-query - program to query the package database
+ * showpkg.c - customizable package listing
+ *
+ * Copyright (C) 2001 Wichert Akkerman <wakkerma@debian.org>
+ *
+ * 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 <stdlib.h>
+#include <string.h>
+
+#include <config.h>
+#include <dpkg.h>
+#include <dpkg-db.h>
+
+#include <parsedump.h>
+#include "main.h"
+
+
+typedef enum { invalid, string, field } itemtype_t;
+
+struct lstitem {
+	itemtype_t type;
+	size_t width;
+	char* data;
+	struct lstitem* next;
+};
+
+
+static struct lstitem* alloclstitem() {
+	struct lstitem*	buf;
+
+	buf=(struct lstitem*)malloc(sizeof(struct lstitem));
+	buf->type=invalid;
+	buf->next=NULL;
+	buf->data=NULL;
+	buf->width=0;
+
+	return buf;
+}
+
+static void parsefield(struct lstitem* cur, const char* fmt, const char* fmtend) {
+	int len;
+
+	len=fmtend-fmt+1;
+
+	cur->type=field;
+	cur->data=(char*)malloc(len+1);
+	memcpy(cur->data, fmt, len);
+	cur->data[len]='\0';
+}
+
+static void parsestring(struct lstitem* cur, const char* fmt, const char* fmtend) {
+	int len;
+	char* write;
+
+	len=fmtend-fmt+1;
+
+	cur->type=string;
+	write=cur->data=(char*)malloc(len+1);
+	while (fmt<fmtend) {
+		if (*fmt=='\\') {
+			fmt++;
+			switch (*fmt) {
+				case 'n':
+					*write='\n';
+					break;
+				case 't':
+					*write='\t';
+					break;
+				case 'r':
+					*write='\r';
+					break;
+				case '\\':
+				default:
+					*write=*fmt;
+					break;
+			}
+		} else
+			*write=*fmt;
+		write++;
+		fmt++;
+	}
+	*write='\0';
+}
+
+
+void freeformat(struct lstitem* head) {
+	struct lstitem* next;
+
+	while (head) {
+		next=head->next;
+		free(head->data);
+		free(head);
+		head=next;
+	}
+}
+
+struct lstitem* parseformat(const char* fmt) {
+	struct lstitem* head;
+	struct lstitem* cur;
+	const char* fmtend;
+
+	head=cur=NULL;
+	
+	while (*fmt) {
+		if (cur)
+			cur=cur->next=alloclstitem();
+		else
+			head=cur=alloclstitem();
+
+		if (fmt[0]=='$' && fmt[1]=='{') {
+			fmtend=strchr(fmt, '}');  // TODO: check for not-found
+			if (!fmtend) {
+				fprintf(stderr, _("Closing brace missing in format\n"));
+				freeformat(head);
+				return NULL;
+			}
+			cur->type=field;
+			parsefield(cur, fmt+2, fmtend-1);
+			fmt=fmtend+1;
+		} else {
+			fmtend=fmt;
+			do {
+				fmtend+=1;
+				fmtend=strchr(fmtend, '$');
+			} while (fmtend && fmtend[1]!='{');
+
+			if (!fmtend)
+				fmtend=fmt+strlen(fmt);
+
+			parsestring(cur, fmt, fmtend-1);
+			fmt=fmtend;
+		}
+	}
+
+	return head;
+}
+
+
+static void dumpchain(struct lstitem* head) {
+	while (head) {
+		printf("Type: %s\n", (head->type==string) ? "string" : "field");
+		printf("Width: %d\n", head->width);
+		printf("Data: %s\n", head->data);
+		printf("\n");
+		head=head->next;
+	}
+}
+
+
+void show1package(const struct lstitem* head, struct pkginfo *pkg) {
+	struct varbuf vb, fb;
+
+	/* Make sure we have package info available, even if it's all empty. */
+	if (!pkg->installed.valid)
+		blankpackageperfile(&pkg->installed);
+
+	varbufinit(&vb);
+	varbufinit(&fb);
+
+	while (head) {
+		int ok;
+
+		ok=0;
+
+		if (head->type==string) {
+			varbufprintf(&fb, "%s", head->data);
+			ok=1;
+		} else if (head->type==field) {
+			const struct fieldinfo* fip;
+
+			for (fip=fieldinfos; fip->name; fip++) 
+				if (strcasecmp(head->data, fip->name)==0)  {
+					size_t len;
+					char* i;
+
+					fip->wcall(&fb,pkg,&pkg->installed,fip);
+					/* Bugger, wcall adds the fieldname and a trailing newline we
+					 * do not need. We should probably improve wcall to only do that
+					 * optionally, but this will do for now (ie this is a TODO)
+					 */
+					fb.buf[fb.used-1]='\0';
+					i=strchr(fb.buf, ':')+2;
+					len=strlen(i)+1;
+					memmove(fb.buf, i, len);
+
+					ok=1;
+					break;
+				}
+
+			if (!fip && pkg->installed.valid) {
+				const struct arbitraryfield* afp;
+
+				for (afp=pkg->installed.arbs; afp; afp=afp->next)
+					if (strcasecmp(head->data, afp->name)==0) {
+						varbufprintf(&fb, "%s", afp->value);
+						ok=1;
+						break;
+					}
+			}
+		}
+
+		if (ok) {
+			size_t len=strlen(fb.buf);
+			if ((head->width>0) && (len>head->width))
+				len=head->width;
+			varbufaddbuf(&vb, fb.buf, len);
+		}
+
+		varbufreset(&fb);
+		head=head->next;
+	}
+
+	if (vb.buf) {
+		varbufaddc(&vb, '\0');
+		fputs(vb.buf,stdout);
+	}
+
+	varbuffree(&fb);
+	varbuffree(&vb);
+}
+