diff options
-rw-r--r-- | debian/changelog | 7 | ||||
-rw-r--r-- | fieldtrie.c | 20 | ||||
-rw-r--r-- | fieldtrie.h | 16 | ||||
-rw-r--r-- | grep-dctrl.1.cp | 32 | ||||
-rw-r--r-- | grep-dctrl.c | 66 | ||||
-rw-r--r-- | paragraph.c | 35 | ||||
-rw-r--r-- | paragraph.h | 5 | ||||
-rw-r--r-- | po/ca.po | 130 | ||||
-rw-r--r-- | po/fi.po | 130 | ||||
-rw-r--r-- | predicate.c | 37 | ||||
-rw-r--r-- | predicate.h | 23 | ||||
-rw-r--r-- | strutil.c | 37 | ||||
-rw-r--r-- | strutil.h | 8 |
13 files changed, 394 insertions, 152 deletions
diff --git a/debian/changelog b/debian/changelog index 1f86687..63defa4 100644 --- a/debian/changelog +++ b/debian/changelog @@ -1,3 +1,10 @@ +grep-dctrl (2.3) experimental; urgency=low + + * Add numeric comparison capability + Closes: #157042 (could allow numeric comparison on fields) + + -- Antti-Juhani Kaijanaho <ajk@debian.org> Sun, 18 Jan 2004 00:46:59 +0200 + grep-dctrl (2.2) experimental; urgency=low * This version starts adding features and thus belongs in experimental. diff --git a/fieldtrie.c b/fieldtrie.c index c9e5418..10a7f8b 100644 --- a/fieldtrie.c +++ b/fieldtrie.c @@ -31,33 +31,37 @@ void fieldtrie_init(fieldtrie_t * trie) trie->nextfree = 0; } -size_t fieldtrie_insert(fieldtrie_t * trie, char const * s) +size_t fieldtrie_insert(fieldtrie_t * trie, char const * s, + struct field_attr attr) { size_t slen = strlen(s); - size_t r = fieldtrie_lookup(trie, s, slen); - if (r != -1) return r; + struct field_attr l_attr = fieldtrie_lookup(trie, s, slen); + if (l_attr.valid) return l_attr.inx; 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->inx = trie->nextfree++; + attr.inx = trie->nextfree++; + attr.valid = true; + b->attr = attr; unsigned char c = tolower((unsigned char)(b->name[0])); b->next = trie->fields[c]; trie->fields[c] = b; - return b->inx; + return b->attr.inx; } -size_t fieldtrie_lookup(fieldtrie_t * trie, char const * s, size_t n) +struct field_attr fieldtrie_lookup(fieldtrie_t * trie, 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->inx; + strncasecmp(s, b->name, n) == 0) return b->attr; } - return (size_t)(-1); + return (struct field_attr){ .valid = false }; } void fieldtrie_clear(fieldtrie_t * trie) diff --git a/fieldtrie.h b/fieldtrie.h index 93bf88c..a77466e 100644 --- a/fieldtrie.h +++ b/fieldtrie.h @@ -1,5 +1,5 @@ /* dctrl-tools - Debian control file inspection tools - Copyright (C) 2003 Antti-Juhani Kaijanaho + Copyright (C) 2003, 2004 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 @@ -21,11 +21,18 @@ #include <limits.h> #include <stddef.h> +#include <stdbool.h> + +struct field_attr { + bool valid : 1; + bool numeric : 1; + size_t inx; +}; struct field_bucket { char const * name; size_t namelen; - size_t inx; + struct field_attr attr; struct field_bucket * next; }; @@ -41,11 +48,10 @@ typedef struct fieldtrie_private fieldtrie_t; void fieldtrie_init(fieldtrie_t *); // case-insensitive -size_t fieldtrie_insert(fieldtrie_t *, char const *); +size_t fieldtrie_insert(fieldtrie_t *, char const *, struct field_attr); // case-insensitive -// (size_t)(-1) if failed -size_t fieldtrie_lookup(fieldtrie_t *, char const *, size_t n); +struct field_attr fieldtrie_lookup(fieldtrie_t *, char const *, size_t n); void fieldtrie_clear(fieldtrie_t *); diff --git a/grep-dctrl.1.cp b/grep-dctrl.1.cp index a315255..5cd5185 100644 --- a/grep-dctrl.1.cp +++ b/grep-dctrl.1.cp @@ -1,4 +1,4 @@ -.TH GREP-DCTRL 1 2004-01-16 "Debian Project" "Debian user's manual" +.TH GREP-DCTRL 1 2004-01-19 "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 @@ -136,6 +136,36 @@ Ignore case when looking for a match in the current atomic predicate. .IP "-X, --exact-match" Do an exact match (as opposed to a substring match) in the current atomic predicate. +.IP "--eq" +Use numeric equality in matching. The pattern must be an integer +literal. Any paragraphs where the field to be searched in does not +parse as an integer literal are regarded as not matching. Note that +using numeric comparison when looking at full paragraphs does not make +sense. +.IP "--lt" +Use numeric strictly-less-than comparison in matching. The pattern +must be an integer literal. Any paragraphs where the field to be +searched in does not parse as an integer literal are regarded as not +matching. Note that using numeric comparison when looking at full +paragraphs does not make sense. +.IP "--le" +Use numeric less-than-or-equal comparison in matching. The pattern +must be an integer literal. Any paragraphs where the field to be +searched in does not parse as an integer literal are regarded as not +matching. Note that using numeric comparison when looking at full +paragraphs does not make sense. +.IP "--gt" +Use numeric strictly-greater-than comparison in matching. The pattern +must be an integer literal. Any paragraphs where the field to be +searched in does not parse as an integer literal are regarded as not +matching. Note that using numeric comparison when looking at full +paragraphs does not make sense. +.IP "--ge" +Use numeric greater-than-or-equal comparison in matching. The pattern +must be an integer literal. Any paragraphs where the field to be +searched in does not parse as an integer literal are regarded as not +matching. Note that using numeric comparison when looking at full +paragraphs does not make sense. .SS Predicate connectives .IP "-!, --not, !" Negate the following predicate. diff --git a/grep-dctrl.c b/grep-dctrl.c index bdc3be9..0724438 100644 --- a/grep-dctrl.c +++ b/grep-dctrl.c @@ -46,6 +46,11 @@ static char progdoc [] = N_("grep-dctrl -- grep Debian control files"); #define OPT_CONFIG 256 #define OPT_OPTPARSE 257 #define OPT_SILENT 258 +#define OPT_EQ 259 +#define OPT_LT 260 +#define OPT_LE 261 +#define OPT_GT 262 +#define OPT_GE 263 #undef BANNER @@ -139,6 +144,11 @@ static struct argp_option options[] = { { "and", 'a', 0, 0, N_("Conjunct predicates.") }, { "or", 'o', 0, 0, N_("Disjunct predicates.") }, { "not", '!', 0, 0, N_("Negate the following predicate.") }, + { "eq", OPT_EQ, 0, 0, N_("Test for numerical equality.") }, + { "lt", OPT_LT, 0, 0, N_("Numerical test: <.") }, + { "le", OPT_LE, 0, 0, N_("Numerical test: <=.") }, + { "gt", OPT_GT, 0, 0, N_("Numerical test: >.") }, + { "ge", OPT_GE, 0, 0, N_("Numerical test: >=.") }, { "debug-optparse", OPT_OPTPARSE, 0, 0, N_("Debug option parsing.") }, { "quiet", 'q', 0, 0, N_("No output to stdout") }, { "silent", OPT_SILENT, 0, 0, N_("No output to stdout") }, @@ -355,6 +365,15 @@ static struct atom * enter_atom(struct arguments * args, bool just_seen_cparen) return rv; } +#define set_mode(nmode) do { \ + atom = ENTER_ATOM; \ + if (atom->mode != M_SUBSTR) { \ + message(L_FATAL, _("inconsistent atom modifiers"), 0); \ + fail(); \ + } \ + atom->mode = (nmode); \ +} while (0) + static error_t parse_opt (int key, char * arg, struct argp_state * state) { struct arguments * args = state->input; @@ -395,7 +414,8 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) &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); + struct field_attr fa = { .numeric = false }; + sf->inx = fieldtrie_insert(&args->p.trie, s, fa); if (sf->inx == description_inx) { args->description_selected = true; } @@ -445,30 +465,35 @@ static error_t parse_opt (int key, char * arg, struct argp_state * state) break; case 'X': debug_message("parse_opt: X", 0); - atom = ENTER_ATOM; - if (atom->mode != M_SUBSTR) { - message(L_FATAL, _("inconsistent atom modifiers"), 0); - fail(); - } - atom->mode = M_EXACT; + set_mode(M_EXACT); break; case 'r': debug_message("parse_opt: r", 0); - atom = ENTER_ATOM; - if (atom->mode != M_SUBSTR) { - message(L_FATAL, _("inconsistent atom modifiers"), 0); - fail(); - } - atom->mode = M_REGEX; + set_mode(M_REGEX); break; case 'e': debug_message("parse_opt: e", 0); - atom = ENTER_ATOM; - if (atom->mode != M_SUBSTR) { - message(L_FATAL, "inconsistent atom modifiers", 0); - fail(); - } - atom->mode = M_EREGEX; + set_mode(M_EREGEX); + break; + case OPT_EQ: + debug_message("parse_opt: eq", 0); + set_mode(M_NUM_EQ); + break; + case OPT_LT: + debug_message("parse_opt: lt", 0); + set_mode(M_NUM_LT); + break; + case OPT_LE: + debug_message("parse_opt: le", 0); + set_mode(M_NUM_LE); + break; + case OPT_GT: + debug_message("parse_opt: gt", 0); + set_mode(M_NUM_GT); + break; + case OPT_GE: + debug_message("parse_opt: ge", 0); + set_mode(M_NUM_GE); break; case 'i': debug_message("parse_opt: i", 0); @@ -684,7 +709,8 @@ int main (int argc, char * argv[]) args.show_field_name = true; msg_set_progname(argv[0]); init_predicate(&args.p); - description_inx = fieldtrie_insert(&args.p.trie, description); + struct field_attr fa = { .numeric = false }; + description_inx = fieldtrie_insert(&args.p.trie, description, fa); argp_parse (&argp, argc, argv, ARGP_IN_ORDER, 0, &args); #ifdef BANNER banner(true); diff --git a/paragraph.c b/paragraph.c index 4a60d72..91362de 100644 --- a/paragraph.c +++ b/paragraph.c @@ -1,5 +1,5 @@ /* dctrl-tools - Debian control file inspection tools - Copyright (C) 2003 Antti-Juhani Kaijanaho + Copyright (C) 2003, 2004 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 @@ -18,12 +18,28 @@ #include "msg.h" #include "paragraph.h" +#include "strutil.h" -void para_init(para_t * para, FSAF * fp, fieldtrie_t * trie) +static +void parse_int(FSAF * fp, struct field_data * fd) +{ + const size_t len = fd->end - fd->start; + struct fsaf_read_rv rd = fsaf_read(fp, fd->start, len); + assert(rd.len == len); + fd->int_valid = false; + bool ok = str2intmax(&fd->parsed, rd.b, len); + if (!ok) { + message(L_INFORMATIONAL, _("parse of a numeric field failed"), + 0); + } + fd->int_valid = ok; +} + +void para_init(para_t * para, FSAF * fp, fieldtrie_t * trie) { para->fp = fp; para->trie = trie; - para->start = 0; + para->start = 0; para->end = 0; para->eof = false; para_parse_next(para); @@ -36,6 +52,7 @@ void para_parse_next(para_t * para) for (size_t i = 0; i < fieldtrie_count(para->trie); i++) { para->fields[i].start = 0; para->fields[i].end = 0; + para->fields[i].int_valid = 0; } fsaf_invalidate(para->fp, para->start); register enum { START, FIELD_NAME, BODY, BODY_NEWLINE, @@ -76,12 +93,13 @@ void para_parse_next(para_t * para) size_t len = (pos-1) - field_start; struct fsaf_read_rv r = fsaf_read(fp, field_start, len); assert(r.len == len); - size_t inx = fieldtrie_lookup(para->trie, r.b, len); - if (inx == -1) { + struct field_attr attr = + fieldtrie_lookup(para->trie, r.b, len); + if (!attr.valid) { field_data = 0; } else { - assert(inx < MAX_FIELDS); - field_data = ¶->fields[inx]; + assert(attr.inx < MAX_FIELDS); + field_data = ¶->fields[attr.inx]; field_data->start = pos; } state = BODY; @@ -104,6 +122,7 @@ void para_parse_next(para_t * para) && fsaf_getc(fp, field_data->start) == ' ') { ++field_data->start; } + parse_int(fp, field_data); } state = BODY_NEWLINE; break; @@ -111,7 +130,7 @@ void para_parse_next(para_t * para) break; case BODY_NEWLINE: switch (c) { - case -1: + case -1: //para->eof = true; /* pass through */ case '\n': diff --git a/paragraph.h b/paragraph.h index a4e15fc..bea414d 100644 --- a/paragraph.h +++ b/paragraph.h @@ -22,11 +22,14 @@ #define MAX_FIELDS 100 #include <stddef.h> +#include <stdint.h> #include "fsaf.h" #include "fieldtrie.h" struct field_data { size_t start, end; /* offsets to the file; [start,end) is the body */ + bool int_valid; /* whether .parsed is valid */ + intmax_t parsed; /* a parsed value for the data */ }; struct paragraph_private { @@ -34,7 +37,7 @@ struct paragraph_private { fieldtrie_t * trie; bool eof; - // CURRENT PARAGRAPH PARSED + // CURRENT PARAGRAPH PARSED size_t start, end; /* offsets to the file; [start,end) is the paragraph */ struct field_data fields[MAX_FIELDS]; @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: dctrl-tools\n" "Report-Msgid-Bugs-To: ajk@debian.org\n" -"POT-Creation-Date: 2004-01-16 03:00+0200\n" +"POT-Creation-Date: 2004-01-18 00:35+0200\n" "PO-Revision-Date: 2004-01-13 13:31+0100\n" "Last-Translator: Jordi Mallach <jordi@debian.org>\n" "Language-Team: Catalan <debian-l10n-catalan@lists.debian.org>\n" @@ -19,35 +19,35 @@ msgstr "" msgid "grep-dctrl -- grep Debian control files" msgstr "grep-dctrl -- cerca patrons en fitxers de control de Debian" -#: grep-dctrl.c:123 +#: grep-dctrl.c:128 msgid "Show the testing banner." msgstr "Mostra l'avís de prova." -#: grep-dctrl.c:125 +#: grep-dctrl.c:130 msgid "LEVEL" msgstr "NIVELL" -#: grep-dctrl.c:125 +#: grep-dctrl.c:130 msgid "Set debugging level to LEVEL." msgstr "Estableix el nivell de depuració a NIVELL." -#: grep-dctrl.c:126 grep-dctrl.c:128 +#: grep-dctrl.c:131 grep-dctrl.c:133 msgid "FIELD,FIELD,..." msgstr "CAMP,CAMP,..." -#: grep-dctrl.c:126 +#: grep-dctrl.c:131 msgid "Restrict pattern matching to the FIELDs given." msgstr "Restringeix la coincidència de patrons als CAMPs donats." -#: grep-dctrl.c:127 +#: grep-dctrl.c:132 msgid "Shorthand for -FPackage" msgstr "Forma curta per a -FPackage" -#: grep-dctrl.c:128 +#: grep-dctrl.c:133 msgid "Show only the body of these fields from the matching paragraphs." msgstr "Mostra només el cos d'aquests camps dels paràgrafs coincidents." -#: grep-dctrl.c:129 +#: grep-dctrl.c:134 msgid "" "Show only the first line of the \"Description\" field from the matching " "paragraphs." @@ -55,167 +55,195 @@ msgstr "" "Mostra només la primera línia del camp «Description» dels paràgrafs " "coincidents." -#: grep-dctrl.c:130 +#: grep-dctrl.c:135 msgid "Suppress field names when showing specified fields." msgstr "Suprimeix els noms dels camps quan mostra els camps especificats." -#: grep-dctrl.c:131 +#: grep-dctrl.c:136 msgid "Regard the pattern as an extended POSIX regular expression." msgstr "Considera el patró com una expressió regular estesa POSIX." -#: grep-dctrl.c:132 +#: grep-dctrl.c:137 msgid "The pattern is a standard POSIX regular expression." msgstr "El patró és una expressió regular estàndard POSIX." -#: grep-dctrl.c:133 +#: grep-dctrl.c:138 msgid "Ignore case when looking for a match." msgstr "" "No distigueixes entre majúscules i minúscules quan cerca una coincidència." -#: grep-dctrl.c:134 +#: grep-dctrl.c:139 msgid "Show only paragraphs that do not match." msgstr "Mostra només els paràgrafs que no coincideixen." -#: grep-dctrl.c:135 +#: grep-dctrl.c:140 msgid "Show only the count of matching paragraphs." msgstr "Mostra només el compte de paràgrafs coincidents." -#: grep-dctrl.c:136 +#: grep-dctrl.c:141 msgid "FNAME" msgstr "NOMFITXER" -#: grep-dctrl.c:136 +#: grep-dctrl.c:141 msgid "Use FNAME as the config file." msgstr "Utilitza NOMFITXER com el fitxer de configuració." -#: grep-dctrl.c:137 +#: grep-dctrl.c:142 msgid "Do an exact match." msgstr "Fes una coincidència exacta." -#: grep-dctrl.c:138 +#: grep-dctrl.c:143 msgid "Print out the copyright license." msgstr "Mostra la llicència del copyright." -#: grep-dctrl.c:139 +#: grep-dctrl.c:144 msgid "Conjunct predicates." msgstr "Predicats conjunts." -#: grep-dctrl.c:140 +#: grep-dctrl.c:145 msgid "Disjunct predicates." msgstr "Predicats disjunts." -#: grep-dctrl.c:141 +#: grep-dctrl.c:146 msgid "Negate the following predicate." msgstr "Nega el següent predicat." -#: grep-dctrl.c:142 +#: grep-dctrl.c:147 +msgid "Test for numerical equality." +msgstr "" + +#: grep-dctrl.c:148 +msgid "Numerical test: <." +msgstr "" + +#: grep-dctrl.c:149 +msgid "Numerical test: <=." +msgstr "" + +#: grep-dctrl.c:150 +msgid "Numerical test: >." +msgstr "" + +#: grep-dctrl.c:151 +msgid "Numerical test: >=." +msgstr "" + +#: grep-dctrl.c:152 msgid "Debug option parsing." msgstr "Depura l'anàlisi d'opcions." -#: grep-dctrl.c:143 grep-dctrl.c:144 +#: grep-dctrl.c:153 grep-dctrl.c:154 msgid "No output to stdout" msgstr "No mostra res a l'eixida estàndard" -#: grep-dctrl.c:208 grep-dctrl.c:278 grep-dctrl.c:344 predicate.c:39 +#: grep-dctrl.c:218 grep-dctrl.c:288 grep-dctrl.c:354 predicate.c:40 msgid "predicate is too complex" msgstr "el predicat és massa complex" -#: grep-dctrl.c:240 +#: grep-dctrl.c:250 msgid "A pattern is mandatory." msgstr "Es necessita un patró." -#: grep-dctrl.c:299 +#: grep-dctrl.c:309 msgid "syntax error in command line" msgstr "hi ha un error de sintaxi a la línia d'ordres" -#: grep-dctrl.c:316 +#: grep-dctrl.c:326 msgid "missing ')' in command line" msgstr "manca un «)» en la línia d'ordres" -#: grep-dctrl.c:334 +#: grep-dctrl.c:344 msgid "Unexpected atom in command line. Did you forget to use a connective?" msgstr "" "S'ha trobat un àtom inesperat en la línia d'ordres. Heu oblidat utilitzar un " "connector?" -#: grep-dctrl.c:411 -msgid "no such log level" -msgstr "aquest nivell de registre no existeix" - -#: grep-dctrl.c:450 grep-dctrl.c:459 +#: grep-dctrl.c:371 msgid "inconsistent atom modifiers" msgstr "els modificadors d'àtom no són consistents" -#: grep-dctrl.c:500 +#: grep-dctrl.c:431 +msgid "no such log level" +msgstr "aquest nivell de registre no existeix" + +#: grep-dctrl.c:525 msgid "unexpected ')' in command line" msgstr "s'ha trobat un «)» inesperat a la línia d'ordres" -#: grep-dctrl.c:512 +#: grep-dctrl.c:537 msgid "too many file names" msgstr "hi ha massa noms de fitxers" -#: grep-dctrl.c:592 +#: grep-dctrl.c:617 #, c-format msgid "%s: command (%s) failed (exit status %d)\n" msgstr "" -#: grep-dctrl.c:601 +#: grep-dctrl.c:626 #, c-format msgid "%s: command (%s) was killed by signal %d\n" msgstr "" -#: grep-dctrl.c:639 +#: grep-dctrl.c:664 #, c-format msgid "%s (child): failed to exec /bin/sh: %s\n" msgstr "" -#: grep-dctrl.c:696 +#: grep-dctrl.c:722 msgid "a predicate is required" msgstr "es requereix un predicat" -#: grep-dctrl.c:702 +#: grep-dctrl.c:728 msgid "too many output fields" msgstr "hi ha massa camps d'eixida" -#: grep-dctrl.c:706 +#: grep-dctrl.c:732 msgid "Adding \"Description\" to selected output fields because of -d" msgstr "" "S'està afegint «Description» als camps d'eixida seleccionats a causa de -d" -#: grep-dctrl.c:715 +#: grep-dctrl.c:741 msgid "cannot suppress field names when showing whole paragraphs" msgstr "no es pot suprimir els noms de camp quan es mostren paràgrafs sencers" -#: grep-dctrl.c:749 +#: grep-dctrl.c:775 #, c-format msgid "%s: %s: cannot stat: %s\n" msgstr "%s: %s: no es pot fer stat(): %s\n" -#: grep-dctrl.c:758 +#: grep-dctrl.c:784 msgid "is a directory, skipping" msgstr "és un directori, s'està ometent" -#: grep-dctrl.c:759 +#: grep-dctrl.c:785 msgid "is a block device, skipping" msgstr "és un dispositiu de bloc, s'està ometent" -#: grep-dctrl.c:760 +#: grep-dctrl.c:786 msgid "internal error" msgstr "s'ha produït un error intern" -#: grep-dctrl.c:761 +#: grep-dctrl.c:787 msgid "is a socket, skipping" msgstr "és un sòcol, s'està ometent" -#: grep-dctrl.c:762 +#: grep-dctrl.c:788 msgid "unknown file type, skipping" msgstr "el tipus de fitxer és desconegut, s'està ometent" -#: paragraph.c:73 paragraph.c:98 +#: predicate.c:76 +msgid "invalid numeric pattern" +msgstr "" + +#: paragraph.c:32 +msgid "parse of a numeric field failed" +msgstr "" + +#: paragraph.c:90 paragraph.c:116 msgid "unexpected end of file" msgstr "s'ha trobat un final de fitxer inesperat" -#: paragraph.c:91 +#: paragraph.c:109 msgid "unexpected end of line" msgstr "s'ha trobat un final de línia inesperat" @@ -7,7 +7,7 @@ msgid "" msgstr "" "Project-Id-Version: dctrl-tools\n" "Report-Msgid-Bugs-To: ajk@debian.org\n" -"POT-Creation-Date: 2004-01-16 03:00+0200\n" +"POT-Creation-Date: 2004-01-18 00:35+0200\n" "PO-Revision-Date: 2004-01-13 00:50+0200\n" "Last-Translator: Antti-Juhani Kaijanaho <ajk@debian.org>\n" "Language-Team: Finnish <debian-l10n-finnish@lists.debian.org>\n" @@ -19,199 +19,227 @@ msgstr "" msgid "grep-dctrl -- grep Debian control files" msgstr "grep-dctrl -- hae Debianin kontrollitiedostoista" -#: grep-dctrl.c:123 +#: grep-dctrl.c:128 msgid "Show the testing banner." msgstr "Näytä testausviesti." -#: grep-dctrl.c:125 +#: grep-dctrl.c:130 msgid "LEVEL" msgstr "TASO" -#: grep-dctrl.c:125 +#: grep-dctrl.c:130 msgid "Set debugging level to LEVEL." msgstr "Aseta vianetsintätasoksi TASO." -#: grep-dctrl.c:126 grep-dctrl.c:128 +#: grep-dctrl.c:131 grep-dctrl.c:133 msgid "FIELD,FIELD,..." msgstr "KENTTÄ,KENTT�,..." -#: grep-dctrl.c:126 +#: grep-dctrl.c:131 msgid "Restrict pattern matching to the FIELDs given." msgstr "Rajoita haku annettuihin KENTTIIN." -#: grep-dctrl.c:127 +#: grep-dctrl.c:132 msgid "Shorthand for -FPackage" msgstr "Lyhyt muoto vivulle -FPackage" -#: grep-dctrl.c:128 +#: grep-dctrl.c:133 msgid "Show only the body of these fields from the matching paragraphs." msgstr "Näytä vain näiden kenttien sisältö täsmäävissä tietueissa" -#: grep-dctrl.c:129 +#: grep-dctrl.c:134 msgid "" "Show only the first line of the \"Description\" field from the matching " "paragraphs." msgstr "" "Näytä täsmäävien tietueiden \"Description\"-kentästä vain ensimmäinen rivi." -#: grep-dctrl.c:130 +#: grep-dctrl.c:135 msgid "Suppress field names when showing specified fields." msgstr "Älä näytä kenttien nimiä silloin kun haetaan vain tietyistä kentistä." -#: grep-dctrl.c:131 +#: grep-dctrl.c:136 msgid "Regard the pattern as an extended POSIX regular expression." msgstr "Käsittele hakuehtoa laajennettuna POSIXin siäännöllisenä lausekkeena." -#: grep-dctrl.c:132 +#: grep-dctrl.c:137 msgid "The pattern is a standard POSIX regular expression." msgstr "Hakuehto on tavallinen POSIXin säännöllinen lauseke." -#: grep-dctrl.c:133 +#: grep-dctrl.c:138 msgid "Ignore case when looking for a match." msgstr "Jätä kirjainkoko huomiotta haussa." -#: grep-dctrl.c:134 +#: grep-dctrl.c:139 msgid "Show only paragraphs that do not match." msgstr "Näytä vain ne tietueet, jotka eivät täsmää." -#: grep-dctrl.c:135 +#: grep-dctrl.c:140 msgid "Show only the count of matching paragraphs." msgstr "Näytä vain täsmäävien tietueiden lukumäärä." -#: grep-dctrl.c:136 +#: grep-dctrl.c:141 msgid "FNAME" msgstr "TIEDNIMI" -#: grep-dctrl.c:136 +#: grep-dctrl.c:141 msgid "Use FNAME as the config file." msgstr "Käytä TIEDNIMI-tiedostoa asetustiedostona." -#: grep-dctrl.c:137 +#: grep-dctrl.c:142 msgid "Do an exact match." msgstr "Käytä täsmällistä hakua." -#: grep-dctrl.c:138 +#: grep-dctrl.c:143 msgid "Print out the copyright license." msgstr "Tulosta tekijänoikeuslisenssi." -#: grep-dctrl.c:139 +#: grep-dctrl.c:144 msgid "Conjunct predicates." msgstr "Yhdistä predikaatit JA-konnektiivilla" -#: grep-dctrl.c:140 +#: grep-dctrl.c:145 msgid "Disjunct predicates." msgstr "Yhdistä predikaatit TAI-konnektiivilla" -#: grep-dctrl.c:141 +#: grep-dctrl.c:146 msgid "Negate the following predicate." msgstr "Negatoi seuraava predikaatti." -#: grep-dctrl.c:142 +#: grep-dctrl.c:147 +msgid "Test for numerical equality." +msgstr "" + +#: grep-dctrl.c:148 +msgid "Numerical test: <." +msgstr "" + +#: grep-dctrl.c:149 +msgid "Numerical test: <=." +msgstr "" + +#: grep-dctrl.c:150 +msgid "Numerical test: >." +msgstr "" + +#: grep-dctrl.c:151 +msgid "Numerical test: >=." +msgstr "" + +#: grep-dctrl.c:152 msgid "Debug option parsing." msgstr "Testaa valitsimien jäsennyst�." -#: grep-dctrl.c:143 grep-dctrl.c:144 +#: grep-dctrl.c:153 grep-dctrl.c:154 msgid "No output to stdout" msgstr "Älä tulosta mitään vakiotulostevirtaan" -#: grep-dctrl.c:208 grep-dctrl.c:278 grep-dctrl.c:344 predicate.c:39 +#: grep-dctrl.c:218 grep-dctrl.c:288 grep-dctrl.c:354 predicate.c:40 msgid "predicate is too complex" msgstr "predikaatti on liian monimutkainen" -#: grep-dctrl.c:240 +#: grep-dctrl.c:250 msgid "A pattern is mandatory." msgstr "Hakuehto on välttämätön." -#: grep-dctrl.c:299 +#: grep-dctrl.c:309 msgid "syntax error in command line" msgstr "komentorivillä on syntaksivirhe" -#: grep-dctrl.c:316 +#: grep-dctrl.c:326 msgid "missing ')' in command line" msgstr "komentoriviltä puuttuu ')'" -#: grep-dctrl.c:334 +#: grep-dctrl.c:344 msgid "Unexpected atom in command line. Did you forget to use a connective?" msgstr "Odottamaton atomi komentorivillä. Unohditko konnektiivin jostain?" -#: grep-dctrl.c:411 -msgid "no such log level" -msgstr "ei sellaista seurantatasoa ole" - -#: grep-dctrl.c:450 grep-dctrl.c:459 +#: grep-dctrl.c:371 msgid "inconsistent atom modifiers" msgstr "ristitiitaiset atomin määritteet" -#: grep-dctrl.c:500 +#: grep-dctrl.c:431 +msgid "no such log level" +msgstr "ei sellaista seurantatasoa ole" + +#: grep-dctrl.c:525 msgid "unexpected ')' in command line" msgstr "odottamaton ')' komentorivill�" -#: grep-dctrl.c:512 +#: grep-dctrl.c:537 msgid "too many file names" msgstr "liikaa tiedostonimiä" -#: grep-dctrl.c:592 +#: grep-dctrl.c:617 #, c-format msgid "%s: command (%s) failed (exit status %d)\n" msgstr "" -#: grep-dctrl.c:601 +#: grep-dctrl.c:626 #, c-format msgid "%s: command (%s) was killed by signal %d\n" msgstr "" -#: grep-dctrl.c:639 +#: grep-dctrl.c:664 #, c-format msgid "%s (child): failed to exec /bin/sh: %s\n" msgstr "" -#: grep-dctrl.c:696 +#: grep-dctrl.c:722 msgid "a predicate is required" msgstr "predikaatti on välttämätön" -#: grep-dctrl.c:702 +#: grep-dctrl.c:728 msgid "too many output fields" msgstr "liikaa tulostettavia kenttiä" -#: grep-dctrl.c:706 +#: grep-dctrl.c:732 msgid "Adding \"Description\" to selected output fields because of -d" msgstr "Merkitsen \"Description\"-kentän tulostettavaksi -d-valitsimen takia" -#: grep-dctrl.c:715 +#: grep-dctrl.c:741 msgid "cannot suppress field names when showing whole paragraphs" msgstr "" "en voi jättää näyttämättä kenttien nimiä, kun näytän kokonaisia tietueita" -#: grep-dctrl.c:749 +#: grep-dctrl.c:775 #, c-format msgid "%s: %s: cannot stat: %s\n" msgstr "%s: %s: stat-kutsu epäonnistui: %s\n" -#: grep-dctrl.c:758 +#: grep-dctrl.c:784 msgid "is a directory, skipping" msgstr "on hakemisto, jätän huomiotta" -#: grep-dctrl.c:759 +#: grep-dctrl.c:785 msgid "is a block device, skipping" msgstr "on lohkolaite, jätän huomiotta" -#: grep-dctrl.c:760 +#: grep-dctrl.c:786 msgid "internal error" msgstr "ohjelman oma virhe" -#: grep-dctrl.c:761 +#: grep-dctrl.c:787 msgid "is a socket, skipping" msgstr "on pistoke, jätän huomiotta" -#: grep-dctrl.c:762 +#: grep-dctrl.c:788 msgid "unknown file type, skipping" msgstr "tuntematon tiedostotyyppi, jätän huomiotta" -#: paragraph.c:73 paragraph.c:98 +#: predicate.c:76 +msgid "invalid numeric pattern" +msgstr "" + +#: paragraph.c:32 +msgid "parse of a numeric field failed" +msgstr "" + +#: paragraph.c:90 paragraph.c:116 msgid "unexpected end of file" msgstr "odottamaton tiedoston loppu" -#: paragraph.c:91 +#: paragraph.c:109 msgid "unexpected end of line" msgstr "odottamaton rivin loppu" diff --git a/predicate.c b/predicate.c index 006ac42..0cf4473 100644 --- a/predicate.c +++ b/predicate.c @@ -24,6 +24,7 @@ #include "msg.h" #include "util.h" #include "predicate.h" +#include "strutil.h" void init_predicate(struct predicate * p) { @@ -45,8 +46,12 @@ void addinsn(struct predicate * p, int insn) void predicate_finish_atom(struct predicate * p) { struct atom * atom = get_current_atom(p); + bool numeric = M_FIRST_NUMERIC <= atom->mode + && atom->mode <= M_LAST_NUMERIC; if (atom->field_name != 0) { - atom->field_inx = fieldtrie_insert(&p->trie, atom->field_name); + struct field_attr fa = { .numeric = numeric }; + atom->field_inx = fieldtrie_insert(&p->trie, atom->field_name, + fa); } if (atom->mode == M_REGEX || atom->mode == M_EREGEX) { @@ -63,20 +68,35 @@ void predicate_finish_atom(struct predicate * p) fail(); } } + + if (numeric) { + bool ok = str2intmax(&atom->intpat, atom->pat, + atom->patlen); + if (!ok) { + message(L_FATAL, _("invalid numeric pattern"), 0); + fail(); + } + } } static bool verify_atom(struct atom * atom, para_t * para) { size_t start, end; + intmax_t intval, intpat = atom->intpat; + bool int_valid; if (atom->field_inx == -1) { /* Take the full paragraph */ start = para->start; end = para->end; + intval = 0; + int_valid = false; } else { /* Take the field */ struct field_data * fd = ¶->fields[atom->field_inx]; start = fd->start; end = fd->end; + intval = fd->parsed; + int_valid = fd->int_valid; } size_t len = end - start; struct fsaf_read_rv r = fsaf_read(para->fp, start, len); @@ -125,6 +145,21 @@ static bool verify_atom(struct atom * atom, para_t * para) free(s); return false; } + case M_NUM_EQ: + if (!int_valid) return false; + return intpat == intval; + case M_NUM_LT: + if (!int_valid) return false; + return intpat > intval; + case M_NUM_LE: + if (!int_valid) return false; + return intpat >= intval; + case M_NUM_GT: + if (!int_valid) return false; + return intpat < intval; + case M_NUM_GE: + if (!int_valid) return false; + return intpat <= intval; } assert(0); } diff --git a/predicate.h b/predicate.h index 24f154a..8f43b17 100644 --- a/predicate.h +++ b/predicate.h @@ -1,5 +1,5 @@ /* dctrl-tools - Debian control file inspection tools - Copyright (C) 2003 Antti-Juhani Kaijanaho + Copyright (C) 2003, 2004 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 @@ -21,6 +21,7 @@ #include <assert.h> #include <regex.h> +#include <stdint.h> #include "fieldtrie.h" #include "paragraph.h" @@ -40,16 +41,26 @@ struct atom { * field_inx is -1. */ char const * field_name; size_t field_inx; /* Matching mode */ - enum { M_SUBSTR, /* substring matching */ - M_REGEX, /* POSIX regular expression match */ - M_EREGEX, /* POSIX extended regular expression matching */ - M_EXACT /* exact match */ - } mode; + enum matching_mode { + M_SUBSTR, /* substring matching */ + M_REGEX, /* POSIX regular expression match */ + M_EREGEX, /* POSIX extended regular expression matching */ + M_EXACT, /* exact string match */ +#define M_FIRST_NUMERIC M_NUM_EQ + M_NUM_EQ, /* numeric equality comparison */ + M_NUM_LT, /* numeric < */ + M_NUM_LE, /* numeric <= */ + M_NUM_GT, /* numeric > */ + M_NUM_GE, /* numeric >= */ +#define M_LAST_NUMERIC M_NUM_GE + } mode; /* Flag: should matching ignore case */ unsigned ignore_case; /* The pattern as given on the command line; interpretation * depends on matching mode. */ char const * pat; size_t patlen; + /* A parsed value of an integer pattern */ + intmax_t intpat; /* A compiled version of pat; valid only when mode is M_REGEX * or M_EREGEX. */ regex_t regex; @@ -19,6 +19,43 @@ #include <ctype.h> #include "strutil.h" +bool str2intmax(intmax_t * rvp, char const * s, size_t len) +{ + bool negative = false; + size_t i = 0; + while (i < len + && s[i] == ' ' + && s[i] == '\t' + && s[i] == '\n' + && s[i] == '\r') + ++i; + if (i < len && s[i] == '-') { + ++i; + negative = true; + } + uintmax_t abs = 0; + for (; i < len; ++i) { + char ch = s[i]; + if (! ('0' <= ch && ch <= '9')) { + break; + } + int r = ch - '0'; + abs = abs * 10 + r; + if (abs > (uintmax_t)INTMAX_MAX) { + return false; + } + } + while (i < len + && s[i] == ' ' + && s[i] == '\t' + && s[i] == '\n' + && s[i] == '\r') + ++i; + if (i < len) return false; // broken input + *rvp = negative ? -abs : abs; + return true; +} + const char * left_trimmed(const char * s) { const char * p; @@ -20,7 +20,15 @@ #ifndef STRUTIL_H__ #define STRUTIL_H__ +#include <stddef.h> #include <string.h> +#include <stdbool.h> +#include <stdint.h> + +/* Parse an integer from the (possibly not null-terminated) string s + * of length len, and place the result in *rvp. If return value is + * false, *rvp is untouched. */ +bool str2intmax(intmax_t * rvp, char const * s, size_t len); /* Return a pointer to first nonblank character in s. */ const char * left_trimmed(const char * s); |