1
0
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:
Bruno Haible
2003-04-12 00:41:03 +00:00
parent ab6f0966b7
commit 6bbdde4f5f
5 changed files with 359 additions and 70 deletions

View File

@@ -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,

View File

@@ -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 (")");
}
/* ------------------------------------------------------------------------- */

View File

@@ -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

View File

@@ -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
View 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;
}