Module Name:    othersrc
Committed By:   dyoung
Date:           Fri Sep 11 01:50:43 UTC 2015

Modified Files:
        othersrc/external/bsd/arfe: Makefile
        othersrc/external/bsd/arfe/dt: Makefile README dt.c dt.h hex.c hex.h
            ipv4.c ipv4.h testit
        othersrc/external/bsd/arfe/dt/rr: if-re0-if-wm0 if-wm0-if-re0
            ifconfig.0-ifconfig.1 ifconfig.0-logger-ifconfig.0
            ifconfig.1-ifconfig.0 logger-ifconfig.0-ifconfig.0 wm0-a-wm0-b
            wm0-b-wm0-a
        othersrc/external/bsd/arfe/it: Makefile README
Added Files:
        othersrc/external/bsd/arfe/dt: macaddr.c macaddr.h
        othersrc/external/bsd/arfe/tt: .cvsignore Makefile README testit.sh

Log Message:
Add a new tool, tt, that transforms its input based on the transform
exemplified by a match/transform-template pair.

Add a data detector for MAC addresses.  Update expected test outputs.


To generate a diff of this commit:
cvs rdiff -u -r1.1 -r1.2 othersrc/external/bsd/arfe/Makefile
cvs rdiff -u -r1.3 -r1.4 othersrc/external/bsd/arfe/dt/Makefile
cvs rdiff -u -r1.5 -r1.6 othersrc/external/bsd/arfe/dt/README
cvs rdiff -u -r1.9 -r1.10 othersrc/external/bsd/arfe/dt/dt.c
cvs rdiff -u -r1.1 -r1.2 othersrc/external/bsd/arfe/dt/dt.h \
    othersrc/external/bsd/arfe/dt/hex.c othersrc/external/bsd/arfe/dt/hex.h \
    othersrc/external/bsd/arfe/dt/ipv4.c othersrc/external/bsd/arfe/dt/ipv4.h
cvs rdiff -u -r0 -r1.1 othersrc/external/bsd/arfe/dt/macaddr.c \
    othersrc/external/bsd/arfe/dt/macaddr.h
cvs rdiff -u -r1.2 -r1.3 othersrc/external/bsd/arfe/dt/testit
cvs rdiff -u -r1.3 -r1.4 othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0 \
    othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0
cvs rdiff -u -r1.4 -r1.5 \
    othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1 \
    othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0 \
    othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0 \
    othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0 \
    othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b \
    othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a
cvs rdiff -u -r1.2 -r1.3 othersrc/external/bsd/arfe/it/Makefile
cvs rdiff -u -r1.3 -r1.4 othersrc/external/bsd/arfe/it/README
cvs rdiff -u -r0 -r1.1 othersrc/external/bsd/arfe/tt/.cvsignore \
    othersrc/external/bsd/arfe/tt/Makefile \
    othersrc/external/bsd/arfe/tt/README \
    othersrc/external/bsd/arfe/tt/testit.sh

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: othersrc/external/bsd/arfe/Makefile
diff -u othersrc/external/bsd/arfe/Makefile:1.1 othersrc/external/bsd/arfe/Makefile:1.2
--- othersrc/external/bsd/arfe/Makefile:1.1	Mon Aug 10 21:10:59 2015
+++ othersrc/external/bsd/arfe/Makefile	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
 .include <bsd.own.mk>
 
-SUBDIR=dt it
+SUBDIR=dt it tt
 
 .include <bsd.subdir.mk>

Index: othersrc/external/bsd/arfe/dt/Makefile
diff -u othersrc/external/bsd/arfe/dt/Makefile:1.3 othersrc/external/bsd/arfe/dt/Makefile:1.4
--- othersrc/external/bsd/arfe/dt/Makefile:1.3	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/Makefile	Fri Sep 11 01:50:42 2015
@@ -1,9 +1,9 @@
-# $ARFE: Makefile 231 2015-09-02 22:31:30Z dyoung $
+# $ARFE: Makefile 239 2015-09-10 22:49:40Z dyoung $
 NOMAN=
 .include <bsd.own.mk>
 
 PROG=dt
-SRCS+=dt.c hex.c ipv4.c
+SRCS+=dt.c hex.c ipv4.c macaddr.c
 #CPPFLAGS+=-DHB_DEBUG
 CPPFLAGS+=-DHB_ASSERT
 DBG+=-g -O3

Index: othersrc/external/bsd/arfe/dt/README
diff -u othersrc/external/bsd/arfe/dt/README:1.5 othersrc/external/bsd/arfe/dt/README:1.6
--- othersrc/external/bsd/arfe/dt/README:1.5	Wed Sep  2 22:45:47 2015
+++ othersrc/external/bsd/arfe/dt/README	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-$ARFE: README 235 2015-09-02 22:44:54Z dyoung $
-$NetBSD: README,v 1.5 2015/09/02 22:45:47 dyoung Exp $
+$ARFE: README 236 2015-09-02 22:47:33Z dyoung $
+$NetBSD: README,v 1.6 2015/09/11 01:50:42 dyoung Exp $
 
 DT---(d)ifferentiate (t)ext---finds a longest common subsequence (LCS)
 of two texts where the numbers and IPv4 addresses are "wild": a span

Index: othersrc/external/bsd/arfe/dt/dt.c
diff -u othersrc/external/bsd/arfe/dt/dt.c:1.9 othersrc/external/bsd/arfe/dt/dt.c:1.10
--- othersrc/external/bsd/arfe/dt/dt.c:1.9	Wed Sep  2 22:45:47 2015
+++ othersrc/external/bsd/arfe/dt/dt.c	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: dt.c,v 1.9 2015/09/02 22:45:47 dyoung Exp $ */
-/* $ARFE: dt.c 235 2015-09-02 22:44:54Z dyoung $ */
+/* $NetBSD: dt.c,v 1.10 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: dt.c 239 2015-09-10 22:49:40Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>
@@ -51,6 +51,7 @@
 #include "dt.h"
 #include "hex.h"
 #include "ipv4.h"
+#include "macaddr.h"
 
 #if defined(HB_ASSERT)
 #define	dbg_assert	assert
@@ -63,19 +64,6 @@ typedef struct origin {
 	int j;
 } origin_t;
 
-typedef struct chainelt {
-	TAILQ_ENTRY(chainelt) ce_link;
-	int ce_column;	/*  0: no column alignment,
-			 * -x: starts at column x (1 = first column)
-			 *  x: ends at column x (1 = first column)
-			 */
-	char *ce_content;
-} chainelt_t;
-
-typedef struct chain {
-	TAILQ_HEAD(chainhead, chainelt)	c_head;
-} chain_t;
-
 typedef struct slice {
 	const char *first;
 	const char *last;
@@ -88,6 +76,7 @@ typedef enum {
 	, KIND_INTMAX_HEX
 	, KIND_INTMAX_0xHEX
 	, KIND_IPv4
+	, KIND_MACADDR
 	, KIND_STRING
 } clocc_kind_t;
 
@@ -96,6 +85,9 @@ typedef enum {
 	, QUAL_ALLCAPS
 } clocc_qual_t;
 
+struct chainelt;
+typedef struct chainelt chainelt_t;
+
 typedef struct clocc {
 	int column;
 	int first;
@@ -106,12 +98,44 @@ typedef struct clocc {
 		intmax_t u_intmax;
 		uintmax_t u_uintmax;
 		uint32_t u_ipv4;
+		uint8_t u_macaddr[6];
 	} val_u;
+	TAILQ_ENTRY(clocc) bucket;
+	chainelt_t *match;
 } clocc_t;
 
+struct chainelt {
+	TAILQ_ENTRY(chainelt) ce_link;
+	int ce_column;	/*  0: no column alignment,
+			 * -x: starts at column x (1 = first column)
+			 *  x: ends at column x (1 = first column)
+			 */
+	char *ce_content;
+	int ce_match_idx;
+};
+
+typedef struct chain {
+	TAILQ_HEAD(chainhead, chainelt)	c_head;
+} chain_t;
+
+TAILQ_HEAD(clocc_bucket, clocc);
+
+typedef struct clocc_bucket clocc_bucket_t;
+
+enum {
+	  MATCH_TBL_IDX = 0
+	, TRANSFORM_TBL_IDX = 1
+	, NTBL = 2
+};
+
+typedef struct clocc_htbl {
+	clocc_bucket_t bucket[1024];
+} clocc_htbl_t;
+
 typedef struct cloccs {
 	int noccs;
 	clocc_t occs[1024];
+	clocc_htbl_t htbl;
 } cloccs_t;
 
 typedef struct scratch {
@@ -122,8 +146,18 @@ typedef struct scratch {
 	cloccs_t Aoccs, Boccs;
 	slice_t *Abasis, *Bbasis;
 	size_t expected_lcs;
-	char dec_op;
-	char hex_op;
+	char ipv4_op;	/* 'p' for prefix (smallest containing subnet),
+			 * 'l' for copy left argument
+			 */
+	char macaddr_op;/* 'p' for prefix (leading octets in common),
+			 * 'l' for copy left argument
+			 */
+	char dec_op;	/* '+' or '-' for add or subtract, 'l' for copy left
+			 * argument
+			 */
+	char hex_op;	/* '&' or '|' for bitwise-AND and -OR, 'l' for copy
+			 * left argument
+			 */
 } scratch_t;
 
 union freeslice;
@@ -390,7 +424,7 @@ clocc_ends_in_slice_at(const cloccs_t *o
 }
 
 static chain_t *
-newchain(char *content, int column)
+newchain_with_match_idx(char *content, int column, int midx)
 {
 	chain_t *c;
 	chainelt_t *ce;
@@ -403,12 +437,19 @@ newchain(char *content, int column)
 
 	ce->ce_column = column;
 	ce->ce_content = content;
+	ce->ce_match_idx = midx;
 	TAILQ_INIT(&c->c_head);
 	TAILQ_INSERT_TAIL(&c->c_head, ce, ce_link);
 
 	return c;
 }
 
+static chain_t *
+newchain(char *content, int column)
+{
+	return newchain_with_match_idx(content, column, -1);
+}
+
 /* Return 0 if the `a' and `b' are not left- or right-aligned on
  * the same column, the column they right-align on, or zero minus
  * the column they left-align on.
@@ -425,24 +466,117 @@ cloccs_to_column(const clocc_t * const a
 		return 0;
 }
 
+static unsigned int
+clocc_hash(const slice_t *s, const clocc_t *c)
+{
+	unsigned int hash;
+	int i;
+
+	assert(c->last >= c->first);
+
+	for (hash = c->kind, i = c->first; i <= c->last; i++) {
+		if (((hash << 1) >> 1) != hash) {
+			hash <<= 1;
+			hash |= 0x1;
+		} else
+			hash <<= 1;
+
+		hash ^= get(s, i);
+	}
+
+	return hash;
+}
+
+/* Look up the class occurrence `occ` on slice `s` in the class occurrences
+ * `occs` occurring on slice `os`.
+ */
+static clocc_t *
+clocc_cross_lookup(cloccs_t *occs, const slice_t *os, const slice_t *s,
+    clocc_t *occ)
+{
+	clocc_htbl_t *tbl = &occs->htbl;
+	unsigned int hash = clocc_hash(s, occ);
+	clocc_bucket_t *bkt = &tbl->bucket[hash % __arraycount(tbl->bucket)];
+	clocc_t *bocc;
+	int i, n;
+
+	TAILQ_FOREACH(bocc, bkt, bucket) {
+		assert(bocc->first <= bocc->last);
+		if (bocc->last - bocc->first != occ->last - occ->first)
+			continue; 
+		n = bocc->last - bocc->first + 1;
+		for (i = 0; i < n; i++) {
+			if (get(os, bocc->first + i) != get(s, occ->first + i))
+				break;
+		}
+		if (i == n)
+			return bocc;
+	}
+	return NULL;
+}
+
+static chain_t *
+mac_clocc(const scratch_t *scratch, int idx_a, int idx_b)
+{
+	int column, i, rc;
+	char *buf;
+	uint8_t combo[6];
+	const clocc_t * const a = &scratch->Aoccs.occs[idx_a],
+	              * const b = &scratch->Boccs.occs[idx_b];
+
+	column = cloccs_to_column(a, b);
+
+	switch (scratch->macaddr_op) {
+	case 'p':
+		for (i = 0; i < 6; i++) {
+			uint8_t l, r;
+			l = a->val_u.u_macaddr[i];
+			r = b->val_u.u_macaddr[i];
+			combo[i] = (l == r) ? l : 0;
+		}
+		break;
+	default:
+	case 'l':
+		memcpy(combo, a->val_u.u_macaddr, sizeof(combo));
+		break;
+	}
+
+	rc = asprintf(&buf, "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
+	    "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8,
+	    combo[0], combo[1], combo[2], combo[3], combo[4], combo[5]);
+
+	if (rc != -1)
+		return newchain_with_match_idx(buf, column, idx_b);
+
+	return newchain_with_match_idx(strdup("<macaddr>"), column, idx_b);
+}
+
 static chain_t *
 ipv4_clocc(const scratch_t *scratch, int idx_a, int idx_b)
 {
 	int column;
 	char *erasep, *ret;
-	uint32_t combo, mask;
+	uint32_t combo, mask, discrepancies;
 	const clocc_t * const a = &scratch->Aoccs.occs[idx_a],
 	              * const b = &scratch->Boccs.occs[idx_b];
-	char buf[sizeof("255.255.255.255")];
+	char buf[sizeof("255.255.255.255/32   ")];
 
 	column = cloccs_to_column(a, b);
 
-	for (mask = 0xffffffff;
-	     ((b->val_u.u_ipv4 ^ a->val_u.u_ipv4) & mask) != 0;
-	     mask &= (mask - 1))
+	switch (scratch->ipv4_op) {
+	case 'p':
+		discrepancies = b->val_u.u_ipv4 ^ a->val_u.u_ipv4;
+		break;
+	default:
+	case 'l':
+		discrepancies = 0;
+		break;
+	}
+
+	for (mask = 0xffffffff; (discrepancies & mask) != 0; mask &= (mask - 1))
 		; // do nothing
 
-	combo = htonl(b->val_u.u_ipv4 & mask);
+	combo = htonl(a->val_u.u_ipv4 & mask);
 
 	ret = inet_net_ntop(AF_INET, &combo, 32, buf, sizeof(buf));
 
@@ -450,9 +584,9 @@ ipv4_clocc(const scratch_t *scratch, int
 		*erasep = '\0';
 
 	if (ret != NULL)
-		return newchain(strdup(buf), column);
+		return newchain_with_match_idx(strdup(buf), column, idx_b);
 
-	return newchain(strdup("<ipv4>"), column);
+	return newchain_with_match_idx(strdup("<ipv4>"), column, idx_b);
 }
 
 static chain_t *
@@ -471,13 +605,21 @@ hex_clocc(const scratch_t *scratch, int 
 	    a->val_u.u_uintmax, a->column,
 	    b->val_u.u_uintmax, b->column, column);
 
-	if (scratch->hex_op == '&')
+	switch (scratch->hex_op) {
+	case '&':
 		result = b->val_u.u_uintmax & a->val_u.u_uintmax;
-	else
+		break;
+	case '|':
 		result = b->val_u.u_uintmax | a->val_u.u_uintmax;
+		break;
+	case 'l':
+	default:
+		result = a->val_u.u_uintmax;
+		break;
+	}
 
 	if (result == 0 && kind == KIND_INTMAX_0xHEX)
-		return newchain(strdup("0x0"), column);
+		return newchain_with_match_idx(strdup("0x0"), column, idx_b);
 
 	if (qual == QUAL_ALLCAPS) {
 		rc = asprintf(&buf,
@@ -486,11 +628,11 @@ hex_clocc(const scratch_t *scratch, int 
 		rc = asprintf(&buf,
 		    (kind == KIND_INTMAX_0xHEX) ? "0x%jx" : "%jx", result);
 	}
-	
+
 	if (rc != -1)
-		return newchain(buf, column);
+		return newchain_with_match_idx(buf, column, idx_b);
 
-	return newchain(strdup("<hexmax>"), column);
+	return newchain_with_match_idx(strdup("<hexmax>"), column, idx_b);
 }
 
 static chain_t *
@@ -508,15 +650,23 @@ int_clocc(const scratch_t *scratch, int 
 	    a->val_u.u_intmax, a->column,
 	    b->val_u.u_intmax, b->column, column);
 
-	if (scratch->dec_op == '-')
+	switch (scratch->dec_op) {
+	case '-':
 		result = b->val_u.u_intmax - a->val_u.u_intmax;
-	else
+		break;
+	case '+':
 		result = b->val_u.u_intmax + a->val_u.u_intmax;
+		break;
+	case 'l':
+	default:
+		result = a->val_u.u_intmax;
+		break;
+	}
 
 	if (asprintf(&ret, "%jd", result) != -1)
-		return newchain(ret, column);
+		return newchain_with_match_idx(ret, column, idx_b);
 
-	return newchain(strdup("<intmax>"), column);
+	return newchain_with_match_idx(strdup("<intmax>"), column, idx_b);
 }
 
 static chain_t *
@@ -526,7 +676,7 @@ clocc(const scratch_t *scratch, int idx_
 	              * const b = &scratch->Boccs.occs[idx_b];
 
 	if (a->kind != b->kind)
-		return newchain(strdup("<clocc>"), 0);
+		return newchain(strdup("<clocc*>"), 0);
 
 	if (b->kind == KIND_INTMAX_0xHEX || b->kind == KIND_INTMAX_HEX) {
 		return hex_clocc(scratch, idx_a, idx_b, b->kind,
@@ -539,7 +689,13 @@ clocc(const scratch_t *scratch, int idx_
 	if (b->kind == KIND_IPv4)
 		return ipv4_clocc(scratch, idx_a, idx_b);
 
-	return newchain(strdup("<word>"), 0);
+	if (b->kind == KIND_MACADDR)
+		return mac_clocc(scratch, idx_a, idx_b);
+
+	if (b->kind == KIND_STRING)
+		return newchain(strdup("<word>"), 0);
+
+	return newchain(strdup("<clocc>"), 0);
 }
 
 static chain_t *
@@ -781,7 +937,8 @@ joinchains(chain_t *ac, chain_t *bc)
 	ace = TAILQ_LAST(&ac->c_head, chainhead);
 	bce = TAILQ_FIRST(&bc->c_head);
 
-	if (ace->ce_column == 0 && bce->ce_column == 0) {
+	if (ace->ce_column == 0 && bce->ce_column == 0 &&
+	    ace->ce_match_idx == -1 && bce->ce_match_idx == -1) {
 		char *c, *c1, *c2;
 		c1 = ace->ce_content;
 		c2 = bce->ce_content;
@@ -996,6 +1153,41 @@ slicestr(const slice_t *s, const char *t
 }
 
 static void
+emit_mac_clocc(mac_detection_t *d, void *arg)
+{
+	cloccs_t *o = arg;
+	uint8_t addr[6];
+	int rc;
+
+	dbg_printf("found mac string %s @ [%d, %d]\n", d->d_string,
+	    d->d_idx.start, d->d_idx.stop);
+
+	if (o->noccs >= (int)__arraycount(o->occs))
+		return;
+
+	rc = sscanf(d->d_string,
+	    "%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":%" SCNx8 ":%" SCNx8 "",
+	    &addr[0], &addr[1], &addr[2], &addr[3], &addr[4], &addr[5]);
+
+	assert(rc == 6);
+
+	dbg_printf("converted ipv4 string %s @ [%d, %d] -> "
+	    "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 ":"
+	    "%02" PRIx8 ":%02" PRIx8 ":%02" PRIx8 "\n",
+	    d->d_string, d->d_idx.start, d->d_idx.stop,
+	    addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
+
+	o->occs[o->noccs].column = d->d_column.start;
+	o->occs[o->noccs].first = d->d_idx.start;
+	o->occs[o->noccs].last = d->d_idx.stop;
+	o->occs[o->noccs].kind = KIND_MACADDR;
+	o->occs[o->noccs].qual = QUAL_NONE;
+	memcpy(&o->occs[o->noccs].val_u.u_macaddr[0], &addr[0],
+	    sizeof(o->occs[o->noccs].val_u.u_macaddr));
+	o->noccs++;
+}
+
+static void
 emit_ipv4_clocc(ipv4_detection_t *d, void *arg)
 {
 	cloccs_t *o = arg;
@@ -1099,15 +1291,43 @@ cloccs_dedup(cloccs_t *o)
 }
 
 static void
+clocc_htbl_init(clocc_htbl_t *tbl)
+{
+	int i;
+
+	for (i = 0; i < (int)__arraycount(tbl->bucket); i++)
+		TAILQ_INIT(&tbl->bucket[i]);
+}
+
+static void
+clocc_htbl_insert(clocc_htbl_t *tbl, const slice_t *s, clocc_t *occ)
+{
+	int i = clocc_hash(s, occ) % __arraycount(tbl->bucket);
+	TAILQ_INSERT_HEAD(&tbl->bucket[i], occ, bucket);
+}
+
+static void
+cloccs_hash(cloccs_t *o, const slice_t *s)
+{
+	int i;
+
+	for (i = 0; i < o->noccs; i++)
+		clocc_htbl_insert(&o->htbl, s, &o->occs[i]);
+}
+
+static void
 cloccs_init(cloccs_t *o, const slice_t *s)
 {
 	hex_parser_t *hex_parser;
 	ipv4_parser_t *ipv4_parser;
+	mac_parser_t *mac_parser;
 	size_t column, i;
 	size_t n = length(s);
 	unsigned int j, k;
 	char digits[64 / 3 + 1]; /* XXX how many digits in an intmax_t? */
 
+	clocc_htbl_init(&o->htbl);
+
 	o->noccs = 0;
 	for (i = 0; i < __arraycount(names); i++) {
 		int loc;
@@ -1124,6 +1344,25 @@ cloccs_init(cloccs_t *o, const slice_t *
 		o->noccs++;
 	}
 
+	mac_parser = mac_parser_alloc(emit_mac_clocc, o);
+	if (mac_parser == NULL)
+		goto parse_ipv4;
+
+	column = 0;
+	for (j = 0; j < n; j++) {
+		char c;
+
+		c = get(s, j);
+		++column;
+		mac_parser_drive(mac_parser, j, column, c);
+		if (c == '\n')
+			column = 0;
+	}
+	mac_parser_drive(mac_parser, n, column + 1, -1);
+
+	mac_parser_free(mac_parser);
+
+parse_ipv4:
 	ipv4_parser = ipv4_parser_alloc(emit_ipv4_clocc, o);
 	if (ipv4_parser == NULL)
 		goto parse_hexadecimal;
@@ -1247,39 +1486,112 @@ printchain(chain_t *c)
 	}
 }
 
+static void
+emit_transformed_text(chain_t *O, cloccs_t *Moccs, cloccs_t *Toccs,
+    const slice_t *match, const slice_t *transform)
+{
+	chainelt_t *ce;
+	int i, next;
+
+	TAILQ_FOREACH(ce, &O->c_head, ce_link) {
+		clocc_t *occ = &Moccs->occs[ce->ce_match_idx];
+
+		if (ce->ce_match_idx == -1)
+			continue;
+
+		if (occ->match == NULL)
+			occ->match = ce;
+	}
+
+	for (next = i = 0; i < Toccs->noccs; i++) {
+		clocc_t *Tocc = &Toccs->occs[i];
+		clocc_t *Mocc = clocc_cross_lookup(Moccs, match, transform,
+		    Tocc);
+
+		for (; next < Tocc->first; next++) {
+			char c = get(transform, next);
+			fputc(c, stdout);	// XXX check error
+		}
+
+		if (Mocc != NULL && Mocc->match != NULL) {
+			fprintf(stdout, "%s", Mocc->match->ce_content);
+			next = Tocc->last + 1;
+		} else
+			next = Tocc->first;
+	}
+
+	for (; next < (int)length(transform); next++) {
+		char c = get(transform, next);
+		fputc(c, stdout);	// XXX check error
+	}
+}
+
 int
 main(int argc, char **argv)
 {
-	slice_t *A, *B;
+	slice_t *left, *match, *transform;
 	size_t n;
-	chain_t *C;
+	chain_t *O;
 	scratch_t scratch;
+	size_t lcs;
+	bool dotransform = false;
+	cloccs_t Toccs;
 
 	setprogname(argv[0]);
 
-	if (argc < 3)
+	if (strcmp(getprogname(), "tt") == 0)
+		dotransform = true;
+
+	switch (argc) {
+	case 4:
+		if (!dotransform)
+			usage();
+		/*FALLTHROUGH*/
+	case 3:
+		break;
+	default:
 		usage();
+		break;
+	}
+
+	left = file_to_slice(argv[1]);
+	match = file_to_slice(argv[2]);
 
-	A = file_to_slice(argv[1]);
-	B = file_to_slice(argv[2]);
-	n = length(B);
-	scratch_init(&scratch, n, A, B);
-	if (strcmp(getprogname(), "dt") == 0) {
+	n = length(match);
+	scratch_init(&scratch, n, left, match);
+	cloccs_init(&scratch.Aoccs, left);
+	cloccs_init(&scratch.Boccs, match);
+	cloccs_hash(&scratch.Boccs, match);
+
+	if (dotransform) {
+		scratch.macaddr_op = 'l';
+		scratch.ipv4_op = 'l';
+		scratch.dec_op = 'l';
+		scratch.hex_op = 'l';
+		transform = file_to_slice(argv[3]);
+		cloccs_init(&Toccs, transform);
+	} else if (strcmp(getprogname(), "dt") == 0) {
+		scratch.macaddr_op = 'p';
+		scratch.ipv4_op = 'p';
 		scratch.dec_op = '-';
 		scratch.hex_op = '&';
 	} else if (strcmp(getprogname(), "it") == 0) {
+		scratch.macaddr_op = 'p';
+		scratch.ipv4_op = 'p';
 		scratch.dec_op = '+';
 		scratch.hex_op = '|';
 	} else
 		errx(EXIT_FAILURE, "not implemented");
 
-	cloccs_init(&scratch.Aoccs, A);
-	cloccs_init(&scratch.Boccs, B);
-	size_t lcs;
-	C = algc(A, B, &scratch, (origin_t){0, 0}, no_expected_lcs, &lcs);
+	O = algc(left, match, &scratch, (origin_t){0, 0}, no_expected_lcs,
+	    &lcs);
 
 	dbg_printf("lcs = %zu\n", lcs);
-	printchain(C);
+	if (dotransform) {
+		emit_transformed_text(O, &scratch.Boccs, &Toccs, match,
+		    transform);
+	} else
+		printchain(O);
 	dbg_printf("\n");
 
 	return EXIT_SUCCESS;

Index: othersrc/external/bsd/arfe/dt/dt.h
diff -u othersrc/external/bsd/arfe/dt/dt.h:1.1 othersrc/external/bsd/arfe/dt/dt.h:1.2
--- othersrc/external/bsd/arfe/dt/dt.h:1.1	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/dt.h	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: dt.h,v 1.1 2015/09/02 22:43:17 dyoung Exp $ */
-/* $ARFE$ */
+/* $NetBSD: dt.h,v 1.2 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: dt.h 237 2015-09-02 22:48:04Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>
Index: othersrc/external/bsd/arfe/dt/hex.c
diff -u othersrc/external/bsd/arfe/dt/hex.c:1.1 othersrc/external/bsd/arfe/dt/hex.c:1.2
--- othersrc/external/bsd/arfe/dt/hex.c:1.1	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/hex.c	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: hex.c,v 1.1 2015/09/02 22:43:17 dyoung Exp $ */
-/* $ARFE$ */
+/* $NetBSD: hex.c,v 1.2 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: hex.c 236 2015-09-02 22:47:33Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>
Index: othersrc/external/bsd/arfe/dt/hex.h
diff -u othersrc/external/bsd/arfe/dt/hex.h:1.1 othersrc/external/bsd/arfe/dt/hex.h:1.2
--- othersrc/external/bsd/arfe/dt/hex.h:1.1	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/hex.h	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: hex.h,v 1.1 2015/09/02 22:43:17 dyoung Exp $ */
-/* $ARFE$ */
+/* $NetBSD: hex.h,v 1.2 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: hex.h 236 2015-09-02 22:47:33Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>
Index: othersrc/external/bsd/arfe/dt/ipv4.c
diff -u othersrc/external/bsd/arfe/dt/ipv4.c:1.1 othersrc/external/bsd/arfe/dt/ipv4.c:1.2
--- othersrc/external/bsd/arfe/dt/ipv4.c:1.1	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/ipv4.c	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: ipv4.c,v 1.1 2015/09/02 22:43:17 dyoung Exp $ */
-/* $ARFE$ */
+/* $NetBSD: ipv4.c,v 1.2 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: ipv4.c 238 2015-09-10 20:16:07Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>
@@ -91,8 +91,6 @@ enum ipv4_state_idxs {
 	, READ_250_255
 	, READ_3_9
 	, SECOND_NUMBER
-	, THIRD_NUMBER = FIRST_NUMBER + (SECOND_NUMBER - FIRST_NUMBER) * 2
-	, FOURTH_NUMBER = FIRST_NUMBER + (SECOND_NUMBER - FIRST_NUMBER) * 3
 };
 
 __CTASSERT(SECOND_NUMBER > FIRST_NUMBER)
Index: othersrc/external/bsd/arfe/dt/ipv4.h
diff -u othersrc/external/bsd/arfe/dt/ipv4.h:1.1 othersrc/external/bsd/arfe/dt/ipv4.h:1.2
--- othersrc/external/bsd/arfe/dt/ipv4.h:1.1	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/ipv4.h	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,5 @@
-/* $NetBSD: ipv4.h,v 1.1 2015/09/02 22:43:17 dyoung Exp $ */
-/* $ARFE$ */
+/* $NetBSD: ipv4.h,v 1.2 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE: ipv4.h 236 2015-09-02 22:47:33Z dyoung $ */
 
 /*-
  * Copyright (c) 2014,2015 David Young <[email protected]>

Index: othersrc/external/bsd/arfe/dt/testit
diff -u othersrc/external/bsd/arfe/dt/testit:1.2 othersrc/external/bsd/arfe/dt/testit:1.3
--- othersrc/external/bsd/arfe/dt/testit:1.2	Sat Aug 22 05:08:48 2015
+++ othersrc/external/bsd/arfe/dt/testit	Fri Sep 11 01:50:42 2015
@@ -1,5 +1,7 @@
 #!/bin/sh
-# $ARFE: testit 216 2015-08-22 05:04:28Z dyoung $
+# $ARFE: testit 239 2015-09-10 22:49:40Z dyoung $
+
+DT=${OBJDIR:-.}/dt
 
 results=rr
 
@@ -9,10 +11,10 @@ while read l r ; do
 	o=${results}/${l}-${r}
 	if [ -e $o ]; then
 		echo diffing $l $r 1>&2
-		./dt t/$l t/$r | diff $o -
+		${DT} t/$l t/$r | diff $o -
 	else
 		echo generating $l $r 1>&2
-		./dt t/$l t/$r > $o
+		${DT} t/$l t/$r > $o
 	fi
 done <<EOF
 netstat-s.0 netstat-s.1

Index: othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0
diff -u othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0:1.3 othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0:1.4
--- othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0:1.3	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/if-re0-if-wm0	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
   0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=3f80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx>
 	enabled=3f80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx>
-	address:  0:-25:c:0: a0:80
+	address: 00:00:00:00:00:00
 	media: Ethernet autoselect (e)
 	status: aie
 	inet 0.0.0.0 netmask 0xff000000 broadcast 0.0.0.0
Index: othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0
diff -u othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0:1.3 othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0:1.4
--- othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0:1.3	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/if-wm0-if-re0	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
   0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=3f80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP-2CSUM_Tx>
 	enabled=3f80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP-2CSUM_Tx>
-	address:  0:25: c:0: a0:80
+	address: 00:00:00:00:00:00
 	media: Ethernet autoselect (e)
 	status: cie
 	inet 0.0.0.0 netmask 0xff000000 broadcast 0.0.0.0

Index: othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1
diff -u othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1:1.4 othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1:1.5
--- othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/ifconfig.0-ifconfig.1	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 	enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-	address:  0: a: b:cd: 0:ef
+	address: 00:0a:0b:cd:01:ef
 	media: Ethernet autoselect (   0baseT full-duplex)
 	status: active
 	input:      61 packets,       5432 bytes,       3 multicasts
Index: othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0
diff -u othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0:1.4 othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0:1.5
--- othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/ifconfig.0-logger-ifconfig.0	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 0
 capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-address: 0:a:b:cd:0:ef
+address: 00:0a:0b:cd:01:ef
 media: Ethernet autoselect (0baseT full-duplex)
 status: active
 input: 0 packets, 0 bytes, 0 multicasts
Index: othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0
diff -u othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0:1.4 othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0:1.5
--- othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/ifconfig.1-ifconfig.0	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 	enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-	address:  0: a: b:cd: 0:ef
+	address: 00:0a:0b:cd:01:ef
 	media: Ethernet autoselect (   0baseT full-duplex)
 	status: active
 	input:     -61 packets,      -5432 bytes,      -3 multicasts
Index: othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0
diff -u othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0:1.4 othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0:1.5
--- othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/logger-ifconfig.0-ifconfig.0	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu 0
 capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-address: 0:a:b:cd:0:ef
+address: 00:0a:0b:cd:01:ef
 media: Ethernet autoselect (0baseT full-duplex)
 status: active
 input: 0 packets, 0 bytes, 0 multicasts
Index: othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b
diff -u othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b:1.4 othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b:1.5
--- othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/wm0-a-wm0-b	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 	enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-	address:  0: a: b:cd: 0:ef
+	address: 00:0a:0b:cd:01:ef
 	media: Ethernet autoselect (   0baseT full-duplex)
 	status: active
 	input:     112 packets,      11380 bytes,      11 multicasts
Index: othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a
diff -u othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a:1.4 othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a:1.5
--- othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a:1.4	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/dt/rr/wm0-b-wm0-a	Fri Sep 11 01:50:43 2015
@@ -1,7 +1,7 @@
 wm0: flags=   0<UP,BROADCAST,RUNNING,SIMPLEX,MULTICAST> mtu    0
 	capabilities=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
 	enabled=2bf80<TSO0,IP0CSUM_Rx,IP0CSUM_Tx,TCP0CSUM_Rx,TCP0CSUM_Tx,UDP0CSUM_Rx,UDP0CSUM_Tx,TCP0CSUM_Tx,UDP0CSUM_Tx>
-	address:  0: a: b:cd: 0:ef
+	address: 00:0a:0b:cd:01:ef
 	media: Ethernet autoselect (   0baseT full-duplex)
 	status: active
 	input:    -112 packets,     -11380 bytes,     -11 multicasts

Index: othersrc/external/bsd/arfe/it/Makefile
diff -u othersrc/external/bsd/arfe/it/Makefile:1.2 othersrc/external/bsd/arfe/it/Makefile:1.3
--- othersrc/external/bsd/arfe/it/Makefile:1.2	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/it/Makefile	Fri Sep 11 01:50:43 2015
@@ -2,7 +2,7 @@ NOMAN=
 .include <bsd.own.mk>
 
 PROG=it
-SRCS+=dt.c hex.c ipv4.c
+SRCS+=dt.c hex.c ipv4.c macaddr.c
 #CPPFLAGS+=-DHB_DEBUG
 DBG+=-g -O3
 #DBG+=-g -O0

Index: othersrc/external/bsd/arfe/it/README
diff -u othersrc/external/bsd/arfe/it/README:1.3 othersrc/external/bsd/arfe/it/README:1.4
--- othersrc/external/bsd/arfe/it/README:1.3	Wed Sep  2 22:43:17 2015
+++ othersrc/external/bsd/arfe/it/README	Fri Sep 11 01:50:43 2015
@@ -1,5 +1,5 @@
-$ARFE$
-$NetBSD: README,v 1.3 2015/09/02 22:43:17 dyoung Exp $
+$ARFE: README 237 2015-09-02 22:48:04Z dyoung $
+$NetBSD: README,v 1.4 2015/09/11 01:50:43 dyoung Exp $
 
 IT---(i)ntegrate (t)ext---is a variation on DT that adds decimal numbers
 instead of subtracts, and bitwise-ORs hexadecimal numbers instead of

Added files:

Index: othersrc/external/bsd/arfe/dt/macaddr.c
diff -u /dev/null othersrc/external/bsd/arfe/dt/macaddr.c:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/dt/macaddr.c	Fri Sep 11 01:50:42 2015
@@ -0,0 +1,336 @@
+/* $NetBSD: macaddr.c,v 1.1 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE:47:33Z dyoung $ */
+
+/*-
+ * Copyright (c) 2014,2015 David Young <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#include <assert.h>
+#include <ctype.h>
+#include <stdbool.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <sys/cdefs.h>	/* for __predict_true() */
+
+#include "dt.h"
+#include "macaddr.h"
+
+typedef enum mac_op {
+	  MAC_OP_NONE = 0
+	, MAC_OP_PUSH
+	, MAC_OP_EMIT
+	, MAC_OP_START
+} mac_op_t;
+
+struct mac_state;
+typedef struct mac_state mac_state_t;
+
+typedef struct mac_transition {
+	const mac_state_t	*t_newstate;
+	mac_op_t		t_op;
+} mac_transition_t;
+
+struct mac_state {
+	const char *s_descr;
+	mac_transition_t s_delimiter;
+	mac_transition_t s_eof;
+	mac_transition_t s_other;
+	mac_transition_t s_colon;
+	mac_transition_t s_hexdigit;
+};
+
+enum mac_state_idxs {
+	  READ_OTHER = 0
+	, READ_DELIMITER	/* Initial state: beginning of file, or read
+				 * Space, or read punctuation other than '.'
+				 */
+	, READ_EOF
+	, FIRST_NUMBER
+	, READ_COLON = FIRST_NUMBER
+	, READ_HEX
+	, READ_HEX_HEX
+	, SECOND_NUMBER
+};
+
+__CTASSERT(SECOND_NUMBER > FIRST_NUMBER)
+
+#define __skip(__n)	((SECOND_NUMBER - FIRST_NUMBER) * ((__n) - 1))
+
+#define	read_colon(__n)		mac_states[READ_COLON + __skip(__n)]
+#define	read_hex(__n)		mac_states[READ_HEX + __skip(__n)]
+#define	read_hex_hex(__n)	mac_states[READ_HEX_HEX + __skip(__n)]
+#define	read_other		mac_states[READ_OTHER]
+#define	read_delimiter		mac_states[READ_DELIMITER]
+#define	read_eof		mac_states[READ_EOF]
+
+#define first(__n)	(__skip(1) + __n)
+#define second(__n)	(__skip(2) + __n)
+#define third(__n)	(__skip(3) + __n)
+#define fourth(__n)	(__skip(4) + __n)
+#define fifth(__n)	(__skip(5) + __n)
+#define sixth(__n)	(__skip(6) + __n)
+
+// see notebook, 9 Sep 2015
+static mac_state_t mac_states[] = {
+   [READ_DELIMITER] = {
+	  .s_descr = "read delimiter"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(1), MAC_OP_START}
+}, [READ_EOF] = {
+	.s_descr = "read eof",
+	.s_other = {&read_eof, MAC_OP_NONE},
+}, [READ_OTHER] = {
+	.s_descr = "read other",
+	.s_other = {&read_other, MAC_OP_NONE},
+	.s_delimiter = {&read_delimiter, MAC_OP_NONE},
+}, [first(READ_COLON)] = {
+	  .s_descr = "read colon"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(2), MAC_OP_PUSH}
+}, [first(READ_HEX_HEX)] = {
+	  .s_descr = "read hex hex"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_colon = {&read_colon(1), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [first(READ_HEX)] = {
+	  .s_descr = "read hex"
+	, .s_colon = {&read_colon(1), MAC_OP_PUSH}
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(1), MAC_OP_PUSH}
+}, [second(READ_COLON)] = {
+	  .s_descr = "read colon 2"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(3), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [second(READ_HEX_HEX)] = {
+	  .s_descr = "read hex hex 2"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_colon = {&read_colon(2), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [second(READ_HEX)] = {
+	  .s_descr = "read hex 2"
+	, .s_colon = {&read_colon(2), MAC_OP_PUSH}
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(2), MAC_OP_PUSH}
+}, [third(READ_COLON)] = {
+	  .s_descr = "read colon 3"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(4), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [third(READ_HEX_HEX)] = {
+	  .s_descr = "read hex hex 3"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_colon = {&read_colon(3), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [third(READ_HEX)] = {
+	  .s_descr = "read hex 3"
+	, .s_colon = {&read_colon(3), MAC_OP_PUSH}
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(3), MAC_OP_PUSH}
+}, [fourth(READ_COLON)] = {
+	  .s_descr = "read colon 4"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(5), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [fourth(READ_HEX_HEX)] = {
+	  .s_descr = "read hex hex 4"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_colon = {&read_colon(4), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [fourth(READ_HEX)] = {
+	  .s_descr = "read hex 4"
+	, .s_colon = {&read_colon(4), MAC_OP_PUSH}
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(4), MAC_OP_PUSH}
+}, [fifth(READ_COLON)] = {
+	  .s_descr = "read colon 5"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex(6), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [fifth(READ_HEX_HEX)] = {
+	  .s_descr = "read hex hex 5"
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_colon = {&read_colon(5), MAC_OP_PUSH}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}, [fifth(READ_HEX)] = {
+	  .s_descr = "read hex 5"
+	, .s_colon = {&read_colon(5), MAC_OP_PUSH}
+	, .s_delimiter = {&read_delimiter, MAC_OP_NONE}
+	, .s_eof = {&read_eof, MAC_OP_NONE}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(5), MAC_OP_PUSH}
+//*****************************
+}, [sixth(READ_HEX)] = {
+	  .s_descr = "read hex"
+	, .s_delimiter = {&read_delimiter, MAC_OP_EMIT}
+	, .s_eof = {&read_eof, MAC_OP_EMIT}
+	, .s_other = {&read_other, MAC_OP_NONE}
+	, .s_hexdigit = {&read_hex_hex(6), MAC_OP_PUSH}
+}, [sixth(READ_HEX_HEX)] = {
+	  .s_descr = "read hex"
+	, .s_delimiter = {&read_delimiter, MAC_OP_EMIT}
+	, .s_eof = {&read_eof, MAC_OP_EMIT}
+	, .s_other = {&read_other, MAC_OP_NONE}
+}};
+
+struct mac_parser {
+	mac_detection_t p_detection;
+#define	p_column	p_detection.d_column
+#define	p_string	p_detection.d_string
+#define	p_idx		p_detection.d_idx
+	char *p_last;
+	const mac_state_t *p_state;
+	mac_emitter_t p_emitter;
+	void *p_arg;
+};
+
+void
+mac_parser_free(mac_parser_t *p)
+{
+	free(p);
+}
+
+static void
+mac_parser_init(mac_parser_t *p, mac_emitter_t emitter, void *arg)
+{
+	memset(p, 0, sizeof(*p));
+	p->p_state = &read_delimiter;
+	p->p_emitter = emitter;
+	p->p_arg = arg;
+}
+
+mac_parser_t *
+mac_parser_alloc(mac_emitter_t emitter, void *arg)
+{
+	mac_parser_t *p;
+
+	p = malloc(sizeof(*p));
+	if (p == NULL)
+		return NULL;
+
+	mac_parser_init(p, emitter, arg);
+	return p;
+}
+
+static const char *
+mac_op_string(mac_op_t op)
+{
+	switch (op) {
+	case MAC_OP_NONE:
+		return "none";
+	case MAC_OP_EMIT:
+		return "emit";
+	case MAC_OP_PUSH:
+		return "push";
+	case MAC_OP_START:
+		return "start";
+	default:
+		return "unknown";
+	}
+}
+
+void
+mac_parser_drive(mac_parser_t *p, int idx, int column, int c)
+{
+	const mac_transition_t *t;
+	const mac_state_t *ns, *s;
+
+	s = p->p_state;
+
+	if (c == -1 && (ns = s->s_eof.t_newstate) != NULL)
+		t = &s->s_eof;
+	else if (strchr("abcdefABCDEF0123456789", c) != NULL &&
+		 (ns = s->s_hexdigit.t_newstate) != NULL)
+		t = &s->s_hexdigit;
+	else if (c == ':' && (ns = s->s_colon.t_newstate) != NULL)
+		t = &s->s_colon;
+	else if ((isspace(c) || ispunct(c)) && c != ':' &&
+	         (ns = s->s_delimiter.t_newstate) != NULL)
+		t = &s->s_delimiter;
+	else if ((ns = s->s_other.t_newstate) != NULL)
+		t = &s->s_other;
+	else
+		ns = NULL;
+
+	assert(ns != NULL);
+	if (c == -1) {
+		dbg_printf("%s: transition (%s, eof) -> %s (op %s)\n", __func__,
+		    s->s_descr, ns->s_descr, mac_op_string(t->t_op));
+	} else {
+		dbg_printf("%s: transition (%s, %c) -> %s (op %s)\n", __func__,
+		    s->s_descr, c, ns->s_descr, mac_op_string(t->t_op));
+	}
+
+	switch (t->t_op) {
+	case MAC_OP_START:
+		p->p_column.start = column;
+		p->p_idx.start = idx;
+		p->p_last = &p->p_string[0];
+		/*FALLTHROUGH*/
+	case MAC_OP_PUSH:
+		if (p->p_last == NULL)
+			;
+		else if (p->p_last - &p->p_string[0] ==
+		         __arraycount(p->p_string) - 1)
+			p->p_last = NULL;
+		else {
+			*p->p_last = c;
+			p->p_last++;
+		}
+		p->p_column.stop = column;
+		p->p_idx.stop = idx;
+		break;
+	case MAC_OP_EMIT:
+		if (p->p_last == NULL)
+			dbg_printf("mac string too long\n");
+		*p->p_last = '\0';
+		(*p->p_emitter)(&p->p_detection, p->p_arg);
+		break;
+	case MAC_OP_NONE:
+		break;
+	}
+
+	p->p_state = ns;
+}
+
Index: othersrc/external/bsd/arfe/dt/macaddr.h
diff -u /dev/null othersrc/external/bsd/arfe/dt/macaddr.h:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/dt/macaddr.h	Fri Sep 11 01:50:42 2015
@@ -0,0 +1,46 @@
+/* $NetBSD: macaddr.h,v 1.1 2015/09/11 01:50:42 dyoung Exp $ */
+/* $ARFE$ */
+
+/*-
+ * Copyright (c) 2014,2015 David Young <[email protected]>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+#ifndef _MACADDR_H_
+#define _MACADDR_H_
+
+typedef struct mac_detection {
+	struct {
+		int start, stop;
+	} d_column, d_idx;
+	char d_string[sizeof("00:11:22:33:44:55")];
+} mac_detection_t;
+
+struct mac_parser;
+typedef struct mac_parser mac_parser_t;
+
+typedef void (*mac_emitter_t)(mac_detection_t *, void *);
+mac_parser_t *mac_parser_alloc(mac_emitter_t, void *);
+void mac_parser_drive(mac_parser_t *, int, int, int);
+void mac_parser_free(mac_parser_t *);
+
+#endif /* _MACADDR_H_ */

Index: othersrc/external/bsd/arfe/tt/.cvsignore
diff -u /dev/null othersrc/external/bsd/arfe/tt/.cvsignore:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/tt/.cvsignore	Fri Sep 11 01:50:43 2015
@@ -0,0 +1,3 @@
+*.d
+.depend
+it
Index: othersrc/external/bsd/arfe/tt/Makefile
diff -u /dev/null othersrc/external/bsd/arfe/tt/Makefile:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/tt/Makefile	Fri Sep 11 01:50:43 2015
@@ -0,0 +1,25 @@
+NOMAN=
+.include <bsd.own.mk>
+
+PROG=tt
+SRCS+=dt.c hex.c ipv4.c macaddr.c
+#CPPFLAGS+=-DHB_DEBUG
+CPPFLAGS+=-DHB_ASSERT
+DBG+=-g -O3
+#DBG+=-g -O0
+#COPTS+=-pg
+#LDFLAGS+=-pg
+CFLAGS+=-std=c99
+WARNS=5
+
+tags: $(SRCS) $(INCS)
+	@rm -f $(.OBJDIR)/tags
+	@ctags -atwd $(.ALLSRC)
+	@sort -o $(.OBJDIR)/tags $(.OBJDIR)/tags
+
+test: ${.OBJDIR}/${PROG}
+	@OBJDIR=${.OBJDIR} sh testit.sh 
+
+.PATH: $(.CURDIR)/../dt
+
+.include <bsd.prog.mk> 
Index: othersrc/external/bsd/arfe/tt/README
diff -u /dev/null othersrc/external/bsd/arfe/tt/README:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/tt/README	Fri Sep 11 01:50:43 2015
@@ -0,0 +1,33 @@
+$ARFE: README 239 2015-09-10 22:49:40Z dyoung $
+$NetBSD: README,v 1.1 2015/09/11 01:50:43 dyoung Exp $
+
+TT---(t)ransform (t)ext---transforms its input based on a
+match/transform-template pair that exemplifies the changes that should
+be made.  Like DT and IT, TT detects data in its input---decimal and
+hexadecimal numbers, network addresses.  TT also detects the data in
+the match and transform templates, and notes occurrences of identical
+data in both templates.  TT aligns its input with the match template in
+the same way that DT and TT do.  Then it generates its output from the
+transform template. Non-data parts of the transform template are copied
+directly to the output.  Whenever a datum in the transform template
+is identical to a datum in the match template, and TT has aligned the
+match datum with an input datum, then TT copies the corresponding datum
+from its input to its output.  Otherwise, data parts of the transform
+template are copied directly to the output.
+
+The TT reads its input from the first command-line argument, the match
+template from the second argument, and the transform template from the
+third.  TT writes the transformed text to standard output.
+
+Example
+-------
+
+TT can transpose a 3x3 matrix.
+
+input       match template   transform template    output
+
+5  9 99     11 12 13         11 21 31              5 6 1
+6 53 10     21 22 23         12 22 32              9 53 8
+1  8 40     31 32 33         13 23 33              99 10 40
+
+See also ../dt/README.
Index: othersrc/external/bsd/arfe/tt/testit.sh
diff -u /dev/null othersrc/external/bsd/arfe/tt/testit.sh:1.1
--- /dev/null	Fri Sep 11 01:50:43 2015
+++ othersrc/external/bsd/arfe/tt/testit.sh	Fri Sep 11 01:50:43 2015
@@ -0,0 +1,21 @@
+#!/bin/sh
+
+TT=${OBJDIR:-.}/tt
+
+for i in $(ls tests)
+do
+	d=./tests/${i}
+	if [ -e $d/expected-output ]; then
+		echo running $i
+		if ! ${TT} $d/input $d/match $d/transform | \
+		    diff $d/expected-output - ; then
+			exit 1
+		fi
+	else
+		echo generating $i ...
+		${TT} $d/input $d/match $d/transform > $d/expected-output ||\
+		    rm -f $d/expected-output
+	fi
+done
+
+exit 0

Reply via email to