diff options
-rw-r--r-- | debian/changelog | 6 | ||||
-rw-r--r-- | grep-dctrl/grep-dctrl.c | 50 | ||||
-rw-r--r-- | lib/atom.c | 36 | ||||
-rw-r--r-- | lib/paragraph.c | 63 | ||||
-rw-r--r-- | lib/paragraph.h | 42 | ||||
-rw-r--r-- | tbl-dctrl/tbl-dctrl.c | 4 | ||||
-rw-r--r-- | tester.sh | 9 | ||||
-rw-r--r-- | tests/bug652034.in | 3 | ||||
-rw-r--r-- | tests/bug652034.out | 10 | ||||
-rw-r--r-- | tests/bug652034.sh | 9 |
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, @@ -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 = ¶->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 = ¶->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 = ¶->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); @@ -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 |