[Dctrl-tools-devel] dctrl-tools-experimental: grep-dctrl: new option --invert-show (-I)

Antti-Juhani Kaijanaho ajk at debian.org
Sun Apr 8 15:55:35 UTC 2007


Sun Apr  8 18:50:12 EEST 2007  Antti-Juhani Kaijanaho <ajk at debian.org>
  * grep-dctrl: new option --invert-show (-I)
  Closes: #144174 (please provide a --filter-fields option of some sort)
  Reported by Yann Dirson <dirson at debian.org>
  Merged with #264905 (show all fields except FIELD,FIELD,...)
  Reported by Dan Jacobson <jidanni at jidanni.org>
diff -rN -u old-dctrl-tools-experimental/grep-dctrl/grep-dctrl.c new-dctrl-tools-experimental/grep-dctrl/grep-dctrl.c
--- old-dctrl-tools-experimental/grep-dctrl/grep-dctrl.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/grep-dctrl/grep-dctrl.c	2007-04-08 18:55:34.000000000 +0300
@@ -42,7 +42,7 @@
 const char * argp_program_bug_address = MAINTAINER;
 
 const char description [] = "Description";
-size_t description_inx;
+struct field_attr *description_attr;
 
 static char progdoc [] = N_("grep-dctrl -- grep Debian control files");
 
@@ -120,6 +120,7 @@
 	{ "regex",	    'r', 0,		    0, N_("The pattern is a standard POSIX regular expression.") },
 	{ "ignore-case",    'i', 0,		    0, N_("Ignore case when looking for a match.") },
 	{ "invert-match",   'v', 0,		    0, N_("Show only paragraphs that do not match.") },
+        { "invert-show",    'I', 0,                 0, N_("Show those fields that have NOT been selected with -s") },
 	{ "count",	    'c', 0,		    0, N_("Show only the count of matching paragraphs.") },
 	{ "config-file",    OPT_CONFIG, N_("FNAME"),0, N_("Use FNAME as the config file.") },
 	{ "exact-match",    'X', 0,		    0, N_("Do an exact match.") },
@@ -186,6 +187,8 @@
 	bool count;
 	/* Invert match? */
 	bool invert_match;
+        /* Show fields that are NOT listed? */
+        bool invert_show;
 	/* First unused position in toks.  */
 	size_t toks_np;
         /* Token read position. */
@@ -205,16 +208,19 @@
 	} *atom_code[MAX_ATOMS];
 	/* File names seen on the command line.  */
 	struct ifile fname[MAX_FNAMES];
-	/**/
-	struct show_fields {
-		char const * name;
-		size_t inx;
-                size_t repl; // the field to use if this is empty
-	} show_fields[MAX_FIELDS];
+        /**/
+        size_t show_fields[MAX_FIELDS];
 	/* Search field names seen during current atom.  */
 	char * search_fields[MAX_FIELDS];
 };
 
+#define IS_SHOW_FIELD(field_app_data) ((field_app_data) & 1)
+#define SET_SHOW_FIELD(field_app_data,val) \
+  ((field_app_data) = ((field_app_data & ~1) | val))
+#define GET_BACKUP_FIELD(field_app_data) ((field_app_data) >> 1)
+#define SET_BACKUP_FIELD(field_app_data,val) \
+  ((field_app_data) = (((field_app_data)&1) | (val<<1)))
+
 struct atom * clone_atom(struct arguments * args)
 {
 	if (args->p.num_atoms >= MAX_ATOMS) {
@@ -399,26 +405,35 @@
 	case 'd':
 		args->short_descr = true;
 		break;
+        case 'I':
+                args->invert_show = true;
+                break;
 	case 's': {
 		char * carg = strdup(arg);
 		if (carg == 0) fatal_enomem(0);
 		for (char * s = strtok(carg, ","); s != 0; s = strtok(0, ",")){
-			struct show_fields * sf =
-				&args->show_fields[args->num_show_fields];
-			sf->name = strdup(s);
-			if (sf->name == 0) fatal_enomem(0);
-                        char * repl = strchr(sf->name, ':');
+                        char * repl = strchr(s, ':');
                         if (repl != NULL) {
                                 *repl = '\0';
                                 ++repl;
                         }
-			sf->inx = fieldtrie_insert(sf->name);
-			if (sf->inx == description_inx) {
-				args->description_selected = true;
-			}
-                        sf->repl = repl == NULL
+                        struct field_attr *fa = fieldtrie_insert(s);
+                        if (args->num_show_fields >= MAX_FIELDS) {
+                                message(L_FATAL, _("too many output fields"), 0);
+                                fail();
+                        }
+                        args->show_fields[args->num_show_fields] = fa->inx;
+                        if (fa == description_attr) {
+                                args->description_selected = true;
+                        }
+                        SET_SHOW_FIELD(fa->application_data, true);
+
+                        size_t repl_inx = repl == NULL
                                 ? (size_t)(-1)
-                                : fieldtrie_insert(repl);
+                                : fieldtrie_insert(repl)->inx;
+
+                        SET_BACKUP_FIELD(fa->application_data, repl_inx);
+
 			++args->num_show_fields;
 		}
 		free(carg);
@@ -732,6 +747,27 @@
 	if (tok != TOK_EOD) unexpected(tok);
 }
 
+static void show_field(struct arguments *args,
+                       struct paragraph *para,
+                       struct field_attr *fa)
+{
+        if (args->show_field_name) {
+                printf("%s: ", fa->name);
+        }
+        struct fsaf_read_rv r 
+                = get_field(para, 
+                            fa->inx,
+                            GET_BACKUP_FIELD(fa->application_data));
+        
+        if (args->short_descr &&
+            fa == description_attr) {
+                char * nl = memchr(r.b, '\n', r.len);
+                if (nl != 0) r.len = nl - r.b;
+        }
+        fwrite(r.b, 1, r.len, stdout);
+        puts("");
+}
+
 static struct argp argp = { .options = options,
 			    .parser = parse_opt,
 			    .args_doc = argsdoc,
@@ -749,7 +785,7 @@
 	args.show_field_name = true;
 	msg_set_progname(argv[0]);
 	init_predicate(&args.p);
-	description_inx = fieldtrie_insert(description);
+	description_attr = fieldtrie_insert(description);
 	argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &args);
 #ifdef BANNER
 	banner(true);
@@ -780,11 +816,17 @@
 		message(L_INFORMATIONAL,
 			_("Adding \"Description\" to selected output fields because of -d"),
 			0);
-		args.show_fields[args.num_show_fields].name = description;
-		args.show_fields[args.num_show_fields].inx = description_inx;
+                SET_SHOW_FIELD(description_attr->application_data, 1);
+                args.show_fields[args.num_show_fields] = description_attr->inx;
 		++args.num_show_fields;
 	}
 
+        if (args.invert_show && args.num_show_fields == 0) {
+                message(L_FATAL,
+                        _("-I requires at least one instance of -s"), 0);
+                fail();
+        }
+
 	if (!args.show_field_name && args.num_show_fields == 0) {
 		message(L_FATAL,
 			_("cannot suppress field names when showing whole paragraphs"),
@@ -820,7 +862,8 @@
 
 		FSAF * fp = fsaf_fdopen(fd, fname.s);
 		para_parser_t pp;
-		para_parser_init(&pp, fp, true, args.ignore_errors);
+		para_parser_init(&pp, fp, true, args.ignore_errors,
+                                 args.invert_show);
 		para_t para;
 		para_init(&pp, &para);
 		while (1) {
@@ -846,23 +889,29 @@
 				putchar('\n');
 				continue;
 			}
-			for (size_t j = 0; j < args.num_show_fields; j++) {
-				if (args.show_field_name) {
-					printf("%s: ", args.show_fields[j].name);
-				}
-				struct fsaf_read_rv r 
-					= get_field(&para, 
-						    args.show_fields[j].inx,
-                                                    args.show_fields[j].repl);
-				if (args.short_descr &&
-				    args.show_fields[j].inx == description_inx) {
-					char * nl = memchr(r.b, '\n', r.len);
-					if (nl != 0) r.len = nl - r.b;
-				}
-				fwrite(r.b, 1, r.len, stdout);
-				puts("");
-				continue;
-			}
+                        if (args.invert_show) {
+                                for (size_t j = 0;
+                                     j < fieldtrie_count() &&
+                                             j < para.nfields; 
+                                     j++) {
+                                        struct field_attr *fa = 
+                                                fieldtrie_get(j);
+                                        if (IS_SHOW_FIELD(fa->application_data)) {
+                                                continue;
+                                        }
+                                        show_field(&args, &para, fa);
+                                }
+                        } else {
+                                for (size_t j = 0;
+                                     j < args.num_show_fields; j++) {
+                                        size_t inx = args.show_fields[j];
+                                        struct field_attr *fa = 
+                                                fieldtrie_get(inx);
+                                        assert(IS_SHOW_FIELD
+                                               (fa->application_data));
+                                        show_field(&args, &para, fa);
+                                }
+                        }
 			if (args.num_show_fields > 1) puts("");
 		}
 
diff -rN -u old-dctrl-tools-experimental/lib/fieldtrie.c new-dctrl-tools-experimental/lib/fieldtrie.c
--- old-dctrl-tools-experimental/lib/fieldtrie.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/fieldtrie.c	2007-04-08 18:55:34.000000000 +0300
@@ -23,8 +23,6 @@
 #include "msg.h"
 
 struct field_bucket {
-	char const * name;
-	size_t namelen;
 	struct field_attr attr;
 	struct field_bucket * next;
 };
@@ -34,6 +32,8 @@
 	/* A one-level trie listing all field names occurring in the
 	 * atomic predicates. */
 	struct field_bucket * fields[UCHAR_MAX];
+        /* An array mapping each field inx to its attributes */
+        struct field_attr * field_map[65536];
 };
 
 static struct fieldtrie_private trie;
@@ -46,34 +46,42 @@
 	trie.nextfree = 0;
 }
 
-size_t fieldtrie_insert(char const * s)
+struct field_attr *fieldtrie_insert_n(char const * s, size_t slen)
 {
-	size_t slen = strlen(s);
-	struct field_attr l_attr = fieldtrie_lookup(s, slen);
-	if (l_attr.valid) return l_attr.inx;
+	struct field_attr *l_attr = fieldtrie_lookup(s, slen);
+	if (l_attr != 0) return l_attr;
 	struct field_bucket * b = malloc(sizeof *b);
 	if (b == 0) fatal_enomem(0);
-	b->name = malloc(slen+1);
-	if (b->name == 0) fatal_enomem(0);
-	strcpy((char*)b->name, s);
-	b->namelen = slen;
-	b->attr.inx = trie.nextfree++;
-	b->attr.valid = true;
-	unsigned char c = tolower((unsigned char)(b->name[0]));
+	char *name = malloc(slen+1);
+	if (name == 0) fatal_enomem(0);
+	strncpy(name, s, slen);
+        (name)[slen] = '\0';
+        *(char**)&b->attr.name = name;
+	*(size_t*)&b->attr.namelen = slen;
+        assert(trie.nextfree < sizeof trie.field_map / sizeof *trie.field_map);
+	*(size_t*)&b->attr.inx = trie.nextfree++;
+        b->attr.application_data = 0;
+	unsigned char c = tolower((unsigned char)(b->attr.name[0]));
 	b->next = trie.fields[c];
 	trie.fields[c] = b;
-	return b->attr.inx;
+        trie.field_map[b->attr.inx] = &b->attr;
+	return &b->attr;
 }
 
-struct field_attr fieldtrie_lookup(char const * s, size_t n)
+struct field_attr *fieldtrie_insert(char const * s)
+{
+        return fieldtrie_insert_n(s, strlen(s));
+}
+
+struct field_attr *fieldtrie_lookup(char const * s, size_t n)
 {
 	for (struct field_bucket * b = trie.fields[tolower((unsigned char)s[0])];
 	     b != 0;
 	     b = b->next) {
-		if (n == b->namelen &&
-		    strncasecmp(s, b->name, n) == 0) return b->attr;
+		if (n == b->attr.namelen &&
+		    strncasecmp(s, b->attr.name, n) == 0) return &b->attr;
 	}
-	return (struct field_attr){ .valid = false };
+	return NULL;
 }
 
 size_t fieldtrie_count(void)
@@ -81,6 +89,12 @@
 	return trie.nextfree;
 }
 
+struct field_attr *fieldtrie_get(size_t inx)
+{
+        assert(inx < sizeof trie.field_map / sizeof *trie.field_map);
+        return trie.field_map[inx];
+}
+
 #if 0
 void fieldtrie_clear(void)
 {
diff -rN -u old-dctrl-tools-experimental/lib/fieldtrie.h new-dctrl-tools-experimental/lib/fieldtrie.h
--- old-dctrl-tools-experimental/lib/fieldtrie.h	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/fieldtrie.h	2007-04-08 18:55:34.000000000 +0300
@@ -24,17 +24,22 @@
 #include <stdbool.h>
 
 struct field_attr {
-	bool valid;
-	size_t inx;
+	char const *const name;
+	const size_t namelen;
+	const size_t inx;
+        unsigned application_data;
 };
 
 void fieldtrie_init(void);
 
 // case-insensitive
-size_t fieldtrie_insert(char const *);
+struct field_attr *fieldtrie_insert(char const *);
+struct field_attr *fieldtrie_insert_n(char const * s, size_t slen);
 
 // case-insensitive
-struct field_attr fieldtrie_lookup(char const *, size_t n);
+struct field_attr *fieldtrie_lookup(char const *, size_t n);
+
+struct field_attr *fieldtrie_get(size_t inx);
 
 //void fieldtrie_clear(void);
 
diff -rN -u old-dctrl-tools-experimental/lib/para_bundle.c new-dctrl-tools-experimental/lib/para_bundle.c
--- old-dctrl-tools-experimental/lib/para_bundle.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/para_bundle.c	2007-04-08 18:55:34.000000000 +0300
@@ -39,7 +39,7 @@
 	sf->next = pb->files;
 	pb->files = sf;
 
-	para_parser_init(&sf->pp, f, false, false);
+	para_parser_init(&sf->pp, f, false, false, false);
 	while (true) {
 		if (pb->num_paras == pb->max_num) {
 			size_t max_num = pb->max_num == 0 ? 256 :
diff -rN -u old-dctrl-tools-experimental/lib/paragraph.c new-dctrl-tools-experimental/lib/paragraph.c
--- old-dctrl-tools-experimental/lib/paragraph.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/paragraph.c	2007-04-08 18:55:34.000000000 +0300
@@ -22,7 +22,8 @@
 #include "strutil.h"
 
 void para_parser_init(para_parser_t * pp, FSAF * fp,
-		      bool invalidate_p, bool ignore_failing_paras)
+		      bool invalidate_p, bool ignore_failing_paras,
+                      bool register_unknown_fields)
 {
 	pp->fp = fp;
 	pp->eof = false;
@@ -30,6 +31,7 @@
 	pp->line = 1;
 	pp->invalidate_p = invalidate_p;
 	pp->ignore_broken_paras = ignore_failing_paras;
+        pp->register_unknown_fields = register_unknown_fields;
 }
 
 void para_init(para_parser_t * pp, para_t * para)
@@ -57,13 +59,28 @@
 	para->fields = 0;
 }
 
+static struct field_data * register_field(para_t * para,
+                                          char const * s, size_t slen)
+{
+        size_t inx = fieldtrie_insert_n(s, slen)->inx;
+        if (inx >= para->nfields) {
+                assert(para->nfields > 0);
+                para->nfields = para->nfields * 2;
+                para->fields = realloc(para->fields,
+                                       para->nfields * sizeof(para->fields[0])
+                                      );
+                if (para->fields == 0) fatal_enomem(0);
+        }
+        struct field_data *field_data = &para->fields[inx];
+        return field_data;
+}
+
 void para_parse_next(para_t * para)
 {
 redo:
 	debug_message("para_parse_next", 0);
 	assert(para != 0);
 	para_parser_t * pp = para->common;
-	assert(para->nfields == fieldtrie_count());
 	para->start = pp->loc;
 	para->line = pp->line;
 	for (size_t i = 0; i < para->nfields; i++) {
@@ -132,13 +149,23 @@
 								  field_start,
 								  len);
 				assert(r.len == len);
-				struct field_attr attr =
+				struct field_attr *attr =
 					fieldtrie_lookup(r.b, len);
-				if (!attr.valid) {
-					field_data = 0;
+				if (attr == NULL) {
+                                        if (para->common->
+                                            register_unknown_fields) {
+                                                field_data =
+                                                        register_field(para,
+                                                                       r.b,
+                                                                       len);
+                                        } else {
+                                                field_data = 0;
+                                        }
 				} else {
-					assert(attr.inx < para->nfields);
-					field_data = &para->fields[attr.inx];
+					assert(attr->inx < para->nfields);
+					field_data = &para->fields[attr->inx];
+                                }
+                                if (field_data != NULL) {
 					field_data->start = pos;
 					field_data->line = line;
 				}
diff -rN -u old-dctrl-tools-experimental/lib/paragraph.h new-dctrl-tools-experimental/lib/paragraph.h
--- old-dctrl-tools-experimental/lib/paragraph.h	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/paragraph.h	2007-04-08 18:55:34.000000000 +0300
@@ -38,6 +38,7 @@
 	size_t line;
 
 	bool ignore_broken_paras;
+        bool register_unknown_fields;
 };
 
 struct paragraph {
@@ -54,7 +55,8 @@
 
 /* Initialize the given para_parser_t, associating with it the given FSAF. */
 void para_parser_init(para_parser_t *, FSAF *,
-		      bool invalidate_p, bool ignore_broken_paras);
+		      bool invalidate_p, bool ignore_broken_paras,
+                      bool register_unknown_fields);
 
 /* Initialize the given para_t for the given parser. */
 void para_init(para_parser_t *, para_t *);
diff -rN -u old-dctrl-tools-experimental/lib/predicate.c new-dctrl-tools-experimental/lib/predicate.c
--- old-dctrl-tools-experimental/lib/predicate.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/lib/predicate.c	2007-04-08 18:55:34.000000000 +0300
@@ -51,11 +51,11 @@
                 char * repl = strchr(atom->field_name, ':');
                 if (repl != NULL) {
                         *repl++ = '\0';
-                        atom->repl_inx = fieldtrie_insert(repl);
+                        atom->repl_inx = fieldtrie_insert(repl)->inx;
                 } else {
                         atom->repl_inx = -1;
                 }
-		atom->field_inx = fieldtrie_insert(atom->field_name);
+		atom->field_inx = fieldtrie_insert(atom->field_name)->inx;
 	}
 
 	if (atom->mode == M_REGEX || atom->mode == M_EREGEX) {
diff -rN -u old-dctrl-tools-experimental/man/grep-dctrl.1.cp new-dctrl-tools-experimental/man/grep-dctrl.1.cp
--- old-dctrl-tools-experimental/man/grep-dctrl.1.cp	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/man/grep-dctrl.1.cp	2007-04-08 18:55:34.000000000 +0300
@@ -182,7 +182,12 @@
 Show only the body of these fields from the matching paragraphs.  The
 field names must not include any colons or commas.  Commas are used to
 delimit field names in the argument to this option.  The fields are
-shown in the order given here.
+shown in the order given here.  See also the option \-I.
+.IP "\-I; \-\-invert\-show"
+Invert the meaning of option \-s: show only the fields that have
+.B not
+been named using a \-s option.  As an artefact of the implementation,
+the order of the fields in the original paragraph is not preserved.
 .PP
 A FIELD specification can contain a colon. In such a case, the part
 up to the colon is taken as the name of the field to be shown, and the
diff -rN -u old-dctrl-tools-experimental/sort-dctrl/sort-dctrl.c new-dctrl-tools-experimental/sort-dctrl/sort-dctrl.c
--- old-dctrl-tools-experimental/sort-dctrl/sort-dctrl.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/sort-dctrl/sort-dctrl.c	2007-04-08 18:55:34.000000000 +0300
@@ -72,7 +72,7 @@
 				*(flags++) = '\0';
 			}
 			struct key key;
-			key.field_inx = fieldtrie_insert(carg);
+			key.field_inx = fieldtrie_insert(carg)->inx;
 			key.type = FT_STRING;
 			key.reverse = false;
 			for (char *p = flags; *p != '\0'; p++) {
@@ -152,7 +152,7 @@
 	argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &args);
 
 	if (args.keys.nks == 0) {
-		size_t inx = fieldtrie_insert("Package");
+		size_t inx = fieldtrie_insert("Package")->inx;
 		keys_append(&args.keys, (struct key){ .field_inx = inx,
 						      .type = FT_STRING,
 						      .reverse = false });
diff -rN -u old-dctrl-tools-experimental/tbl-dctrl/tbl-dctrl.c new-dctrl-tools-experimental/tbl-dctrl/tbl-dctrl.c
--- old-dctrl-tools-experimental/tbl-dctrl/tbl-dctrl.c	2007-04-08 18:55:34.000000000 +0300
+++ new-dctrl-tools-experimental/tbl-dctrl/tbl-dctrl.c	2007-04-08 18:55:34.000000000 +0300
@@ -259,7 +259,7 @@
 		if (fn != NULL) *(fn++) = '\0';
 		struct column *col = &args->columns[args->num_columns];
 		col->heading = carg;
-		col->field_inx = fieldtrie_insert(fn == NULL ? carg : fn);
+		col->field_inx = fieldtrie_insert(fn == NULL ? carg : fn)->inx;
 		size_t n = 0;
 		_Bool err = 0;
 		for (char const *p = lens; *p != '\0'; p++) {
@@ -417,7 +417,7 @@
 
 			FSAF * fp = fsaf_fdopen(fd, fname.s);
 			para_parser_t pp;
-			para_parser_init(&pp, fp, true, false);
+			para_parser_init(&pp, fp, true, false, false);
 			para_t para;
 			para_init(&pp, &para);
 			while (1) {
diff -rN -u old-dctrl-tools-experimental/tests/bug144174.out new-dctrl-tools-experimental/tests/bug144174.out
--- old-dctrl-tools-experimental/tests/bug144174.out	1970-01-01 02:00:00.000000000 +0200
+++ new-dctrl-tools-experimental/tests/bug144174.out	2007-04-08 18:55:34.000000000 +0300
@@ -0,0 +1,31 @@
+Description: Command-line tools to process Debian package information
+ Debian package information is generally stored in files having a
+ special file format, dubbed the Debian control file format (the dctrl
+ format), a special case of the record jar file format.  These tools
+ operate on any files conforming in a general sense to that format and
+ are therefore widely applicable whenever those formats are in play.
+ .
+ Included are:
+ .
+   grep-dctrl     - Grep dctrl-format files
+   grep-available - Grep the DPKG available database
+   grep-status    - Grep the DPKG status database
+   grep-aptavail  - Grep the APT available database
+ .
+   sort-dctrl     - Sort dctrl-format files
+ .
+   tbl-dctrl      - Tabulate dctrl-format files
+ .
+   sync-available - Sync the dpkg available database with
+                    the apt database
+Priority: optional
+Section: utils
+Installed-Size: 512
+Maintainer: Antti-Juhani Kaijanaho <ajk at debian.org>
+Architecture: amd64
+Version: 2.10
+Replaces: grep-dctrl
+Provides: grep-dctrl
+Depends: libc6 (>= 2.3.5-1)
+Suggests: apt
+Conflicts: grep-dctrl
diff -rN -u old-dctrl-tools-experimental/tests/bug144174.sh new-dctrl-tools-experimental/tests/bug144174.sh
--- old-dctrl-tools-experimental/tests/bug144174.sh	1970-01-01 02:00:00.000000000 +0200
+++ new-dctrl-tools-experimental/tests/bug144174.sh	2007-04-08 18:55:34.000000000 +0300
@@ -0,0 +1,5 @@
+#!/bin/sh
+
+set -e
+
+$GREP_DCTRL -I -sPackage '' 0001.out





More information about the Dctrl-tools-devel mailing list