diff options
author | Antti-Juhani Kaijanaho <ajk@debian.org> | 2006-01-28 21:33:40 +0100 |
---|---|---|
committer | Antti-Juhani Kaijanaho <ajk@debian.org> | 2006-01-28 21:33:40 +0100 |
commit | f8f9060a67f9973e94ce5bf8c176950b52bed9b4 (patch) | |
tree | adef05add5240387d47d84a76a06243641d4a06d | |
parent | 8876f79f1c606e83eb52123bbc78f8b6ccec4565 (diff) | |
download | dctrl-tools-f8f9060a67f9973e94ce5bf8c176950b52bed9b4.tar.gz |
Import 1.104
-rw-r--r-- | debian/NEWS | 8 | ||||
-rw-r--r-- | debian/changelog | 26 | ||||
-rw-r--r-- | debian/control | 2 | ||||
-rw-r--r-- | grep-dctrl.1.cp | 11 | ||||
-rw-r--r-- | grep-dctrl.c | 204 | ||||
-rw-r--r-- | predicate.c | 4 | ||||
-rw-r--r-- | predicate.h | 8 |
7 files changed, 199 insertions, 64 deletions
diff --git a/debian/NEWS b/debian/NEWS index e75e0e1..97546a6 100644 --- a/debian/NEWS +++ b/debian/NEWS @@ -1,3 +1,11 @@ +grep-dctrl (1.104) unstable; urgency=low + + One of the documented regressions have been removed in this version: + multiple field names in -F and multiple -F options in one atom are + again supported. + + -- Antti-Juhani Kaijanaho <ajk@debian.org> Sat, 3 Jan 2004 20:09:06 +0200 + grep-dctrl (1.103) unstable; urgency=low The annoying banner which was added in version 1.100 and which asked diff --git a/debian/changelog b/debian/changelog index ef4fd12..c6312c5 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,29 @@ +grep-dctrl (1.104) unstable; urgency=low + + * grep-dctrl.c (parse_option [case 's']): free carg after use + * grep-dctrl.c (parse_option): Replace remaining FIXME-tagged asserts + with proper error checking + * Bring back support for multiple -F options in one atom and multiple + field names in one -F option: + - grep-dctrl.c (struct arguments, leave, prim_enter): Allow an + instruction sequence in the parser stack. + - grep-dctrl.c (clone_atom): New function. + - grep-dctrl.c (finish_atom, parse_option [case 'F']): + Handle multiple field names. + - grep-dctrl.1.cp: Remove note of the regression. + - debian/NEWS: Note this change. + This gets rid of one of the documented regressions. + * grep-dctrl.c (options): Make --banner existence contingent on the + BANNER #define. + * grep-dctrl.c, predicate.h, predicate.c, grep-dctrl.1.cp: Add a new + instruction, I_TRUE, and use it to implement --true. + * grep-dctrl.c (to_stdout, parse_option [case 'C']): Implement -C. + Closes: #207995 (grep-dctrl: -C: (PROGRAM ERROR) Option should have + been recognized!?) + * debian/control (Standards-Version): 3.6.1, no changes required. + + -- Antti-Juhani Kaijanaho <ajk@debian.org> Sat, 3 Jan 2004 20:54:36 +0200 + grep-dctrl (1.103) unstable; urgency=low * grep_dctrl.c (banner, main, parse_option): Disable the banner. diff --git a/debian/control b/debian/control index 3531777..3ce1ab5 100644 --- a/debian/control +++ b/debian/control @@ -2,7 +2,7 @@ Source: grep-dctrl Section: utils Priority: optional Maintainer: Antti-Juhani Kaijanaho <ajk@debian.org> -Standards-Version: 3.6.0 +Standards-Version: 3.6.1 Package: grep-dctrl Architecture: any diff --git a/grep-dctrl.1.cp b/grep-dctrl.1.cp index 2173545..50e7fdd 100644 --- a/grep-dctrl.1.cp +++ b/grep-dctrl.1.cp @@ -1,4 +1,4 @@ -.TH GREP-DCTRL 1 2004-01-01 "Debian Project" "Debian user's manual" +.TH GREP-DCTRL 1 2004-01-03 "Debian Project" "Debian user's manual" \" Copyright (C) 1999, 2000, 2001, 2002, 2003, 2004 \" Antti-Juhani Kaijanaho <gaia@iki.fi> \" Permission is granted to make and distribute verbatim copies of @@ -109,9 +109,10 @@ available and status files, respectively. .SH OPTIONS .SS Atomic predicate modifiers .IP "-F FIELD,FIELD,...; --field=FIELD,FIELD,..." -Restrict pattern matching to the FIELDs given. -.B Multiple fields in one -F is broken currently. -Use the -o option in the mean time. +Restrict pattern matching to the FIELDs given. Multiple field names +in one -F option and multiple -F options in one atom are allowed; the +search named by the atom will be performed (disjunctively) among all +fields named. .IP -P Shorthand for "-FPackage". .IP "-e, --eregex" @@ -166,6 +167,8 @@ immediately after finding the first match. .SS Miscellaneous .IP "--config-file=FNAME" Use FNAME as the config file instead of the defaults. +.IP "--debug-optparse" +Show how the current command line has been parsed. .IP "-l LEVEL, --errorlevel=LEVEL" Set debugging level to LEVEL. LEVEL is one of "fatal", "important", "informational" and "debug", but the last may not be available, diff --git a/grep-dctrl.c b/grep-dctrl.c index b20d421..b0574fa 100644 --- a/grep-dctrl.c +++ b/grep-dctrl.c @@ -47,6 +47,34 @@ static char progdoc [] = "grep-dctrl -- grep Debian control files"; #undef BANNER +#define COPYING "/usr/share/common-licenses/GPL" + +/* Copy the file called fname to standard outuput stream. Return zero + iff problems were encountered. */ +static int to_stdout (const char * fname) +{ + FILE * f; + int c; + int rv = 1; + + f = fopen (fname, "r"); + if (f == 0) { + message (L_FATAL, strerror (errno), COPYING); + return 0; + } + + while ( ( c = getc (f)) != EOF) putchar (c); + + if (ferror (f)) { + message (L_FATAL, strerror (errno), COPYING); + rv = 0; + } + + fclose (f); + + return rv; +} + #ifdef BANNER void banner(bool automatic) { @@ -89,33 +117,35 @@ end: #endif static struct argp_option options[] = { - { "banner", 'B', 0, 0, "Show the testing banner." }, - { "errorlevel", 'l', "LEVEL", 0, "Set debugging level to LEVEL." }, - { "field", 'F', "FIELD,FIELD,...", 0, "Restrict pattern matching to the FIELDs given." }, - { 0, 'P', 0, 0, "Shorthand for -FPackage" }, - { "show-field", 's', "FIELD,FIELD,...", 0, "Show only the body of these fields from the matching paragraphs." }, - { 0, 'd', 0, 0, "Show only the first line of the Description field from the matching paragraphs." }, - { "no-field-names", 'n', 0, 0, "Suppress field names when showing specified fields." }, - { "eregex", 'e', 0, 0, "Regard the pattern as an extended POSIX regular expression." }, - { "regex", 'r', 0, 0, "The pattern is a standard POSIX regular expression." }, - { "ignore-case", 'i', 0, 0, "Ignore case when looking for a match." }, - { "invert-match", 'v', 0, 0, "Show only paragraphs that do not match." }, - { "count", 'c', 0, 0, "Show only the count of matching paragraphs." }, +#ifdef BANNER + { "banner", 'B', 0, 0, "Show the testing banner." }, +#endif + { "errorlevel", 'l', "LEVEL", 0, "Set debugging level to LEVEL." }, + { "field", 'F', "FIELD,FIELD,...", 0, "Restrict pattern matching to the FIELDs given." }, + { 0, 'P', 0, 0, "Shorthand for -FPackage" }, + { "show-field", 's', "FIELD,FIELD,...", 0, "Show only the body of these fields from the matching paragraphs." }, + { 0, 'd', 0, 0, "Show only the first line of the Description field from the matching paragraphs." }, + { "no-field-names", 'n', 0, 0, "Suppress field names when showing specified fields." }, + { "eregex", 'e', 0, 0, "Regard the pattern as an extended POSIX regular expression." }, + { "regex", 'r', 0, 0, "The pattern is a standard POSIX regular expression." }, + { "ignore-case", 'i', 0, 0, "Ignore case when looking for a match." }, + { "invert-match", 'v', 0, 0, "Show only paragraphs that do not match." }, + { "count", 'c', 0, 0, "Show only the count of matching paragraphs." }, { "config-file", OPT_CONFIG, "FNAME", 0, "Use FNAME as the config file." }, - { "exact-match", 'X', 0, 0, "Do an exact match." }, - { "copying", 'C', 0, 0, "Print out the copyright license." }, - { "and", 'a', 0, 0, "Conjunct predicates." }, - { "or", 'o', 0, 0, "Disjunct predicates." }, - { "not", '!', 0, 0, "Negate the following predicate." }, - { "debug-optparse", OPT_OPTPARSE, 0, 0, "Debug option parsing." }, - { "quiet", 'q', 0, 0, "No output to stdout" }, - { "silent", OPT_SILENT, 0, 0, "No output to stdout" }, + { "exact-match", 'X', 0, 0, "Do an exact match." }, + { "copying", 'C', 0, 0, "Print out the copyright license." }, + { "and", 'a', 0, 0, "Conjunct predicates." }, + { "or", 'o', 0, 0, "Disjunct predicates." }, + { "not", '!', 0, 0, "Negate the following predicate." }, + { "debug-optparse", OPT_OPTPARSE, 0, 0, "Debug option parsing." }, + { "quiet", 'q', 0, 0, "No output to stdout" }, + { "silent", OPT_SILENT, 0, 0, "No output to stdout" }, { 0 } }; -enum state { STATE_ATOM, STATE_NEG, STATE_CONJ, STATE_DISJ, STATE_PAREN, - STATE_START, STATE_FINISHED }; +enum state { STATE_ATOM, STATE_NEG, STATE_CONJ, STATE_DISJ, + STATE_PAREN, STATE_START, STATE_FINISHED }; #define MAX_FNAMES 4096 @@ -130,6 +160,8 @@ struct arguments { size_t num_fnames; /**/ size_t num_show_fields; + /**/ + size_t num_search_fields; /* A machine-readable representation of the predicate. */ struct predicate p; /* Configuration file name */ @@ -147,9 +179,13 @@ struct arguments { /* Invert match? */ bool invert_match; /* Parser stack. */ - struct { + struct stack_elem { enum state state; - int insn; + /* A linked list of instructions. */ + struct insn_node { + int insn; + struct insn_node * next; + } * insns_first, * insns_last; } stack[MAX_OPS]; /* File names seen on the command line. */ char const * fname[MAX_FNAMES]; @@ -158,8 +194,41 @@ struct arguments { char const * name; size_t inx; } show_fields[MAX_FIELDS]; + /* Search field names seen during current atom. */ + char * search_fields[MAX_FIELDS]; }; +struct atom * clone_atom(struct arguments * args) +{ + if (args->p.num_atoms >= MAX_ATOMS) { + message(L_FATAL, "predicate is too complex", 0); + fail(); + } + struct atom * atom = get_current_atom(&args->p); + int push_insn = I_PUSH(args->p.num_atoms); + struct atom * rv = &args->p.atoms[args->p.num_atoms++]; + rv->field_name = atom->field_name; + rv->field_inx = atom->field_inx; + rv->mode = atom->mode; + rv->ignore_case = atom->ignore_case; + rv->pat = atom->pat; + rv->patlen = atom->patlen; + assert(args->top > 0); + struct stack_elem * selem = &args->stack[args->top-1]; + assert(selem->insns_first != 0); + assert(selem->insns_last != 0); + struct insn_node * node1 = malloc(sizeof *node1); + struct insn_node * node2 = malloc(sizeof *node2); + if (node1 == 0 || node2 == 0) fatal_enomem(0); + node1->insn = push_insn; + node2->insn = I_OR; + node1->next = node2; + node2->next = 0; + selem->insns_last->next = node1; + selem->insns_last = node2; + return rv; +} + static void finish_atom(struct arguments * args) { struct atom * atom = get_current_atom(&args->p); @@ -167,10 +236,14 @@ static void finish_atom(struct arguments * args) message(L_FATAL, "A pattern is mandatory.", 0); fail(); } - predicate_finish_atom(&args->p); + for (size_t i = 0; i < args->num_search_fields; i++) { + if (i > 0) atom = clone_atom(args); + atom->field_name = args->search_fields[i]; + predicate_finish_atom(&args->p); + } } -/* Pop off one stack state, inserting the associated instruction to +/* Pop off one stack state, inserting the associated instructions to * the predicate program. If paren is true, current state must be * STATE_PAREN, and if paren is false, it must not be STATE_PAREN. */ static void leave(struct arguments * args, int paren) @@ -180,7 +253,15 @@ static void leave(struct arguments * args, int paren) if (args->state == STATE_ATOM) finish_atom(args); assert(args->top > 0); --args->top; - addinsn(&args->p, args->stack[args->top].insn); + for (struct insn_node * it = args->stack[args->top].insns_first; + it != 0;) { + addinsn(&args->p, it->insn); + struct insn_node * next = it->next; + free(it); + it = next; + } + args->stack[args->top].insns_first = 0; + args->stack[args->top].insns_last = 0; args->state = args->stack[args->top].state; } @@ -192,7 +273,13 @@ static void prim_enter(struct arguments * args, const enum state state, const in message(L_FATAL, "predicate is too complex", 0); fail(); } - args->stack[args->top].insn = insn; +// args->stack[args->top].insn = insn; + struct insn_node * node = malloc(sizeof *node); + if (node == 0) fatal_enomem(0); + node->insn = insn; + node->next = 0; + args->stack[args->top].insns_first = node; + args->stack[args->top].insns_last = node; args->stack[args->top].state = args->state; ++args->top; args->state = state; @@ -264,12 +351,12 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) struct atom * atom; debug_message("parse_opt", 0); switch (key) { - case 'B': + case 'C': + if (!to_stdout (COPYING)) fail(); + exit(0); #ifdef BANNER + case 'B': banner(false); -#else - fprintf(stderr, "Banner is disabled.\n"); - fail(); #endif case 'v': args->invert_match = true; @@ -291,8 +378,9 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) 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]; + 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); sf->inx = fieldtrie_insert(&args->p.trie, s); @@ -301,6 +389,7 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) } ++args->num_show_fields; } + free(carg); } break; case 'l': { @@ -330,34 +419,43 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) debug_message("parse_opt: P", 0); arg = "Package"; /* pass through */ - case 'F': - debug_message("parse_opt: F", 0); + case 'F': { atom = ENTER_ATOM; - if (atom->field_name != 0) { - message(L_FATAL, "multiple -F (or -P) options are " - " currently broken; workaround: --or", 0); - fail(); + char * carg = strdup(arg); + if (carg == 0) fatal_enomem(0); + for (char * s = strtok(carg, ","); s != 0; s = strtok(0, ",")){ + char * tmp = strdup(s); + if (tmp == 0) fatal_enomem(0); + args->search_fields[args->num_search_fields++] = tmp; } -//assert(atom->field_name == 0); /* FIXME */ - atom->field_name = strdup(arg); - if (atom->field_name == 0) fatal_enomem(0); + free(carg); + } break; case 'X': debug_message("parse_opt: X", 0); atom = ENTER_ATOM; - assert(atom->mode == M_SUBSTR); /* FIXME */ + if (atom->mode != M_SUBSTR) { + message(L_FATAL, "inconsistent atom modifiers", 0); + fail(); + } atom->mode = M_EXACT; break; case 'r': debug_message("parse_opt: r", 0); atom = ENTER_ATOM; - assert(atom->mode == M_SUBSTR); /* FIXME */ + if (atom->mode != M_SUBSTR) { + message(L_FATAL, "inconsistent atom modifiers", 0); + fail(); + } atom->mode = M_REGEX; break; case 'e': debug_message("parse_opt: e", 0); atom = ENTER_ATOM; - assert(atom->mode == M_SUBSTR); /* FIXME */ + if (atom->mode != M_SUBSTR) { + message(L_FATAL, "inconsistent atom modifiers", 0); + fail(); + } atom->mode = M_EREGEX; break; case 'i': @@ -369,7 +467,7 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) debug_message("parse_opt: optparse", 0); debug_optparse = 1; break; - case ARGP_KEY_ARG: + case ARGP_KEY_ARG: debug_message("parse_opt: argument", 0); redo: debug_message("!!!", 0); @@ -384,7 +482,7 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) break; } if (strcmp(arg, ")") == 0) { - debug_message("parse_opt: )", 0); + debug_message("parse_opt: )", 0); while (args->state != STATE_PAREN) { if (args->top == 0) { message(L_FATAL, "unexpected ')' in command line", 0); @@ -418,7 +516,7 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) debug_message("parse_opt: end", 0); if (args->state != STATE_FINISHED) FINISH; break; - case ARGP_KEY_ARGS: case ARGP_KEY_INIT: case ARGP_KEY_SUCCESS: + case ARGP_KEY_ARGS: case ARGP_KEY_INIT: case ARGP_KEY_SUCCESS: case ARGP_KEY_ERROR: case ARGP_KEY_FINI: case ARGP_KEY_NO_ARGS: debug_message("parse_opt: ignored", 0); break; @@ -449,10 +547,10 @@ static void dump_args(struct arguments * args) int op = args->p.program[i]; printf("program[%zi] = ", i); switch (op) { - case I_NOP: puts("NOP"); break; - case I_NEG: puts("NEG"); break; - case I_AND: puts("AND"); break; - case I_OR: puts("OR"); break; + case I_NOP: puts("NOP"); break; + case I_NEG: puts("NEG"); break; + case I_AND: puts("AND"); break; + case I_OR: puts("OR"); break; default: printf("PUSH(%i)\n", op - I_PUSH(0)); } diff --git a/predicate.c b/predicate.c index 421079a..3d7dbbd 100644 --- a/predicate.c +++ b/predicate.c @@ -146,7 +146,7 @@ bool does_para_satisfy(struct predicate * p, para_t * para) for (size_t i = 0; i < p->proglen; i++) { switch (p->program[i]) { case I_NOP: break; - case I_NEG: + case I_NEG: assert(sp >= 1); stack[sp-1] = !stack[sp-1]; break; @@ -160,7 +160,7 @@ bool does_para_satisfy(struct predicate * p, para_t * para) stack[sp-2] = stack[sp-2] || stack[sp-1]; --sp; break; - default: + default: { int atom = p->program[i] - I_PUSH(0); assert(atom <= p->num_atoms); diff --git a/predicate.h b/predicate.h index f60a6ea..24f154a 100644 --- a/predicate.h +++ b/predicate.h @@ -27,10 +27,10 @@ #define MAX_OPS 4096 #define MAX_ATOMS 4096 -#define I_NOP 0 -#define I_NEG 1 /* --not; 1-1 */ -#define I_AND 2 /* --and; 2-1 */ -#define I_OR 3 /* --or; 2-1 */ +#define I_NOP 0 +#define I_NEG 1 /* --not; 1-1 */ +#define I_AND 2 /* --and; 2-1 */ +#define I_OR 3 /* --or; 2-1 */ #define I_PUSH(n) (4+(n)) /* push result of nth atomic proposition */ /* An atomic predicate. */ |