chiark / gitweb /
*.c: General spring-clean of the coding style.
[anag] / mono.c
1 /* -*-c-*-
2  *
3  * Monoalphabetic matcher
4  *
5  * (c) 2003 Mark Wooding
6  */
7
8 /*----- Licensing notice --------------------------------------------------*
9  *
10  * This file is part of Anag: a simple wordgame helper.
11  *
12  * Anag is free software; you can redistribute it and/or modify
13  * it under the terms of the GNU General Public License as published by
14  * the Free Software Foundation; either version 2 of the License, or
15  * (at your option) any later version.
16  *
17  * Anag is distributed in the hope that it will be useful,
18  * but WITHOUT ANY WARRANTY; without even the implied warranty of
19  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  * GNU General Public License for more details.
21  *
22  * You should have received a copy of the GNU General Public License
23  * along with Anag; if not, write to the Free Software Foundation,
24  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25  */
26
27 /*----- Header files ------------------------------------------------------*/
28
29 #include "anag.h"
30
31 /*----- Data structures ---------------------------------------------------*/
32
33 typedef struct node_mono {
34   node n;
35   unsigned len;
36   unsigned char *p;
37 } node_mono;
38
39 /*----- Main code ---------------------------------------------------------*/
40
41 /* --- Matching --- */
42
43 static int n_mono(node *nn, const char *p, size_t sz)
44 {
45   node_mono *n = (node_mono *)nn;
46   unsigned map[UCHAR_MAX];
47   const unsigned char *q = n->p;
48   unsigned max = 0;
49   int ch;
50
51   /* Monoalphabetic substitution preserves length. */
52   if (sz != n->len) return (0);
53
54   /* Canonicalize this string as we did the pattern.  Fail if we find a
55    * mismatch.
56    */
57   memset(map, UCHAR_MAX, sizeof(map));
58   while (*p) {
59     ch = *p++;
60     if (map[ch] >= max) map[ch] = max++;
61     if (max >= UCHAR_MAX) return (0);
62     if (*q++ != map[ch]) return (0);
63   }
64   return (1);
65 }
66
67 /* --- Node creation --- */
68
69 node *mono(const char *const *av)
70 {
71   unsigned char map[UCHAR_MAX];
72   const char *p = av[0];
73   unsigned char *q;
74   unsigned max = 0;
75   int ch;
76
77   node_mono *n = xmalloc(sizeof(*n));
78   n->n.func = n_mono;
79   n->p = q = xmalloc(n->len);
80   n->len = strlen(p);
81
82   /* Convert the string into the canonical representative of its equivalence
83    * class, specifically the lexically first string which is equivalent under
84    * monoalphabetic substitution.  That is: replace the first distinct
85    * character with zero, the second with one, and so on.
86    */
87   memset(map, UCHAR_MAX, sizeof(map));
88   while (*p) {
89     ch = *p++;
90     if (map[ch] >= max) map[ch] = max++;
91     assert(max < UCHAR_MAX);
92     *q++ = map[ch];
93   }
94
95   return (&n->n);
96 }
97
98 /*----- That's all, folks -------------------------------------------------*/