--- /dev/null
+
+#include "defs.h"
+
+#include "recognize_extra.h"
+
+static gint eval_filter(GList *s, gunichar2 arg)
+{
+ GdkPoint *p0 = (GdkPoint*)g_list_first(s)->data;
+ GdkPoint *pn = (GdkPoint*)g_list_last(s)->data;
+ switch( arg )
+ {
+ case 'x':
+ return p0->x;
+ case 'y':
+ return p0->y;
+ case 'i':
+ return pn->x;
+ case 'j':
+ return pn->y;
+ case 'a':
+ return ((p0->x + pn->x) >> 1);
+ case 'b':
+ return ((p0->y + pn->y) >> 1);
+ case 'l':
+ {
+ int dx = p0->x - pn->x;
+ int dy = p0->y - pn->y;
+ return abs(dx) + abs(dy);
+ }
+ }
+ return 0;
+}
+
+static void get_sz(GList *strokes, gint *sz)
+{
+ int xmin, ymin, xmax, ymax;
+ GdkPoint *pt = (GdkPoint*)(((GList*)strokes->data)->data);
+ xmin = xmax = pt->x;
+ ymin = ymax = pt->y;
+ GList *s, *s1;
+ for(s = g_list_first(strokes); s; s = g_list_next(s))
+ {
+ for(s1 = (GList*)s->data; s1; s1 = g_list_next(s1))
+ {
+ pt = (GdkPoint*)s1->data;
+ if(pt->x < xmin)
+ xmin = pt->x;
+ if(pt->y < ymin)
+ ymin = pt->y;
+ if(pt->x > xmax)
+ xmax = pt->x;
+ if(pt->y > ymax)
+ ymax = pt->y;
+ }
+ }
+ gint w = xmax - xmin, h = ymax - ymin;
+ *sz = (w > h) ? w : h;
+}
+
+gint pass_extra_filters(GList *strokes, gunichar2 *entry)
+{
+ gunichar2 arg[2], fn, c;
+ gint stroke[2];
+ gint sc, val[2];
+ gint index = 0;
+ gboolean must = False;
+ gint score = 0;
+
+ arg[0] = arg[1] = 0;
+ stroke[0] = stroke[1] = 0;
+
+ /* Simple parser for Filter strings. assumes a1-b1 structure,
+ * where a and b can be any single alphabetic cmd char, the
+ * numbers can be multiple digit, and b1 can optionally be
+ * followed by '!' to insist on the filter passing. There can
+ * be multiple filters but they have to be separated by '!' or
+ * space(s). The filter string is terminated by a null byte
+ * or an 8-bit char, the beginning of the next entry.
+ * Leading spaces and trailing spaces are ignored. -rwells, 970722.
+ */
+
+ for(c = *entry; True; entry++, c = *entry )
+ {
+ switch( c )
+ {
+ case 'x':
+ case 'y':
+ case 'i':
+ case 'j':
+ case 'a':
+ case 'b':
+ case 'l':
+ arg[index] = c;
+ break;
+
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ stroke[index] = stroke[index] * 10 + (c - '0');
+ break;
+
+ case '-':
+ case '<':
+ case '=':
+ fn = c;
+ index = 1;
+ break;
+
+ case '!':
+ must = True;
+
+ case ' ':
+ default:
+ if(index == 1) // second argument
+ {
+ gint n = g_list_length(strokes);
+ if((n > stroke[0]) || (n > stroke[1]))
+ {
+ val[0] = eval_filter(g_list_nth_data(strokes, stroke[0] - 1), arg[0]);
+ val[1] = eval_filter(g_list_nth_data(strokes, stroke[1] - 1), arg[1]);
+ gint sz;
+ get_sz(strokes, &sz);
+ if(fn == '-')
+ {
+ sc = ((val[0] - val[1]) < 0) ? 1 : -1;
+ if(must) sc *= 2;
+ score += sc;
+ }
+ else if(fn == '=')
+ {
+ sc = ((val[0] - val[1]) > sz/4) ? 1 : -1;
+ if(must) sc *= 2;
+ score += sc;
+ }
+ else if(fn == '<')
+ {
+ sc = (abs(val[1] - val[0]) > sz/2) ? 1 : -1;
+ if(must) sc *= 2;
+ score += sc;
+ }
+ }
+
+ // reset
+ index = 0;
+ must = False;
+ arg[0] = arg[1] = 0;
+ stroke[0] = stroke[1] = 0;
+ }
+
+ if( c == '\r' || c == '\0' )
+ return score;
+ }
+ }
+ return score;
+}
+