mirror of
https://github.com/urbit/shrub.git
synced 2024-12-25 13:04:17 +03:00
Merge remote-tracking branch 'urbit/newnextbreach'
this obsoletes newnextbreach, nextbreach, newbreach, et cetera. Conflicts: gen164/4/in.c urb/zod/arvo/hoon.hoon
This commit is contained in:
commit
c4d01192dc
19
Makefile
19
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
|
||||
@ -57,11 +57,13 @@ endif
|
||||
INCLUDE=include
|
||||
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
|
||||
|
@ -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 },
|
||||
{}
|
||||
|
135
gen164/4/by_int.c
Normal file
135
gen164/4/by_int.c
Normal file
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
||||
|
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -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 },
|
||||
{}
|
||||
};
|
||||
|
||||
|
97
gen164/4/in_int.c
Normal file
97
gen164/4/in_int.c
Normal file
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
||||
|
139
gen164/4/in_uni.c
Normal file
139
gen164/4/in_uni.c
Normal file
@ -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 },
|
||||
{ }
|
||||
};
|
||||
|
@ -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 ) {
|
||||
|
@ -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;
|
||||
|
@ -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 {
|
||||
|
468
gen164/6/ap.c
468
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
|
||||
@ -321,14 +504,67 @@
|
||||
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)[] = {
|
||||
{ }
|
||||
};
|
||||
|
||||
|
@ -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);
|
||||
{
|
||||
|
@ -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);
|
||||
{
|
||||
|
@ -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);
|
||||
{
|
||||
|
34
gen164/pit.h
34
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
|
||||
|
@ -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')
|
||||
|
@ -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
|
||||
|
1
outside/anachronism/.gitignore
vendored
Normal file
1
outside/anachronism/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
build/
|
19
outside/anachronism/LICENSE
Normal file
19
outside/anachronism/LICENSE
Normal file
@ -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.
|
65
outside/anachronism/Makefile
Normal file
65
outside/anachronism/Makefile
Normal file
@ -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
|
158
outside/anachronism/README.md
Normal file
158
outside/anachronism/README.md
Normal file
@ -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 <stdio.h>
|
||||
#include <anachronism/nvt.h>
|
||||
|
||||
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 <stdio.h>
|
||||
#include <anachronism/nvt.h>
|
||||
|
||||
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<br>
|
||||
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!
|
50
outside/anachronism/doc/channels.md
Normal file
50
outside/anachronism/doc/channels.md
Normal file
@ -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:
|
||||
|
||||
<server> IAC DO NAWS
|
||||
<server> IAC WILL MCCP
|
||||
<client> IAC WILL NAWS
|
||||
<client> IAC SB NAWS \x50 \x00 \x50 \x00 IAC SE
|
||||
<client> IAC DO MCCP
|
||||
<server> IAC SB MCCP IAC SE
|
||||
<server> (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
|
BIN
outside/anachronism/doc/parser.png
Normal file
BIN
outside/anachronism/doc/parser.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 148 KiB |
24
outside/anachronism/include/anachronism/common.h
Normal file
24
outside/anachronism/include/anachronism/common.h
Normal file
@ -0,0 +1,24 @@
|
||||
#ifndef ANACHRONISM_COMMON_H
|
||||
#define ANACHRONISM_COMMON_H
|
||||
|
||||
#include <stdlib.h> /* 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
|
214
outside/anachronism/include/anachronism/nvt.h
Normal file
214
outside/anachronism/include/anachronism/nvt.h
Normal file
@ -0,0 +1,214 @@
|
||||
#ifndef ANACHRONISM_ANACHRONISM_H
|
||||
#define ANACHRONISM_ANACHRONISM_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <anachronism/common.h>
|
||||
|
||||
// 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
|
73
outside/anachronism/include/anachronism/parser.h
Normal file
73
outside/anachronism/include/anachronism/parser.h
Normal file
@ -0,0 +1,73 @@
|
||||
#ifndef ANACHRONISM_PARSER_H
|
||||
#define ANACHRONISM_PARSER_H
|
||||
|
||||
#include <anachronism/common.h>
|
||||
|
||||
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
|
6
outside/anachronism/src/README.md
Normal file
6
outside/anachronism/src/README.md
Normal file
@ -0,0 +1,6 @@
|
||||
* parser_common.rl
|
||||
<br>The language-agnostic Ragel grammar for the Telnet protocol.
|
||||
* parser.rl
|
||||
<br>The C implementation of the Ragel grammar. Compiled to parser.c by Ragel.
|
||||
* nvt.c
|
||||
<br>The core implementation of Anachronism's NVT and Channel constructs.
|
631
outside/anachronism/src/nvt.c
Normal file
631
outside/anachronism/src/nvt.c
Normal file
@ -0,0 +1,631 @@
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <anachronism/nvt.h>
|
||||
#include <anachronism/parser.h>
|
||||
|
||||
|
||||
#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, <option>, IAC, and SE frame around the data.
|
||||
size_t bufsize = (sizeof(telnet_byte) * length * 2) + 5;
|
||||
telnet_byte* buf = malloc(bufsize);
|
||||
if (!buf)
|
||||
return TELNET_E_ALLOC;
|
||||
|
||||
// Begin with IAC SB <option>
|
||||
telnet_byte iac[] = {IAC_IAC, IAC_SB, option};
|
||||
memcpy(buf, iac, 3);
|
||||
|
||||
// Add the subnegotiation body
|
||||
size_t escaped_length = telnet_escape(data, length, buf+3, bufsize-3) + 3;
|
||||
|
||||
// End with IAC SE
|
||||
iac[1] = IAC_SE;
|
||||
memcpy(buf+escaped_length, iac, 2);
|
||||
escaped_length += 2;
|
||||
|
||||
SEND_CALLBACK(nvt, buf, escaped_length);
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
|
||||
return TELNET_E_OK;
|
||||
}
|
||||
|
||||
|
||||
telnet_error telnet_telopt_enable(telnet_nvt* nvt,
|
||||
telnet_byte telopt,
|
||||
telnet_telopt_location where)
|
||||
{
|
||||
if (!nvt)
|
||||
return TELNET_E_BAD_NVT;
|
||||
|
||||
telnet_qstate* q = &nvt->options[telopt];
|
||||
if (where == TELNET_LOCAL) {
|
||||
switch (q->local)
|
||||
{
|
||||
case Q_NO:
|
||||
q->local = Q_WANTYES;
|
||||
send_option(nvt, IAC_WILL, telopt);
|
||||
break;
|
||||
case Q_WANTNO:
|
||||
q->local = Q_WANTNOYES;
|
||||
break;
|
||||
case Q_WANTYESNO:
|
||||
q->local = Q_WANTYES;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (q->remote)
|
||||
{
|
||||
case Q_NO:
|
||||
q->remote = Q_WANTYES;
|
||||
send_option(nvt, IAC_DO, telopt);
|
||||
break;
|
||||
case Q_WANTNO:
|
||||
q->remote = Q_WANTNOYES;
|
||||
break;
|
||||
case Q_WANTYESNO:
|
||||
q->remote = Q_WANTYES;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_telopt_disable(telnet_nvt* nvt,
|
||||
telnet_byte telopt,
|
||||
telnet_telopt_location where)
|
||||
{
|
||||
if (!nvt)
|
||||
return TELNET_E_BAD_NVT;
|
||||
|
||||
telnet_qstate* q = &nvt->options[telopt];
|
||||
if (where == TELNET_LOCAL) {
|
||||
switch (q->local)
|
||||
{
|
||||
case Q_YES:
|
||||
send_option(nvt, IAC_WONT, telopt);
|
||||
q->local = Q_WANTNO;
|
||||
TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_LOCAL, 0);
|
||||
break;
|
||||
case Q_WANTNOYES:
|
||||
q->local = Q_WANTNO;
|
||||
break;
|
||||
case Q_WANTYES:
|
||||
q->local = Q_WANTYESNO;
|
||||
break;
|
||||
}
|
||||
} else {
|
||||
switch (q->remote)
|
||||
{
|
||||
case Q_YES:
|
||||
send_option(nvt, IAC_DONT, telopt);
|
||||
q->remote = Q_WANTNO;
|
||||
TELOPT_TOGGLE_CALLBACK(nvt, telopt, TELNET_REMOTE, 0);
|
||||
break;
|
||||
case Q_WANTNOYES:
|
||||
q->remote = Q_WANTNO;
|
||||
break;
|
||||
case Q_WANTYES:
|
||||
q->remote = Q_WANTYESNO;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_telopt_status(telnet_nvt* nvt,
|
||||
telnet_byte telopt,
|
||||
telnet_telopt_location where,
|
||||
unsigned char* status)
|
||||
{
|
||||
if (!nvt)
|
||||
return TELNET_E_BAD_NVT;
|
||||
|
||||
*status = telopt_status(nvt, telopt, where);
|
||||
return TELNET_E_OK;
|
||||
}
|
459
outside/anachronism/src/parser.c
Normal file
459
outside/anachronism/src/parser.c
Normal file
@ -0,0 +1,459 @@
|
||||
|
||||
#line 1 "src/parser.rl"
|
||||
#include <string.h>
|
||||
#include <anachronism/parser.h>
|
||||
|
||||
#define BASE_EV(ev, t) \
|
||||
(ev).SUPER_.type = TELNET_EV_PARSER_##t
|
||||
|
||||
#define EV_DATA(ev, text, len) do {\
|
||||
BASE_EV(ev, DATA);\
|
||||
(ev).data = (text);\
|
||||
(ev).length = (len);\
|
||||
} while (0)
|
||||
|
||||
#define EV_COMMAND(ev, cmd) do {\
|
||||
BASE_EV(ev, COMMAND);\
|
||||
(ev).command = (cmd);\
|
||||
} while (0)
|
||||
|
||||
#define EV_OPTION(ev, cmd, opt) do {\
|
||||
BASE_EV(ev, OPTION);\
|
||||
(ev).command = (cmd);\
|
||||
(ev).option = (opt);\
|
||||
} while (0)
|
||||
|
||||
#define EV_SUBNEGOTIATION(ev, act, opt) do {\
|
||||
BASE_EV(ev, SUBNEGOTIATION);\
|
||||
(ev).active = (act);\
|
||||
(ev).option = (opt);\
|
||||
} while (0)
|
||||
|
||||
#define EV_WARNING(ev, msg, pos) do {\
|
||||
BASE_EV(ev, WARNING);\
|
||||
(ev).message = (msg);\
|
||||
(ev).position = (pos);\
|
||||
} while (0)
|
||||
|
||||
struct telnet_parser {
|
||||
int cs; /* current Ragel state */
|
||||
const telnet_byte* p; /* current position */
|
||||
const telnet_byte* pe; /* end of current packet */
|
||||
const telnet_byte* eof; /* end-of-file marker */
|
||||
|
||||
telnet_byte option_mark; /* temporary storage for a command byte */
|
||||
unsigned char interrupted; /* Flag for interrupts */
|
||||
|
||||
telnet_parser_callback callback; /* Receiver of Telnet events*/
|
||||
void* userdata; /* Context for parser callback */
|
||||
};
|
||||
|
||||
|
||||
#line 53 "src/parser.c"
|
||||
static const int telnet_parser_start = 7;
|
||||
static const int telnet_parser_first_final = 7;
|
||||
static const int telnet_parser_error = -1;
|
||||
|
||||
static const int telnet_parser_en_main = 7;
|
||||
|
||||
|
||||
#line 130 "src/parser.rl"
|
||||
|
||||
|
||||
telnet_parser* telnet_parser_new(void* userdata,
|
||||
telnet_parser_callback callback)
|
||||
{
|
||||
telnet_parser* parser = malloc(sizeof(telnet_parser));
|
||||
if (parser)
|
||||
{
|
||||
memset(parser, 0, sizeof(*parser));
|
||||
|
||||
#line 72 "src/parser.c"
|
||||
{
|
||||
parser->cs = telnet_parser_start;
|
||||
}
|
||||
|
||||
#line 140 "src/parser.rl"
|
||||
parser->callback = callback;
|
||||
parser->userdata = userdata;
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
void telnet_parser_free(telnet_parser* parser)
|
||||
{
|
||||
free(parser);
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_get_userdata(telnet_parser* parser, void** userdata)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
*userdata = parser->userdata;
|
||||
return TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_parse(telnet_parser* parser,
|
||||
const telnet_byte* data,
|
||||
size_t length,
|
||||
size_t* bytes_used)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
// Reset the interrupt flag
|
||||
parser->interrupted = 0;
|
||||
|
||||
// Only bother saving text if it'll be used
|
||||
telnet_byte* buf = NULL;
|
||||
size_t buflen = 0;
|
||||
if (parser->callback)
|
||||
{
|
||||
// Because of how the parser translates data, a run of text is guaranteed to
|
||||
// be at most 'length' characters long. In practice it's usually less, due to
|
||||
// escaped characters (IAC IAC -> IAC) and text separated by commands.
|
||||
buf = malloc(length * sizeof(*buf));
|
||||
if (!buf)
|
||||
return TELNET_E_ALLOC;
|
||||
}
|
||||
|
||||
parser->p = data;
|
||||
parser->pe = data + length;
|
||||
parser->eof = parser->pe;
|
||||
|
||||
|
||||
#line 127 "src/parser.c"
|
||||
{
|
||||
if ( ( parser->p) == ( parser->pe) )
|
||||
goto _test_eof;
|
||||
switch ( parser->cs )
|
||||
{
|
||||
tr1:
|
||||
#line 6 "src/parser_common.rl"
|
||||
{( parser->p)--;}
|
||||
#line 111 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_warning_event ev;
|
||||
EV_WARNING(ev, "Invalid \\r: not followed by \\n or \\0.", ( parser->p)-data);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
goto st7;
|
||||
tr2:
|
||||
#line 67 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
buf[buflen++] = (*( parser->p));
|
||||
}
|
||||
goto st7;
|
||||
tr3:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
#line 72 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
{
|
||||
telnet_parser_command_event ev;
|
||||
EV_COMMAND(ev, (*( parser->p)));
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
goto st7;
|
||||
tr12:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
#line 6 "src/parser_common.rl"
|
||||
{( parser->p)--;}
|
||||
#line 119 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_warning_event ev;
|
||||
EV_WARNING(ev, "IAC followed by invalid command.", ( parser->p)-data);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
#line 102 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_subnegotiation_event ev;
|
||||
EV_SUBNEGOTIATION(ev, 0, parser->option_mark);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
goto st7;
|
||||
tr13:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
#line 102 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_subnegotiation_event ev;
|
||||
EV_SUBNEGOTIATION(ev, 0, parser->option_mark);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
goto st7;
|
||||
tr14:
|
||||
#line 84 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
{
|
||||
telnet_parser_option_event ev;
|
||||
EV_OPTION(ev, parser->option_mark, (*( parser->p)));
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
goto st7;
|
||||
st7:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof7;
|
||||
case 7:
|
||||
#line 252 "src/parser.c"
|
||||
switch( (*( parser->p)) ) {
|
||||
case 13u: goto tr15;
|
||||
case 255u: goto st1;
|
||||
}
|
||||
goto tr2;
|
||||
tr15:
|
||||
#line 67 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
buf[buflen++] = (*( parser->p));
|
||||
}
|
||||
goto st0;
|
||||
st0:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof0;
|
||||
case 0:
|
||||
#line 269 "src/parser.c"
|
||||
switch( (*( parser->p)) ) {
|
||||
case 0u: goto st7;
|
||||
case 10u: goto tr2;
|
||||
}
|
||||
goto tr1;
|
||||
st1:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof1;
|
||||
case 1:
|
||||
switch( (*( parser->p)) ) {
|
||||
case 250u: goto tr4;
|
||||
case 255u: goto tr2;
|
||||
}
|
||||
if ( 251u <= (*( parser->p)) && (*( parser->p)) <= 254u )
|
||||
goto tr5;
|
||||
goto tr3;
|
||||
tr4:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
goto st2;
|
||||
st2:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof2;
|
||||
case 2:
|
||||
#line 302 "src/parser.c"
|
||||
goto tr6;
|
||||
tr11:
|
||||
#line 6 "src/parser_common.rl"
|
||||
{( parser->p)--;}
|
||||
#line 111 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_warning_event ev;
|
||||
EV_WARNING(ev, "Invalid \\r: not followed by \\n or \\0.", ( parser->p)-data);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
goto st3;
|
||||
tr7:
|
||||
#line 67 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
buf[buflen++] = (*( parser->p));
|
||||
}
|
||||
goto st3;
|
||||
tr6:
|
||||
#line 93 "src/parser.rl"
|
||||
{
|
||||
parser->option_mark = (*( parser->p));
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_subnegotiation_event ev;
|
||||
EV_SUBNEGOTIATION(ev, 1, parser->option_mark);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
goto st3;
|
||||
st3:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof3;
|
||||
case 3:
|
||||
#line 350 "src/parser.c"
|
||||
switch( (*( parser->p)) ) {
|
||||
case 13u: goto tr8;
|
||||
case 255u: goto st5;
|
||||
}
|
||||
goto tr7;
|
||||
tr8:
|
||||
#line 67 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buf)
|
||||
buf[buflen++] = (*( parser->p));
|
||||
}
|
||||
goto st4;
|
||||
st4:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof4;
|
||||
case 4:
|
||||
#line 367 "src/parser.c"
|
||||
switch( (*( parser->p)) ) {
|
||||
case 0u: goto st3;
|
||||
case 10u: goto tr7;
|
||||
}
|
||||
goto tr11;
|
||||
st5:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof5;
|
||||
case 5:
|
||||
switch( (*( parser->p)) ) {
|
||||
case 240u: goto tr13;
|
||||
case 255u: goto tr7;
|
||||
}
|
||||
goto tr12;
|
||||
tr5:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
#line 81 "src/parser.rl"
|
||||
{
|
||||
parser->option_mark = (*( parser->p));
|
||||
}
|
||||
goto st6;
|
||||
st6:
|
||||
if ( ++( parser->p) == ( parser->pe) )
|
||||
goto _test_eof6;
|
||||
case 6:
|
||||
#line 402 "src/parser.c"
|
||||
goto tr14;
|
||||
}
|
||||
_test_eof7: parser->cs = 7; goto _test_eof;
|
||||
_test_eof0: parser->cs = 0; goto _test_eof;
|
||||
_test_eof1: parser->cs = 1; goto _test_eof;
|
||||
_test_eof2: parser->cs = 2; goto _test_eof;
|
||||
_test_eof3: parser->cs = 3; goto _test_eof;
|
||||
_test_eof4: parser->cs = 4; goto _test_eof;
|
||||
_test_eof5: parser->cs = 5; goto _test_eof;
|
||||
_test_eof6: parser->cs = 6; goto _test_eof;
|
||||
|
||||
_test_eof: {}
|
||||
if ( ( parser->p) == ( parser->eof) )
|
||||
{
|
||||
switch ( parser->cs ) {
|
||||
case 3:
|
||||
case 7:
|
||||
#line 57 "src/parser.rl"
|
||||
{
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
break;
|
||||
#line 431 "src/parser.c"
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#line 189 "src/parser.rl"
|
||||
|
||||
if (bytes_used != NULL)
|
||||
*bytes_used = parser->p - data;
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
parser->p = parser->pe = parser->eof = NULL;
|
||||
|
||||
return (parser->interrupted) ? TELNET_E_INTERRUPT : TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_interrupt(telnet_parser* parser)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
// Force the parser to stop where it's at.
|
||||
if (parser->p)
|
||||
parser->eof = parser->pe = parser->p + 1;
|
||||
|
||||
parser->interrupted = 1;
|
||||
return TELNET_E_OK;
|
||||
}
|
211
outside/anachronism/src/parser.rl
Normal file
211
outside/anachronism/src/parser.rl
Normal file
@ -0,0 +1,211 @@
|
||||
#include <string.h>
|
||||
#include <anachronism/parser.h>
|
||||
|
||||
#define BASE_EV(ev, t) \
|
||||
(ev).SUPER_.type = TELNET_EV_PARSER_##t
|
||||
|
||||
#define EV_DATA(ev, text, len) do {\
|
||||
BASE_EV(ev, DATA);\
|
||||
(ev).data = (text);\
|
||||
(ev).length = (len);\
|
||||
} while (0)
|
||||
|
||||
#define EV_COMMAND(ev, cmd) do {\
|
||||
BASE_EV(ev, COMMAND);\
|
||||
(ev).command = (cmd);\
|
||||
} while (0)
|
||||
|
||||
#define EV_OPTION(ev, cmd, opt) do {\
|
||||
BASE_EV(ev, OPTION);\
|
||||
(ev).command = (cmd);\
|
||||
(ev).option = (opt);\
|
||||
} while (0)
|
||||
|
||||
#define EV_SUBNEGOTIATION(ev, act, opt) do {\
|
||||
BASE_EV(ev, SUBNEGOTIATION);\
|
||||
(ev).active = (act);\
|
||||
(ev).option = (opt);\
|
||||
} while (0)
|
||||
|
||||
#define EV_WARNING(ev, msg, pos) do {\
|
||||
BASE_EV(ev, WARNING);\
|
||||
(ev).message = (msg);\
|
||||
(ev).position = (pos);\
|
||||
} while (0)
|
||||
|
||||
struct telnet_parser {
|
||||
int cs; /* current Ragel state */
|
||||
const telnet_byte* p; /* current position */
|
||||
const telnet_byte* pe; /* end of current packet */
|
||||
const telnet_byte* eof; /* end-of-file marker */
|
||||
|
||||
telnet_byte option_mark; /* temporary storage for a command byte */
|
||||
unsigned char interrupted; /* Flag for interrupts */
|
||||
|
||||
telnet_parser_callback callback; /* Receiver of Telnet events*/
|
||||
void* userdata; /* Context for parser callback */
|
||||
};
|
||||
|
||||
%%{
|
||||
machine telnet_parser;
|
||||
|
||||
access parser->;
|
||||
variable p parser->p;
|
||||
variable pe parser->pe;
|
||||
variable eof parser->eof;
|
||||
|
||||
action flush_text {
|
||||
if (parser->callback && buflen > 0)
|
||||
{
|
||||
telnet_parser_data_event ev;
|
||||
EV_DATA(ev, buf, buflen);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
buflen = 0;
|
||||
}
|
||||
}
|
||||
|
||||
action char {
|
||||
if (parser->callback && buf)
|
||||
buf[buflen++] = fc;
|
||||
}
|
||||
|
||||
action basic_command {
|
||||
if (parser->callback && buf)
|
||||
{
|
||||
telnet_parser_command_event ev;
|
||||
EV_COMMAND(ev, fc);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
|
||||
action option_mark {
|
||||
parser->option_mark = fc;
|
||||
}
|
||||
action option_command {
|
||||
if (parser->callback && buf)
|
||||
{
|
||||
telnet_parser_option_event ev;
|
||||
EV_OPTION(ev, parser->option_mark, fc);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
|
||||
action subneg_command {
|
||||
parser->option_mark = fc;
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_subnegotiation_event ev;
|
||||
EV_SUBNEGOTIATION(ev, 1, parser->option_mark);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
action subneg_command_end {
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_subnegotiation_event ev;
|
||||
EV_SUBNEGOTIATION(ev, 0, parser->option_mark);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
|
||||
action warning_cr {
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_warning_event ev;
|
||||
EV_WARNING(ev, "Invalid \\r: not followed by \\n or \\0.", fpc-data);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
action warning_iac {
|
||||
if (parser->callback && buf != NULL)
|
||||
{
|
||||
telnet_parser_warning_event ev;
|
||||
EV_WARNING(ev, "IAC followed by invalid command.", fpc-data);
|
||||
parser->callback(parser, (telnet_parser_event*)&ev);
|
||||
}
|
||||
}
|
||||
|
||||
include telnet_parser_common "parser_common.rl";
|
||||
write data;
|
||||
}%%
|
||||
|
||||
telnet_parser* telnet_parser_new(void* userdata,
|
||||
telnet_parser_callback callback)
|
||||
{
|
||||
telnet_parser* parser = malloc(sizeof(telnet_parser));
|
||||
if (parser)
|
||||
{
|
||||
memset(parser, 0, sizeof(*parser));
|
||||
%% write init;
|
||||
parser->callback = callback;
|
||||
parser->userdata = userdata;
|
||||
}
|
||||
return parser;
|
||||
}
|
||||
|
||||
void telnet_parser_free(telnet_parser* parser)
|
||||
{
|
||||
free(parser);
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_get_userdata(telnet_parser* parser, void** userdata)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
*userdata = parser->userdata;
|
||||
return TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_parse(telnet_parser* parser,
|
||||
const telnet_byte* data,
|
||||
size_t length,
|
||||
size_t* bytes_used)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
// Reset the interrupt flag
|
||||
parser->interrupted = 0;
|
||||
|
||||
// Only bother saving text if it'll be used
|
||||
telnet_byte* buf = NULL;
|
||||
size_t buflen = 0;
|
||||
if (parser->callback)
|
||||
{
|
||||
// Because of how the parser translates data, a run of text is guaranteed to
|
||||
// be at most 'length' characters long. In practice it's usually less, due to
|
||||
// escaped characters (IAC IAC -> IAC) and text separated by commands.
|
||||
buf = malloc(length * sizeof(*buf));
|
||||
if (!buf)
|
||||
return TELNET_E_ALLOC;
|
||||
}
|
||||
|
||||
parser->p = data;
|
||||
parser->pe = data + length;
|
||||
parser->eof = parser->pe;
|
||||
|
||||
%% write exec;
|
||||
|
||||
if (bytes_used != NULL)
|
||||
*bytes_used = parser->p - data;
|
||||
|
||||
free(buf);
|
||||
buf = NULL;
|
||||
parser->p = parser->pe = parser->eof = NULL;
|
||||
|
||||
return (parser->interrupted) ? TELNET_E_INTERRUPT : TELNET_E_OK;
|
||||
}
|
||||
|
||||
telnet_error telnet_parser_interrupt(telnet_parser* parser)
|
||||
{
|
||||
if (!parser)
|
||||
return TELNET_E_BAD_PARSER;
|
||||
|
||||
// Force the parser to stop where it's at.
|
||||
if (parser->p)
|
||||
parser->eof = parser->pe = parser->p + 1;
|
||||
|
||||
parser->interrupted = 1;
|
||||
return TELNET_E_OK;
|
||||
}
|
85
outside/anachronism/src/parser_common.rl
Normal file
85
outside/anachronism/src/parser_common.rl
Normal file
@ -0,0 +1,85 @@
|
||||
%%{
|
||||
machine telnet_parser_common;
|
||||
alphtype unsigned char;
|
||||
|
||||
# Shorthand for tidiness.
|
||||
action fhold {fhold;}
|
||||
|
||||
# Special bytes that must be handled differently from normal text:
|
||||
CR = "\r"; # Only \0 or \n may follow
|
||||
IAC = 255; # Telnet command marker
|
||||
special_byte = CR | IAC;
|
||||
|
||||
# The only bytes that may follow a CR:
|
||||
NL = "\n";
|
||||
NUL = "\0";
|
||||
|
||||
# The only bytes that may follow an IAC:
|
||||
SE = 240;
|
||||
NOP = 241;
|
||||
DM = 242;
|
||||
BRK = 243;
|
||||
IP = 244;
|
||||
AO = 245;
|
||||
AYT = 246;
|
||||
EC = 247;
|
||||
EL = 248;
|
||||
GA = 249;
|
||||
SB = 250;
|
||||
WILL = 251;
|
||||
WONT = 252;
|
||||
DO = 253;
|
||||
DONT = 254;
|
||||
# IAC IAC is interpreted as a plain-text IAC byte.
|
||||
|
||||
# Sorting the above IAC commands by type:
|
||||
iac_option_type = WILL | WONT | DO | DONT;
|
||||
iac_subneg_type = SB;
|
||||
iac_command_type = ^(iac_option_type | iac_subneg_type | IAC);
|
||||
|
||||
###
|
||||
# Plain text
|
||||
###
|
||||
plain_text = (^special_byte) @char;
|
||||
cr_seq = CR @char
|
||||
( NUL
|
||||
| NL @char
|
||||
| ^(NUL|NL) @fhold @warning_cr @flush_text
|
||||
);
|
||||
|
||||
###
|
||||
# IAC sequence
|
||||
###
|
||||
iac_command = iac_command_type @basic_command;
|
||||
|
||||
iac_option = iac_option_type @option_mark
|
||||
any @option_command;
|
||||
|
||||
iac_subneg = iac_subneg_type any @subneg_command
|
||||
( plain_text
|
||||
| cr_seq
|
||||
| IAC IAC @char
|
||||
)** %/flush_text
|
||||
IAC
|
||||
( SE
|
||||
| ^(IAC|SE) @fhold @warning_iac
|
||||
) >flush_text @subneg_command_end;
|
||||
|
||||
iac_seq = ( iac_command
|
||||
| iac_option
|
||||
| iac_subneg
|
||||
);
|
||||
|
||||
###
|
||||
# Telnet stream
|
||||
###
|
||||
telnet_stream = ( plain_text
|
||||
| cr_seq
|
||||
| IAC
|
||||
( IAC @char
|
||||
| iac_seq >flush_text
|
||||
)
|
||||
)** %/flush_text;
|
||||
|
||||
main := telnet_stream;
|
||||
}%%
|
14
v/ames.c
14
v/ames.c
@ -122,8 +122,8 @@ _ames_lane_ip(u2_noun lan, c3_s* por_s, c3_w* pip_w)
|
||||
{
|
||||
switch ( u2h(lan) ) {
|
||||
case c3__if: {
|
||||
*por_s= (c3_s) u2h(u2t(lan));
|
||||
*pip_w = u2_cr_word(0, u2t(u2t(lan)));
|
||||
*por_s= (c3_s) u2h(u2t(u2t(lan)));
|
||||
*pip_w = u2_cr_word(0, u2t(u2t(u2t(lan))));
|
||||
|
||||
return u2_yes;
|
||||
} break;
|
||||
@ -235,7 +235,7 @@ _ames_time_cb(uv_timer_t* tim_u, c3_i sas_i)
|
||||
{
|
||||
u2_reck_plan
|
||||
(u2A,
|
||||
u2nt(c3__gold, c3__ames, u2_nul),
|
||||
u2nt(u2_blip, c3__ames, u2_nul),
|
||||
u2nc(c3__wake, u2_nul));
|
||||
}
|
||||
u2_lo_shut(u2_no);
|
||||
@ -266,8 +266,10 @@ _ames_recv_cb(uv_udp_t* wax_u,
|
||||
// fprintf(stderr, "ames: plan\r\n");
|
||||
u2_reck_plan
|
||||
(u2A,
|
||||
u2nt(c3__gold, c3__ames, u2_nul),
|
||||
u2nt(c3__hear, u2nt(c3__if, por_s, u2_ci_words(1, &pip_w)), msg));
|
||||
u2nt(u2_blip, c3__ames, u2_nul),
|
||||
u2nt(c3__hear,
|
||||
u2nq(c3__if, u2k(u2A->now), por_s, u2_ci_words(1, &pip_w)),
|
||||
msg));
|
||||
}
|
||||
_ames_free(buf_u.base);
|
||||
u2_lo_shut(u2_yes);
|
||||
@ -359,7 +361,7 @@ void
|
||||
u2_ames_io_poll()
|
||||
{
|
||||
u2_ames* sam_u = &u2_Host.sam_u;
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(c3__gold, c3__ames, u2_nul));
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(u2_blip, c3__ames, u2_nul));
|
||||
|
||||
if ( (u2_nul != wen) &&
|
||||
(u2_yes == u2du(wen)) &&
|
||||
|
4
v/batz.c
4
v/batz.c
@ -49,7 +49,7 @@ _batz_time_cb(uv_timer_t* tim_u, c3_i sas_i)
|
||||
{
|
||||
u2_reck_plan
|
||||
(u2A,
|
||||
u2nt(c3__gold, c3__batz, u2_nul),
|
||||
u2nt(u2_blip, c3__batz, u2_nul),
|
||||
u2nc(c3__wake, u2_nul));
|
||||
}
|
||||
u2_lo_shut(u2_no);
|
||||
@ -61,7 +61,7 @@ void
|
||||
u2_batz_io_poll(void)
|
||||
{
|
||||
u2_batz* beh_u = &u2_Host.beh_u;
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(c3__gold, c3__batz, u2_nul));
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(u2_blip, c3__batz, u2_nul));
|
||||
|
||||
if ( (u2_nul != wen) &&
|
||||
(u2_yes == u2du(wen)) &&
|
||||
|
2
v/cttp.c
2
v/cttp.c
@ -440,7 +440,7 @@ static void
|
||||
_cttp_httr(c3_l num_l, c3_w sas_w, u2_noun mes, u2_noun uct)
|
||||
{
|
||||
u2_noun htr = u2nt(sas_w, mes, uct);
|
||||
u2_noun pox = u2nt(c3__iron, c3__http, u2_nul);
|
||||
u2_noun pox = u2nt(u2_blip, c3__http, u2_nul);
|
||||
|
||||
u2_reck_plan(u2_Host.arv_u, pox, u2nt(c3__they, num_l, htr));
|
||||
}
|
||||
|
16
v/http.c
16
v/http.c
@ -260,6 +260,15 @@ _http_respond_request(u2_hreq* req_u,
|
||||
req_u->end = u2_yes;
|
||||
}
|
||||
|
||||
/* _http_conn_free_early(): free http connection on failure.
|
||||
*/
|
||||
static void
|
||||
_http_conn_free_early(uv_handle_t* han_t)
|
||||
{
|
||||
u2_hcon* hon_u = (void*) han_t;
|
||||
free(hon_u);
|
||||
}
|
||||
|
||||
/* _http_conn_free(): free http connection on close.
|
||||
*/
|
||||
static void
|
||||
@ -605,8 +614,7 @@ _http_conn_new(u2_http *htp_u)
|
||||
uL(fprintf(uH, "http: accept: %s\n",
|
||||
uv_strerror(uv_last_error(u2L))));
|
||||
|
||||
uv_close((uv_handle_t*)&hon_u->wax_u, 0);
|
||||
free(hon_u);
|
||||
uv_close((uv_handle_t*)&hon_u->wax_u, _http_conn_free_early);
|
||||
}
|
||||
else {
|
||||
uv_read_start((uv_stream_t*)&hon_u->wax_u,
|
||||
@ -791,7 +799,7 @@ _http_pox_to_noun(c3_w sev_l, c3_w coq_l, c3_w seq_l)
|
||||
{
|
||||
return
|
||||
u2nt(
|
||||
c3__iron,
|
||||
u2_blip,
|
||||
c3__http,
|
||||
u2nq(u2_dc("scot", c3_s2('u','v'), sev_l),
|
||||
u2_dc("scot", c3_s2('u','d'), coq_l),
|
||||
@ -960,7 +968,7 @@ _http_respond(u2_hrep* rep_u)
|
||||
void
|
||||
u2_http_ef_bake(void)
|
||||
{
|
||||
u2_noun pax = u2nq(c3__gold, c3__http, u2k(u2A->sen), u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__http, u2k(u2A->sen), u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, pax, u2nc(c3__born, u2_nul));
|
||||
}
|
||||
|
5
v/loop.c
5
v/loop.c
@ -178,6 +178,7 @@ _lo_talk()
|
||||
u2_unix_io_talk();
|
||||
u2_ames_io_talk();
|
||||
u2_http_io_talk();
|
||||
u2_term_io_talk();
|
||||
}
|
||||
|
||||
/* u2_lo_exit(): terminate I/O across the process.
|
||||
@ -501,7 +502,7 @@ _lo_bench_noop(c3_w num_w)
|
||||
c3_w i_w;
|
||||
|
||||
for ( i_w = 0; i_w < num_w; i_w++ ) {
|
||||
u2_reck_plan(u2A, u2nq(c3__gold, c3__term, 1, u2_nul),
|
||||
u2_reck_plan(u2A, u2nq(u2_blip, c3__term, 1, u2_nul),
|
||||
u2nc(c3__noop, u2_nul));
|
||||
}
|
||||
|
||||
@ -668,7 +669,7 @@ u2_lo_lead(u2_reck* rec_u)
|
||||
_lo_talk();
|
||||
{
|
||||
u2_unix_ef_look();
|
||||
u2_reck_plan(rec_u, u2nt(c3__gold, c3__ames, u2_nul),
|
||||
u2_reck_plan(rec_u, u2nt(u2_blip, c3__ames, u2_nul),
|
||||
u2nc(c3__kick, u2k(rec_u->now)));
|
||||
}
|
||||
_lo_poll();
|
||||
|
10
v/main.c
10
v/main.c
@ -66,13 +66,13 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
u2_Host.ops_u.loh = u2_no;
|
||||
u2_Host.ops_u.dem = u2_no;
|
||||
u2_Host.ops_u.fog = u2_no;
|
||||
u2_Host.ops_u.fak = u2_no;
|
||||
u2_Host.ops_u.pro = u2_no;
|
||||
u2_Host.ops_u.veb = u2_yes;
|
||||
u2_Host.ops_u.nuu = u2_no;
|
||||
u2_Host.ops_u.vno = u2_no;
|
||||
u2_Host.ops_u.kno_w = DefaultKernel;
|
||||
|
||||
while ( (ch_i = getopt(argc, argv, "I:X:f:k:l:n:p:r:LabcdgqvV")) != -1 ) {
|
||||
while ( (ch_i = getopt(argc, argv, "I:X:f:k:l:n:p:r:LabcdgqvF")) != -1 ) {
|
||||
switch ( ch_i ) {
|
||||
case 'I': {
|
||||
u2_Host.ops_u.imp_c = strdup(optarg);
|
||||
@ -117,6 +117,11 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
break;
|
||||
}
|
||||
case 'L': { u2_Host.ops_u.loh = u2_yes; break; }
|
||||
case 'F': {
|
||||
u2_Host.ops_u.loh = u2_yes;
|
||||
u2_Host.ops_u.fak = u2_yes;
|
||||
break;
|
||||
}
|
||||
case 'a': { u2_Host.ops_u.abo = u2_yes; break; }
|
||||
case 'b': { u2_Host.ops_u.bat = u2_yes; break; }
|
||||
case 'c': { u2_Host.ops_u.nuu = u2_yes; break; }
|
||||
@ -124,7 +129,6 @@ _main_getopt(c3_i argc, c3_c** argv)
|
||||
case 'g': { u2_Host.ops_u.gab = u2_yes; break; }
|
||||
case 'q': { u2_Host.ops_u.veb = u2_no; break; }
|
||||
case 'v': { u2_Host.ops_u.veb = u2_yes; break; }
|
||||
case 'V': { u2_Host.ops_u.vno = u2_yes; break; }
|
||||
case '?': default: {
|
||||
return u2_no;
|
||||
}
|
||||
|
16
v/raft.c
16
v/raft.c
@ -1525,6 +1525,7 @@ _raft_lame(u2_reck* rec_u, u2_noun ovo, u2_noun why, u2_noun tan)
|
||||
u2z(vab);
|
||||
|
||||
uL(fprintf(uH, "crude: all delivery failed!\n"));
|
||||
u2_lo_punt(2, u2_ckb_flop(u2k(tan)));
|
||||
c3_assert(!"crud");
|
||||
}
|
||||
}
|
||||
@ -1561,6 +1562,7 @@ _raft_punk(u2_reck* rec_u, u2_noun ovo)
|
||||
#ifdef GHETTO
|
||||
struct timeval b4, f2, d0;
|
||||
gettimeofday(&b4, 0);
|
||||
uL(fprintf(uH, "%%soft %s\n", txt_c));
|
||||
#endif
|
||||
|
||||
gon = u2_lo_soft(rec_u, sec_w, u2_reck_poke, u2k(ovo));
|
||||
@ -1619,7 +1621,6 @@ _raft_comm(u2_reck* rec_u, c3_d bid_d)
|
||||
egg_u = rec_u->ova.egg_u;
|
||||
while ( egg_u ) {
|
||||
if ( egg_u->ent_d <= bid_d ) {
|
||||
egg_u->did = u2_yes;
|
||||
egg_u->cit = u2_yes;
|
||||
} else break;
|
||||
egg_u = egg_u->nex_u;
|
||||
@ -1709,15 +1710,7 @@ u2_raft_work(u2_reck* rec_u)
|
||||
rec_u->ova.egg_u = egg_u->nex_u;
|
||||
}
|
||||
|
||||
if ( u2_yes == egg_u->cit ) {
|
||||
_raft_kick_all(rec_u, vir);
|
||||
}
|
||||
else {
|
||||
// We poked an event, but Raft failed to persist it.
|
||||
// TODO: gracefully recover.
|
||||
uL(fprintf(uH, "vere: event executed but not persisted\n"));
|
||||
c3_assert(0);
|
||||
}
|
||||
egg_u->cit = u2_yes;
|
||||
free(egg_u);
|
||||
}
|
||||
else break;
|
||||
@ -1787,9 +1780,8 @@ u2_raft_work(u2_reck* rec_u)
|
||||
rec_u->ova.geg_u->nex_u = egg_u;
|
||||
rec_u->ova.geg_u = egg_u;
|
||||
}
|
||||
}
|
||||
else {
|
||||
_raft_kick_all(rec_u, vir);
|
||||
egg_u->did = u2_yes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
34
v/reck.c
34
v/reck.c
@ -223,33 +223,6 @@ _reck_scot(u2_reck* rec_u, u2_noun dim)
|
||||
return u2_do("scot", dim);
|
||||
}
|
||||
|
||||
#if 0
|
||||
/* _reck_spoo(): noun path from c, kind of a hack.
|
||||
*/
|
||||
static u2_noun
|
||||
_reck_spoo(c3_c* pax_c)
|
||||
{
|
||||
if ( !*pax_c ) {
|
||||
return u2_nul;
|
||||
} else {
|
||||
c3_c* ash_c = strchr(pax_c, '/');
|
||||
|
||||
if ( !ash_c ) {
|
||||
return u2nc(u2_ci_string(pax_c), u2_nul);
|
||||
}
|
||||
else {
|
||||
u2_noun pan;
|
||||
|
||||
*ash_c = 0;
|
||||
pan = u2_ci_string(pax_c);
|
||||
*ash_c = '/';
|
||||
|
||||
return u2nc(pan, _reck_spoo(ash_c + 1));
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
/* u2_reck_time(): set the reck time.
|
||||
*/
|
||||
void
|
||||
@ -592,7 +565,10 @@ _reck_kick_spec(u2_reck* rec_u, u2_noun pox, u2_noun fav)
|
||||
u2_noun i_pox, t_pox;
|
||||
|
||||
if ( (u2_no == u2_cr_cell(pox, &i_pox, &t_pox)) ||
|
||||
((i_pox != c3__gold) && (i_pox != c3__iron) && (i_pox != c3__lead)) )
|
||||
((i_pox != u2_blip) &&
|
||||
(i_pox != c3__gold) &&
|
||||
(i_pox != c3__iron) &&
|
||||
(i_pox != c3__lead)) )
|
||||
{
|
||||
u2z(pox); u2z(fav); return u2_no;
|
||||
} else {
|
||||
@ -738,7 +714,7 @@ u2_reck_kick(u2_reck* rec_u, u2_noun ovo)
|
||||
(c3__init == u2h(u2t(ovo))) )
|
||||
#endif
|
||||
{
|
||||
u2_reck_plan(rec_u, u2nt(c3__gold, c3__term, u2_nul),
|
||||
u2_reck_plan(rec_u, u2nt(u2_blip, c3__term, u2_nul),
|
||||
u2nc(c3__flog, u2k(u2t(ovo))));
|
||||
}
|
||||
else {
|
||||
|
34
v/sist.c
34
v/sist.c
@ -307,11 +307,11 @@ _sist_home(u2_reck* rec_u)
|
||||
}
|
||||
}
|
||||
|
||||
// Copy zod files, if we're generating zod.
|
||||
// Copy zod files, if we're generating a carrier.
|
||||
//
|
||||
if ( u2_Host.ops_u.imp_c && 0 == strcmp(u2_Host.ops_u.imp_c, "~zod") ) {
|
||||
snprintf(ful_c, 2048, "cp -r %s/zod %s/",
|
||||
U2_LIB, u2_Host.cpu_c);
|
||||
if ( u2_Host.ops_u.imp_c ) {
|
||||
snprintf(ful_c, 2048, "cp -r %s/zod %s/%s",
|
||||
U2_LIB, u2_Host.cpu_c, u2_Host.ops_u.imp_c+1);
|
||||
if ( 0 != system(ful_c) ) {
|
||||
uL(fprintf(uH, "could not %s\n", ful_c));
|
||||
u2_lo_bail(rec_u);
|
||||
@ -1176,7 +1176,7 @@ _sist_rest(u2_reck* rec_u)
|
||||
|
||||
// Hey, fscker! It worked.
|
||||
{
|
||||
u2_term_ef_boil(tno_l);
|
||||
u2_term_ef_boil();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1210,7 +1210,7 @@ u2_sist_boot(void)
|
||||
u2_noun ten = _sist_zen(u2A);
|
||||
uL(fprintf(uH, "generating 2048-bit RSA pair...\n"));
|
||||
|
||||
pig = u2nq(c3__make, u2_nul, 11, ten);
|
||||
pig = u2nq(c3__make, u2_nul, 11, u2nc(ten, u2_Host.ops_u.fak));
|
||||
}
|
||||
else {
|
||||
u2_noun imp = u2_ci_string(u2_Host.ops_u.imp_c);
|
||||
@ -1221,14 +1221,24 @@ u2_sist_boot(void)
|
||||
u2_lo_bail(u2A);
|
||||
}
|
||||
else {
|
||||
u2_noun gen = _sist_text(u2A, "generator");
|
||||
u2_noun gun = u2_dc("slaw", c3__uw, gen);
|
||||
u2_noun gen = u2_nul;
|
||||
u2_noun gun = u2_nul;
|
||||
if (u2_no == u2_Host.ops_u.fak) {
|
||||
gen = _sist_text(u2A, "generator");
|
||||
gun = u2_dc("slaw", c3__uw, gen);
|
||||
|
||||
if ( u2_nul == gun ) {
|
||||
fprintf(stderr, "czar: incorrect format\r\n");
|
||||
u2_lo_bail(u2A);
|
||||
if ( u2_nul == gun ) {
|
||||
fprintf(stderr, "czar: incorrect format\r\n");
|
||||
u2_lo_bail(u2A);
|
||||
}
|
||||
}
|
||||
pig = u2nt(c3__sith, u2k(u2t(whu)), u2k(u2t(gun)));
|
||||
else {
|
||||
gun = u2nc(u2_nul, u2_nul);
|
||||
}
|
||||
pig = u2nq(c3__sith,
|
||||
u2k(u2t(whu)),
|
||||
u2k(u2t(gun)),
|
||||
u2_Host.ops_u.fak);
|
||||
|
||||
u2z(whu); u2z(gun);
|
||||
}
|
||||
|
370
v/term.c
370
v/term.c
@ -18,11 +18,20 @@
|
||||
#include <curses.h>
|
||||
#include <termios.h>
|
||||
#include <term.h>
|
||||
|
||||
#include <anachronism/common.h>
|
||||
#include <anachronism/nvt.h>
|
||||
#include "all.h"
|
||||
#include "v/vere.h"
|
||||
|
||||
static void _term_read_tn_cb(uv_stream_t*, ssize_t, uv_buf_t);
|
||||
static void _term_read_cb(uv_stream_t*, ssize_t, uv_buf_t);
|
||||
static void _term_suck(u2_utty*, const c3_y*, ssize_t);
|
||||
static void _tel_event(telnet_nvt*, telnet_event*);
|
||||
static void _tel_opt(telnet_nvt*, telnet_byte, telnet_telopt_event*);
|
||||
|
||||
#define _T_ECHO 1 // local echo
|
||||
#define _T_CTIM 3 // suppress GA/char-at-a-time
|
||||
#define _T_NAWS 31 // negotiate about window size
|
||||
|
||||
/* _term_alloc(): libuv buffer allocator.
|
||||
*/
|
||||
@ -32,6 +41,44 @@ _term_alloc(uv_handle_t* had_u, size_t len_i)
|
||||
return uv_buf_init(c3_malloc(len_i), len_i);
|
||||
}
|
||||
|
||||
/* _term_close_cb(): free terminal.
|
||||
*/
|
||||
static void
|
||||
_term_close_cb(uv_handle_t* han_t)
|
||||
{
|
||||
u2_utty* tty_u = (void*) han_t;
|
||||
if ( u2_Host.uty_u == tty_u ) {
|
||||
u2_Host.uty_u = tty_u->nex_u;
|
||||
}
|
||||
else {
|
||||
u2_utty* uty_u;
|
||||
for (uty_u = u2_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) {
|
||||
if ( uty_u->nex_u == tty_u ) {
|
||||
uty_u->nex_u = tty_u->nex_u;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
u2_noun tid = u2_dc("scot", c3__ud, tty_u->tid_l);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, tid, u2_nul);
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__hook, u2_nul));
|
||||
u2z(pax);
|
||||
}
|
||||
free(tty_u);
|
||||
}
|
||||
|
||||
/* _tel_close_cb(): close telnet terminal
|
||||
*/
|
||||
static void
|
||||
_tel_close_cb(uv_handle_t* han_t)
|
||||
{
|
||||
u2_utel* pty_u = (u2_utel*)(void*)han_t;
|
||||
telnet_nvt_free(pty_u->tel_u);
|
||||
_term_close_cb(han_t);
|
||||
}
|
||||
|
||||
/* u2_term_io_init(): initialize terminal.
|
||||
*/
|
||||
void
|
||||
@ -77,7 +124,6 @@ u2_term_io_init()
|
||||
|
||||
uty_u->ufo_u.inn.max_w = 0;
|
||||
|
||||
#if 1
|
||||
_utfo(inn, kcuu1);
|
||||
_utfo(inn, kcud1);
|
||||
_utfo(inn, kcub1);
|
||||
@ -94,18 +140,6 @@ u2_term_io_init()
|
||||
_utfo(out, cud1);
|
||||
// _utfo(out, cub);
|
||||
// _utfo(out, cuf);
|
||||
#else
|
||||
// libuv hardcodes an ansi terminal - which doesn't seem to work...
|
||||
//
|
||||
uty_u->ufo_u.out.clear_y = "\033[H\033[J";
|
||||
uty_u->ufo_u.out.el_y = "\033[K";
|
||||
uty_u->ufo_u.out.ed_y = "\033[J";
|
||||
uty_u->ufo_u.out.bel_y = "\007";
|
||||
uty_u->ufo_u.out.cub1_y = "\010";
|
||||
uty_u->ufo_u.out.cud1_y = "\033[B";
|
||||
uty_u->ufo_u.out.cuu1_y = "\033[A";
|
||||
uty_u->ufo_u.out.cuf1_y = "\033[C";
|
||||
#endif
|
||||
|
||||
// Terminfo chronically reports the wrong sequence for arrow
|
||||
// keys on xterms. Drastic fix for ridiculous unacceptable bug.
|
||||
@ -142,7 +176,6 @@ u2_term_io_init()
|
||||
|
||||
// Load old terminal state to restore.
|
||||
//
|
||||
#if 1
|
||||
{
|
||||
if ( 0 != tcgetattr(uty_u->fid_i, &uty_u->bak_u) ) {
|
||||
c3_assert(!"init-tcgetattr");
|
||||
@ -167,7 +200,6 @@ u2_term_io_init()
|
||||
uty_u->raw_u.c_cc[VMIN] = 0;
|
||||
uty_u->raw_u.c_cc[VTIME] = 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
// Initialize mirror and accumulator state.
|
||||
//
|
||||
@ -188,10 +220,8 @@ u2_term_io_init()
|
||||
//
|
||||
{
|
||||
uty_u->tid_l = 1;
|
||||
|
||||
uty_u->nex_u = u2_Host.uty_u;
|
||||
uty_u->nex_u = 0;
|
||||
u2_Host.uty_u = uty_u;
|
||||
u2_Host.tem_u = uty_u;
|
||||
}
|
||||
|
||||
if ( u2_no == u2_Host.ops_u.dem ) {
|
||||
@ -208,6 +238,120 @@ u2_term_io_init()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_term_listen_cb(uv_stream_t *wax_u, int sas_i)
|
||||
{
|
||||
u2_utel* pty_u = calloc(1, sizeof(*pty_u));
|
||||
u2_utty* tty_u = &pty_u->uty_t;
|
||||
uv_tcp_init(u2L, &tty_u->wax_u);
|
||||
if ( 0 != uv_accept(wax_u, (uv_stream_t*)&tty_u->wax_u) ) {
|
||||
uL(fprintf(uH, "term: accept: %s\n",
|
||||
uv_strerror(uv_last_error(u2L))));
|
||||
|
||||
uv_close((uv_handle_t*)&tty_u->wax_u, NULL);
|
||||
free(tty_u);
|
||||
}
|
||||
else {
|
||||
uv_read_start((uv_stream_t*)&tty_u->wax_u,
|
||||
_term_alloc,
|
||||
_term_read_tn_cb);
|
||||
|
||||
tty_u->ufo_u.out.clear_y = (const c3_y*)"\033[H\033[J";
|
||||
tty_u->ufo_u.out.el_y = (const c3_y*)"\033[K";
|
||||
tty_u->ufo_u.out.ed_y = (const c3_y*)"\033[J";
|
||||
tty_u->ufo_u.out.bel_y = (const c3_y*)"\007";
|
||||
tty_u->ufo_u.out.cub1_y = (const c3_y*)"\010";
|
||||
tty_u->ufo_u.out.cud1_y = (const c3_y*)"\033[B";
|
||||
tty_u->ufo_u.out.cuu1_y = (const c3_y*)"\033[A";
|
||||
tty_u->ufo_u.out.cuf1_y = (const c3_y*)"\033[C";
|
||||
|
||||
tty_u->ufo_u.inn.kcuu1_y = (const c3_y*)"\033[A";
|
||||
tty_u->ufo_u.inn.kcud1_y = (const c3_y*)"\033[B";
|
||||
tty_u->ufo_u.inn.kcuf1_y = (const c3_y*)"\033[C";
|
||||
tty_u->ufo_u.inn.kcub1_y = (const c3_y*)"\033[D";
|
||||
tty_u->ufo_u.inn.max_w = strlen("\033[D");
|
||||
|
||||
tty_u->fid_i = -1;
|
||||
|
||||
tty_u->tat_u.mir.lin_w = 0;
|
||||
tty_u->tat_u.mir.len_w = 0;
|
||||
tty_u->tat_u.mir.cus_w = 0;
|
||||
|
||||
tty_u->tat_u.esc.ape = u2_no;
|
||||
tty_u->tat_u.esc.bra = u2_no;
|
||||
|
||||
tty_u->tat_u.fut.len_w = 0;
|
||||
tty_u->tat_u.fut.wid_w = 0;
|
||||
|
||||
tty_u->tat_u.siz.col_l = 80;
|
||||
tty_u->tat_u.siz.row_l = 25;
|
||||
|
||||
tty_u->tid_l = u2_Host.uty_u->tid_l + 1;
|
||||
tty_u->nex_u = u2_Host.uty_u;
|
||||
u2_Host.uty_u = tty_u;
|
||||
pty_u->tel_u = telnet_nvt_new(tty_u, _tel_event, _tel_opt, NULL);
|
||||
|
||||
{
|
||||
u2_noun tid = u2_dc("scot", c3__ud, tty_u->tid_l);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, tid, u2_nul);
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__blew, u2nc(80, 25)));
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__hail, u2_nul));
|
||||
u2z(pax);
|
||||
}
|
||||
|
||||
telnet_telopt_enable(pty_u->tel_u, _T_ECHO, TELNET_LOCAL);
|
||||
telnet_telopt_enable(pty_u->tel_u, _T_CTIM, TELNET_LOCAL);
|
||||
telnet_telopt_enable(pty_u->tel_u, _T_NAWS, TELNET_REMOTE);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
u2_term_io_talk(void)
|
||||
{
|
||||
struct sockaddr_in add_u;
|
||||
u2_utel* tel_u = &u2_Host.tel_u;
|
||||
|
||||
uv_tcp_init(u2L, &tel_u->uty_t.wax_u);
|
||||
tel_u->por_s = 10023;
|
||||
|
||||
memset(&add_u, 0, sizeof(add_u));
|
||||
add_u.sin_family = AF_INET;
|
||||
add_u.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
|
||||
|
||||
/* Try ascending ports.
|
||||
*/
|
||||
while ( 1 ) {
|
||||
add_u.sin_port = htons(tel_u->por_s);
|
||||
|
||||
if ( 0 != uv_tcp_bind(&tel_u->uty_t.wax_u, add_u) ) {
|
||||
uv_err_t las_u = uv_last_error(u2L);
|
||||
|
||||
if ( UV_EADDRINUSE == las_u.code ) {
|
||||
tel_u->por_s++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
uL(fprintf(uH, "term: bind: %s\n", uv_strerror(las_u)));
|
||||
}
|
||||
}
|
||||
if ( 0 != uv_listen((uv_stream_t*)&tel_u->uty_t.wax_u,
|
||||
16, _term_listen_cb) )
|
||||
{
|
||||
uv_err_t las_u = uv_last_error(u2L);
|
||||
|
||||
if ( UV_EADDRINUSE == las_u.code ) {
|
||||
tel_u->por_s++;
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
uL(fprintf(uH, "term: listen: %s\n", uv_strerror(las_u)));
|
||||
}
|
||||
}
|
||||
uL(fprintf(uH, "term: live on %d\n", tel_u->por_s));
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* u2_term_io_exit(): clean up terminal.
|
||||
*/
|
||||
void
|
||||
@ -220,6 +364,7 @@ u2_term_io_exit(void)
|
||||
u2_utty* uty_u;
|
||||
|
||||
for ( uty_u = u2_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) {
|
||||
if ( uty_u->fid_i == -1 ) { continue; }
|
||||
if ( 0 != tcsetattr(uty_u->fid_i, TCSADRAIN, &uty_u->bak_u) ) {
|
||||
c3_assert(!"exit-tcsetattr");
|
||||
}
|
||||
@ -520,11 +665,85 @@ static void
|
||||
_term_io_belt(u2_utty* uty_u, u2_noun blb)
|
||||
{
|
||||
u2_noun tid = u2_dc("scot", c3__ud, uty_u->tid_l);
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, tid, u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, tid, u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, pax, u2nc(c3__belt, blb));
|
||||
}
|
||||
|
||||
/* _tel_event(): telnet sucker
|
||||
*/
|
||||
#define _te_nvt telnet_nvt
|
||||
#define _te_evt telnet_event
|
||||
#define _te_dvt telnet_data_event
|
||||
#define _te_svt telnet_send_event
|
||||
static void
|
||||
_tel_event(_te_nvt* nvt, _te_evt* evt)
|
||||
{
|
||||
u2_utel* tel_u;
|
||||
c3_assert(0 < telnet_get_userdata(nvt, (void**)&tel_u));
|
||||
switch (evt->type)
|
||||
{
|
||||
case TELNET_EV_DATA:
|
||||
{
|
||||
_te_dvt* dv = (_te_dvt*)evt;
|
||||
_term_suck((u2_utty*)tel_u, dv->data, dv->length);
|
||||
break;
|
||||
}
|
||||
|
||||
case TELNET_EV_SEND:
|
||||
{
|
||||
_te_svt* sv = (_te_svt*)evt;
|
||||
_term_it_write_bytes((u2_utty*)tel_u, sv->length, sv->data);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define _to_evt telnet_telopt_event
|
||||
#define _to_dvt telnet_telopt_data_event
|
||||
#define _to_tvt telnet_telopt_toggle_event
|
||||
/* _tel_opt(): telnet event sucker
|
||||
*/
|
||||
static void
|
||||
_tel_opt(_te_nvt* nvt, telnet_byte opt, _to_evt* evt)
|
||||
{
|
||||
switch (evt->type)
|
||||
{
|
||||
default: break;
|
||||
case TELNET_EV_TELOPT_DATA:
|
||||
{
|
||||
_to_dvt* dv = (_to_dvt*)evt;
|
||||
u2_utel* tel_u;
|
||||
u2_noun pax;
|
||||
u2_noun blu;
|
||||
u2_noun tid;
|
||||
c3_s col_s;
|
||||
c3_s row_s;
|
||||
|
||||
if ( opt != _T_NAWS ) {
|
||||
return;
|
||||
}
|
||||
|
||||
c3_assert(0 < telnet_get_userdata(nvt, (void**)&tel_u));
|
||||
|
||||
col_s = dv->data[1] | (dv->data[0] << 8);
|
||||
row_s = dv->data[3] | (dv->data[2] << 8);
|
||||
|
||||
tel_u->uty_t.tat_u.siz.col_l = col_s;
|
||||
tel_u->uty_t.tat_u.siz.row_l = row_s;
|
||||
|
||||
tid = u2_dc("scot", c3__ud, tel_u->uty_t.tid_l);
|
||||
pax = u2nq(u2_blip, c3__term, tid, u2_nul);
|
||||
blu = u2nc(col_s, row_s);
|
||||
u2_reck_plan(u2A, pax, u2nc(c3__blew, blu));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* _term_io_suck_char(): process a single character.
|
||||
*/
|
||||
static void
|
||||
@ -532,8 +751,6 @@ _term_io_suck_char(u2_utty* uty_u, c3_y cay_y)
|
||||
{
|
||||
u2_utat* tat_u = &uty_u->tat_u;
|
||||
|
||||
// uL(fprintf(uH, "suck-char %x\n", cay_y));
|
||||
|
||||
if ( u2_yes == tat_u->esc.ape ) {
|
||||
if ( u2_yes == tat_u->esc.bra ) {
|
||||
switch ( cay_y ) {
|
||||
@ -611,6 +828,58 @@ _term_io_suck_char(u2_utty* uty_u, c3_y cay_y)
|
||||
}
|
||||
}
|
||||
|
||||
/* _term_read_tn_cb(): telnet read callback.
|
||||
*/
|
||||
static void
|
||||
_term_read_tn_cb(uv_stream_t* str_u,
|
||||
ssize_t siz_i,
|
||||
uv_buf_t buf_u)
|
||||
{
|
||||
u2_utel* pty_u = (u2_utel*)(void*)str_u;
|
||||
|
||||
u2_lo_open();
|
||||
{
|
||||
if ( siz_i < 0 ) {
|
||||
uv_err_t las_u = uv_last_error(u2L);
|
||||
|
||||
uL(fprintf(uH, "term %d: read: %s\n",
|
||||
pty_u->uty_t.tid_l, uv_strerror(las_u)));
|
||||
uv_close((uv_handle_t*)str_u, _tel_close_cb);
|
||||
goto err;
|
||||
}
|
||||
else {
|
||||
telnet_receive(pty_u->tel_u, (const telnet_byte*)buf_u.base, siz_i, 0);
|
||||
}
|
||||
|
||||
err:
|
||||
free(buf_u.base);
|
||||
}
|
||||
u2_lo_shut(u2_yes);
|
||||
}
|
||||
|
||||
/* _term_suck(): process a chunk of input
|
||||
*/
|
||||
static inline void
|
||||
_term_suck(u2_utty* uty_u, const c3_y* buf, ssize_t siz_i)
|
||||
{
|
||||
u2_lo_open();
|
||||
{
|
||||
if ( siz_i < 0 ) {
|
||||
uv_err_t las_u = uv_last_error(u2L);
|
||||
|
||||
uL(fprintf(uH, "term %d: read: %s\n", uty_u->tid_l, uv_strerror(las_u)));
|
||||
}
|
||||
else {
|
||||
c3_i i;
|
||||
|
||||
for ( i=0; i < siz_i; i++ ) {
|
||||
_term_io_suck_char(uty_u, buf[i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
u2_lo_shut(u2_yes);
|
||||
}
|
||||
|
||||
/* _term_read_cb(): server read callback.
|
||||
*/
|
||||
static void
|
||||
@ -619,27 +888,8 @@ _term_read_cb(uv_stream_t* str_u,
|
||||
uv_buf_t buf_u)
|
||||
{
|
||||
u2_utty* uty_u = (u2_utty*)(void*)str_u;
|
||||
|
||||
u2_lo_open();
|
||||
{
|
||||
if ( siz_i < 0 ) {
|
||||
uv_err_t las_u = uv_last_error(u2L);
|
||||
|
||||
uL(fprintf(uH, "term: read: %s\n", uv_strerror(las_u)));
|
||||
}
|
||||
else {
|
||||
c3_i i;
|
||||
|
||||
for ( i=0; i < siz_i; i++ ) {
|
||||
_term_io_suck_char(uty_u, buf_u.base[i]);
|
||||
}
|
||||
}
|
||||
|
||||
if ( buf_u.base ) {
|
||||
free(buf_u.base);
|
||||
}
|
||||
}
|
||||
u2_lo_shut(u2_yes);
|
||||
_term_suck(uty_u, (const c3_y*)buf_u.base, siz_i);
|
||||
free(buf_u.base);
|
||||
}
|
||||
|
||||
/* _term_main(): return main or console terminal.
|
||||
@ -650,7 +900,7 @@ _term_main()
|
||||
u2_utty* uty_u;
|
||||
|
||||
for ( uty_u = u2_Host.uty_u; uty_u; uty_u = uty_u->nex_u ) {
|
||||
if ( uty_u->fid_i <= 2 ) {
|
||||
if ( (uty_u->fid_i != -1) && (uty_u->fid_i <= 2) ) {
|
||||
return uty_u;
|
||||
}
|
||||
}
|
||||
@ -682,7 +932,6 @@ u2_term_get_blew(c3_l tid_l)
|
||||
u2_utty* uty_u = _term_ef_get(tid_l);
|
||||
c3_l col_l, row_l;
|
||||
|
||||
#if 1
|
||||
struct winsize siz_u;
|
||||
if ( uty_u && (0 == ioctl(uty_u->fid_i, TIOCGWINSZ, &siz_u)) ) {
|
||||
col_l = siz_u.ws_col;
|
||||
@ -691,15 +940,7 @@ u2_term_get_blew(c3_l tid_l)
|
||||
col_l = 80;
|
||||
row_l = 24;
|
||||
}
|
||||
#else
|
||||
{
|
||||
c3_i col_i, row_i;
|
||||
|
||||
uv_tty_get_winsize(&uty_u->wax_u, &col_i, &row_i);
|
||||
col_l = col_i;
|
||||
row_l = row_i;
|
||||
}
|
||||
#endif
|
||||
if ( uty_u ) {
|
||||
uty_u->tat_u.siz.col_l = col_l;
|
||||
uty_u->tat_u.siz.row_l = row_l;
|
||||
@ -713,7 +954,7 @@ u2_term_get_blew(c3_l tid_l)
|
||||
void
|
||||
u2_term_ef_winc(void)
|
||||
{
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, '1', u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, '1', u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, pax, u2nc(c3__blew, u2_term_get_blew(1)));
|
||||
}
|
||||
@ -723,7 +964,7 @@ u2_term_ef_winc(void)
|
||||
void
|
||||
u2_term_ef_ctlc(void)
|
||||
{
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, '1', u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, '1', u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, pax, u2nt(c3__belt, c3__ctl, 'c'));
|
||||
}
|
||||
@ -731,24 +972,13 @@ u2_term_ef_ctlc(void)
|
||||
/* u2_term_ef_boil(): initial effects for loaded servers.
|
||||
*/
|
||||
void
|
||||
u2_term_ef_boil(c3_l ono_l)
|
||||
u2_term_ef_boil(void)
|
||||
{
|
||||
if ( ono_l ) {
|
||||
u2_noun tid_l;
|
||||
|
||||
for ( tid_l = 2; tid_l <= ono_l; tid_l++ ) {
|
||||
u2_noun tin = u2_dc("scot", c3__ud, tid_l);
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, tin, u2_nul);
|
||||
u2_noun hud = u2nc(c3__wipe, u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, pax, hud);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, '1', u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, '1', u2_nul);
|
||||
|
||||
// u2_reck_plan(u2A, u2k(pax), u2nc(c3__init, u2k(u2h(u2A->own))));
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__harm, u2_nul));
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__blew, u2_term_get_blew(1)));
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__hail, u2_nul));
|
||||
|
||||
@ -761,7 +991,7 @@ u2_term_ef_boil(c3_l ono_l)
|
||||
void
|
||||
u2_term_ef_bake(u2_noun fav)
|
||||
{
|
||||
u2_noun pax = u2nq(c3__gold, c3__term, '1', u2_nul);
|
||||
u2_noun pax = u2nq(u2_blip, c3__term, '1', u2_nul);
|
||||
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__boot, fav));
|
||||
u2_reck_plan(u2A, u2k(pax), u2nc(c3__blew, u2_term_get_blew(1)));
|
||||
|
8
v/unix.c
8
v/unix.c
@ -834,7 +834,7 @@ _unix_desk_sync_into(u2_noun who,
|
||||
if ( u2_no == u2_sing(xun, bur) ) {
|
||||
doz = u2_dc("cost", xun, bur);
|
||||
|
||||
pax = u2nq(c3__gold, c3__sync, u2k(u2A->sen), u2_nul);
|
||||
pax = u2nq(u2_blip, c3__sync, u2k(u2A->sen), u2_nul);
|
||||
fav = u2nq(c3__into, who, syd, u2nt(u2_yes, u2_nul, doz));
|
||||
|
||||
u2_reck_plan(u2A, pax, fav);
|
||||
@ -1177,7 +1177,7 @@ u2_unix_ef_init(u2_noun who)
|
||||
{
|
||||
_unix_hot_gain(u2k(who), u2_yes);
|
||||
|
||||
u2_reck_plan(u2A, u2nq(c3__gold, c3__sync, u2k(u2A->sen), u2_nul),
|
||||
u2_reck_plan(u2A, u2nq(u2_blip, c3__sync, u2k(u2A->sen), u2_nul),
|
||||
u2nq(c3__into, who,
|
||||
u2_blip,
|
||||
u2nq(u2_yes, u2_nul,
|
||||
@ -1299,7 +1299,7 @@ _unix_time_cb(uv_timer_t* tim_u, c3_i sas_i)
|
||||
{
|
||||
u2_reck_plan
|
||||
(u2A,
|
||||
u2nt(c3__gold, c3__clay, u2_nul),
|
||||
u2nt(u2_blip, c3__clay, u2_nul),
|
||||
u2nc(c3__wake, u2_nul));
|
||||
}
|
||||
u2_lo_shut(u2_no);
|
||||
@ -1438,7 +1438,7 @@ void
|
||||
u2_unix_io_poll(void)
|
||||
{
|
||||
u2_unix* unx_u = &u2_Host.unx_u;
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(c3__gold, c3__clay, u2_nul));
|
||||
u2_noun wen = u2_reck_keep(u2A, u2nt(u2_blip, c3__clay, u2_nul));
|
||||
|
||||
if ( (u2_nul != wen) &&
|
||||
(u2_yes == u2du(wen)) &&
|
||||
|
Loading…
Reference in New Issue
Block a user