mirror of
https://git.savannah.gnu.org/git/gperf.git
synced 2025-12-02 21:19:24 +00:00
Fix the comparison of the first byte when using gperf_case_strcmp.
This commit is contained in:
14
ChangeLog
14
ChangeLog
@@ -1,3 +1,17 @@
|
||||
2003-01-01 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
* src/output.c (Output_Compare::output_firstchar_comparison): New
|
||||
method.
|
||||
(Output_Compare_Strcmp::output_comparison,
|
||||
Output_Compare_Strncmp::output_comparison,
|
||||
Output_Compare_Memcmp::output_comparison): Use it.
|
||||
* tests/permutc2.exp: Update.
|
||||
|
||||
* tests/smtp.gperf: New file, based on a contribution by Bruce Lilly.
|
||||
* tests/Makefile.in (check-smtp): New rule.
|
||||
(check): Depend on it.
|
||||
(clean): Update.
|
||||
|
||||
2002-12-12 Bruno Haible <bruno@clisp.org>
|
||||
|
||||
* src/search.h (Search::init_selchars_tuple,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/* Output routines.
|
||||
Copyright (C) 1989-1998, 2000, 2002 Free Software Foundation, Inc.
|
||||
Copyright (C) 1989-1998, 2000, 2002-2003 Free Software Foundation, Inc.
|
||||
Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
|
||||
and Bruno Haible <bruno@clisp.org>.
|
||||
|
||||
@@ -183,7 +183,8 @@ struct Output_Enum : public Output_Constants
|
||||
virtual void output_start ();
|
||||
virtual void output_item (const char *name, int value);
|
||||
virtual void output_end ();
|
||||
Output_Enum (const char *indent) : _indentation (indent) {}
|
||||
Output_Enum (const char *indent)
|
||||
: _indentation (indent) {}
|
||||
virtual ~Output_Enum () {}
|
||||
private:
|
||||
const char *_indentation;
|
||||
@@ -464,10 +465,42 @@ struct Output_Compare
|
||||
generated hash table. */
|
||||
virtual void output_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const = 0;
|
||||
/* Outputs the comparison expression for the first byte.
|
||||
Returns true if the this comparison is complete. */
|
||||
bool output_firstchar_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const;
|
||||
Output_Compare () {}
|
||||
virtual ~Output_Compare () {}
|
||||
};
|
||||
|
||||
bool Output_Compare::output_firstchar_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const
|
||||
{
|
||||
/* First, we emit a comparison of the first byte of the two strings.
|
||||
This catches most cases where the string being looked up is not in the
|
||||
hash table but happens to have the same hash code as an element of the
|
||||
hash table. */
|
||||
if (option[UPPERLOWER])
|
||||
{
|
||||
/* Incomplete comparison, just for speedup. */
|
||||
printf ("(((unsigned char)*");
|
||||
expr1.output_expr ();
|
||||
printf (" ^ (unsigned char)*");
|
||||
expr2.output_expr ();
|
||||
printf (") & ~32) == 0");
|
||||
return false;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Complete comparison. */
|
||||
printf ("*");
|
||||
expr1.output_expr ();
|
||||
printf (" == *");
|
||||
expr2.output_expr ();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
/* This class outputs a comparison using strcmp. */
|
||||
|
||||
struct Output_Compare_Strcmp : public Output_Compare
|
||||
@@ -481,18 +514,25 @@ struct Output_Compare_Strcmp : public Output_Compare
|
||||
void Output_Compare_Strcmp::output_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const
|
||||
{
|
||||
printf ("*");
|
||||
expr1.output_expr ();
|
||||
printf (" == *");
|
||||
expr2.output_expr ();
|
||||
bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
||||
printf (" && !");
|
||||
if (option[UPPERLOWER])
|
||||
printf ("gperf_case_");
|
||||
printf ("strcmp (");
|
||||
if (firstchar_done)
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (" + 1, ");
|
||||
expr2.output_expr ();
|
||||
printf (" + 1)");
|
||||
printf (" + 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (", ");
|
||||
expr2.output_expr ();
|
||||
}
|
||||
printf (")");
|
||||
}
|
||||
|
||||
/* This class outputs a comparison using strncmp.
|
||||
@@ -510,18 +550,26 @@ struct Output_Compare_Strncmp : public Output_Compare
|
||||
void Output_Compare_Strncmp::output_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const
|
||||
{
|
||||
printf ("*");
|
||||
expr1.output_expr ();
|
||||
printf (" == *");
|
||||
expr2.output_expr ();
|
||||
bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
||||
printf (" && !");
|
||||
if (option[UPPERLOWER])
|
||||
printf ("gperf_case_");
|
||||
printf ("strncmp (");
|
||||
if (firstchar_done)
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (" + 1, ");
|
||||
expr2.output_expr ();
|
||||
printf (" + 1, len - 1) && ");
|
||||
printf (" + 1, len - 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (", ");
|
||||
expr2.output_expr ();
|
||||
printf (", len");
|
||||
}
|
||||
printf (") && ");
|
||||
expr2.output_expr ();
|
||||
printf ("[len] == '\\0'");
|
||||
}
|
||||
@@ -542,18 +590,26 @@ struct Output_Compare_Memcmp : public Output_Compare
|
||||
void Output_Compare_Memcmp::output_comparison (const Output_Expr& expr1,
|
||||
const Output_Expr& expr2) const
|
||||
{
|
||||
printf ("*");
|
||||
expr1.output_expr ();
|
||||
printf (" == *");
|
||||
expr2.output_expr ();
|
||||
bool firstchar_done = output_firstchar_comparison (expr1, expr2);
|
||||
printf (" && !");
|
||||
if (option[UPPERLOWER])
|
||||
printf ("gperf_case_");
|
||||
printf ("memcmp (");
|
||||
if (firstchar_done)
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (" + 1, ");
|
||||
expr2.output_expr ();
|
||||
printf (" + 1, len - 1)");
|
||||
printf (" + 1, len - 1");
|
||||
}
|
||||
else
|
||||
{
|
||||
expr1.output_expr ();
|
||||
printf (", ");
|
||||
expr2.output_expr ();
|
||||
printf (", len");
|
||||
}
|
||||
printf (")");
|
||||
}
|
||||
|
||||
/* ------------------------------------------------------------------------- */
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
# Makefile for gperf/tests
|
||||
|
||||
# Copyright (C) 1989, 1992, 1993, 1995, 1998, 2000, 2002 Free Software Foundation, Inc.
|
||||
# Copyright (C) 1989, 1992, 1993, 1995, 1998, 2000, 2002, 2003 Free Software Foundation, Inc.
|
||||
# Written by Douglas C. Schmidt <schmidt@ics.uci.edu>
|
||||
# and Bruno Haible <bruno@clisp.org>.
|
||||
#
|
||||
@@ -58,7 +58,7 @@ installdirs :
|
||||
|
||||
uninstall :
|
||||
|
||||
check : check-link-c check-link-c++ check-c check-ada check-modula3 check-pascal check-lang-utf8 check-lang-ucs2 check-test
|
||||
check : check-link-c check-link-c++ check-c check-ada check-modula3 check-pascal check-lang-utf8 check-lang-ucs2 check-smtp check-test
|
||||
@true
|
||||
|
||||
extracheck : @CHECK_LANG_SYNTAX@
|
||||
@@ -121,6 +121,19 @@ check-lang-ucs2:
|
||||
./lu2out -v < $(srcdir)/lang-ucs2.in > lang-ucs2.out
|
||||
diff $(srcdir)/lang-ucs2.exp lang-ucs2.out
|
||||
|
||||
# check case-insensitive lookup
|
||||
check-smtp:
|
||||
@echo "testing SMTP keywords, case-insensitive"
|
||||
$(GPERF) --struct-type --readonly-table --enum --global -K field_name -N header_entry --ignore-case $(srcdir)/smtp.gperf > smtp.c
|
||||
$(CC) $(CFLAGS) -o smtp smtp.c
|
||||
./smtp
|
||||
$(GPERF) --struct-type --readonly-table --enum --global -K field_name -N header_entry --ignore-case --compare-strncmp $(srcdir)/smtp.gperf > smtp.c
|
||||
$(CC) $(CFLAGS) -o smtp smtp.c
|
||||
./smtp
|
||||
$(GPERF) --struct-type --readonly-table --enum --global -K field_name -N header_entry --ignore-case --compare-lengths $(srcdir)/smtp.gperf > smtp.c
|
||||
$(CC) $(CFLAGS) -o smtp smtp.c
|
||||
./smtp
|
||||
|
||||
# these next 5 are demos that show off the generated code
|
||||
check-test:
|
||||
$(GPERF) -L C -F ', 0, 0' -p -j1 -i 1 -g -o -t -G -N is_reserved_word -k1,3,'$$' < $(srcdir)/c-parse.gperf > c-parse.out
|
||||
@@ -273,7 +286,7 @@ check-lang-syntax : force
|
||||
mostlyclean : clean
|
||||
|
||||
clean : force
|
||||
$(RM) *.o core *inset.c output.* *.out aout cout lu2out lu8out m3out pout preout tmp-* valitest*
|
||||
$(RM) *.o core *inset.c output.* *.out aout cout lu2out lu8out m3out pout preout smtp.c smtp tmp-* valitest*
|
||||
|
||||
distclean : clean
|
||||
$(RM) config.status config.log config.cache Makefile
|
||||
|
||||
@@ -108,7 +108,7 @@ in_word_set (str, len)
|
||||
{
|
||||
register const char *s = wordlist[key];
|
||||
|
||||
if (*str == *s && !gperf_case_strcmp (str + 1, s + 1))
|
||||
if ((((unsigned char)*str ^ (unsigned char)*s) & ~32) == 0 && !gperf_case_strcmp (str, s))
|
||||
return s;
|
||||
}
|
||||
}
|
||||
|
||||
206
tests/smtp.gperf
Normal file
206
tests/smtp.gperf
Normal file
@@ -0,0 +1,206 @@
|
||||
%{
|
||||
/* gperf --struct-type --readonly-table --enum --global -K field_name -N header_entry --ignore-case */
|
||||
/* Contributed by Bruce Lilly
|
||||
derived from http://users.erols.com/blilly/mailparse/fields.gperf */
|
||||
|
||||
#include <string.h>
|
||||
|
||||
%}
|
||||
struct header_state { const char *field_name; };
|
||||
%%
|
||||
Accept-Language
|
||||
Action
|
||||
Alternate-Recipient
|
||||
Approved
|
||||
Archive
|
||||
Arrival-Date
|
||||
Autoforwarded
|
||||
Autosubmitted
|
||||
Bcc
|
||||
Cc
|
||||
Comments
|
||||
Complaints-To
|
||||
Content-alternative
|
||||
Content-Base
|
||||
Content-Description
|
||||
Content-Disposition
|
||||
Content-Duration
|
||||
Content-Features
|
||||
Content-ID
|
||||
Content-Language
|
||||
Content-Location
|
||||
Content-MD5
|
||||
Content-Transfer-Encoding
|
||||
Content-Type
|
||||
Control
|
||||
Conversion
|
||||
Conversion-With-Loss
|
||||
DL-Expansion-History
|
||||
DSN-Gateway
|
||||
Date
|
||||
Deferred-Delivery
|
||||
Delivery-Date
|
||||
Diagnostic-Code
|
||||
Discarded-X400-IPMS-Extensions
|
||||
Discarded-X400-MTS-Extensions
|
||||
Disclose-Recipients
|
||||
Disposition
|
||||
Disposition-Notification-Options
|
||||
Disposition-Notification-To
|
||||
Distribution
|
||||
Encrypted
|
||||
Error
|
||||
Expires
|
||||
Failure
|
||||
Final-Log-ID
|
||||
Final-Recipient
|
||||
Followup-To
|
||||
From
|
||||
Generate-Delivery-Report
|
||||
Importance
|
||||
In-Reply-To
|
||||
Incomplete-Copy
|
||||
Injector-Info
|
||||
Keywords
|
||||
Last-Attempt-Date
|
||||
Latest-Delivery-Time
|
||||
Lines
|
||||
List-Archive
|
||||
List-Help
|
||||
List-ID
|
||||
List-Post
|
||||
List-Owner
|
||||
List-Subscribe
|
||||
List-Unsubscribe
|
||||
MDN-Gateway
|
||||
Media-Accept-Features
|
||||
MIME-Version
|
||||
Mail-Copies-To
|
||||
Message-ID
|
||||
Message-Type
|
||||
Newsgroups
|
||||
Organization
|
||||
Original-Encoded-Information-Types
|
||||
Original-Envelope-ID
|
||||
Original-Message-ID
|
||||
Original-Recipient
|
||||
Originator-Return-Address
|
||||
Path
|
||||
Posted-And-Mailed
|
||||
Prevent-Nondelivery-Report
|
||||
Priority
|
||||
Received
|
||||
Received-content-MIC
|
||||
Received-From-MTA
|
||||
References
|
||||
Remote-MTA
|
||||
Reply-By
|
||||
Reply-To
|
||||
Reporting-MTA
|
||||
Reporting-UA
|
||||
Return-Path
|
||||
Sender
|
||||
Sensitivity
|
||||
Status
|
||||
Subject
|
||||
Summary
|
||||
Supersedes
|
||||
To
|
||||
User-Agent
|
||||
Warning
|
||||
Will-Retry-Until
|
||||
X400-Content-Identifier
|
||||
X400-Content-Return
|
||||
X400-Content-Type
|
||||
X400-MTS-Identifier
|
||||
X400-Originator
|
||||
X400-Received
|
||||
X400-Recipients
|
||||
Xref
|
||||
%%
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <ctype.h>
|
||||
|
||||
static int
|
||||
my_case_strcmp (s1, s2)
|
||||
register const char *s1;
|
||||
register const char *s2;
|
||||
{
|
||||
for (;;)
|
||||
{
|
||||
unsigned char c1 = *s1++;
|
||||
unsigned char c2 = *s2++;
|
||||
if (c1 >= 'A' && c1 <= 'Z')
|
||||
c1 += 'a' - 'A';
|
||||
if (c2 >= 'A' && c2 <= 'Z')
|
||||
c2 += 'a' - 'A';
|
||||
if (c1 != 0 && c1 == c2)
|
||||
continue;
|
||||
return (int)c1 - (int)c2;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
main (argc, argv)
|
||||
int argc;
|
||||
char *argv[];
|
||||
{
|
||||
int i, j, k, n, exitcode;
|
||||
unsigned int len;
|
||||
const struct header_state *hs;
|
||||
|
||||
n = 1;
|
||||
if (argc > 1)
|
||||
n = atoi (argv[1]);
|
||||
if (n < 1)
|
||||
n = 1;
|
||||
|
||||
exitcode = 0;
|
||||
for (i = 0; i < n; i++)
|
||||
{
|
||||
for (j = 0; j <= MAX_HASH_VALUE; j++)
|
||||
{
|
||||
const char *s = wordlist[j].field_name;
|
||||
len = strlen (s);
|
||||
if (len)
|
||||
{
|
||||
hs = header_entry (s, len);
|
||||
if (!(hs && strcmp (hs->field_name, s) == 0))
|
||||
{
|
||||
fprintf (stderr, "%s != %s\n", s, hs ? hs->field_name : "(null)");
|
||||
exitcode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
for (j = 0; j <= MAX_HASH_VALUE; j++)
|
||||
{
|
||||
char s[MAX_WORD_LENGTH+1];
|
||||
/* expensive copy with case conversion (for testing) */
|
||||
strcpy (s, wordlist[j].field_name);
|
||||
len = strlen (s);
|
||||
if (len)
|
||||
{
|
||||
for (k = 0; k < len; k++)
|
||||
if (isupper (s[k]))
|
||||
s[k] = tolower (s[k]);
|
||||
else if (islower (s[k]))
|
||||
s[k] = toupper (s[k]);
|
||||
hs = header_entry (s, len);
|
||||
if (!(hs && my_case_strcmp (hs->field_name, s) == 0))
|
||||
{
|
||||
fprintf (stderr, "%s != %s\n", s, hs ? hs->field_name : "(null)");
|
||||
exitcode = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
hs = header_entry ("Dave", 4);
|
||||
if (hs)
|
||||
{
|
||||
fprintf (stderr, "Dave == %s\n", hs->field_name);
|
||||
exitcode = 1;
|
||||
}
|
||||
}
|
||||
return exitcode;
|
||||
}
|
||||
Reference in New Issue
Block a user