summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAntti-Juhani Kaijanaho <ajk@debian.org>2011-12-14 20:36:48 +0200
committerAntti-Juhani Kaijanaho <ajk@debian.org>2011-12-14 20:39:13 +0200
commit34ce3e24a1d922b8778ec0b764540e5bc43155b4 (patch)
treea29ed01eb8f0afcaa26943e7b45f99ca80d368a3
parentfd8f94781f285d202662afea4bd98f68fd7b19d4 (diff)
downloaddctrl-tools-34ce3e24a1d922b8778ec0b764540e5bc43155b4.tar.gz
Bug #652034: Handle multiple instances of the same field gracefully.
For grep-dctrl, this means having -F search for all of the same-name fields disjunctively. The -s option selects all same-name fields for printing. For the other tools, all but the first are ignored. No string changes, so committing to maint-2.20 for release with 2.20.1. Signed-off-by: Antti-Juhani Kaijanaho <ajk@debian.org>
-rw-r--r--debian/changelog6
-rw-r--r--grep-dctrl/grep-dctrl.c50
-rw-r--r--lib/atom.c36
-rw-r--r--lib/paragraph.c63
-rw-r--r--lib/paragraph.h42
-rw-r--r--tbl-dctrl/tbl-dctrl.c4
-rw-r--r--tester.sh9
-rw-r--r--tests/bug652034.in3
-rw-r--r--tests/bug652034.out10
-rw-r--r--tests/bug652034.sh9
10 files changed, 146 insertions, 86 deletions
diff --git a/debian/changelog b/debian/changelog
index 5cf885c..b6c0269 100644
--- a/debian/changelog
+++ b/debian/changelog
@@ -5,7 +5,11 @@ dctrl-tools (2.20.1) UNRELEASED; urgency=low
#651218).
* man pages order in SEE ALSO, thanks to Chris Leick (closes: #651219).
- -- David Prévot <taffit@debian.org> Wed, 07 Dec 2011 11:56:51 -0400
+ [ Antti-Juhani Kaijanaho ]
+ * Handle multiple instances of the same field gracefully. No string changes.
+ Closes: #652034 (reported by myself)
+
+ -- Antti-Juhani Kaijanaho <ajk@debian.org> Wed, 14 Dec 2011 20:33:28 +0200
dctrl-tools (2.20) unstable; urgency=low
diff --git a/grep-dctrl/grep-dctrl.c b/grep-dctrl/grep-dctrl.c
index 9e661bb..99ea398 100644
--- a/grep-dctrl/grep-dctrl.c
+++ b/grep-dctrl/grep-dctrl.c
@@ -753,36 +753,38 @@ static void show_field(struct arguments *args,
struct paragraph *para,
struct field_attr *fa)
{
- struct field_data *fd =
+ struct field_data fds =
find_field_wr(para,
fa->inx,
GET_BACKUP_FIELD(fa->application_data));
- if (fd == NULL) return;
- struct fsaf_read_rv r =
- fsaf_read(para->common->fp, fd->start, fd->end - fd->start);
-
- if (args->short_descr &&
- fa == description_attr) {
- char * nl = memchr(r.b, '\n', r.len);
- if (nl != 0) r.len = nl - r.b;
- }
+ for (struct field_datum *fd = fds.first; fd != NULL; fd = fd->next) {
+ struct fsaf_read_rv r =
+ fsaf_read(para->common->fp,
+ fd->start, fd->end - fd->start);
- if (r.len == 0) {
- /* don't display a field with an empty value */
- return;
- }
+ if (args->short_descr &&
+ fa == description_attr) {
+ char * nl = memchr(r.b, '\n', r.len);
+ if (nl != 0) r.len = nl - r.b;
+ }
- if (args->show_field_name) {
- struct fsaf_read_rv rn =
- fsaf_read(para->common->fp,
- fd->name_start,
- fd->name_end - fd->name_start);
- fwrite(rn.b, 1, rn.len, stdout);
- fputs(": ", stdout);
- }
+ if (r.len == 0) {
+ /* don't display a field with an empty value */
+ break;
+ }
+
+ if (args->show_field_name) {
+ struct fsaf_read_rv rn =
+ fsaf_read(para->common->fp,
+ fd->name_start,
+ fd->name_end - fd->name_start);
+ fwrite(rn.b, 1, rn.len, stdout);
+ fputs(": ", stdout);
+ }
- fwrite(r.b, 1, r.len, stdout);
- puts("");
+ fwrite(r.b, 1, r.len, stdout);
+ puts("");
+ }
}
static struct argp argp = { .options = options,
diff --git a/lib/atom.c b/lib/atom.c
index 831620b..26d223a 100644
--- a/lib/atom.c
+++ b/lib/atom.c
@@ -69,26 +69,11 @@ void atom_finish(struct atom * atom)
}
-bool atom_verify(struct atom * atom, para_t * para)
+static bool atom_field_verify(struct atom * atom, FSAF * fp,
+ size_t start, size_t end)
{
- size_t start = 0;
- size_t end = 0;
- if (atom->field_inx == -1) {
- /* Take the full paragraph */
- start = para->start;
- end = para->end;
- } else {
- /* Take the field */
- struct field_data * fd = find_field_wr(para,
- atom->field_inx,
- atom->repl_inx);
- if (fd != NULL) {
- start = fd->start;
- end = fd->end;
- }
- }
size_t len = end - start;
- struct fsaf_read_rv r = fsaf_read(para->common->fp, start, len);
+ struct fsaf_read_rv r = fsaf_read(fp, start, len);
assert(r.len == len);
switch (atom->mode) {
case M_EXACT:
@@ -169,3 +154,18 @@ bool atom_verify(struct atom * atom, para_t * para)
}
assert(0);
}
+
+bool atom_verify(struct atom * at, para_t * par)
+{
+ FSAF * fp = par->common->fp;
+ if (at->field_inx == -1) {
+ /* Take the full paragraph */
+ return atom_field_verify(at, fp, par->start, par->end);
+ }
+ /* Test field(s) */
+ struct field_data fds = find_field_wr(par, at->field_inx, at->repl_inx);
+ for (struct field_datum * fd = fds.first; fd != NULL; fd = fd->next) {
+ if (atom_field_verify(at, fp, fd->start, fd->end)) return true;
+ }
+ return false;
+}
diff --git a/lib/paragraph.c b/lib/paragraph.c
index 4f91a2e..0cc2ea7 100644
--- a/lib/paragraph.c
+++ b/lib/paragraph.c
@@ -46,7 +46,8 @@ void para_init(para_parser_t * pp, para_t * para)
para->fields = malloc(para->nfields * sizeof *para->fields);
if (para->fields == 0) fatal_enomem(0);
for (size_t i = 0; i < para->nfields; i++) {
- para->fields[i].present = 0;
+ para->fields[i].first = 0;
+ para->fields[i].last = 0;
}
} else {
para->fields = NULL;
@@ -59,6 +60,14 @@ void para_finalize(para_t * para)
para->start = 0;
para->end = 0;
if (para->fields != 0) {
+ for (size_t i = 0; i < para->nfields; i++) {
+ struct field_datum *fp = para->fields[i].first;
+ while (fp != 0) {
+ struct field_datum *tmp = fp;
+ fp = fp->next;
+ free(tmp);
+ }
+ }
free(para->fields);
}
para->maxfields = 0;
@@ -80,7 +89,11 @@ static struct field_data * register_field(para_t * para,
sizeof(para->fields[0]));
if (para->fields == 0) fatal_enomem(0);
}
- if (inx >= para->nfields) para->nfields = inx + 1;
+ if (inx >= para->nfields) {
+ para->nfields = inx + 1;
+ para->fields[inx].first = 0;
+ para->fields[inx].last = 0;
+ }
assert(para->nfields <= para->maxfields);
struct field_data *field_data = &para->fields[inx];
return field_data;
@@ -94,9 +107,14 @@ redo:
para->start = pp->loc;
para->line = pp->line;
for (size_t i = 0; i < para->nfields; i++) {
- para->fields[i].present = 0;
- para->fields[i].start = 0;
- para->fields[i].end = 0;
+ struct field_datum *fp = para->fields[i].first;
+ while (fp != 0) {
+ struct field_datum *tmp = fp;
+ fp = fp->next;
+ free(tmp);
+ }
+ para->fields[i].first = 0;
+ para->fields[i].last = 0;
}
if (pp->invalidate_p) {
fsaf_invalidate(pp->fp, para->start);
@@ -106,7 +124,7 @@ redo:
register size_t line = para->line;
register FSAF * fp = pp->fp;
size_t field_start = 0;
- struct field_data * field_data = 0;
+ struct field_datum * field_datum = 0;
#define GETC (c = fsaf_getc(fp, pos++), c == '\n' ? line++ : line)
#define UNGETC (fsaf_getc(fp, --pos) == '\n' ? --line : line)
@@ -176,17 +194,22 @@ FIELD_NAME:
}
attr = fieldtrie_lookup(r.b, len);
if (attr == NULL) {
- field_data = 0;
+ field_datum = 0;
} else {
assert(attr->inx < para->nfields);
- field_data = &para->fields[attr->inx];
- }
- if (field_data != NULL) {
- field_data->present = 1;
- field_data->start = pos;
- field_data->line = line;
- field_data->name_start = field_start;
- field_data->name_end = pos-1;
+ struct field_data * fds = &para->fields[attr->inx];
+ assert((fds->first == 0) == (fds->last == 0));
+ field_datum = malloc(sizeof *field_datum);
+ if (field_datum == 0) enomem(0);
+ field_datum->start = pos;
+ field_datum->line = line;
+ field_datum->name_start = field_start;
+ field_datum->name_end = pos-1;
+ field_datum->next = 0;
+ field_datum->prev = fds->last;
+ if (fds->last != 0) fds->last->next = field_datum;
+ fds->last = field_datum;
+ if (fds->first == 0) fds->first = field_datum;
}
goto BODY;
}
@@ -198,12 +221,12 @@ FIELD_NAME:
BODY:
GETC;
if (c == -1 || c == '\n') {
- if (field_data != 0) {
- field_data->end = pos-1;
- while (field_data->start < field_data->end
- && fsaf_getc(fp, field_data->start)
+ if (field_datum != 0) {
+ field_datum->end = pos-1;
+ while (field_datum->start < field_datum->end
+ && fsaf_getc(fp, field_datum->start)
== ' ') {
- ++field_data->start;
+ ++field_datum->start;
}
}
goto BODY_NEWLINE;
diff --git a/lib/paragraph.h b/lib/paragraph.h
index a8be095..c76d124 100644
--- a/lib/paragraph.h
+++ b/lib/paragraph.h
@@ -25,11 +25,16 @@
#include "fsaf.h"
#include "fieldtrie.h"
-struct field_data {
- _Bool present;
+struct field_datum {
size_t line;
size_t start, end; /* offsets to the file; [start,end) is the body */
size_t name_start, name_end; /* as start and end, but for the name */
+ struct field_datum *next, *prev;
+};
+
+struct field_data {
+ struct field_datum *first;
+ struct field_datum *last;
};
struct paragraph_parser {
@@ -71,49 +76,52 @@ struct fsaf_read_rv get_whole_para(para_t * p)
}
static inline
-struct field_data * find_field(const para_t *p, size_t fld_inx)
+struct field_data find_field(const para_t *p, size_t fld_inx)
{
- struct field_data * fd = fld_inx < p->nfields
- ? &p->fields[fld_inx]
- : NULL;
- if (fd != NULL && !fd->present) fd = NULL;
- return fd;
+ return fld_inx < p->nfields
+ ? p->fields[fld_inx]
+ : (struct field_data){ NULL, NULL };
}
static inline
-struct field_data *find_field_wr(const para_t *p,
- size_t fld_inx,
- size_t repl_inx)
+struct field_data find_field_wr(const para_t *p,
+ size_t fld_inx,
+ size_t repl_inx)
{
- struct field_data * fd = find_field(p, fld_inx);
- if ((fd == NULL || fd->start == fd->end) && repl_inx != (size_t)(-1)) {
+ struct field_data fd = find_field(p, fld_inx);
+ if (fd.first == NULL && repl_inx != (size_t)(-1)) {
fd = find_field(p, repl_inx);
}
return fd;
}
+// NOTE: get_field finds the FIRST field of the name!
static inline
struct fsaf_read_rv get_field(para_t * p, size_t fld_inx, size_t repl_inx)
{
- struct field_data *fd = find_field_wr(p, fld_inx, repl_inx);
- if (fd == NULL) {
+ struct field_data fds = find_field_wr(p, fld_inx, repl_inx);
+ if (fds.first == NULL) {
const struct fsaf_read_rv fail = {
.b = NULL,
.len = 0
};
return fail;
}
+ struct field_datum *fd = fds.first;
return fsaf_read(p->common->fp, fd->start, fd->end - fd->start);
}
+// NOTE: get_field_as finds the FIRST field of the name!
static inline
char * get_field_as(const para_t * p, size_t fld_inx)
{
- struct field_data * fd = find_field(p, fld_inx);
- if (fd == NULL) return strdup("");
+ struct field_data fds = find_field(p, fld_inx);
+ if (fds.first == NULL) return strdup("");
+ struct field_datum *fd = fds.first;
return fsaf_getas(p->common->fp, fd->start, fd->end - fd->start);
}
+
static inline
bool para_eof(para_parser_t * para) { return para->eof; }
diff --git a/tbl-dctrl/tbl-dctrl.c b/tbl-dctrl/tbl-dctrl.c
index b90a578..848f3f3 100644
--- a/tbl-dctrl/tbl-dctrl.c
+++ b/tbl-dctrl/tbl-dctrl.c
@@ -1,5 +1,5 @@
/* dctrl-tools - Debian control file inspection tools
- Copyright © 2005, 2006, 2007, 2008, 2009, 2010 Antti-Juhani Kaijanaho
+ Copyright © 2005, 2006, 2007, 2008, 2009, 2010, 2011 Antti-Juhani Kaijanaho
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
@@ -418,7 +418,7 @@ int main(int argc, char * argv[])
struct paragraph *p = pb.paras[i];
assert(p->nfields <= n);
for (size_t j = 0; j < p->nfields; j++) {
- if (!p->fields[j].present) continue;
+ if (p->fields[j].first == NULL) continue;
struct fsaf_read_rv r = get_field(p, j, -1);
size_t len = mbs_len(r.b, r.len,
p->common->fp->fname);
diff --git a/tester.sh b/tester.sh
index 1c35d0b..dfe609e 100644
--- a/tester.sh
+++ b/tester.sh
@@ -46,6 +46,9 @@ for tst in $tests ; do
if [ ! -r $tst_in ] ; then
tst_in=/dev/null
fi
+ if [ ! -r $tst_ero ] ; then
+ tst_ero=/dev/null
+ fi
if [ ! -r $tst_out ] && [ ! -r $tst_err ] ; then
echo 1>&2 "neither $tst_out nor $tst_err exists"
exit 1
@@ -82,10 +85,8 @@ for tst in $tests ; do
echo "FAILED."
echo "stdout diff:"
cat .diffout
- if [ -r $tst_ero ] ; then
- echo "stderr diff:"
- cat .differr
- fi
+ echo "stderr diff:"
+ cat .differr
rv=1
fi
done
diff --git a/tests/bug652034.in b/tests/bug652034.in
new file mode 100644
index 0000000..287f616
--- /dev/null
+++ b/tests/bug652034.in
@@ -0,0 +1,3 @@
+Foo: a
+Foo: b
+
diff --git a/tests/bug652034.out b/tests/bug652034.out
new file mode 100644
index 0000000..845b68c
--- /dev/null
+++ b/tests/bug652034.out
@@ -0,0 +1,10 @@
+Foo: a
+Foo: b
+
+###
+Foo: a
+Foo: b
+
+###
+Foo: a
+Foo: b
diff --git a/tests/bug652034.sh b/tests/bug652034.sh
new file mode 100644
index 0000000..af5e018
--- /dev/null
+++ b/tests/bug652034.sh
@@ -0,0 +1,9 @@
+#!/bin/sh
+
+set -e
+
+${GREP_DCTRL:-grep-dctrl} -FFoo a bug652034.in
+echo '###'
+${GREP_DCTRL:-grep-dctrl} -FFoo b bug652034.in
+echo '###'
+${GREP_DCTRL:-grep-dctrl} -sFoo -FFoo b bug652034.in