diff --git a/Makefile b/Makefile index e2d56955a2..d9dd6b4731 100644 --- a/Makefile +++ b/Makefile @@ -34,7 +34,7 @@ RM=rm -f CC=gcc CXX=g++ CXXFLAGS=$(CFLAGS) -CLD=g++ -O -g -L/usr/local/lib -L/opt/local/lib +CLD=g++ -O2 -g -L/usr/local/lib -L/opt/local/lib ifeq ($(OS),osx) CLDOSFLAGS=-bind_at_load @@ -55,13 +55,15 @@ LIBS=-lssl -lcrypto -lgmp -lncurses -lsigsegv $(OSLIBS) endif INCLUDE=include -MDEFINES=-DU2_OS_$(OS) -DU2_OS_ENDIAN_$(ENDIAN) -D U2_LIB=\"$(LIB)\" +MDEFINES=-DU2_OS_$(OS) -DU2_OS_ENDIAN_$(ENDIAN) -D U2_LIB=\"$(LIB)\" -CFLAGS= -O3 \ +CFLAGS= -O2 -g \ + -funsigned-char \ -I/usr/local/include \ -I/opt/local/include \ -I$(INCLUDE) \ -Ioutside/libuv/include \ + -Ioutside/anachronism/include \ -Ioutside/bpt \ -Ioutside/re2 \ -Ioutside/cre2/src/src \ @@ -151,13 +153,16 @@ J164_4_OFILES=\ gen164/4/in.o \ gen164/4/by.o \ gen164/4/in_has.o \ + gen164/4/in_int.o \ gen164/4/in_gas.o \ gen164/4/in_mer.o \ gen164/4/in_put.o \ gen164/4/in_tap.o \ + gen164/4/in_uni.o \ gen164/4/by_gas.o \ gen164/4/by_get.o \ gen164/4/by_has.o \ + gen164/4/by_int.o \ gen164/4/by_put.o \ gen164/4/by_uni.o @@ -293,6 +298,8 @@ LIBRE2=outside/re2/obj/libre2.a LIBED25519=outside/ed25519/ed25519.a +LIBANACHRONISM=outside/anachronism/build/libanachronism.a + BPT_O=outside/bpt/bitmapped_patricia_tree.o all: $(BIN)/vere @@ -306,6 +313,9 @@ $(LIBRE2): $(LIBED25519): $(MAKE) -C outside/ed25519 +$(LIBANACHRONISM): + $(MAKE) -C outside/anachronism static + $(BPT_O): outside/bpt/bitmapped_patricia_tree.c $(CC) -g -O2 -o $@ -c $< @@ -314,9 +324,9 @@ $(CRE2_OFILES): outside/cre2/src/src/cre2.cpp outside/cre2/src/src/cre2.h $(LIBR $(V_OFILES) f/loom.o f/trac.o: include/v/vere.h -$(BIN)/vere: $(LIBCRE) $(VERE_OFILES) $(LIBUV) $(LIBRE2) $(LIBED25519) $(BPT_O) +$(BIN)/vere: $(LIBCRE) $(VERE_OFILES) $(LIBUV) $(LIBRE2) $(LIBED25519) $(BPT_O) $(LIBANACHRONISM) mkdir -p $(BIN) - $(CLD) $(CLDOSFLAGS) -o $(BIN)/vere $(VERE_OFILES) $(LIBUV) $(LIBCRE) $(LIBRE2) $(LIBED25519) $(BPT_O) $(LIBS) + $(CLD) $(CLDOSFLAGS) -o $(BIN)/vere $(VERE_OFILES) $(LIBUV) $(LIBCRE) $(LIBRE2) $(LIBED25519) $(BPT_O) $(LIBANACHRONISM) $(LIBS) tags: ctags -R -f .tags --exclude=root @@ -350,6 +360,7 @@ distclean: clean $(MAKE) -C outside/libuv clean $(MAKE) -C outside/re2 clean $(MAKE) -C outside/ed25519 clean + $(MAKE) -C outside/anachronism clean $(RM) $(BPT_O) .PHONY: clean debbuild debinstalldistclean etags osxpackage tags diff --git a/gen164/4/by.c b/gen164/4/by.c index 5ac8ab96a3..878b075378 100644 --- a/gen164/4/by.c +++ b/gen164/4/by.c @@ -10,6 +10,7 @@ extern u2_ho_jet j2_mcj(Pt4, by, gas)[]; extern u2_ho_jet j2_mcj(Pt4, by, get)[]; extern u2_ho_jet j2_mcj(Pt4, by, has)[]; + extern u2_ho_jet j2_mcj(Pt4, by, int)[]; extern u2_ho_jet j2_mcj(Pt4, by, put)[]; extern u2_ho_jet j2_mcj(Pt4, by, uni)[]; @@ -20,6 +21,7 @@ { j2_sc(Pt4, by, gas), j2_mcj(Pt4, by, gas), 0, 0, u2_none }, { j2_sc(Pt4, by, get), j2_mcj(Pt4, by, get), 0, 0, u2_none }, { j2_sc(Pt4, by, has), j2_mcj(Pt4, by, has), 0, 0, u2_none }, + { j2_sc(Pt4, by, int), j2_mcj(Pt4, by, int), 0, 0, u2_none }, { j2_sc(Pt4, by, put), j2_mcj(Pt4, by, put), 0, 0, u2_none }, { j2_sc(Pt4, by, uni), j2_mcj(Pt4, by, uni), 0, 0, u2_none }, {} diff --git a/gen164/4/by_int.c b/gen164/4/by_int.c new file mode 100644 index 0000000000..3080dbf701 --- /dev/null +++ b/gen164/4/by_int.c @@ -0,0 +1,135 @@ +/* j/4/by_int.c +** +** This file is in the public domain. +*/ +#include "all.h" +#include "../pit.h" + +/* functions +*/ + u2_weak // transfer + j2_mcc(Pt4, by, int)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b) // retain + { + if ( u2_nul == a ) { + return u2_rx(wir_r, u2_nul); + } + else if ( u2_nul == b ) { + return u2_rx(wir_r, u2_nul); + } + else { + u2_noun l_a, n_a, r_a, lr_a, p_n_a, q_n_a; + u2_noun l_b, n_b, r_b, lr_b, p_n_b, q_n_b; + + if ( (u2_no == u2_as_cell(a, &n_a, &lr_a)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( (u2_no == u2_as_cell(b, &n_b, &lr_b)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_a, &l_a, &r_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_b, &l_b, &r_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(n_a, &p_n_a, &q_n_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(n_b, &p_n_b, &q_n_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_yes == j2_mbc(Pt3, vor)(wir_r, p_n_a, p_n_b) ) { + if ( u2_yes == u2_sing(p_n_a, p_n_b) ) { + return u2_rt( + wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, by, int)(wir_r, u2_rx(wir_r, l_a), u2_rx(wir_r, l_b)), + j2_mcc(Pt4, by, int)(wir_r, u2_rx(wir_r, r_a), u2_rx(wir_r, r_b))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, p_n_b, p_n_a) ) { + return j2_mcc(Pt4, by, uni)( + wir_r, + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, l_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, l_b), + u2_rx(wir_r, u2_nul))), + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, a), + u2_rx(wir_r, r_b))); + } + else { + return j2_mcc(Pt4, by, uni)( + wir_r, + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, r_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_b))), + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, a), + u2_rx(wir_r, l_b))); + } + } + else if ( u2_yes == u2_sing(p_n_b, p_n_a) ) { + return u2_rt( + wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, by, int)(wir_r, u2_rx(wir_r, l_b), u2_rx(wir_r, l_a)), + j2_mcc(Pt4, by, int)(wir_r, u2_rx(wir_r, r_b), u2_rx(wir_r, r_a))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, p_n_a, p_n_b) ) { + return j2_mcc(Pt4, by, uni)( + wir_r, + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, l_b), + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, l_a), + u2_rx(wir_r, u2_nul))), + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, a), + u2_rx(wir_r, r_a))); + } + else { + return j2_mcc(Pt4, by, uni)( + wir_r, + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, r_b), + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_a))), + j2_mcc(Pt4, by, int)(wir_r, + u2_rx(wir_r, a), + u2_rx(wir_r, l_a))); + } + } + } + u2_weak // transfer + j2_mc(Pt4, by, int)(u2_wire wir_r, + u2_noun cor) // retain + { + u2_noun a, b; + + if ( u2_no == u2_mean(cor, u2_cv_sam, &b, u2_cv_con_sam, &a, 0) ) { + return u2_bl_bail(wir_r, c3__exit); + } else { + return j2_mcc(Pt4, by, int)(wir_r, a, b); + } + } + +/* structures +*/ + u2_ho_jet + j2_mcj(Pt4, by, int)[] = { + { ".2", c3__lite, j2_mc(Pt4, by, int), Tier4, u2_none, u2_none }, + { } + }; + + + diff --git a/gen164/4/by_uni.c b/gen164/4/by_uni.c index 4de9cb9302..f76e50a4ac 100644 --- a/gen164/4/by_uni.c +++ b/gen164/4/by_uni.c @@ -1,4 +1,4 @@ -/* j/4/uni.c +/* j/4/by_uni.c ** ** This file is in the public domain. */ @@ -12,25 +12,105 @@ u2_noun a, // retain u2_noun b) // retain { - if ( u2_nul == b ) { - return u2k(a); + if ( u2_nul == a ) { + return u2_rx(wir_r, b); + } + else if ( u2_nul == b ) { + return u2_rx(wir_r, a); } else { - u2_noun l_b, n_b, r_b; - u2_noun pn_b, qn_b; + u2_noun l_a, n_a, r_a, lr_a, p_n_a, q_n_a; + u2_noun l_b, n_b, r_b, lr_b, p_n_b, q_n_b; - if ( (u2_no == u2_as_trel(b, &n_b, &l_b, &r_b)) || - (u2_no == u2_as_cell(n_b, &pn_b, &qn_b)) ) - { + if ( (u2_no == u2_as_cell(a, &n_a, &lr_a)) ) { return u2_bl_bail(wir_r, c3__exit); } + else if ( (u2_no == u2_as_cell(b, &n_b, &lr_b)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( (u2_no == u2_as_cell(n_a, &p_n_a, &q_n_a)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( (u2_no == u2_as_cell(n_b, &p_n_b, &q_n_b)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_a, &l_a, &r_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_b, &l_b, &r_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_yes == j2_mbc(Pt3, vor)(wir_r, p_n_a, p_n_b) ) { + if ( u2_yes == u2_sing(p_n_a, p_n_b) ) { + return u2_rt(wir_r, u2_rx(wir_r, n_b), + j2_mcc(Pt4, by, uni)( + wir_r, u2_rx(wir_r, l_a), u2_rx(wir_r, l_b)), + j2_mcc(Pt4, by, uni)( + wir_r, u2_rx(wir_r, r_a), u2_rx(wir_r, r_b))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, p_n_b, p_n_a) ) { + return j2_mcc(Pt4, by, uni)( + wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + j2_mcc(Pt4, by, uni)(wir_r, + u2_rx(wir_r, l_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, l_b), + u2_rx(wir_r, u2_nul))), + u2_rx(wir_r, r_a)), + u2_rx(wir_r, r_b)); + } + else { + return j2_mcc(Pt4, by, uni)( + wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, l_a), + j2_mcc(Pt4, by, uni)(wir_r, + u2_rx(wir_r, r_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_b)))), + u2_rx(wir_r, l_b)); + } + } + else if ( u2_yes == u2_sing(p_n_b, p_n_a) ) { + return u2_rt( + wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, by, uni)(wir_r, u2_rx(wir_r, r_b), u2_rx(wir_r, r_a)), + j2_mcc(Pt4, by, uni)(wir_r, u2_rx(wir_r, l_b), u2_rx(wir_r, l_a))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, p_n_a, p_n_b) ) { + return j2_mcc(Pt4, by, uni)( + wir_r, + u2_rx(wir_r, r_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, by, uni)(wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, l_a), + u2_rx(wir_r, u2_nul)), + u2_rx(wir_r, l_b)), + u2_rx(wir_r, r_b))); + } else { - u2_noun l = j2_mcc(Pt4, by, uni)(wir_r, a, l_b); - u2_noun r = j2_mcc(Pt4, by, uni)(wir_r, l, r_b); - u2_noun z = j2_mcc(Pt4, by, put)(wir_r, r, pn_b, qn_b); - - u2z(l); u2z(r); - return z; + return j2_mcc(Pt4, by, uni)( + wir_r, + u2_rx(wir_r, l_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, l_b), + j2_mcc(Pt4, by, uni)(wir_r, + u2_rx(wir_r, r_b), + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_a))))); } } } @@ -54,3 +134,4 @@ { ".2", c3__lite, j2_mc(Pt4, by, uni), Tier4, u2_none, u2_none }, { } }; + diff --git a/gen164/4/in.c b/gen164/4/in.c index 9562f1a769..9e43721ba2 100644 --- a/gen164/4/in.c +++ b/gen164/4/in.c @@ -10,8 +10,10 @@ extern u2_ho_jet j2_mcj(Pt4, in, gas)[]; extern u2_ho_jet j2_mcj(Pt4, in, has)[]; extern u2_ho_jet j2_mcj(Pt4, in, mer)[]; + extern u2_ho_jet j2_mcj(Pt4, in, int)[]; extern u2_ho_jet j2_mcj(Pt4, in, put)[]; extern u2_ho_jet j2_mcj(Pt4, in, tap)[]; + extern u2_ho_jet j2_mcj(Pt4, in, uni)[]; /* structures */ @@ -20,8 +22,10 @@ { j2_sc(Pt4, in, gas), j2_mcj(Pt4, in, gas), 0, 0, u2_none }, { j2_sc(Pt4, in, has), j2_mcj(Pt4, in, has), 0, 0, u2_none }, { j2_sc(Pt4, in, mer), j2_mcj(Pt4, in, mer), 0, 0, u2_none }, + { j2_sc(Pt4, in, int), j2_mcj(Pt4, in, int), 0, 0, u2_none }, { j2_sc(Pt4, in, put), j2_mcj(Pt4, in, put), 0, 0, u2_none }, { j2_sc(Pt4, in, tap), j2_mcj(Pt4, in, tap), 0, 0, u2_none }, + { j2_sc(Pt4, in, uni), j2_mcj(Pt4, in, uni), 0, 0, u2_none }, {} }; diff --git a/gen164/4/in_int.c b/gen164/4/in_int.c new file mode 100644 index 0000000000..1156962d69 --- /dev/null +++ b/gen164/4/in_int.c @@ -0,0 +1,97 @@ +/* j/4/in_int.c +** +** This file is in the public domain. +*/ +#include "all.h" +#include "../pit.h" + +/* functions +*/ + u2_weak // transfer + j2_mcc(Pt4, in, int)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b) // retain + { + if ( u2_nul == a ) { + return u2_rx(wir_r, u2_nul); + } + else if ( u2_nul == b ) { + return u2_rx(wir_r, u2_nul); + } + else { + u2_noun l_a, n_a, r_a, lr_a; + u2_noun l_b, n_b, r_b, lr_b; + u2_noun c; + + if ( (u2_no == u2_as_cell(a, &n_a, &lr_a)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( (u2_no == u2_as_cell(b, &n_b, &lr_b)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else { + if ( u2_yes == j2_mbc(Pt3, vor)(wir_r, n_b, n_a) ) { + c = a; a = b; b = c; + c = n_a; n_a = n_b; n_b = c; + c = lr_a; lr_a = lr_b; lr_b = c; + } + if ( u2_no == u2_as_cell(lr_a, &l_a, &r_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_b, &l_b, &r_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_yes == u2_sing(n_a, n_b) ) { + return u2_rt(wir_r, u2_rx(wir_r, n_a), + j2_mcc(Pt4, in, int)(wir_r, l_a, l_b), + j2_mcc(Pt4, in, int)(wir_r, r_a, r_b)); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, n_b, n_a) ) { + return j2_mcc(Pt4, in, uni)(wir_r, + j2_mcc(Pt4, in, int)(wir_r, + l_a, + u2_rt(wir_r, + n_b, + l_b, + u2_nul)), + j2_mcc(Pt4, in, int)(wir_r, + a, + r_b)); + } + else { + return j2_mcc(Pt4, in, uni)(wir_r, + j2_mcc(Pt4, in, int)(wir_r, + r_a, + u2_rt(wir_r, + n_b, + u2_nul, + r_b)), + j2_mcc(Pt4, in, int)(wir_r, + a, + l_b)); + } + } + } + } + u2_weak // transfer + j2_mc(Pt4, in, int)(u2_wire wir_r, + u2_noun cor) // retain + { + u2_noun a, b; + + if ( u2_no == u2_mean(cor, u2_cv_sam, &b, u2_cv_con_sam, &a, 0) ) { + return u2_bl_bail(wir_r, c3__exit); + } else { + return j2_mcc(Pt4, in, int)(wir_r, a, b); + } + } + +/* structures +*/ + u2_ho_jet + j2_mcj(Pt4, in, int)[] = { + { ".2", c3__lite, j2_mc(Pt4, in, int), Tier4, u2_none, u2_none }, + { } + }; + + diff --git a/gen164/4/in_uni.c b/gen164/4/in_uni.c new file mode 100644 index 0000000000..8a6273bc82 --- /dev/null +++ b/gen164/4/in_uni.c @@ -0,0 +1,139 @@ +/* j/4/in_uni.c +** +** This file is in the public domain. +*/ +#include "all.h" +#include "../pit.h" + +/* functions +*/ + u2_weak // transfer + j2_mcc(Pt4, in, uni)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b) // retain + { + if ( u2_nul == a ) { + return u2_rx(wir_r, b); + } + else if ( u2_nul == b ) { + return u2_rx(wir_r, a); + } + else { + u2_noun l_a, n_a, r_a, lr_a; + u2_noun l_b, n_b, r_b, lr_b; + + if ( (u2_no == u2_as_cell(a, &n_a, &lr_a)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( (u2_no == u2_as_cell(b, &n_b, &lr_b)) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else { + if ( u2_yes == j2_mbc(Pt3, vor)(wir_r, n_a, n_b) ) { + if ( u2_no == u2_as_cell(lr_a, &l_a, &r_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_b, &l_b, &r_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_yes == u2_sing(n_a, n_b) ) { + return u2_rt( + wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, in, uni)(wir_r, u2_rx(wir_r, l_a), u2_rx(wir_r, l_b)), + j2_mcc(Pt4, in, uni)(wir_r, u2_rx(wir_r, r_a), u2_rx(wir_r, r_b))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, n_b, n_a) ) { + return j2_mcc(Pt4, in, uni)( + wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + j2_mcc(Pt4, in, uni)(wir_r, + u2_rx(wir_r, l_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, l_b), + u2_rx(wir_r, u2_nul))), + u2_rx(wir_r, r_a)), + u2_rx(wir_r, r_b)); + } + else { + return j2_mcc(Pt4, in, uni)( + wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, l_a), + j2_mcc(Pt4, in, uni)(wir_r, + u2_rx(wir_r, r_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_b)))), + u2_rx(wir_r, l_b)); + } + } + else if ( u2_no == u2_as_cell(lr_b, &l_b, &r_b) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_no == u2_as_cell(lr_a, &l_a, &r_a) ) { + return u2_bl_bail(wir_r, c3__exit); + } + else if ( u2_yes == u2_sing(n_b, n_a) ) { + return u2_rt( + wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, in, uni)(wir_r, u2_rx(wir_r, r_b), u2_rx(wir_r, r_a)), + j2_mcc(Pt4, in, uni)(wir_r, u2_rx(wir_r, l_b), u2_rx(wir_r, l_a))); + } + else if ( u2_yes == j2_mbc(Pt3, hor)(wir_r, n_a, n_b) ) { + return j2_mcc(Pt4, in, uni)( + wir_r, + u2_rx(wir_r, r_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + j2_mcc(Pt4, in, uni)(wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, l_a), + u2_nul), + u2_rx(wir_r, l_b)), + u2_rx(wir_r, r_b))); + } + else { + return j2_mcc(Pt4, in, uni)( + wir_r, + u2_rx(wir_r, l_a), + u2_rt(wir_r, + u2_rx(wir_r, n_b), + u2_rx(wir_r, l_b), + j2_mcc(Pt4, in, uni)(wir_r, + u2_rt(wir_r, + u2_rx(wir_r, n_a), + u2_rx(wir_r, u2_nul), + u2_rx(wir_r, r_a)), + u2_rx(wir_r, r_b)))); + } + } + } + } + u2_weak // transfer + j2_mc(Pt4, in, uni)(u2_wire wir_r, + u2_noun cor) // retain + { + u2_noun a, b; + + if ( u2_no == u2_mean(cor, u2_cv_sam, &b, u2_cv_con_sam, &a, 0) ) { + return u2_bl_bail(wir_r, c3__exit); + } else { + return j2_mcc(Pt4, in, uni)(wir_r, a, b); + } + } + +/* structures +*/ + u2_ho_jet + j2_mcj(Pt4, in, uni)[] = { + { ".2", c3__lite, j2_mc(Pt4, in, uni), Tier4, u2_none, u2_none }, + { } + }; + diff --git a/gen164/5/co_emco.c b/gen164/5/co_emco.c index 7a5b32c7c7..67d0cf4f81 100644 --- a/gen164/5/co_emco.c +++ b/gen164/5/co_emco.c @@ -24,12 +24,12 @@ mpz_t bas_mp, dar_mp, hol_mp, rad_mp; if ( u2_no == u2_mean(cor, u2_cv_sam_4, &bas, - u2_cv_sam_5, &min, - u2_cv_sam_3, &par, - u2_cv_sam_6, &rex, + u2_cv_sam_5, &min, + u2_cv_sam_3, &par, + u2_cv_sam_6, &rex, 0) ) { - return u2_bl_bail(wir_r, c3__exit); + return u2_bl_bail(wir_r, c3__exit); } while ( 1 ) { @@ -42,7 +42,7 @@ mpz_tdiv_q(rad_mp, hol_mp, bas_mp); mpz_tdiv_r(dar_mp, hol_mp, bas_mp); - + if ( min ) { min--; } @@ -50,7 +50,7 @@ u2_rl_mp(hol, dar_mp); // rex (par =(0 dar) rad rex) - } + } } /* structures */ diff --git a/gen164/5/co_oxco.c b/gen164/5/co_oxco.c index fac733d810..4fece9d934 100644 --- a/gen164/5/co_oxco.c +++ b/gen164/5/co_oxco.c @@ -15,11 +15,11 @@ u2_atom bas, gop; u2_noun dug; if ( u2_no == u2_mean(cor, u2_cv_sam_4, &bas, - u2_cv_sam_5, &gop, - u2_cv_sam_3, &dug, + u2_cv_sam_5, &gop, + u2_cv_sam_3, &dug, 0) ) { - return u2_bl_bail(wir_r, c3__exit); + return u2_bl_bail(wir_r, c3__exit); } return 0; diff --git a/gen164/5/co_roco.c b/gen164/5/co_roco.c index 2d5fd56687..50dbf42e77 100644 --- a/gen164/5/co_roco.c +++ b/gen164/5/co_roco.c @@ -28,7 +28,7 @@ /* { */ /* return u2_bl_bail(wir_r, c3__exit); */ /* } */ - + return 0; } /* structures diff --git a/gen164/5/rd.c b/gen164/5/rd.c index ca6ca0cbb0..e3f4479650 100644 --- a/gen164/5/rd.c +++ b/gen164/5/rd.c @@ -32,7 +32,7 @@ union doub { { union doub b; b.d = (double) u2_chub(0, a); - + return u2_ci_chubs(1, &b.c); } @@ -62,7 +62,7 @@ union doub { c.c = u2_chub(0, a); d.c = u2_chub(0, b); e.d = c.d * d.d; - + return u2_ci_chubs(1, &e.c); } @@ -94,7 +94,7 @@ union doub { c.c = u2_chub(0, a); d.c = u2_chub(0, b); e.d = c.d / d.d; - + return u2_ci_chubs(1, &e.c); } @@ -126,7 +126,7 @@ union doub { c.c = u2_chub(0, a); d.c = u2_chub(0, b); e.d = c.d + d.d; - + return u2_ci_chubs(1, &e.c); } @@ -158,7 +158,7 @@ union doub { c.c = u2_chub(0, a); d.c = u2_chub(0, b); e.d = c.d - d.d; - + return u2_ci_chubs(1, &e.c); } @@ -189,7 +189,7 @@ union doub { union doub c, d; c.c = u2_chub(0, a); d.c = u2_chub(0, b); - + return u2_say(c.d <= d.d); } @@ -220,7 +220,7 @@ union doub { union doub c, d; c.c = u2_chub(0, a); d.c = u2_chub(0, b); - + return u2_say(c.d < d.d); } @@ -251,7 +251,7 @@ union doub { union doub c, d; c.c = u2_chub(0, a); d.c = u2_chub(0, b); - + return u2_say(c.d >= d.d); } @@ -282,7 +282,7 @@ union doub { union doub c, d; c.c = u2_chub(0, a); d.c = u2_chub(0, b); - + return u2_say(c.d > d.d); } diff --git a/gen164/5/repg.c b/gen164/5/repg.c index 585117c793..dc7a595a96 100644 --- a/gen164/5/repg.c +++ b/gen164/5/repg.c @@ -18,7 +18,6 @@ c3_y* rep_y = u2_cr_tape(rep); - char* rec = (char*)lub_y; char* end; while(*rec != 0) { @@ -59,7 +58,7 @@ opt = cre2_opt_new(); if (opt) { cre2_opt_set_log_errors(opt, 0); - cre2_opt_set_encoding(opt, CRE2_Latin1); + cre2_opt_set_encoding(opt, CRE2_UTF8); cre2_opt_set_perl_classes(opt, 1); cre2_opt_set_one_line(opt, 1); cre2_opt_set_longest_match(opt, 1); @@ -76,7 +75,7 @@ if (!match) { if(rad_y[ic]) - ret = u2_cn_cell((u2_atom)rad_y[ic], ret); + ret = u2_cn_cell((c3_y)rad_y[ic], ret); ic++; } else { diff --git a/gen164/6/ap.c b/gen164/6/ap.c index ee43320607..45a856b004 100644 --- a/gen164/6/ap.c +++ b/gen164/6/ap.c @@ -39,42 +39,117 @@ static u2_weak _open_in(u2_wire wir_r, + u2_noun ter, u2_noun gen); + static u2_noun + _al_core(u2_wire wir_r, + u2_noun ter, + u2_noun gen) + { + u2_weak hoc = u2_ds_look(wir_r, ter, "al"); + + if ( u2_none == hoc ) { + return u2_cm_bail(c3__fail); + } + else { + u2_noun gat = u2_nk_soft(wir_r, u2_rx(wir_r, ter), hoc); + u2_noun cor = u2_rl_molt(wir_r, gat, + u2_cv_sam, u2_rx(wir_r, gen), + 0); + + u2_rz(wir_r, hoc); + u2_rz(wir_r, gat); + + return cor; + } + } + + static u2_noun + _by_core(u2_wire wir_r, + u2_noun ter, + u2_noun gen) + { + u2_weak hoc = u2_ds_look(wir_r, ter, "by"); + + if ( u2_none == hoc ) { + return u2_cm_bail(c3__fail); + } + else { + u2_noun gat = u2_nk_soft(wir_r, u2_rx(wir_r, ter), hoc); + u2_noun cor = u2_rl_molt(wir_r, gat, + u2_cv_sam, u2_rx(wir_r, gen), + 0); + + u2_rz(wir_r, hoc); + u2_rz(wir_r, gat); + + return cor; + } + } + /** open cases **/ #define _open_do_p(stem) \ static u2_noun _open_in_##stem \ - (u2_wire wir_r, u2_noun p_gen) + (u2_wire wir_r, u2_noun ter, u2_noun p_gen) #define _open_do_pq(stem) \ static u2_noun _open_in_##stem \ - (u2_wire wir_r, u2_noun p_gen, u2_noun q_gen) + (u2_wire wir_r, u2_noun ter, u2_noun p_gen, u2_noun q_gen) #define _open_do_pqr(stem) \ static u2_noun _open_in_##stem \ - (u2_wire wir_r, u2_noun p_gen, u2_noun q_gen, u2_noun r_gen) + (u2_wire wir_r, u2_noun ter, u2_noun p_gen, u2_noun q_gen, u2_noun r_gen) #define _open_do_pqrs(stem) \ static u2_noun _open_in_##stem \ - (u2_wire wir_r, u2_noun p_gen, u2_noun q_gen, u2_noun r_gen, u2_noun s_gen) + (u2_wire wir_r, u2_noun ter, u2_noun p_gen, u2_noun q_gen, u2_noun r_gen, \ + u2_noun s_gen) /*** **** ***/ + _open_do_pq(tsbr) // =: + { + return + u2_bt(wir_r, c3__tsls, + j2_mcy(Pt6, al, bunt)(wir_r, + _al_core(wir_r, ter, p_gen), p_gen), + u2_rx(wir_r, q_gen)); + } + _open_do_pq(tscl) // =: + { + return u2_bt(wir_r, c3__tsgr, + u2_bt(wir_r, c3__cncb, + u2_bc(wir_r, u2_bc(wir_r, u2_nul, _1), + u2_nul), + u2_rx(wir_r, p_gen)), + u2_rx(wir_r, q_gen)); + } + _open_do_pqr(tsdt) // =. + { + return + u2_bt(wir_r, c3__tsgr, + u2_bt(wir_r, c3__cncb, + u2_bc(wir_r, u2_bc(wir_r, u2_nul, _1), + u2_nul), + u2_bc(wir_r, u2_bc(wir_r, u2_rx(wir_r, p_gen), + u2_rx(wir_r, q_gen)), + u2_nul)), + u2_rx(wir_r, r_gen)); + } _open_do_pq(tsgl) // =< { return u2_bt(wir_r, c3__tsgr, u2_rx(wir_r, q_gen), u2_rx(wir_r, p_gen)); } - _open_do_pq(tshp) // =- { return u2_bt(wir_r, c3__tsls, u2_rx(wir_r, q_gen), u2_rx(wir_r, p_gen)); } - _open_do_pq(tsls) // =+ { return u2_bt @@ -83,15 +158,52 @@ u2_bc(wir_r, u2_nul, _1)), u2_rx(wir_r, q_gen)); } + _open_do_p(tssg) // =~ + { + u2_noun tp_gen = u2_t(p_gen); + u2_noun ip_gen = u2_h(p_gen); + + if ( (u2_nul == p_gen) ) { + return u2_bc(wir_r, c3__zpzp, u2_nul); + } + else if ( (u2_nul == tp_gen) ) { + return u2_rx(wir_r, ip_gen); + } + else { + return u2_bt(wir_r, c3__tsgr, + u2_rx(wir_r, ip_gen), + _open_in_tssg(wir_r, ter, tp_gen)); + } + } +/*** +**** +***/ + _open_do_p(bccb) // $_ + { + return j2_mcy(Pt6, al, bunt)(wir_r, _al_core(wir_r, ter, p_gen), p_gen); + } + _open_do_p(bctr) // $* + { + return + u2_bc(wir_r, c3__ktsg, + j2_mcy(Pt6, al, bunt)(wir_r, + _al_core(wir_r, ter, p_gen), + p_gen)); + } + _open_do_p(bczp) // $! + { + return u2_bt + (wir_r, c3__bccb, c3__axil, u2_rx(wir_r, p_gen)); + } /*** **** ***/ _open_do_p(brhp) // |- { return u2_bt - (wir_r, c3__tsgr, - u2_bc(wir_r, c3__brdt, u2_rx(wir_r, p_gen)), - u2_bc(wir_r, c3__cnzy, u2_blip)); + (wir_r, c3__tsgl, + u2_bc(wir_r, c3__cnzy, u2_blip), + u2_bc(wir_r, c3__brdt, u2_rx(wir_r, p_gen))); } _open_do_p(brdt) // |. { @@ -102,9 +214,7 @@ u2_nul, u2_nul)); } -/*** -**** -***/ + /*** **** ***/ @@ -121,9 +231,19 @@ (wir_r, c3__wtcl, u2_rx(wir_r, ip_gen), u2_bt(wir_r, c3__dtzz, 'f', u2_yes), - _open_in_wtbr(wir_r, tp_gen)); + _open_in_wtbr(wir_r, ter, tp_gen)); } } + _open_do_pqr(wtkt) // ?^ + { + return u2_bq + (wir_r, c3__wtcl, + u2_bt(wir_r, c3__wtts, + u2_bt(wir_r, c3__axil, c3__atom, u2_blip), + u2_rx(wir_r, p_gen)), + u2_rx(wir_r, r_gen), + u2_rx(wir_r, q_gen)); + } _open_do_pq(wtgl) // ?< { return u2_bq @@ -147,11 +267,12 @@ u2_rx(wir_r, q_gen), u2_bc(wir_r, c3__zpzp, u2_nul)); } -#if 0 - _open_do_pq(wthp) // ?- + _open_do_pq(wthp) // ?- { if ( (u2_nul == q_gen) ) { - return u2_bc(wir_r, c3__zpfs, u2_rx(wir_r, p_gen)); + return u2_bc(wir_r, c3__zpfs, + u2_bc(wir_r, c3__cnzz, + u2_rx(wir_r, p_gen))); } else { u2_noun iq_gen = u2_h(q_gen); @@ -166,10 +287,9 @@ u2_rx(wir_r, piq_gen), u2_rx(wir_r, p_gen)), u2_rx(wir_r, qiq_gen), - _open_in_wthp(wir_r, p_gen, tq_gen)); + _open_in_wthp(wir_r, ter, p_gen, tq_gen)); } } -#endif _open_do_p(wtpm) // ?& { if ( (u2_nul == p_gen) ) { @@ -182,15 +302,13 @@ return u2_bq (wir_r, c3__wtcl, u2_rx(wir_r, ip_gen), - _open_in_wtpm(wir_r, tp_gen), + _open_in_wtpm(wir_r, ter, tp_gen), u2_bt(wir_r, c3__dtzz, 'f', u2_no)); } } -#if 0 _open_do_pqr(wtls) // ?+ - { - u2_noun tul = u2_bc(wir_r, - u2_bc(wir_r, u2_bc(wir_r, c3__bcts, c3__noun), + { u2_noun tul = u2_bc(wir_r, + u2_bc(wir_r, u2_bc(wir_r, c3__axil, c3__noun), u2_rx(wir_r, q_gen)), u2_nul); u2_noun zal = j2_mbc(Pt2, weld)(wir_r, r_gen, tul); @@ -198,8 +316,28 @@ u2_rz(wir_r, tul); return ret; + + } + _open_do_pqr(wtpt) // ?@ + { + return u2_bq(wir_r, c3__wtcl, + u2_bt(wir_r, c3__wtts, + u2_bt(wir_r, c3__axil, + c3__atom, + u2_blip), + u2_rx(wir_r, p_gen)), + u2_rx(wir_r, q_gen), + u2_rx(wir_r, r_gen)); + } + _open_do_pqr(wtsg) // ?~ + { + return u2_bq(wir_r, c3__wtcl, + u2_bt(wir_r, c3__wtts, + u2_bc(wir_r, c3__axil, c3__null), + u2_rx(wir_r, p_gen)), + u2_rx(wir_r, q_gen), + u2_rx(wir_r, r_gen)); } -#endif _open_do_p(wtzp) // ?! { return u2_bq @@ -211,6 +349,45 @@ /*** **** ***/ + _open_do_pq(zpcb) // !_ + { + return u2_rx(wir_r, q_gen); + } + _open_do_p(zpgr) // !> + { + return u2_bq + (wir_r, c3__cnhp, + u2_bc(wir_r, c3__cnzy, c3__onan), + u2_bt(wir_r, c3__zpsm, + u2_bc(wir_r, c3__bctr, + u2_bc(wir_r, c3__herb, + u2_bc(wir_r, c3__cnzy, + c3__abel))), + u2_rx(wir_r, p_gen)), + u2_nul); + } +/*** +**** +***/ + _open_do_pq(clhp) // :- + { + return u2_bc + (wir_r, u2_rx(wir_r, p_gen), + u2_rx(wir_r, q_gen)); + } + _open_do_pq(clcb) // :_ + { + return u2_bc + (wir_r, u2_rx(wir_r, q_gen), + u2_rx(wir_r, p_gen)); + } + _open_do_p(clcn) // :% + { + return u2_bc + (wir_r, u2_bc(wir_r, c3__clsg, + u2_rx(wir_r, p_gen)), + u2_bc(wir_r, c3__bczp, c3__null)); + } _open_do_pqrs(clkt) // :^ { return u2_bq @@ -224,7 +401,6 @@ return u2_bt (wir_r, u2_rx(wir_r, p_gen), u2_rx(wir_r, q_gen), u2_rx(wir_r, r_gen)); } -#if 0 _open_do_p(clsg) // :~ { if ( (u2_nul == p_gen) ) { @@ -235,10 +411,9 @@ u2_noun tp_gen = u2_t(p_gen); return u2_bc(wir_r, u2_rx(wir_r, ip_gen), - _open_in_clsg(wir_r, tp_gen)); + _open_in_clsg(wir_r, ter, tp_gen)); } } - _open_do_p(cltr) // :* { if ( (u2_nul == p_gen) ) { @@ -253,14 +428,22 @@ } else { return u2_bc (wir_r, u2_rx(wir_r, ip_gen), - _open_in_cltr(wir_r, tp_gen)); + _open_in_cltr(wir_r, ter, tp_gen)); } } } -#endif /*** **** ***/ + _open_do_pq(cncb) // %_ + { + return u2_bc + (wir_r, c3__ktls, + u2_bq(wir_r, u2_bc(wir_r, c3__cnzz, u2_rx(wir_r, p_gen)), + c3__cnts, + u2_rx(wir_r, p_gen), + u2_rx(wir_r, q_gen))); + } _open_do_pq(cncl) // %: { return u2_bq @@ -317,18 +500,71 @@ u2_rx(wir_r, q_gen), u2_bo(wir_r, u2_bc(wir_r, - u2_bo(wir_r, + u2_bo(wir_r, u2_bc(wir_r, u2_nul, _6)), u2_rx(wir_r, r_gen)))); } - + _open_do_p(cnzy) // %cnzy + { + return u2_bt + (wir_r, c3__cnts, + u2_bc(wir_r, u2_rx(wir_r, p_gen), u2_nul), + u2_nul); + } + _open_do_p(cnzz) // %cnzz + { + return u2_bt + (wir_r, c3__cnts, u2_rx(wir_r, p_gen), u2_nul); + } /*** **** ***/ - _open_do_pq(brkt) // &- + _open_do_p(hxgl) // #< + { + return u2_bq + (wir_r, c3__cnhp, + u2_bc(wir_r, c3__cnzy, c3__noah), + u2_bc(wir_r, c3__zpgr, + u2_bc(wir_r, c3__cltr, u2_rx(wir_r, p_gen))), + u2_nul); + } + _open_do_p(hxgr) // #> + { + return u2_bq + (wir_r, c3__cnhp, + u2_bc(wir_r, c3__cnzy, c3__cain), + u2_bc(wir_r, c3__zpgr, + u2_bc(wir_r, c3__cltr, u2_rx(wir_r, p_gen))), + u2_nul); + } +/*** +**** +***/ + _open_do_pq(ktdt) // ^. + { + return u2_bt + (wir_r, c3__ktls, + u2_bq(wir_r, c3__cnhp, u2_rx(wir_r, p_gen), u2_rx(wir_r, q_gen), u2_nul), + u2_rx(wir_r, q_gen)); + } + _open_do_pq(kthp) // ^- + { + return u2_bt + (wir_r, c3__ktls, + j2_mcy(Pt6, al, bunt)(wir_r, _al_core(wir_r, ter, p_gen), p_gen), + u2_rx(wir_r, q_gen)); + } +/*** +**** +***/ + _open_do_pq(brcb) // |_ + { + return u2_bt(wir_r, c3__tsls, + u2_bc(wir_r, c3__bctr, u2_rx(wir_r, p_gen)), + u2_bc(wir_r, c3__brcn, u2_rx(wir_r, q_gen))); + } + _open_do_pq(brkt) // |^ { - // [%brkt *] [%tsgr [%brcn (~(put by q.gen) %% [%ash p.gen])] %%] - // u2_noun diz = u2_bc(wir_r, c3__ash, u2_rx(wir_r, p_gen)); u2_noun ret = u2_bt (wir_r, @@ -341,6 +577,19 @@ u2_rz(wir_r, diz); return ret; } + _open_do_pq(brls) // |+ + { + return u2_bc(wir_r, c3__ktbr, + u2_bt(wir_r, c3__brts, + u2_rx(wir_r, p_gen), + u2_rx(wir_r, q_gen))); + } + _open_do_p(brwt) // |? + { + return u2_bt(wir_r, c3__ktwt, + c3__brdt, + u2_rx(wir_r, p_gen)); + } /*** **** ***/ @@ -371,6 +620,15 @@ u2_bq(wir_r, c3__live, c3__dtzz, u2_blip, u2_rx(wir_r, p_gen)), u2_rx(wir_r, q_gen)); + } + _open_do_pq(sgcb) // ~_ + { + return u2_bt + (wir_r, c3__sggr, + u2_bc(wir_r, c3__mean, + u2_bc(wir_r, c3__brdt, + u2_rx(wir_r, p_gen))), + u2_rx(wir_r, q_gen)); } static u2_noun _sgcn_a(u2_wire wir_r, @@ -408,6 +666,15 @@ _sgcn_a(wir_r, r_gen, u2_nul))), u2_rx(wir_r, s_gen)); } + _open_do_pq(sgfs) // ~/ + { + return u2_bc + (wir_r, c3__sgcn, + u2_bq(wir_r, u2_rx(wir_r, p_gen), + u2_bc(wir_r, u2_nul, _7), + u2_nul, + u2_rx(wir_r, q_gen))); + } _open_do_pq(sgls) // ~+ { return u2_bt @@ -415,6 +682,30 @@ u2_bq(wir_r, c3__memo, c3__dtzz, u2_blip, u2_rx(wir_r, p_gen)), u2_rx(wir_r, q_gen)); } + _open_do_pqr(sgpm) // ~& + { + return u2_bt + (wir_r, + c3__sggr, + u2_bt(wir_r, + c3__slog, + u2_bt(wir_r, c3__dtzy, u2_blip, u2_rx(wir_r, p_gen)), + u2_bq(wir_r, c3__cnhp, u2_bc(wir_r, c3__cnzy, c3__cain), + u2_bc(wir_r, c3__zpgr, u2_rx(wir_r, q_gen)), u2_nul)), + u2_rx(wir_r, r_gen)); + } + _open_do_pqrs(sgwt) // ~? + { + return u2_bq(wir_r, c3__tsgl, + u2_rx(wir_r, s_gen), + c3__wtdt, + u2_bq(wir_r, u2_rx(wir_r, q_gen), + u2_bc(wir_r, u2_nul, _1), + c3__sgpm, + u2_bt(wir_r, u2_rx(wir_r, p_gen), + u2_rx(wir_r, r_gen), + u2_bc(wir_r, u2_nul, _1)))); + } /*** **** ***/ @@ -459,18 +750,39 @@ } } #if 0 - _open_do_p(smdq) + _open_do_pq(smsm) { - return _ap_snig(p_gen); + return + u2_bt(wir_r, c3__tsgr, u2_bq(wir_r, c3__ktts, c3__v, u2_nul, _1), + u2_bt(wir_r, c3__tsls, + u2_bt(wir_r, c3__ktts, c3__a, + u2_bt(wir_r, c3__tsgr, u2_bc(wir_r, c3__cnzy, c3__v), + u2_rx(wir_r, p_gen))), + u2_bt(wir_r, c3__tsls, + u2_bt(wir_r, c3__ktts, c3__b, + u2_bt(wir_r, c3__tsgr, + u2_bc(wir_r, c3__cnzy, c3__v), + u2_rx(wir_r, q_gen))), + u2_bt(wir_r, c3__tsls, + u2_bt(wir_r, c3__ktts, c3__c, + u2_bq(wir_r, c3__cnhp, + u2_bc(wir_r, c3__cnzy, c3__a), + u2_bc(wir_r, c3__cnzy, c3__b), + u2_nul)), + u2_bt(wir_r, c3__wtgr, + u2_bt(wir_r, c3__dtts, + u2_bc(wir_r, c3__cnzy, c3__c), + u2_bc(wir_r, c3__cnzy, c3__b)), + u2_bc(wir_r, c3__cnzy, c3__c)))))); } #endif - /* functions */ /** open **/ static u2_weak _open_in(u2_wire wir_r, + u2_noun ter, u2_noun gen) { u2_noun p_gen, q_gen, r_gen, s_gen; @@ -497,19 +809,19 @@ # define _open_p(stem) \ case c3__##stem: \ - return _open_in_##stem(wir_r, u2_t(gen)); \ + return _open_in_##stem(wir_r, ter, u2_t(gen)); \ # define _open_pq(stem) \ case c3__##stem: \ if ( u2_no == u2_as_cell(u2_t(gen), &p_gen, &q_gen) ) { \ return u2_bl_bail(wir_r, c3__fail); \ - } else return _open_in_##stem(wir_r, p_gen, q_gen); + } else return _open_in_##stem(wir_r, ter, p_gen, q_gen); # define _open_pqr(stem) \ case c3__##stem: \ if ( u2_no == u2_as_trel(u2_t(gen), &p_gen, &q_gen, &r_gen) ) { \ return u2_bl_bail(wir_r, c3__fail); \ - } else return _open_in_##stem(wir_r, p_gen, q_gen, r_gen); + } else return _open_in_##stem(wir_r, ter, p_gen, q_gen, r_gen); # define _open_pqrs(stem) \ case c3__##stem: \ @@ -517,49 +829,78 @@ (u2_t(gen), &p_gen, &q_gen, &r_gen, &s_gen) )\ { \ return u2_bl_bail(wir_r, c3__fail); \ - } else return _open_in_##stem(wir_r, p_gen, q_gen, r_gen, s_gen); + } else return _open_in_##stem(wir_r, ter, p_gen, q_gen, r_gen, s_gen); - _open_pq (tsgl); - _open_pq (tshp); - _open_pq (tsls); + _open_p (bccb); + _open_p (bctr); + _open_p (bczp); - _open_p (brhp); _open_p (brdt); + _open_pq (brcb); + _open_p (brhp); + _open_pq (brkt); + _open_pq (brls); + _open_p (brwt); + _open_pq (clcb); + _open_p (clcn); + _open_pq (clhp); _open_pqrs(clkt); _open_pqr (clls); - // _open_p (cltr); - // _open_p (clsg); - - _open_pqr (wtdt); - _open_pq (wtgl); - _open_p (wtzp); - _open_p (wtbr); - _open_p (wtpm); - // _open_pqr (wtls); - // _open_pqr (wtsg); - // _open_pq (wthp); - _open_pq (wtgr); - + _open_p (cltr); + _open_p (clsg); + _open_pq (cncb); _open_pq (cncl); _open_pq (cndt); _open_pqrs(cnkt); _open_pq (cnhp); _open_pqr (cnls); - _open_pqr (cnsg); + _open_pqr (cnsg); + _open_p (cnzy); + _open_p (cnzz); - _open_pq (brkt); + _open_p (hxgl); + _open_p (hxgr); + + _open_pq (ktdt); + _open_pq (kthp); _open_pq (sgts); _open_pq (sgbr); _open_pq (sggl); _open_pq (sgbc); + _open_pq (sgcb); _open_pqrs(sgcn); + _open_pq (sgfs); _open_pq (sgls); + _open_pqr (sgpm); + _open_pqrs(sgwt); _open_pq (smcl); - // _open_p (smdq); - // _open_pq (smsg); + // _open_pq (smsm); + + _open_pq (tsbr); + _open_pq (tscl); + _open_pqr (tsdt); + _open_pq (tsgl); + _open_pq (tshp); + _open_pq (tsls); + _open_p (tssg); + + _open_pqr (wtdt); + _open_pq (wtgl); + _open_pqr (wtpt); + _open_pqr (wtsg); + _open_p (wtzp); + _open_p (wtbr); + _open_pq (wthp); + _open_pq (wtgr); + _open_pqr (wtls); + _open_pqr (wtkt); + _open_p (wtpm); + + _open_pq (zpcb); + _open_p (zpgr); } } @@ -575,7 +916,7 @@ return u2_bc(wir_r, u2_rx(wir_r, gen), u2_nul); } else switch ( u2_h(gen) ) { - default: return u2_bl_error(wir_r, "rake-gene"); + default: return u2_bl_error(wir_r, "rake-twig"); case u2_nul: return u2_bc(wir_r, u2_rx(wir_r, gen), u2_nul); @@ -771,7 +1112,7 @@ u2_noun ter, // retain u2_noun gen) // retain { - u2_weak pro = _open_in(wir_r, gen); + u2_weak pro = _open_in(wir_r, ter, gen); if ( u2_none != pro ) { return pro; @@ -841,4 +1182,3 @@ j2_mbd(Pt6, ap)[] = { { } }; - diff --git a/gen164/6/ut_mint.c b/gen164/6/ut_mint.c index 5ae1a6d995..ebc6070eb1 100644 --- a/gen164/6/ut_mint.c +++ b/gen164/6/ut_mint.c @@ -5,6 +5,8 @@ #include "all.h" #include "../pit.h" +int FOO; + /* logic */ static u2_noun @@ -662,6 +664,27 @@ u2_rz(wir_r, zel); return ret; } + case c3__kthx: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); + _mint_used(wir_r); + { + u2_noun huz = j2_mcy(Pt6, ut, play)(wir_r, van, sut, p_gen); + u2_noun hif = _mint_nice(wir_r, van, gol, huz); + u2_noun zel = _mint_in(wir_r, van, sut, hif, q_gen); + u2_noun ret = u2_bc(wir_r, hif, u2_rx(wir_r, u2_t(zel))); + + { + u2_noun goz = j2_mcy(Pt6, ut, play)(wir_r, van, sut, q_gen); + u2_noun bar; + + FOO = 1; + fprintf(stderr, "\r\n"); + bar = j2_mcy(Pt6, ut, nest)(wir_r, van, huz, u2_no, goz); + fprintf(stderr, "kthx: bar %d\r\n", bar); + FOO = 0; + } + u2_rz(wir_r, zel); + return ret; + } case c3__tsgr: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); _mint_used(wir_r); { diff --git a/gen164/6/ut_mull.c b/gen164/6/ut_mull.c index 0a9f73c5fb..7571b7f52f 100644 --- a/gen164/6/ut_mull.c +++ b/gen164/6/ut_mull.c @@ -604,6 +604,19 @@ u2_rz(wir_r, zel); return ret; } + case c3__kthx: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); + _mull_used(wir_r); + { + u2_noun p_hif = _mull_nice + (wir_r, van, gol, j2_mcy(Pt6, ut, play)(wir_r, van, sut, p_gen)); + u2_noun q_hif = j2_mcy(Pt6, ut, play)(wir_r, van, dox, p_gen); + + u2_noun zel = _mull_in(wir_r, van, sut, p_hif, dox, q_gen); + u2_noun ret = u2_bc(wir_r, p_hif, q_hif); + + u2_rz(wir_r, zel); + return ret; + } case c3__tsgr: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); _mull_used(wir_r); { diff --git a/gen164/6/ut_play.c b/gen164/6/ut_play.c index bf88c34ab8..45e7274e4a 100644 --- a/gen164/6/ut_play.c +++ b/gen164/6/ut_play.c @@ -339,6 +339,11 @@ { return _play_x(wir_r, van, sut, p_gen); } + case c3__kthx: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); + _play_used(wir_r); + { + return _play_x(wir_r, van, sut, p_gen); + } case c3__ktls: u2_bi_cell(wir_r, u2_t(gen), &p_gen, &q_gen); _play_used(wir_r); { diff --git a/gen164/pit.h b/gen164/pit.h index ab55fd54fb..e5b32f915f 100644 --- a/gen164/pit.h +++ b/gen164/pit.h @@ -294,11 +294,6 @@ /** Tier 4. **/ - u2_weak // transfer - j2_mcc(Pt4, in, put)(u2_wire wir_r, - u2_noun a, // retain - u2_noun b); // retain - u2_weak // transfer j2_mcc(Pt4, in, gas)(u2_wire wir_r, u2_noun a, // retain @@ -309,16 +304,42 @@ u2_noun a, // retain u2_noun b); // retain + u2_weak // transfer + j2_mcc(Pt4, in, int)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b); // retain + + u2_weak // transfer + j2_mcc(Pt4, in, put)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b); // retain + u2_weak // transfer j2_mcc(Pt4, in, tap)(u2_wire wir_r, u2_noun a, // retain u2_noun b); // retain + u2_weak // transfer + j2_mcc(Pt4, in, uni)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b); // retain + + u2_noun // transfer j2_mcc(Pt4, by, get)(u2_wire wir_r, u2_noun a, // retain u2_noun b); // retain + u2_weak // transfer + j2_mcc(Pt4, by, gas)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b); // retain + + u2_weak // transfer + j2_mcc(Pt4, by, int)(u2_wire wir_r, + u2_noun a, // retain + u2_noun b); // retain + u2_weak // transfer j2_mcc(Pt4, by, put)(u2_wire wir_r, u2_noun a, // retain @@ -326,9 +347,10 @@ u2_noun c); // retain u2_weak // transfer - j2_mcc(Pt4, by, gas)(u2_wire wir_r, + j2_mcc(Pt4, by, uni)(u2_wire wir_r, u2_noun a, // retain u2_noun b); // retain + /** Tier 5. **/ u2_noun // transfer diff --git a/include/c/motes.h b/include/c/motes.h index ba4e51e50b..ce99544d79 100644 --- a/include/c/motes.h +++ b/include/c/motes.h @@ -4,6 +4,9 @@ */ /** Definitions. **/ + +# define c3__a c3_s1('a') +# define c3__abel c3_s4('a','b','e','l') # define c3__abo c3_s3('a','b','o') # define c3__actd c3_s4('a','c','t','d') # define c3__add c3_s3('a','d','d') @@ -21,7 +24,9 @@ # define c3__at c3_s2('a','t') # define c3__atom c3_s4('a','t','o','m') # define c3__axe c3_s3('a','x','e') +# define c3__axil c3_s4('a','x','i','l') # define c3__axis c3_s4('a','x','i','s') +# define c3__b c3_s1('b') # define c3__bac c3_s3('b','a','c') # define c3__bach c3_s4('b','a','c','h') # define c3__bag c3_s3('b','a','g') @@ -39,6 +44,7 @@ # define c3__bbye c3_s4('b','b','y','e') # define c3__bcbn c3_s4('b','c','b','n') # define c3__bcbr c3_s4('b','c','b','r') +# define c3__bccb c3_s4('b','c','c','b') # define c3__bccn c3_s4('b','c','c','n') # define c3__bcdg c3_s4('b','c','d','g') # define c3__bckt c3_s4('b','c','k','t') @@ -49,6 +55,7 @@ # define c3__bcsg c3_s4('b','c','s','g') # define c3__bctr c3_s4('b','c','t','r') # define c3__bcts c3_s4('b','c','t','s') +# define c3__bczp c3_s4('b','c','z','p') # define c3__bead c3_s4('b','e','a','d') # define c3__bean c3_s4('b','e','a','n') # define c3__bear c3_s4('b','e','a','r') @@ -97,6 +104,7 @@ # define c3__bran c3_s4('b','r','a','n') # define c3__brax c3_s4('b','r','a','x') # define c3__brbn c3_s4('b','r','b','n') +# define c3__brcb c3_s4('b','r','c','b') # define c3__brcn c3_s4('b','r','c','n') # define c3__brcs c3_s4('b','r','c','s') # define c3__brdg c3_s4('b','r','d','g') @@ -125,6 +133,7 @@ # define c3__brtg c3_s4('b','r','t','g') # define c3__brtr c3_s4('b','r','t','r') # define c3__brts c3_s4('b','r','t','s') +# define c3__brwt c3_s4('b','r','w','t') # define c3__brzp c3_s4('b','r','z','p') # define c3__bud c3_s3('b','u','d') # define c3__bull c3_s4('b','u','l','l') @@ -138,7 +147,9 @@ # define c3__butt c3_s4('b','u','t','t') # define c3__by c3_s2('b','y') # define c3__byte c3_s4('b','y','t','e') +# define c3__c c3_s1('c') # define c3__cage c3_s4('c','a','g','e') +# define c3__cain c3_s4('c','a','i','n') # define c3__call c3_s4('c','a','l','l') # define c3__can c3_s3('c','a','n') # define c3__cap c3_s3('c','a','p') @@ -171,6 +182,8 @@ # define c3__clap c3_s4('c','l','a','p') # define c3__clat c3_s4('c','l','a','t') # define c3__clay c3_s4('c','l','a','y') +# define c3__clcb c3_s4('c','l','c','b') +# define c3__clcn c3_s4('c','l','c','n') # define c3__clep c3_s4('c','l','e','p') # define c3__clet c3_s4('c','l','e','t') # define c3__clhp c3_s4('c','l','h','p') @@ -184,6 +197,7 @@ # define c3__cltr c3_s4('c','l','t','r') # define c3__cnbc c3_s4('c','n','b','c') # define c3__cnbr c3_s4('c','n','b','r') +# define c3__cncb c3_s4('c','n','c','b') # define c3__cncl c3_s4('c','n','c','l') # define c3__cndt c3_s4('c','n','d','t') # define c3__cnhp c3_s4('c','n','h','p') @@ -450,6 +464,7 @@ # define c3__hand c3_s4('h','a','n','d') # define c3__hang c3_s4('h','a','n','g') # define c3__hard c3_s4('h','a','r','d') +# define c3__harm c3_s4('h','a','r','m') # define c3__harp c3_s4('h','a','r','p') # define c3__have c3_s4('h','a','v','e') # define c3__head c3_s4('h','e','a','d') @@ -458,6 +473,7 @@ # define c3__helo c3_s4('h','e','l','o') # define c3__hep c3_s3('h','e','p') # define c3__hept c3_s4('h','e','p','t') +# define c3__herb c3_s4('h','e','r','b') # define c3__hevy c3_s4('h','e','v','y') # define c3__hez c3_s3('h','e','z') # define c3__hide c3_s4('h','i','d','e') @@ -495,6 +511,8 @@ # define c3__hunk c3_s4('h','u','n','k') # define c3__hxtr c3_s4('h','x','t','r') # define c3__hxts c3_s4('h','x','t','s') +# define c3__hxgl c3_s4('h','x','g','l') +# define c3__hxgr c3_s4('h','x','g','r') # define c3__ic c3_s2('i','c') # define c3__ice c3_s3('i','c','e') # define c3__if c3_s2('i','f') @@ -535,6 +553,8 @@ # define c3__ktdt c3_s4('k','t','d','t') # define c3__ktgl c3_s4('k','t','g','l') # define c3__ktgr c3_s4('k','t','g','r') +# define c3__kthp c3_s4('k','t','h','p') +# define c3__kthx c3_s4('k','t','h','x') # define c3__ktlc c3_s4('k','t','l','c') # define c3__ktld c3_s4('k','t','l','d') # define c3__ktls c3_s4('k','t','l','s') @@ -679,6 +699,7 @@ # define c3__nil c3_s3('n','i','l') # define c3__nilk c3_s4('n','i','l','k') # define c3__no c3_s2('n','o') +# define c3__noah c3_s4('n','o','a','h') # define c3__nock c3_s4('n','o','c','k') # define c3__none c3_s4('n','o','n','e') # define c3__nop c3_s3('n','o','p') @@ -695,6 +716,7 @@ # define c3__off c3_s3('o','f','f') # define c3__old c3_s3('o','l','d') # define c3__on c3_s2('o','n') +# define c3__onan c3_s4('o','n','a','n') # define c3__one c3_s3('o','n','e') # define c3__only c3_s4('o','n','l','y') # define c3__op c3_s2('o','p') @@ -867,6 +889,7 @@ # define c3__sgdp c3_s4('s','g','d','p') # define c3__sgdt c3_s4('s','g','d','t') # define c3__sgdx c3_s4('s','g','d','x') +# define c3__sgfs c3_s4('s','g','f','s') # define c3__sggl c3_s4('s','g','g','l') # define c3__sggr c3_s4('s','g','g','r') # define c3__sghp c3_s4('s','g','h','p') @@ -884,6 +907,7 @@ # define c3__sgsg c3_s4('s','g','s','g') # define c3__sgsp c3_s4('s','g','s','p') # define c3__sgts c3_s4('s','g','t','s') +# define c3__sgwt c3_s4('s','g','w','t') # define c3__sgzp c3_s4('s','g','z','p') # define c3__show c3_s4('s','h','o','w') # define c3__shud c3_s4('s','h','u','d') @@ -915,6 +939,7 @@ # define c3__smcl c3_s4('s','m','c','l') # define c3__smdq c3_s4('s','m','d','q') # define c3__smsg c3_s4('s','m','s','g') +# define c3__smsm c3_s4('s','m','s','m') # define c3__smts c3_s4('s','m','t','s') # define c3__snap c3_s4('s','n','a','p') # define c3__so c3_s2('s','o') @@ -1021,11 +1046,15 @@ # define c3__trop c3_s4('t','r','o','p') # define c3__trup c3_s4('t','r','u','p') # define c3__try c3_s3('t','r','y') +# define c3__tsbr c3_s4('t','s','b','r') +# define c3__tscl c3_s4('t','s','c','l') +# define c3__tsdt c3_s4('t','s','d','t') # define c3__tsgl c3_s4('t','s','g','l') # define c3__tsgr c3_s4('t','s','g','r') # define c3__tshp c3_s4('t','s','h','p') # define c3__tsls c3_s4('t','s','l','s') # define c3__tsms c3_s4('t','s','m','s') +# define c3__tssg c3_s4('t','s','s','g') # define c3__tstr c3_s4('t','s','t','r') # define c3__tub c3_s3('t','u','b') # define c3__tul c3_s3('t','u','l') @@ -1053,6 +1082,7 @@ # define c3__uv c3_s2('u','v') # define c3__uw c3_s2('u','w') # define c3__ux c3_s2('u','x') +# define c3__v c3_s1('v') # define c3__vamp c3_s4('v','a','m','p') # define c3__vane c3_s4('v','a','n','e') # define c3__var c3_s3('v','a','r') @@ -1100,9 +1130,11 @@ # define c3__wtgr c3_s4('w','t','g','r') # define c3__wthp c3_s4('w','t','h','p') # define c3__wthx c3_s4('w','t','h','x') +# define c3__wtkt c3_s4('w','t','k','t') # define c3__wtls c3_s4('w','t','l','s') # define c3__wtms c3_s4('w','t','m','s') # define c3__wtpm c3_s4('w','t','p','m') +# define c3__wtpt c3_s4('w','t','p','t') # define c3__wtsg c3_s4('w','t','s','g') # define c3__wtts c3_s4('w','t','t','s') # define c3__wtzp c3_s4('w','t','z','p') @@ -1129,6 +1161,7 @@ # define c3__zpdg c3_s4('z','p','d','g') # define c3__zpdx c3_s4('z','p','d','x') # define c3__zpfs c3_s4('z','p','f','s') +# define c3__zpgr c3_s4('z','p','g','r') # define c3__zphs c3_s4('z','p','h','x') # define c3__zphx c3_s4('z','p','h','x') # define c3__zplc c3_s4('z','p','l','c') diff --git a/include/v/vere.h b/include/v/vere.h index e5135886af..1e74672fb7 100644 --- a/include/v/vere.h +++ b/include/v/vere.h @@ -409,26 +409,37 @@ /* u2_utim: unix timer control. */ typedef struct _u2_utim { - uv_timer_t wat_u; // libev timer control - u2_uwen* wen_u; // timers in ascending order + uv_timer_t wat_u; // timer control + u2_uwen* wen_u; // timers in ascending order }; #endif /* u2_utty: unix tty. */ typedef struct _u2_utty { - uv_pipe_t pop_u; - struct termios bak_u; // cooked terminal state - struct termios raw_u; // raw terminal state + union { + uv_pipe_t pop_u; + uv_tcp_t wax_u; + }; + struct _u2_utty* nex_u; // next in host list c3_i fid_i; // file descriptor - c3_i cug_i; // blocking fcntl flags - c3_i nob_i; // nonblocking fcntl flags c3_w tid_l; // terminal identity number u2_utfo ufo_u; // terminfo strings + c3_i cug_i; // blocking fcntl flags + c3_i nob_i; // nonblocking fcntl flags u2_utat tat_u; // control state - struct _u2_utty* nex_u; // next in host list + struct termios bak_u; // cooked terminal state + struct termios raw_u; // raw terminal state } u2_utty; + /* u2_utel: unix telnet listener. + */ + typedef struct _u2_utel { + struct _u2_utty uty_t; // pseudo-tty + c3_s por_s; // file descriptor + void* tel_u; // telnet context + } u2_utel; + /* u2_raty: raft server type. */ typedef enum { @@ -515,6 +526,7 @@ u2_bean gab; // -g u2_bean dem; // -d, dem u2_bean fog; // -Xwtf, skip last event + u2_bean fak; // -F, fake carrier u2_bean loh; // -L, local-only networking u2_bean pro; // , profile u2_bean veb; // -v, verbose (inverse of -q) @@ -533,8 +545,8 @@ uv_loop_t* lup_u; // libuv event loop u2_http* htp_u; // http servers u2_cttp ctp_u; // http clients - u2_utty* uty_u; // all terminals - u2_utty* tem_u; // main terminal (1) + u2_utel tel_u; // telnet listener + u2_utty* uty_u; // linked terminal list u2_ames sam_u; // packet interface u2_save sav_u; // autosave u2_opts ops_u; // commandline options @@ -568,9 +580,6 @@ c3_global u2_bean u2_Flag_Profile; c3_global u2_bean u2_Flag_Verbose; -# define u2_ve_at() ( &u2_Host.ver_e[u2_Host.kno_w] ) - - /** Functions. **/ /* Urbit time: 128 bits, leap-free. @@ -903,7 +912,7 @@ /* u2_term_ef_boil(): initial effects for restored server. */ void - u2_term_ef_boil(c3_l ono_l); + u2_term_ef_boil(); /* u2_term_ef_winc(): window change. */ @@ -931,6 +940,11 @@ void u2_term_io_init(void); + /* u2_term_io_talk(): start terminal listener. + */ + void + u2_term_io_talk(void); + /* u2_term_io_exit(): terminate terminal I/O. */ void diff --git a/outside/anachronism/.gitignore b/outside/anachronism/.gitignore new file mode 100644 index 0000000000..567609b123 --- /dev/null +++ b/outside/anachronism/.gitignore @@ -0,0 +1 @@ +build/ diff --git a/outside/anachronism/LICENSE b/outside/anachronism/LICENSE new file mode 100644 index 0000000000..72d4b706ee --- /dev/null +++ b/outside/anachronism/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2010 Jonathan Castello + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN +THE SOFTWARE. diff --git a/outside/anachronism/Makefile b/outside/anachronism/Makefile new file mode 100644 index 0000000000..729a33dac5 --- /dev/null +++ b/outside/anachronism/Makefile @@ -0,0 +1,65 @@ +SHELL = sh + +CC = gcc +FLAGS = -c -fPIC -Iinclude/ +CFLAGS = --pedantic -Wall -Wextra -march=native -std=gnu99 +INCLUDE = include/anachronism + +VERSION_MAJOR = 0 +VERSION = $(VERSION_MAJOR).3.1 + +SO = libanachronism.so +SOFILE = $(SO).$(VERSION) +SONAME = $(SO).$(VERSION_MAJOR) + + +all: static shared +shared: build/ build/$(SOFILE) +static: build/ build/libanachronism.a + +build/: + mkdir build + +build/$(SOFILE): build/nvt.o build/parser.o + $(CC) -shared -Wl,-soname,$(SONAME) -o build/$(SOFILE) build/nvt.o build/parser.o + +build/libanachronism.a: build/nvt.o build/parser.o + ar rcs build/libanachronism.a build/nvt.o build/parser.o + +build/nvt.o: src/nvt.c $(INCLUDE)/nvt.h $(INCLUDE)/common.h + $(CC) $(FLAGS) $(CFLAGS) src/nvt.c -o build/nvt.o + +build/parser.o: src/parser.c $(INCLUDE)/parser.h $(INCLUDE)/common.h + $(CC) $(FLAGS) $(CFLAGS) src/parser.c -o build/parser.o + +src/parser.c: src/parser.rl src/parser_common.rl + ragel -C -G2 src/parser.rl -o src/parser.c + + +graph: doc/parser.png + +doc/parser.png: src/parser.rl src/parser_common.rl + ragel -V -p src/parser.rl | dot -Tpng > doc/parser.png + +install: all + install -D -d /usr/local/include/anachronism/ /usr/local/lib + install -D include/anachronism/* /usr/local/include/anachronism/ + install -D build/$(SOFILE) /usr/local/lib/$(SOFILE) + install -D build/libanachronism.a /usr/local/lib/libanachronism.a + ln -s -f /usr/local/lib/$(SOFILE) /usr/local/lib/$(SONAME) + ln -s -f /usr/local/lib/$(SOFILE) /usr/local/lib/$(SO) + +uninstall: + -rm -rf /usr/local/include/anachronism + -rm /usr/local/lib/libanachronism.a + -rm /usr/local/lib/$(SOFILE) + -rm /usr/local/lib/$(SONAME) + -rm /usr/local/lib/$(SO) + +clean: + -rm -f build/nvt.o build/router.o build/parser.o + +distclean: clean + -rm -f build/libanachronism.a build/$(SOFILE) + +.PHONY: all static shared clean distclean install uninstall diff --git a/outside/anachronism/README.md b/outside/anachronism/README.md new file mode 100644 index 0000000000..894825e045 --- /dev/null +++ b/outside/anachronism/README.md @@ -0,0 +1,158 @@ +# Anachronism +Anachronism is a fully-compliant implementation of [the Telnet protocol][wiki-telnet]. Fallen +out of favor in this day and age, most people only know it as a command-line +tool for debugging HTTP. Today, Telnet is most commonly used in the realm of +[MUDs][wiki-muds], though there are still a few other niches filled by Telnet. + +Anachronism offers a simple API for translating between streams of data and +events, and is completely network-agnostic. Anachronism also offers **channels**, an +abstraction layer which treats Telnet as a data multiplexer. Channels make it +extremely easy to build reusable modules for Telnet sub-protocols such +as MCCP (MUD Client Compression Protocol), which can be written once and plugged +into any application that wants to include support. + +[wiki-telnet]: http://en.wikipedia.org/wiki/Telnet (Telnet at Wikipedia) +[wiki-muds]: http://en.wikipedia.org/wiki/MUD (MUDs at Wikipedia) + +## Installation +While Anachronism has no dependencies and is theoretically cross-platform, I've +only written a Makefile for Linux. Help would be appreciated for making this +work across more platforms. + + make + sudo make install + +This will install Anachronism's shared and static libraries to /usr/local/lib, +and its header files to /usr/local/include/anachronism/. You may also need to +run `ldconfig` to make Anachronism available to your project's compiler/linker. + +## Usage +The anachronism/nvt.h header can be consulted for more complete documentation. + +### Basic usage +The core type exposed by Anachronism is the telnet\_nvt, which represents the +Telnet RFC's "Network Virtual Terminal". An NVT is created using +telnet\_nvt\_new(). When creating an NVT, you must provide it with a set of +callbacks to send events to, and an optional void\* to store as the event +handler's context. You can use telnet\_recv() to process incoming data, and +the telnet\_send\_\*() set of functions to emit outgoing data. + + #include + #include + + void on_event(telnet_nvt* nvt, telnet_event* event) + { + switch (event->type) + { + // A data event (normal text received) + case TELNET_EV_DATA: + { + telnet_data_event* ev = (telnet_data_event*)event; + printf("[IN]: %.*s\n", ev->length, ev->data); + break; + } + + // Outgoing data emitted by the NVT + case TELNET_EV_SEND: + { + telnet_send_event* ev = (telnet_send_event*)event; + printf("[OUT]: %.*s\n", ev->length, ev->data); + break; + } + } + } + + int main() + { + // Create an NVT + telnet_nvt* nvt = telnet_nvt_new(NULL, &on_event, NULL, NULL); + + // Process some incoming data + const char* data = "foo bar baz"; + telnet_receive(nvt, (const telnet_byte*)data, strlen(data), NULL); + + // Free the NVT + telnet_nvt_free(nvt); + return 0; + } + +### Telopts +Anachronism provides an easy-to-use interface to Telnet's "telopt" functionality +via the telnet\_telopt\_*() set of functions. As telopts are negotiated and +utilized, events are sent to the telopt callback provided to telnet_nvt_new(). + + #include + #include + + void on_event(telnet_nvt* nvt, telnet_event* event) + { + switch (event->type) + { + // Outgoing data emitted by the NVT + case TELNET_EV_SEND: + { + telnet_send_event* ev = (telnet_send_event*)event; + printf("[OUT]: %.*s\n", ev->length, ev->data); + break; + } + } + } + + void on_telopt_event(telnet_nvt* nvt, telnet_byte telopt, telnet_telopt_event* event) + { + // telopt is the telopt this event was triggered for + + switch (event->type) + { + case TELNET_EV_TELOPT_TOGGLE: + telnet_telopt_toggle_event* ev = (telnet_telopt_toggle_event*)event; + // ev->where is TELNET_TELOPT_LOCAL or TELNET_TELOPT_REMOTE, + // corresponding to Telnet's WILL/WONT and DO/DONT commands. + // ev->status is TELNET_TELOPT_ON or TELNET_TELOPT_OFF. + break; + case TELNET_EV_TELOPT_FOCUS: + telnet_telopt_focus_event* ev = (telnet_telopt_focus_event*)event; + // ev->focus is 1 or 0 depending on if a subnegotiation packet has + // begun or ended. + break; + case TELNET_EV_TELOPT_DATA: + telnet_telopt_data_event* ev = (telnet_telopt_data_event*)event; + // ev->data is a pointer to the received data. + // ev->length is the length of the data buffer. + break; + } + } + + int main() + { + // Create an NVT + telnet_nvt* nvt = telnet_nvt_new(NULL, &on_event, &on_telopt_event, NULL); + + // Ask to enable a telopt locally (a WILL command) + telnet_request_enable(nvt, 230, TELNET_LOCAL); + + // Process some incoming data + const char* data = "\xFF\xFD\xE6" // IAC DO 230 (turn channel on) + "\xFF\xFA\xE6" // IAC SB 230 (switch to channel) + "foo bar baz" (send data) + "\xFF\xF0"; // IAC SE (switch to main) + telnet_receive(nvt, (const telnet_byte*)data, strlen(data), NULL); + + // Free the NVT + telnet_nvt_free(nvt); + return 0; + } + +### Interrupting + TODO: Explain how to interrupt the parser. + +## Alternatives +* [libtelnet][github-libtelnet], by Elanthis
+ It incorporates a number of (rather MUD-specific) protocols by default, + though its API is quite different. + +[github-libtelnet]: https://github.com/elanthis/libtelnet (libtelnet on GitHub) + +## Credits +Someone from #startups on Freenode IRC suggested the name (I'm sure as a joke). +If you read this, remind me who you are so I can credit you properly! diff --git a/outside/anachronism/doc/channels.md b/outside/anachronism/doc/channels.md new file mode 100644 index 0000000000..bfcbf838cf --- /dev/null +++ b/outside/anachronism/doc/channels.md @@ -0,0 +1,50 @@ +# Telnet + +## Channels +Telnet supports data multiplexing by way of 256 built-in sub-channels, each +identified by a byte in the interval [\x00-\xFF]. By switching between +channels, you can send completely separate streams of data through the same +connection. + +All channels start out closed by default. To open a channel, one host must +request or offer a channel using IAC WILL <id> or IAC DO <id>. The remote host +then responds with IAC DO <id> or IAC WILL <id>, respectively. Alternatively, +the request may be denied using IAC DONT <id> or IAC WONT <id>, respectively. + +In order to switch to a specific channel, the IAC SB <id> sequence must +be used. All data sent afterwards will be routed through that specific channel. +To switch back to the main channel, IAC SE must be used. Note that subchannels +do not support any IAC sequences except IAC IAC (an escaped \xFF byte) and +IAC SE (return to the main channel). In particular, you cannot switch directly +from one subchannel to another: you must revert to the main channel first. + +Due to the unbiased nature of Telnet, neither side of the connection is +automatically recognized as the server or the client. However, a host may either +request a channel (as a client) or offer a channel (as a server). The WILL/WONT +commands are used in the role of server ("I will", "I wont"), while DO/DONT +are used in the role of client ("You do", "You do not"). As such, a channel +may be opened twice (even simultaneously). + +As an example, lets assume a terminal is connected to a server using Telnet. The +server offers MCCP (data compression), but wants to know what the terminal's +window size is. The following communication might occur: + + IAC DO NAWS + IAC WILL MCCP + IAC WILL NAWS + IAC SB NAWS \x50 \x00 \x50 \x00 IAC SE + IAC DO MCCP + IAC SB MCCP IAC SE + (compressed data) + +Notice that MCCP was negotiated such that the server offers the compression. +Only the server-to-client flow of data is compressed; the client would not +compress its data unless the channel was negotiated in the other direction as +well. + +In general, a specific subchannel is tied to a specific Telnet subprotocol. For +example, the EXOPL subprotocol is assigned to channel 255, so that channel +should be avoided for any other purpose. A full list of registered subprotocols +can be found on the [IANA website][1]. + +[1]: http://www.iana.org/assignments/telnet-options diff --git a/outside/anachronism/doc/parser.png b/outside/anachronism/doc/parser.png new file mode 100644 index 0000000000..b6a5e05a9e Binary files /dev/null and b/outside/anachronism/doc/parser.png differ diff --git a/outside/anachronism/include/anachronism/common.h b/outside/anachronism/include/anachronism/common.h new file mode 100644 index 0000000000..9dcc157a87 --- /dev/null +++ b/outside/anachronism/include/anachronism/common.h @@ -0,0 +1,24 @@ +#ifndef ANACHRONISM_COMMON_H +#define ANACHRONISM_COMMON_H + +#include /* for size_t */ + +// Telnet bytes must be unsigned +typedef unsigned char telnet_byte; + +// Error codes returned from API functions +// Positive codes are success/notice codes. +// Nonpositive codes are errors. +// ALLOC is 0 for parity with the NULL result from malloc(). +typedef enum telnet_error +{ + TELNET_E_NOT_SUBNEGOTIABLE = -4, // The telopt is not open for subnegotiation. + TELNET_E_BAD_PARSER = -3, // The telnet_parser* passed is NULL + TELNET_E_BAD_NVT = -2, // The telnet_nvt* passed is NULL + TELNET_E_INVALID_COMMAND = -1, // The telnet_byte passed is not an allowed command in this API method + TELNET_E_ALLOC = 0, // Not enough memory to allocate essential library structures + TELNET_E_OK = 1, // Huge Success! + TELNET_E_INTERRUPT = 2, // Parser interrupted by user code. +} telnet_error; + +#endif // ANACHRONISM_COMMON_H diff --git a/outside/anachronism/include/anachronism/nvt.h b/outside/anachronism/include/anachronism/nvt.h new file mode 100644 index 0000000000..3ab5d5a576 --- /dev/null +++ b/outside/anachronism/include/anachronism/nvt.h @@ -0,0 +1,214 @@ +#ifndef ANACHRONISM_ANACHRONISM_H +#define ANACHRONISM_ANACHRONISM_H + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +// predefined Telnet commands from 240-255 +enum +{ + IAC_SE = 240, + IAC_NOP, + IAC_DM, + IAC_BRK, + IAC_IP, + IAC_AO, + IAC_AYT, + IAC_EC, + IAC_EL, + IAC_GA, + IAC_SB, + IAC_WILL, + IAC_WONT, + IAC_DO, + IAC_DONT, + IAC_IAC, +}; + +typedef enum telnet_telopt_location +{ + TELNET_LOCAL, + TELNET_REMOTE, +} telnet_telopt_location; + + +/** + * NVT Events + */ + +typedef enum telnet_event_type +{ + TELNET_EV_DATA, /* A stretch of plain data was received. (data, length) */ + TELNET_EV_COMMAND, /* A simple IAC comamnd was recevied. (command) */ + TELNET_EV_WARNING, /* A non-fatal invalid sequence was received. (message, position) */ + TELNET_EV_SEND, /* Outgoing data to be sent. (data, length) */ +} telnet_event_type; + +typedef struct telnet_event +{ + telnet_event_type type; +} telnet_event; + +typedef struct telnet_data_event +{ + telnet_event SUPER_; + const telnet_byte* data; + size_t length; +} telnet_data_event; + +typedef struct telnet_command_event +{ + telnet_event SUPER_; + telnet_byte command; +} telnet_command_event; + +typedef struct telnet_warning_event +{ + telnet_event SUPER_; + const char* message; + size_t position; +} telnet_warning_event; + +typedef struct telnet_send_event +{ + telnet_event SUPER_; + const telnet_byte* data; + size_t length; +} telnet_send_event; + + +/** + * Telopt Events + */ + +typedef enum telnet_telopt_event_type +{ + TELNET_EV_TELOPT_TOGGLE, + TELNET_EV_TELOPT_FOCUS, + TELNET_EV_TELOPT_DATA, +} telnet_telopt_event_type; + +typedef struct telnet_telopt_event +{ + telnet_telopt_event_type type; +} telnet_telopt_event; + +typedef struct telnet_telopt_toggle_event +{ + telnet_telopt_event SUPER_; + telnet_telopt_location where; + unsigned char status; +} telnet_telopt_toggle_event; + +typedef struct telnet_telopt_focus_event +{ + telnet_telopt_event SUPER_; + unsigned char focus; +} telnet_telopt_focus_event; + +typedef struct telnet_telopt_data_event +{ + telnet_telopt_event SUPER_; + const telnet_byte* data; + size_t length; +} telnet_telopt_data_event; + + + +typedef struct telnet_nvt telnet_nvt; + + +typedef void (*telnet_nvt_event_callback)(telnet_nvt* nvt, telnet_event* event); +typedef void (*telnet_telopt_event_callback)(telnet_nvt* nvt, telnet_byte telopt, telnet_telopt_event* event); +typedef unsigned char (*telnet_negotiate_event_callback)(telnet_nvt* nvt, telnet_byte telopt, telnet_telopt_location where); + +/** + Creates a new Telnet NVT. + + Errors: + TELNET_E_ALLOC - Unable to allocate enough memory for the NVT. + */ +telnet_nvt* telnet_nvt_new(void* userdata, + telnet_nvt_event_callback nvt_callback, + telnet_telopt_event_callback telopt_callback, + telnet_negotiate_event_callback negotiate_callback); + +void telnet_nvt_free(telnet_nvt* nvt); + +/** + Every NVT can have some user-specific data attached, such as a user-defined struct. + This can be accessed (primarily by event callbacks) to differentiate between NVTs. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + + Example: + // assuming a FILE was passed to telnet_nvt_new(): + FILE out = NULL; + telnet_get_userdata(nvt, (void**)&out); + */ +telnet_error telnet_get_userdata(telnet_nvt* nvt, void** udata); + +/** + Processes incoming data. + If `bytes_used` is non-NULL, it will be set to the length of the string that + was read. This is generally only useful if you use telnet_halt() in a callback. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + TELNET_E_ALLOC - Unable to allocate destination buffer for incoming text. + TELNET_E_INTERRUPT - User code interrupted the parser. + */ +telnet_error telnet_receive(telnet_nvt* nvt, const telnet_byte* data, size_t length, size_t* bytes_used); + +/** + If currently parsing (i.e. telnet_recv() is running), interrupts the parser. + This is useful for things such as MCCP, where a Telnet sequence hails the start of + data that must be decompressed before being parsed. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + */ +telnet_error telnet_interrupt(telnet_nvt* nvt); + + +/** + Sends a string as a stream of escaped Telnet data. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + TELNET_E_ALLOC - Unable to allocate destination buffer for outgoing text. + */ +telnet_error telnet_send_data(telnet_nvt* nvt, const telnet_byte* data, const size_t length); + +/** + Sends a Telnet command. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + TELNET_E_INVALID_COMMAND - The command cannot be WILL, WONT, DO, DONT, SB, or SE. + */ +telnet_error telnet_send_command(telnet_nvt* nvt, const telnet_byte command); + +/** + Sends a subnegotiation packet. + + Errors: + TELNET_E_BAD_NVT - Invalid telnet_nvt* parameter. + TELNET_E_ALLOC - Unable to allocate destination buffer for outgoing text. + */ +telnet_error telnet_send_subnegotiation(telnet_nvt* nvt, const telnet_byte option, const telnet_byte* data, const size_t length); + + +telnet_error telnet_telopt_enable(telnet_nvt* nvt, const telnet_byte telopt, telnet_telopt_location where); +telnet_error telnet_telopt_disable(telnet_nvt* nvt, const telnet_byte telopt, telnet_telopt_location where); +telnet_error telnet_telopt_status(telnet_nvt* nvt, const telnet_byte telopt, telnet_telopt_location where, unsigned char* status); + +#ifdef __cplusplus +} +#endif + +#endif // ANACHRONISM_ANACHRONISM_H diff --git a/outside/anachronism/include/anachronism/parser.h b/outside/anachronism/include/anachronism/parser.h new file mode 100644 index 0000000000..8309ee5aec --- /dev/null +++ b/outside/anachronism/include/anachronism/parser.h @@ -0,0 +1,73 @@ +#ifndef ANACHRONISM_PARSER_H +#define ANACHRONISM_PARSER_H + +#include + +typedef enum telnet_parser_event_type +{ + TELNET_EV_PARSER_DATA, + TELNET_EV_PARSER_COMMAND, + TELNET_EV_PARSER_OPTION, + TELNET_EV_PARSER_SUBNEGOTIATION, + TELNET_EV_PARSER_WARNING, +} telnet_parser_event_type; + +typedef struct telnet_parser_event +{ + telnet_parser_event_type type; +} telnet_parser_event; + +typedef struct telnet_parser_data_event +{ + telnet_parser_event SUPER_; + const telnet_byte* data; + size_t length; +} telnet_parser_data_event; + +typedef struct telnet_parser_command_event +{ + telnet_parser_event SUPER_; + telnet_byte command; +} telnet_parser_command_event; + +typedef struct telnet_parser_option_event +{ + telnet_parser_event SUPER_; + telnet_byte command; + telnet_byte option; +} telnet_parser_option_event; + +typedef struct telnet_parser_subnegotiation_event +{ + telnet_parser_event SUPER_; + int active; + telnet_byte option; +} telnet_parser_subnegotiation_event; + +typedef struct telnet_parser_warning_event +{ + telnet_parser_event SUPER_; + const char* message; + size_t position; +} telnet_parser_warning_event; + + + +typedef struct telnet_parser telnet_parser; + +typedef void (*telnet_parser_callback)(telnet_parser* parser, telnet_parser_event* event); + + +telnet_parser* telnet_parser_new(void* userdata, telnet_parser_callback callback); +void telnet_parser_free(telnet_parser* parser); + +telnet_error telnet_parser_get_userdata(telnet_parser* parser, void** userdata); + +telnet_error telnet_parser_parse(telnet_parser* parser, + const telnet_byte* data, + size_t length, + size_t* bytes_used); + +telnet_error telnet_parser_interrupt(telnet_parser* parser); + +#endif // ANACHRONISM_PARSER_H diff --git a/outside/anachronism/src/README.md b/outside/anachronism/src/README.md new file mode 100644 index 0000000000..8ee6808236 --- /dev/null +++ b/outside/anachronism/src/README.md @@ -0,0 +1,6 @@ +* parser_common.rl +
The language-agnostic Ragel grammar for the Telnet protocol. +* parser.rl +
The C implementation of the Ragel grammar. Compiled to parser.c by Ragel. +* nvt.c +
The core implementation of Anachronism's NVT and Channel constructs. diff --git a/outside/anachronism/src/nvt.c b/outside/anachronism/src/nvt.c new file mode 100644 index 0000000000..f33d93f752 --- /dev/null +++ b/outside/anachronism/src/nvt.c @@ -0,0 +1,631 @@ +#include +#include +#include +#include + + +#define TELOPT_TOGGLE_CALLBACK(nvt, telopt, where_, status_) do { \ + if ((nvt)->telopt_callback) { \ + telnet_telopt_toggle_event ev; \ + ev.SUPER_.type = TELNET_EV_TELOPT_TOGGLE; \ + ev.where = (where_); \ + ev.status = (status_); \ + \ + (nvt)->telopt_callback((nvt), (telopt), (telnet_telopt_event*)&ev); \ + } \ +} while (0) + +#define TELOPT_FOCUS_CALLBACK(nvt, telopt, status_) do { \ + if ((nvt)->telopt_callback) { \ + telnet_telopt_focus_event ev; \ + ev.SUPER_.type = TELNET_EV_TELOPT_FOCUS; \ + ev.status = (status_); \ + \ + (nvt)->telopt_callback((nvt), (telopt), (telnet_telopt_event*)&ev); \ + } \ +} while (0) + +#define TELOPT_DATA_CALLBACK(nvt, telopt, data_, length_) do { \ + if ((nvt)->telopt_callback) { \ + telnet_telopt_data_event ev; \ + ev.SUPER_.type = TELNET_EV_TELOPT_DATA; \ + ev.data = (data_); \ + ev.length = (length_); \ + \ + (nvt)->telopt_callback((nvt), (telopt), (telnet_telopt_event*)&ev); \ + } \ +} while (0) + +#define SEND_CALLBACK(nvt, data_, length_) do { \ + if ((nvt)->callback) { \ + telnet_send_event ev; \ + ev.SUPER_.type = TELNET_EV_SEND; \ + ev.data = (data_); \ + ev.length = (length_); \ + \ + (nvt)->callback((nvt), (telnet_event*)&ev); \ + } \ +} while (0) + + +// Q Method of Implementing TELNET Option Negotiation +// ftp://ftp.rfc-editor.org/in-notes/rfc1143.txt +typedef enum qstate { + Q_NO = 0, Q_WANTYES, Q_WANTYESNO, + Q_YES, Q_WANTNO, Q_WANTNOYES, +} qstate; + +typedef struct telnet_qstate +{ + unsigned remote : 3; + unsigned local : 3; +} telnet_qstate; + +struct telnet_nvt +{ + telnet_parser* parser; + telnet_qstate options[256]; // track the state of each subnegotiation option + short current_remote; + + telnet_nvt_event_callback callback; + telnet_telopt_event_callback telopt_callback; + telnet_negotiate_event_callback negotiate_callback; + + void* userdata; +}; + +static unsigned char telopt_status(telnet_nvt* nvt, + telnet_byte telopt, + telnet_telopt_location where) +{ + unsigned int qval = (where == TELNET_LOCAL) ? + nvt->options[telopt].local : + nvt->options[telopt].remote; + + switch (qval) { + case Q_YES: case Q_WANTNO: case Q_WANTNOYES: + return 1; + default: + return 0; + } +} +#define telopt_subnegotiable(nvt, telopt) (telopt_status((nvt), (telopt), TELNET_REMOTE) || telopt_status((nvt), (telopt), TELNET_LOCAL)) + + +static void send_option(telnet_nvt* nvt, telnet_byte command, telnet_byte telopt) +{ + const telnet_byte buf[] = {IAC_IAC, command, telopt}; + SEND_CALLBACK(nvt, buf, 3); +} + +static void process_option_event(telnet_nvt* nvt, + telnet_byte command, + telnet_byte telopt) +{ + telnet_qstate* q = &nvt->options[telopt]; + // Every qstate begins zeroed-out, and Q_NO is 0. + + switch (command) + { + case IAC_WILL: + switch (q->remote) + { + case Q_NO: + if (nvt->negotiate_callback && nvt->negotiate_callback(nvt, telopt, TELNET_REMOTE)) { + send_option(nvt, IAC_DO, telopt); + q->remote = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 1); + } else { + send_option(nvt, IAC_DONT, telopt); + } + break; + case Q_WANTNO: + // error + q->remote = Q_NO; + break; + case Q_WANTNOYES: + // error + q->remote = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 1); + break; + case Q_WANTYES: + q->remote = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 1); + break; + case Q_WANTYESNO: + send_option(nvt, IAC_DONT, telopt); + q->remote = Q_WANTNO; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 1); + break; + } + break; + case IAC_WONT: + switch (q->remote) + { + case Q_YES: + send_option(nvt, IAC_DONT, telopt); + q->remote = Q_NO; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 0); + break; + case Q_WANTNO: + q->remote = Q_NO; + break; + case Q_WANTNOYES: + send_option(nvt, IAC_DO, telopt); + q->remote = Q_WANTYES; + break; + case Q_WANTYES: + q->remote = Q_NO; + break; + case Q_WANTYESNO: + q->remote = Q_NO; + break; + } + break; + case IAC_DO: + switch (q->local) + { + case Q_NO: + if (nvt->negotiate_callback && nvt->negotiate_callback(nvt, telopt, TELNET_LOCAL)) { + send_option(nvt, IAC_WILL, telopt); + q->local = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 1); + } else { + send_option(nvt, IAC_WONT, telopt); + } + break; + case Q_WANTNO: + // error + q->local = Q_NO; + break; + case Q_WANTNOYES: + // error + q->local = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 1); + break; + case Q_WANTYES: + q->local = Q_YES; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 1); + break; + case Q_WANTYESNO: + send_option(nvt, IAC_WONT, telopt); + q->local = Q_WANTNO; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 1); + break; + } + break; + case IAC_DONT: + switch (q->local) + { + case Q_YES: + send_option(nvt, IAC_DONT, telopt); + q->local = Q_NO; + TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 0); + break; + case Q_WANTNO: + q->local = Q_NO; + break; + case Q_WANTNOYES: + send_option(nvt, IAC_WILL, telopt); + q->local = Q_WANTYES; + break; + case Q_WANTYES: + q->local = Q_NO; + break; + case Q_WANTYESNO: + q->local = Q_NO; + break; + } + break; + } +} + +static void process_data_event(telnet_nvt* nvt, + const telnet_byte* data, + size_t length) +{ + if (nvt->current_remote == -1) { + // Main-line data + if (nvt->callback) { + telnet_data_event ev; + ev.SUPER_.type = TELNET_EV_DATA; + ev.data = data; + ev.length = length; + nvt->callback(nvt, (telnet_event*)&ev); + } + } else { + // Telopt data + telnet_byte telopt = (telnet_byte)nvt->current_remote; + + if (nvt->telopt_callback) { + // Make sure the telopt is enabled + if (telopt_subnegotiable(nvt, telopt)) { + telnet_telopt_data_event ev; + ev.SUPER_.type = TELNET_EV_TELOPT_DATA; + ev.data = data; + ev.length = length; + nvt->telopt_callback(nvt, telopt, (telnet_telopt_event*)&ev); + } + } + } +} + +static void process_subnegotiation_event(telnet_nvt* nvt, + int open, + telnet_byte telopt) +{ + if (open) { + nvt->current_remote = telopt; + } else { + nvt->current_remote = -1; + } + + if (nvt->telopt_callback) { + // Make sure the telopt is enabled + if (telopt_subnegotiable(nvt, telopt)) { + telnet_telopt_focus_event ev; + ev.SUPER_.type = TELNET_EV_TELOPT_FOCUS; + ev.focus = open; + nvt->telopt_callback(nvt, telopt, (telnet_telopt_event*)&ev); + } + } +} + +static void process_event(telnet_parser* parser, telnet_parser_event* event) +{ + telnet_nvt* nvt = NULL; + telnet_parser_get_userdata(parser, (void*)&nvt); + + switch (event->type) + { + case TELNET_EV_PARSER_DATA: + { + telnet_parser_data_event* ev = (telnet_parser_data_event*)event; + process_data_event(nvt, ev->data, ev->length); + break; + } + + case TELNET_EV_PARSER_OPTION: + { + telnet_parser_option_event* ev = (telnet_parser_option_event*)event; + process_option_event(nvt, ev->command, ev->option); + break; + } + + case TELNET_EV_PARSER_SUBNEGOTIATION: + { + telnet_parser_subnegotiation_event* ev = (telnet_parser_subnegotiation_event*)event; + process_subnegotiation_event(nvt, ev->active, ev->option); + break; + } + + case TELNET_EV_PARSER_COMMAND: + { + if (nvt->callback) { + telnet_parser_command_event* parser_ev = (telnet_parser_command_event*) event; + + telnet_command_event ev; + ev.SUPER_.type = TELNET_EV_COMMAND; + ev.command = parser_ev->command; + nvt->callback(nvt, (telnet_event*)&ev); + } + break; + } + + case TELNET_EV_PARSER_WARNING: + { + if (nvt->callback) { + telnet_parser_warning_event* parser_ev = (telnet_parser_warning_event*) event; + + telnet_warning_event ev; + ev.SUPER_.type = TELNET_EV_WARNING; + ev.message = parser_ev->message; + ev.position = parser_ev->position; + nvt->callback(nvt, (telnet_event*)&ev); + } + break; + } + + default: + break; + } +} + + +telnet_nvt* telnet_nvt_new(void* userdata, + telnet_nvt_event_callback nvt_callback, + telnet_telopt_event_callback telopt_callback, + telnet_negotiate_event_callback negotiate_callback) +{ + telnet_nvt* nvt = malloc(sizeof(telnet_nvt)); + if (nvt) + { + telnet_parser* parser = telnet_parser_new((void*)nvt, &process_event); + if (parser) + { + memset(nvt, 0, sizeof(*nvt)); + nvt->parser = parser; + nvt->callback = nvt_callback; + nvt->telopt_callback = telopt_callback; + nvt->negotiate_callback = negotiate_callback; + nvt->userdata = userdata; + nvt->current_remote = -1; + } + else + { + free(nvt); + nvt = NULL; + } + } + return nvt; +} + +void telnet_nvt_free(telnet_nvt* nvt) +{ + if (nvt) + { + telnet_parser_free(nvt->parser); + free(nvt); + } +} + +telnet_error telnet_get_userdata(telnet_nvt* nvt, void** userdata) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + + *userdata = nvt->userdata; + return TELNET_E_OK; +} + +telnet_error telnet_receive(telnet_nvt* nvt, const telnet_byte* data, size_t length, size_t* bytes_used) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + + return telnet_parser_parse(nvt->parser, data, length, bytes_used); +} + +telnet_error telnet_interrupt(telnet_nvt* nvt) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + + return telnet_parser_interrupt(nvt->parser); +} + + +static int safe_concat(const telnet_byte* in, size_t inlen, telnet_byte* out, size_t outlen) +{ + // Copy as much as possible into the buffer. + memcpy(out, in, (outlen < inlen) ? outlen : inlen); + + // true if everything could be copied, false otherwise + return outlen >= inlen; +} + +// Escapes any special characters in data, writing the result data to out. +// Returns -1 if not everything could be copied (and out is full). +// Otherwise returns the length of the data in out. +// +// To avoid potential -1 return values, pass in an out buffer double the length of the data buffer. +static size_t telnet_escape(const telnet_byte* data, size_t length, telnet_byte* out, size_t outsize) +{ + if (data == NULL || out == NULL) + return 0; + + size_t outlen = 0; + size_t left = 0; + size_t right = 0; + const char* seq = NULL; + for (; right < length; ++right) + { + switch (data[right]) + { + case IAC_IAC: + seq = "\xFF\xFF"; + break; + case '\r': + // Only escape \r if it doesn't immediately precede \n. + if (right + 1 >= length || data[right+1] != '\n') + { + seq = "\r\0"; + break; + } + // !!FALLTHROUGH!! + default: + continue; // Move to the next character + } + + // Add any normal data that hasn't been added yet. + if (safe_concat(data+left, right-left, out+outlen, outsize-outlen) == 0) + return -1; + outlen += right - left; + left = right + 1; + + // Add the escape sequence. + if (safe_concat((const telnet_byte*)seq, 2, out+outlen, outsize-outlen) == 0) + return -1; + outlen += 2; + } + + // Add any leftover normal data. + if (left < right) + { + if (safe_concat(data+left, right-left, out+outlen, outsize-outlen) == 0) + return -1; + outlen += right - left; + } + + return outlen; +} + +telnet_error telnet_send_data(telnet_nvt* nvt, const telnet_byte* data, const size_t length) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + else if (!nvt->callback) + return TELNET_E_OK; // immediate success since they apparently don't want the data to go anywhere + + // Due to the nature of the protocol, the most any one byte can be encoded as is two bytes. + // Hence, the smallest buffer guaranteed to contain any input is double the length of the source. + size_t bufsize = sizeof(telnet_byte) * length * 2; + telnet_byte* buf = malloc(bufsize); + if (!buf) + return TELNET_E_ALLOC; + + bufsize = telnet_escape(data, length, buf, bufsize); + + SEND_CALLBACK(nvt, buf, bufsize); + + free(buf); + buf = NULL; + + return TELNET_E_OK; +} + +telnet_error telnet_send_command(telnet_nvt* nvt, const telnet_byte command) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + else if (command >= IAC_SB || command == IAC_SE) + return TELNET_E_INVALID_COMMAND; // Invalid command + + const telnet_byte buf[] = {IAC_IAC, command}; + SEND_CALLBACK(nvt, buf, 2); + + return TELNET_E_OK; +} + +telnet_error telnet_send_subnegotiation(telnet_nvt* nvt, const telnet_byte option, const telnet_byte* data, const size_t length) +{ + if (!nvt) + return TELNET_E_BAD_NVT; + else if (!telopt_subnegotiable(nvt, option)) + return TELNET_E_NOT_SUBNEGOTIABLE; + else if (!nvt->callback) + return TELNET_E_OK; + + // length*2 is the maximum buffer size needed for an escaped string. + // The extra five bytes are for the IAC, SB,