summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--debian/changelog7
-rw-r--r--fieldtrie.c20
-rw-r--r--fieldtrie.h16
-rw-r--r--grep-dctrl.1.cp32
-rw-r--r--grep-dctrl.c66
-rw-r--r--paragraph.c35
-rw-r--r--paragraph.h5
-rw-r--r--po/ca.po130
-rw-r--r--po/fi.po130
-rw-r--r--predicate.c37
-rw-r--r--predicate.h23
-rw-r--r--strutil.c37
-rw-r--r--strutil.h8
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 = &para->fields[inx];
+ assert(attr.inx < MAX_FIELDS);
+ field_data = &para->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];
diff --git a/po/ca.po b/po/ca.po
index d684ee8..e8e6446 100644
--- a/po/ca.po
+++ b/po/ca.po
@@ -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"
diff --git a/po/fi.po b/po/fi.po
index 5976aa9..83791b3 100644
--- a/po/fi.po
+++ b/po/fi.po
@@ -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 = &para->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;
diff --git a/strutil.c b/strutil.c
index 4d729f6..3f5cd77 100644
--- a/strutil.c
+++ b/strutil.c
@@ -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;
diff --git a/strutil.h b/strutil.h
index e0c38a1..c442169 100644
--- a/strutil.h
+++ b/strutil.h
@@ -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);